diff --git a/cmd/kosli/add.go b/cmd/kosli/add.go new file mode 100644 index 00000000..6a615d84 --- /dev/null +++ b/cmd/kosli/add.go @@ -0,0 +1,23 @@ +package main + +import ( + "io" + + "github.com/spf13/cobra" +) + +const addDesc = `All Kosli add commands.` + +func newAddCmd(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "add", + Short: addDesc, + Long: addDesc, + } + + // Add subcommands + cmd.AddCommand( + newAddEnvironmentCmd(out), + ) + return cmd +} diff --git a/cmd/kosli/addEnvironment.go b/cmd/kosli/addEnvironment.go new file mode 100644 index 00000000..5ea287f7 --- /dev/null +++ b/cmd/kosli/addEnvironment.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" + "io" + "net/http" + + "github.com/kosli-dev/cli/internal/requests" + "github.com/spf13/cobra" +) + +const addEnvironmentShortDesc = `Add a physical environment to a logical environment.` + +const addEnvironmentLongDesc = addEnvironmentShortDesc + ` +Add a physical Kosli environment to a logical Kosli environment. +` + +const addEnvironmentExample = ` +# add a physical environment to a logical environment: +kosli add environment \ + --physical prod-k8 \ + --logical prod \ + --api-token yourAPIToken \ + --org yourOrgName +` + +type addEnvironmentOptions struct { + payload AddEnvironmentPayload + logical string +} + +type AddEnvironmentPayload struct { + Pysical string `json:"physical_env_name"` +} + +func newAddEnvironmentCmd(out io.Writer) *cobra.Command { + o := new(addEnvironmentOptions) + cmd := &cobra.Command{ + Use: "environment", + Aliases: []string{"env"}, + Short: addEnvironmentShortDesc, + Long: addEnvironmentLongDesc, + Example: addEnvironmentExample, + Args: cobra.ExactArgs(0), + PreRunE: func(cmd *cobra.Command, args []string) error { + err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) + if err != nil { + return ErrorBeforePrintingUsage(cmd, err.Error()) + } + + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + url := fmt.Sprintf("%s/api/v2/environments/%s/%s/add-physical-env-to-logical", global.Host, global.Org, o.logical) + + reqParams := &requests.RequestParams{ + Method: http.MethodPut, + URL: url, + Payload: o.payload, + DryRun: global.DryRun, + Password: global.ApiToken, + } + _, err := kosliClient.Do(reqParams) + if err == nil && !global.DryRun { + logger.Info("environment '%s' was added to '%s'", o.payload.Pysical, o.logical) + } + return err + }, + } + + cmd.Flags().StringVar(&o.payload.Pysical, "physical", "", physicalEnvFlag) + cmd.Flags().StringVar(&o.logical, "logical", "", logicalEnvFlag) + err := RequireFlags(cmd, []string{"physical", "logical"}) + if err != nil { + logger.Error("failed to configure required flags: %v", err) + } + + addDryRunFlag(cmd) + return cmd +} diff --git a/cmd/kosli/addEnvironment_test.go b/cmd/kosli/addEnvironment_test.go new file mode 100644 index 00000000..fe97f470 --- /dev/null +++ b/cmd/kosli/addEnvironment_test.go @@ -0,0 +1,70 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" +) + +// Define the suite, and absorb the built-in basic suite +// functionality from testify - including a T() method which +// returns the current testing context +type AddEnvironmentCommandTestSuite struct { + suite.Suite + defaultKosliArguments string + logicalEnvName string + physicalEnvName string +} + +func (suite *AddEnvironmentCommandTestSuite) SetupTest() { + suite.logicalEnvName = "mixForAdd" + suite.physicalEnvName = "pysicalToBeAdded" + + global = &GlobalOpts{ + ApiToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6ImNkNzg4OTg5In0.e8i_lA_QrEhFncb05Xw6E_tkCHU9QfcY4OLTVUCHffY", + Org: "docs-cmd-test-user", + Host: "http://localhost:8001", + } + suite.defaultKosliArguments = fmt.Sprintf(" --host %s --org %s --api-token %s", global.Host, global.Org, global.ApiToken) + CreateEnv(global.Org, suite.logicalEnvName, "logical", suite.T()) + CreateEnv(global.Org, suite.physicalEnvName, "server", suite.T()) +} + +func (suite *AddEnvironmentCommandTestSuite) TestAddEnvironmentCmd() { + tests := []cmdTestCase{ + { + name: "can add Physical env to Logical environments", + cmd: fmt.Sprintf(`add environment --physical %s --logical %s %s`, + suite.physicalEnvName, suite.logicalEnvName, suite.defaultKosliArguments), + golden: fmt.Sprintf("environment '%s' was added to '%s'\n", suite.physicalEnvName, suite.logicalEnvName), + }, + { + wantError: true, + name: "must have --physical flag", + cmd: fmt.Sprintf(`add environment --logical %s %s`, suite.logicalEnvName, suite.defaultKosliArguments), + golden: "Error: required flag(s) \"physical\" not set\n", + }, + { + wantError: true, + name: "must have --logical flag", + cmd: fmt.Sprintf(`add environment --physical %s %s`, suite.physicalEnvName, suite.defaultKosliArguments), + golden: "Error: required flag(s) \"logical\" not set\n", + }, + { + wantError: true, + name: "accept no arguments", + cmd: fmt.Sprintf(`add environment --physical %s --logical %s SomeThingExtra %s`, + suite.physicalEnvName, suite.logicalEnvName, suite.defaultKosliArguments), + golden: "Error: accepts 0 arg(s), received 1\n", + }, + } + + runTestCmd(suite.T(), tests) +} + +// In order for 'go test' to run this suite, we need to create +// a normal test function and pass our suite to suite.Run +func TestAddEnvironmentCommandTestSuite(t *testing.T) { + suite.Run(t, new(AddEnvironmentCommandTestSuite)) +} diff --git a/cmd/kosli/root.go b/cmd/kosli/root.go index a1d8c40e..0c8b89ee 100644 --- a/cmd/kosli/root.go +++ b/cmd/kosli/root.go @@ -228,6 +228,8 @@ The ^.kosli_ignore^ will be treated as part of the artifact like any other file, sonarProjectKeyFlag = "[conditional] The project key of the SonarCloud/SonarQube project. Only required if you want to use the project key/revision to get the scan results rather than using Sonar's metadata file." sonarServerURLFlag = "[conditional] The URL of your SonarQube server. Only required if you are using SonarQube and not using SonarQube's metadata file to get scan results." sonarRevisionFlag = "[conditional] The revision of the SonarCloud/SonarQube project. Only required if you want to use the project key/revision to get the scan results rather than using Sonar's metadata file and you have overridden the default revision, or you aren't using a CI. Defaults to the value of the git commit flag." + logicalEnvFlag = "[required] The logical environment." + physicalEnvFlag = "[required] The physical environment." ) var global *GlobalOpts @@ -347,6 +349,7 @@ func newRootCmd(out io.Writer, args []string) (*cobra.Command, error) { newAllowCmd(out), newListCmd(out), newRenameCmd(out), + newAddCmd(out), newArchiveCmd(out), newSnapshotCmd(out), newRequestCmd(out),