Skip to content

Commit

Permalink
feat: add workspace switch cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
healthjyk committed Mar 19, 2024
1 parent 3b2af58 commit ac5fbbb
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 1 deletion.
4 changes: 3 additions & 1 deletion pkg/cmd/workspace/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"kusionstack.io/kusion/pkg/cmd/workspace/del"
"kusionstack.io/kusion/pkg/cmd/workspace/list"
"kusionstack.io/kusion/pkg/cmd/workspace/show"
cmdswitch "kusionstack.io/kusion/pkg/cmd/workspace/switch"
"kusionstack.io/kusion/pkg/cmd/workspace/update"
"kusionstack.io/kusion/pkg/util/i18n"
)
Expand Down Expand Up @@ -37,7 +38,8 @@ func NewCmd() *cobra.Command {
showCmd := show.NewCmd()
listCmd := list.NewCmd()
delCmd := del.NewCmd()
cmd.AddCommand(createCmd, updateCmd, showCmd, listCmd, delCmd)
switchCmd := cmdswitch.NewCmd()
cmd.AddCommand(createCmd, updateCmd, showCmd, listCmd, delCmd, switchCmd)

return cmd
}
45 changes: 45 additions & 0 deletions pkg/cmd/workspace/switch/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package cmdswitch

import (
"github.com/spf13/cobra"
"k8s.io/kubectl/pkg/util/templates"

"kusionstack.io/kusion/pkg/cmd/util"
"kusionstack.io/kusion/pkg/util/i18n"
)

func NewCmd() *cobra.Command {
var (
short = i18n.T(`Switch the current workspace`)

long = i18n.T(`
This command switches the workspace, where the workspace must be created.`)

example = i18n.T(`
# Switch the current workspace
kusion workspace switch dev
# Switch the current workspace in a specified backend
kusion workspace switch prod --backend oss-prod
`)
)

o := NewOptions()
cmd := &cobra.Command{
Use: "switch",
Short: short,
Long: templates.LongDesc(long),
Example: templates.Examples(example),
DisableFlagsInUseLine: true,
RunE: func(cmd *cobra.Command, args []string) (err error) {
defer util.RecoverErr(&err)
util.CheckErr(o.Complete(args))
util.CheckErr(o.Validate())
util.CheckErr(o.Run())
return
},
}

cmd.Flags().StringVarP(&o.Backend, "backend", "", "", i18n.T("the backend name"))
return cmd
}
24 changes: 24 additions & 0 deletions pkg/cmd/workspace/switch/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cmdswitch

import (
"testing"

"github.com/bytedance/mockey"
"github.com/stretchr/testify/assert"
)

func TestNewCmd(t *testing.T) {
t.Run("successfully switch workspace", func(t *testing.T) {
mockey.PatchConvey("mock cmd", t, func() {
mockey.Mock((*Options).Complete).To(func(o *Options, args []string) error {
o.Name = "dev"
return nil
}).Build()
mockey.Mock((*Options).Run).Return(nil).Build()

cmd := NewCmd()
err := cmd.Execute()
assert.Nil(t, err)
})
})
}
46 changes: 46 additions & 0 deletions pkg/cmd/workspace/switch/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cmdswitch

import (
"fmt"

"kusionstack.io/kusion/pkg/backend"
"kusionstack.io/kusion/pkg/cmd/workspace/util"
)

type Options struct {
Name string
Backend string
}

func NewOptions() *Options {
return &Options{}
}

func (o *Options) Complete(args []string) error {
name, err := util.GetNameFromArgs(args)
if err != nil {
return err
}
o.Name = name
return nil
}

func (o *Options) Validate() error {
if err := util.ValidateName(o.Name); err != nil {
return err
}
return nil
}

func (o *Options) Run() error {
storage, err := backend.NewWorkspaceStorage(o.Backend)
if err != nil {
return err
}

if err = storage.SetCurrent(o.Name); err != nil {
return err
}
fmt.Printf("switch current workspace to %s successfully\n", o.Name)
return nil
}
104 changes: 104 additions & 0 deletions pkg/cmd/workspace/switch/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package cmdswitch

import (
"reflect"
"testing"

"github.com/bytedance/mockey"
"github.com/stretchr/testify/assert"

v1 "kusionstack.io/kusion/pkg/apis/core/v1"
"kusionstack.io/kusion/pkg/backend"
"kusionstack.io/kusion/pkg/cmd/workspace/util"
workspacestorages "kusionstack.io/kusion/pkg/workspace/storages"
)

func TestOptions_Complete(t *testing.T) {
testcases := []struct {
name string
args []string
success bool
expectedOpts *Options
}{
{
name: "successfully complete options",
args: []string{"dev"},
success: true,
expectedOpts: &Options{Name: "dev"},
},
{
name: "complete field invalid args",
args: []string{"dev", "prod"},
success: false,
expectedOpts: nil,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
opts := NewOptions()
err := opts.Complete(tc.args)
assert.Equal(t, tc.success, err == nil)
if tc.success {
assert.True(t, reflect.DeepEqual(opts, tc.expectedOpts))
}
})
}
}

func TestOptions_Validate(t *testing.T) {
testcases := []struct {
name string
opts *Options
success bool
}{
{
name: "valid options",
opts: &Options{
Name: "dev",
},
success: true,
},
{
name: "invalid options empty name",
opts: &Options{},
success: false,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
err := tc.opts.Validate()
assert.Equal(t, tc.success, err == nil)
})
}
}

func TestOptions_Run(t *testing.T) {
testcases := []struct {
name string
opts *Options
success bool
}{
{
name: "successfully run",
opts: &Options{
Name: "dev",
},
success: true,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
mockey.PatchConvey("mock switch workspace", t, func() {
mockey.Mock(backend.NewWorkspaceStorage).Return(&workspacestorages.LocalStorage{}, nil).Build()
mockey.Mock((*workspacestorages.LocalStorage).SetCurrent).Return(nil).Build()
mockey.Mock(util.GetValidWorkspaceFromFile).Return(&v1.Workspace{Name: "dev"}, nil).Build()

err := tc.opts.Run()
assert.Equal(t, tc.success, err == nil)
})
})
}
}

0 comments on commit ac5fbbb

Please sign in to comment.