Skip to content

Commit

Permalink
feat: add config cmd, including subcmds get,list,set,unset (#950)
Browse files Browse the repository at this point in the history
  • Loading branch information
healthjyk committed Mar 21, 2024
1 parent b3d65e6 commit 6e33e7b
Show file tree
Hide file tree
Showing 21 changed files with 1,031 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/evanphx/json-patch v4.12.0+incompatible
github.com/fluxcd/pkg/sourceignore v0.5.0
github.com/fluxcd/pkg/tar v0.4.0
github.com/go-git/go-git/v5 v5.11.0
github.com/go-sql-driver/mysql v1.7.0
github.com/go-test/deep v1.0.3
github.com/goccy/go-yaml v1.11.0
Expand Down Expand Up @@ -95,7 +96,6 @@ require (
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-git/go-git/v5 v5.11.0 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 h1:X9dsIWPuuEJlPX//UmRKophhOKCGXc46RVIGuttks68=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7/go.mod h1:UxoP3EypF8JfGEjAII8jx1q8rQyDnX8qdTCs/UQBVIE=
github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
Expand Down
39 changes: 39 additions & 0 deletions pkg/cmd/config/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package config

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

"kusionstack.io/kusion/pkg/cmd/config/get"
"kusionstack.io/kusion/pkg/cmd/config/list"
"kusionstack.io/kusion/pkg/cmd/config/set"
"kusionstack.io/kusion/pkg/cmd/config/unset"
"kusionstack.io/kusion/pkg/util/i18n"
)

func NewCmd() *cobra.Command {
var (
short = i18n.T(`Interact with the Kusion config`)

long = i18n.T(`
Config contains the operation of Kusion configurations.`)
)

cmd := &cobra.Command{
Use: "config",
Short: short,
Long: templates.LongDesc(long),
SilenceErrors: true,
RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Help()
},
}

getCmd := get.NewCmd()
listCmd := list.NewCmd()
setCmd := set.NewCmd()
unsetCmd := unset.NewCmd()
cmd.AddCommand(getCmd, listCmd, setCmd, unsetCmd)

return cmd
}
14 changes: 14 additions & 0 deletions pkg/cmd/config/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package config

import (
"testing"

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

func TestNewCmd(t *testing.T) {
t.Run("successfully get config help", func(t *testing.T) {
cmd := NewCmd()
assert.NotNil(t, cmd)
})
}
39 changes: 39 additions & 0 deletions pkg/cmd/config/get/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package get

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(`Get a config item`)

long = i18n.T(`
This command gets the value of a specified kusion config item, where the config item must be registered.`)

example = i18n.T(`
# Get a config item
kusion config get backends.current`)
)

o := NewOptions()
cmd := &cobra.Command{
Use: "get",
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
},
}
return cmd
}
24 changes: 24 additions & 0 deletions pkg/cmd/config/get/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package get

import (
"testing"

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

func TestNewCmd(t *testing.T) {
t.Run("successfully get config item", func(t *testing.T) {
mockey.PatchConvey("mock cmd", t, func() {
mockey.Mock((*Options).Complete).To(func(o *Options, args []string) error {
o.Item = "backends.current"
return nil
}).Build()
mockey.Mock((*Options).Run).Return(nil).Build()

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

import (
"fmt"

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

type Options struct {
Item string
}

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

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

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

func (o *Options) Run() error {
val, err := config.GetEncodedConfigItem(o.Item)
if err != nil {
return err
}

fmt.Print(val)
return nil
}
100 changes: 100 additions & 0 deletions pkg/cmd/config/get/options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package get

import (
"testing"

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

"kusionstack.io/kusion/pkg/config"
)

func TestOptions_Complete(t *testing.T) {
testcases := []struct {
name string
args []string
success bool
expectedOpts *Options
}{
{
name: "successfully complete options",
args: []string{"backends.current"},
success: true,
expectedOpts: &Options{
Item: "backends.current",
},
},
{
name: "complete field invalid args",
args: nil,
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.Equal(t, tc.expectedOpts, opts)
}
})
}
}

func TestOptions_Validate(t *testing.T) {
testcases := []struct {
name string
opts *Options
success bool
}{
{
name: "valid options",
opts: &Options{
Item: "backends.current",
},
success: true,
},
{
name: "invalid options empty config item",
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{
Item: "backends.current",
},
success: true,
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
mockey.PatchConvey("mock get config item", t, func() {
mockey.Mock(config.GetEncodedConfigItem).Return("", nil).Build()

err := tc.opts.Run()
assert.Equal(t, tc.success, err == nil)
})
})
}
}
60 changes: 60 additions & 0 deletions pkg/cmd/config/list/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package list

import (
"fmt"

"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
"k8s.io/kubectl/pkg/util/templates"

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

func NewCmd() *cobra.Command {
var (
short = i18n.T(`List all config items`)

long = i18n.T(`
This command lists all the kusion config items and their values.`)

example = i18n.T(`
# List config items
kusion config list`)
)

cmd := &cobra.Command{
Use: "list",
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(Validate(args))
util.CheckErr(Run())
return
},
}
return cmd
}

func Validate(args []string) error {
return configutil.ValidateNoArg(args)
}

func Run() error {
cfg, err := config.GetConfig()
if err != nil {
return err
}

content, err := yaml.Marshal(cfg)
if err != nil {
return fmt.Errorf("yaml marshal config configuration failed: %w", err)
}
fmt.Print(string(content))
return nil
}
Loading

0 comments on commit 6e33e7b

Please sign in to comment.