diff --git a/cmd/kosli/rename.go b/cmd/kosli/rename.go index 0abdd3cc6..0dcc76a6b 100644 --- a/cmd/kosli/rename.go +++ b/cmd/kosli/rename.go @@ -18,6 +18,7 @@ func newRenameCmd(out io.Writer) *cobra.Command { // Add subcommands cmd.AddCommand( newRenameEnvironmentCmd(out), + newRenameFlowCmd(out), ) return cmd } diff --git a/cmd/kosli/renameEnvironment_test.go b/cmd/kosli/renameEnvironment_test.go index 800736568..c5576dc01 100644 --- a/cmd/kosli/renameEnvironment_test.go +++ b/cmd/kosli/renameEnvironment_test.go @@ -28,7 +28,7 @@ func (suite *RenameEnvironmentCommandTestSuite) SetupTest() { CreateEnv(global.Org, suite.envName, "server", suite.T()) } -func (suite *RenameEnvironmentCommandTestSuite) TestListSnapshotsCmd() { +func (suite *RenameEnvironmentCommandTestSuite) TestRenameEnvironmentCmd() { tests := []cmdTestCase{ { name: "can rename environment", diff --git a/cmd/kosli/renameFlow.go b/cmd/kosli/renameFlow.go new file mode 100644 index 000000000..6b5c72d4a --- /dev/null +++ b/cmd/kosli/renameFlow.go @@ -0,0 +1,65 @@ +package main + +import ( + "fmt" + "io" + "net/http" + + "github.com/kosli-dev/cli/internal/requests" + "github.com/spf13/cobra" +) + +const renameFlowShortDesc = `Rename a Kosli flow.` + +const renameFlowLongDesc = renameFlowShortDesc + ` +The flow will remain accessible under its old name until that name is taken by another flow. +` + +const renameFlowExample = ` +# rename a Kosli flow: +kosli rename flow oldName newName \ + --api-token yourAPIToken \ + --org yourOrgName +` + +type RenameFlowPayload struct { + NewName string `json:"new_name"` +} + +func newRenameFlowCmd(out io.Writer) *cobra.Command { + payload := new(RenameFlowPayload) + cmd := &cobra.Command{ + Use: "flow OLD_NAME NEW_NAME", + Short: renameFlowShortDesc, + Long: renameFlowLongDesc, + Example: renameFlowExample, + Args: cobra.ExactArgs(2), + 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/flows/%s/%s/rename", global.Host, global.Org, args[0]) + payload.NewName = args[1] + + reqParams := &requests.RequestParams{ + Method: http.MethodPut, + URL: url, + Payload: payload, + DryRun: global.DryRun, + Password: global.ApiToken, + } + _, err := kosliClient.Do(reqParams) + if err == nil && !global.DryRun { + logger.Info("flow %s was renamed to %s", args[0], payload.NewName) + } + return err + }, + } + addDryRunFlag(cmd) + return cmd +} diff --git a/cmd/kosli/renameFlow_test.go b/cmd/kosli/renameFlow_test.go new file mode 100644 index 000000000..2dfd13838 --- /dev/null +++ b/cmd/kosli/renameFlow_test.go @@ -0,0 +1,71 @@ +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 RenameFlowCommandTestSuite struct { + suite.Suite + defaultKosliArguments string + flowName string +} + +func (suite *RenameFlowCommandTestSuite) SetupTest() { + suite.flowName = "rename-flow" + + 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) + CreateFlow(suite.flowName, suite.T()) +} + +func (suite *RenameFlowCommandTestSuite) TestRenameFlowCmd() { + tests := []cmdTestCase{ + { + name: "can rename flow", + cmd: fmt.Sprintf(`rename flow %s new-name-456 %s`, suite.flowName, suite.defaultKosliArguments), + golden: "flow rename-flow was renamed to new-name-456\n", + }, + { + wantError: true, + name: "renaming flow fails if the new name is illegal", + cmd: fmt.Sprintf(`rename flow %s new_illegal_name %s`, suite.flowName, suite.defaultKosliArguments), + golden: "Error: 'new_illegal_name' is an invalid name for flows. Valid names should only contain alphanumeric characters, '.', and '-'.\n", + }, + { + wantError: true, + name: "renaming non-existing flow fails", + cmd: fmt.Sprintf(`rename flow non-existing new-name-345 %s`, suite.defaultKosliArguments), + golden: "Error: Flow named 'non-existing' does not exist for organization 'docs-cmd-test-user'\n", + }, + { + wantError: true, + name: "rename flow fails when 3 args are provided", + cmd: fmt.Sprintf(`rename flow %s arg2 arg3 %s`, suite.flowName, suite.defaultKosliArguments), + golden: "Error: accepts 2 arg(s), received 3\n", + }, + { + wantError: true, + name: "rename flow fails when no args are provided", + cmd: fmt.Sprintf(`rename flow %s`, suite.defaultKosliArguments), + golden: "Error: accepts 2 arg(s), received 0\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 TestRenameFlowCommandTestSuite(t *testing.T) { + suite.Run(t, new(RenameFlowCommandTestSuite)) +}