diff --git a/.vscode/launch.json b/.vscode/launch.json index 7f89c7f..62edd92 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch Package", + "name": "b3lbctl init config", "type": "go", "request": "launch", "mode": "auto", @@ -14,6 +14,17 @@ "init", "config" ] + }, + { + "name": "b3lbctl init instances", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "cmd/b3lbctl/main.go", + "args": [ + "init", + "instances" + ] } ] } \ No newline at end of file diff --git a/pkg/cmd/init/config.go b/pkg/cmd/init/config.go index 1ee4e3f..192303a 100644 --- a/pkg/cmd/init/config.go +++ b/pkg/cmd/init/config.go @@ -13,11 +13,13 @@ import ( const fsRights = 0755 +// InitConfigCmd represents the `b3lbctl init config` command type InitConfigCmd struct { Command *cobra.Command - Flags *InitConfigFlags + Flags *ConfigFlags } +// NewInitConfigCmd initialize a new InitConfigCmd struct func NewInitConfigCmd() *cobra.Command { cmd := &InitConfigCmd{ Command: &cobra.Command{ @@ -31,31 +33,23 @@ func NewInitConfigCmd() *cobra.Command { cmd.ApplyFlags() cmd.Command.RunE = cmd.init + cmd.Command.PreRunE = cmd.prerun return cmd.Command } +// ApplyFlags apply command flags to InitConfigCmd func (cmd *InitConfigCmd) ApplyFlags() { cmd.Command.Flags().StringVarP(&cmd.Flags.B3LB, "b3lb", "b", "", "B3lb url") cmd.Command.Flags().StringVarP(&cmd.Flags.APIKey, "key", "k", "", "B3lb admin api key") - cmd.Command.Flags().StringVarP(&cmd.Flags.Destination, "destination", "d", b3lbconfig.DefaultConfigFolder, "Configuration file folder destination") + cmd.Command.Flags().StringVarP(&cmd.Flags.Destination, "dest", "d", b3lbconfig.DefaultConfigFolder, "Configuration file folder destination") } func (cmd *InitConfigCmd) init(command *cobra.Command, args []string) error { - cmd.Command.SilenceUsage = true dest := cmd.Flags.Destination - if dest == b3lbconfig.DefaultConfigFolder { - formalized, err := formalizeDefaultConfigFolder() - if err != nil { - return fmt.Errorf("unable to initialize configuration: %s", err.Error()) - } - - dest = formalized - } - filePath := path.Join(dest, config.DefaultConfigFileName) - if info, _ := os.Stat(filePath); info != nil { + if fileAlreadyExists(filePath) { return fmt.Errorf("configuration already exists, see %s", filePath) } @@ -70,7 +64,7 @@ func (cmd *InitConfigCmd) init(command *cobra.Command, args []string) error { content, err := yaml.Marshal(conf) if err != nil { - return fmt.Errorf("unable to marshal yaml configuation: %s", err.Error()) + return fmt.Errorf("unable to marshal yaml configuration: %s", err.Error()) } if err := os.WriteFile(path.Join(dest, config.DefaultConfigFileName), content, fsRights); err != nil { @@ -80,11 +74,13 @@ func (cmd *InitConfigCmd) init(command *cobra.Command, args []string) error { return nil } -func formalizeDefaultConfigFolder() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", err +func (cmd *InitConfigCmd) prerun(command *cobra.Command, args []string) error { + cmd.Command.SilenceUsage = true + dest, err := processDestination(cmd.Flags.Destination) + if err == nil { + cmd.Flags.Destination = dest + return nil } - return path.Join(home, ".b3lb"), nil + return err } diff --git a/pkg/cmd/init/config_test.go b/pkg/cmd/init/config_test.go index e78c515..7a610cc 100644 --- a/pkg/cmd/init/config_test.go +++ b/pkg/cmd/init/config_test.go @@ -20,11 +20,11 @@ func TestInitConfig(t *testing.T) { return } - os.Remove(fmt.Sprintf("%s/.b3lb/.b3lbctl.yml", homedir)) + os.Remove(fmt.Sprintf("%s/.b3lb", homedir)) tests := []test.CmdTest{ { - Name: "a valid request should init configuration with parameters", + Name: "a valid command should init configuration with parameters", Mock: func() {}, Args: []string{"-b", "http://localhost:8090", "-k", "api_key"}, Validator: func(t *testing.T, output *bytes.Buffer, err error) { diff --git a/pkg/cmd/init/flags.go b/pkg/cmd/init/flags.go index 1eb0a35..611f491 100644 --- a/pkg/cmd/init/flags.go +++ b/pkg/cmd/init/flags.go @@ -1,11 +1,23 @@ package init -type InitConfigFlags struct { +// ConfigFlags represents `b3lbctl init config` flags +type ConfigFlags struct { B3LB string APIKey string Destination string } -func NewInitConfigFlags() *InitConfigFlags { - return &InitConfigFlags{} +// NewInitConfigFlags initialize a new InitConfigFlags struct +func NewInitConfigFlags() *ConfigFlags { + return &ConfigFlags{} +} + +// InstancesFlags represents `b3lbctl init instances` flags +type InstancesFlags struct { + Destination string +} + +// NewInitInstancesFlags initialize a new InitInstancesFlags struct +func NewInitInstancesFlags() *InstancesFlags { + return &InstancesFlags{} } diff --git a/pkg/cmd/init/helper.go b/pkg/cmd/init/helper.go new file mode 100644 index 0000000..84ebd28 --- /dev/null +++ b/pkg/cmd/init/helper.go @@ -0,0 +1,10 @@ +package init + +import ( + "os" +) + +func fileAlreadyExists(path string) bool { + info, _ := os.Stat(path) + return info != nil +} diff --git a/pkg/cmd/init/init.go b/pkg/cmd/init/init.go index 545e294..d6f6027 100644 --- a/pkg/cmd/init/init.go +++ b/pkg/cmd/init/init.go @@ -17,6 +17,7 @@ func NewCmd() *cobra.Command { } cmd.AddCommand(NewInitConfigCmd()) + cmd.AddCommand(NewInitInstancesCmd()) return cmd } diff --git a/pkg/cmd/init/instances.go b/pkg/cmd/init/instances.go new file mode 100644 index 0000000..9902425 --- /dev/null +++ b/pkg/cmd/init/instances.go @@ -0,0 +1,83 @@ +package init + +import ( + "fmt" + "os" + "path" + + b3lbadmin "github.com/SLedunois/b3lb/v2/pkg/admin" + b3lbconfig "github.com/SLedunois/b3lb/v2/pkg/config" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" +) + +const instancesConfigFilename = "instances.yml" + +// InstancesCmd represents the `b3lbctl init instances` command +type InstancesCmd struct { + Command *cobra.Command + Flags *InstancesFlags +} + +// NewInitInstancesCmd initialize a new InitInstancesCmd +func NewInitInstancesCmd() *cobra.Command { + cmd := &InstancesCmd{ + Command: &cobra.Command{ + Use: "instances [flags]", + Short: "Initialize b3lb instances file", + Long: "Create instances list file if it does not exists", + }, + Flags: NewInitInstancesFlags(), + } + + cmd.ApplyFlags() + + cmd.Command.RunE = cmd.init + cmd.Command.PreRunE = cmd.preRunE + + return cmd.Command +} + +// ApplyFlags apply command flags to InitInstancesCmd +func (cmd *InstancesCmd) ApplyFlags() { + cmd.Command.Flags().StringVarP(&cmd.Flags.Destination, "dest", "d", b3lbconfig.DefaultConfigFolder, "File folder destination") +} + +func (cmd *InstancesCmd) init(command *cobra.Command, args []string) error { + destFile := path.Join(cmd.Flags.Destination, instancesConfigFilename) + if fileAlreadyExists(destFile) { + return fmt.Errorf("instances configuration file already exists. Please consider editing %s file", destFile) + } + + instances := &b3lbadmin.InstanceList{ + Kind: "InstanceList", + } + + if err := os.MkdirAll(cmd.Flags.Destination, fsRights); err != nil { + return fmt.Errorf("unable to create destination folder: %s", err.Error()) + } + + content, err := yaml.Marshal(instances) + if err != nil { + return fmt.Errorf("unable to marshal yaml instances file: %s", err.Error()) + } + + if err := os.WriteFile(destFile, content, fsRights); err != nil { + return fmt.Errorf("failed to write instances file: %s", err.Error()) + } + + command.Println(fmt.Sprintf("instances file successfully initialized. Please check %s file", destFile)) + + return nil +} + +func (cmd *InstancesCmd) preRunE(command *cobra.Command, args []string) error { + cmd.Command.SilenceUsage = true + dest, err := processDestination(cmd.Flags.Destination) + if err == nil { + cmd.Flags.Destination = dest + return nil + } + + return err +} diff --git a/pkg/cmd/init/instances_test.go b/pkg/cmd/init/instances_test.go new file mode 100644 index 0000000..f8df64e --- /dev/null +++ b/pkg/cmd/init/instances_test.go @@ -0,0 +1,69 @@ +package init + +import ( + "bytes" + "fmt" + "os" + "testing" + + b3lbadmin "github.com/SLedunois/b3lb/v2/pkg/admin" + "github.com/SLedunois/b3lbctl/internal/test" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" +) + +func TestInitInstances(t *testing.T) { + homedir, err := os.UserHomeDir() + if err != nil { + t.Fatal(err) + return + } + + os.Remove(fmt.Sprintf("%s/.b3lb", homedir)) + + tests := []test.CmdTest{ + { + Name: "a valid command should init instances configuration file", + Mock: func() {}, + Args: []string{}, + Validator: func(t *testing.T, output *bytes.Buffer, err error) { + file := fmt.Sprintf("%s/.b3lb/instances.yml", homedir) + b, err := os.ReadFile(file) + if err != nil { + t.Fatal(err) + return + } + + var instances b3lbadmin.InstanceList + if err := yaml.Unmarshal(b, &instances); err != nil { + t.Fatal(err) + return + } + + assert.Equal(t, "InstanceList", instances.Kind) + assert.Equal(t, 0, len(instances.Instances)) + }, + }, + { + Name: "an existing file should return an error", + Mock: func() {}, + Args: []string{}, + Validator: func(t *testing.T, output *bytes.Buffer, err error) { + assert.NotNil(t, err) + assert.Equal(t, "instances configuration file already exists. Please consider editing /home/codespace/.b3lb/instances.yml file", err.Error()) + }, + }, + } + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + b := bytes.NewBufferString("") + cmd := NewInitInstancesCmd() + cmd.SetArgs(test.Args) + cmd.SetOut(b) + test.Mock() + err := cmd.Execute() + test.Validator(t, b, err) + }) + } +} diff --git a/pkg/cmd/init/prerun.go b/pkg/cmd/init/prerun.go new file mode 100644 index 0000000..01834ed --- /dev/null +++ b/pkg/cmd/init/prerun.go @@ -0,0 +1,31 @@ +package init + +import ( + "fmt" + "os" + "path" + + b3lbconfig "github.com/SLedunois/b3lb/v2/pkg/config" +) + +func processDestination(dest string) (string, error) { + if dest == b3lbconfig.DefaultConfigFolder { + formalized, err := formalizeDefaultConfigFolder() + if err != nil { + return "", fmt.Errorf("unable to initialize configuration: %s", err.Error()) + } + + dest = formalized + } + + return dest, nil +} + +func formalizeDefaultConfigFolder() (string, error) { + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + + return path.Join(home, ".b3lb"), nil +}