From a3d944e68f0902beb7e33c9e1461082f26044cf5 Mon Sep 17 00:00:00 2001 From: Tore Martin Hagen Date: Mon, 27 Jul 2026 14:53:13 +0200 Subject: [PATCH] feat!: remove deprecated approval commands Removes kosli assert approval, get approval, list approvals, report approval, and request approval, all of which have been deprecated for a while. The request parent command is also removed since request approval was its only subcommand. Co-Authored-By: Claude Sonnet 5 --- cmd/kosli/assert.go | 1 - cmd/kosli/assertApproval.go | 131 -------- cmd/kosli/assertApproval_test.go | 139 --------- cmd/kosli/get.go | 1 - cmd/kosli/getApproval.go | 167 ---------- cmd/kosli/getApproval_test.go | 86 ------ cmd/kosli/list.go | 1 - cmd/kosli/listApprovals.go | 147 --------- cmd/kosli/listApprovals_test.go | 98 ------ cmd/kosli/pipelineCommand_test.go | 17 -- cmd/kosli/report.go | 1 - cmd/kosli/reportApproval.go | 287 ------------------ cmd/kosli/reportApproval_test.go | 97 ------ cmd/kosli/request.go | 25 -- cmd/kosli/requestApproval.go | 100 ------ cmd/kosli/root.go | 5 - cmd/kosli/testHelpers.go | 27 -- .../output/get/get-approval-latest.txt | 13 - .../testdata/output/get/get-approval.txt | 13 - .../testdata/output/list/list-approvals.txt | 5 - internal/docgen/mintlify.go | 4 +- 21 files changed, 1 insertion(+), 1364 deletions(-) delete mode 100644 cmd/kosli/assertApproval.go delete mode 100644 cmd/kosli/assertApproval_test.go delete mode 100644 cmd/kosli/getApproval.go delete mode 100644 cmd/kosli/getApproval_test.go delete mode 100644 cmd/kosli/listApprovals.go delete mode 100644 cmd/kosli/listApprovals_test.go delete mode 100644 cmd/kosli/reportApproval.go delete mode 100644 cmd/kosli/reportApproval_test.go delete mode 100644 cmd/kosli/request.go delete mode 100644 cmd/kosli/requestApproval.go delete mode 100644 cmd/kosli/testdata/output/get/get-approval-latest.txt delete mode 100644 cmd/kosli/testdata/output/get/get-approval.txt delete mode 100644 cmd/kosli/testdata/output/list/list-approvals.txt diff --git a/cmd/kosli/assert.go b/cmd/kosli/assert.go index f028fc86c..163f917c3 100644 --- a/cmd/kosli/assert.go +++ b/cmd/kosli/assert.go @@ -21,7 +21,6 @@ func newAssertCmd(out io.Writer) *cobra.Command { newAssertStatusCmd(out), newAssertArtifactCmd(out), newAssertSnapshotCmd(out), - newAssertApprovalCmd(out), ) return cmd diff --git a/cmd/kosli/assertApproval.go b/cmd/kosli/assertApproval.go deleted file mode 100644 index 090955b8b..000000000 --- a/cmd/kosli/assertApproval.go +++ /dev/null @@ -1,131 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - - "github.com/kosli-dev/cli/internal/requests" - "github.com/spf13/cobra" -) - -const assertApprovalShortDesc = `Assert an artifact in Kosli has been approved for deployment. ` - -const assertApprovalLongDesc = assertApprovalShortDesc + ` -Exits with non-zero code if the artifact has not been approved. -` + fingerprintDesc - -const assertApprovalExample = ` -# Assert that a file type artifact has been approved -kosli assert approval FILE.tgz \ - --api-token yourAPIToken \ - --artifact-type file \ - --org yourOrgName \ - --flow yourFlowName - - -# Assert that an artifact with a provided fingerprint (sha256) has been approved -kosli assert approval \ - --api-token yourAPIToken \ - --org yourOrgName \ - --flow yourFlowName \ - --fingerprint yourArtifactFingerprint -` - -type assertApprovalOptions struct { - fingerprintOptions *fingerprintOptions - fingerprint string - flowName string -} - -func newAssertApprovalCmd(out io.Writer) *cobra.Command { - o := new(assertApprovalOptions) - o.fingerprintOptions = new(fingerprintOptions) - cmd := &cobra.Command{ - Use: "approval [IMAGE-NAME | FILE-PATH | DIR-PATH]", - Short: assertApprovalShortDesc, - Long: assertApprovalLongDesc, - Example: assertApprovalExample, - Deprecated: deprecatedCommandMsg, - PreRunE: func(cmd *cobra.Command, args []string) error { - err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - - err = ValidateArtifactArg(args, o.fingerprintOptions.artifactType, o.fingerprint, false) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - - err = MuXRequiredFlags(cmd, []string{"fingerprint", "artifact-type"}, true) - if err != nil { - return err - } - - return ValidateRegistryFlags(cmd, o.fingerprintOptions) - - }, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run(args) - }, - } - - cmd.Flags().StringVarP(&o.fingerprint, "fingerprint", "F", "", fingerprintFlag) - cmd.Flags().StringVarP(&o.flowName, "flow", "f", "", flowNameFlag) - addFingerprintFlags(cmd, o.fingerprintOptions) - addDryRunFlag(cmd) - - err := RequireFlags(cmd, []string{"flow"}) - if err != nil { - logger.Error("failed to configure required flags: %v", err) - } - - return cmd -} - -func (o *assertApprovalOptions) run(args []string) error { - var err error - if o.fingerprint == "" { - o.fingerprint, err = GetSha256Digest(args[0], o.fingerprintOptions, logger) - if err != nil { - return err - } - } - - url, err := url.JoinPath(global.Host, "api/v2/artifacts", global.Org, o.flowName, o.fingerprint, "approvals") - if err != nil { - return err - } - - reqParams := &requests.RequestParams{ - Method: http.MethodGet, - URL: url, - Token: global.ApiToken, - } - response, err := kosliClient.Do(reqParams) - if err != nil { - return err - } - - var approvals []map[string]interface{} - - err = json.Unmarshal([]byte(response.Body), &approvals) - if err != nil { - return err - } - if len(approvals) == 0 { - return fmt.Errorf("artifact with fingerprint %s has no approvals created", o.fingerprint) - } - - state, ok := approvals[len(approvals)-1]["state"].(string) - if ok && state == "APPROVED" { - approvalNumber := approvals[len(approvals)-1]["release_number"] - logger.Info("artifact with fingerprint %s is approved (approval no. [%v])", o.fingerprint, approvalNumber) - return nil - } else { - return fmt.Errorf("artifact with fingerprint %s is not approved", o.fingerprint) - } -} diff --git a/cmd/kosli/assertApproval_test.go b/cmd/kosli/assertApproval_test.go deleted file mode 100644 index a5586f406..000000000 --- a/cmd/kosli/assertApproval_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - "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 AssertApprovalCommandTestSuite struct { - suite.Suite - defaultKosliArguments string - flowName string - artifactName string - artifactPath string - fingerprint string -} - -type assertApprovalTestConfig struct { - createApproval bool - isRequest bool -} - -func (suite *AssertApprovalCommandTestSuite) SetupTest() { - suite.flowName = "assert-approval" - suite.artifactName = "arti" - suite.artifactPath = "testdata/folder1/hello.txt" - 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()) - fingerprintOptions := &fingerprintOptions{ - artifactType: "file", - } - var err error - suite.fingerprint, err = GetSha256Digest(suite.artifactPath, fingerprintOptions, logger) - require.NoError(suite.T(), err) - CreateArtifact(suite.flowName, suite.fingerprint, suite.artifactName, suite.T()) -} - -func (suite *AssertApprovalCommandTestSuite) TestAssertApprovalCmd() { - tests := []cmdTestCase{ - { - wantError: true, - name: "1 missing --org fails", - cmd: fmt.Sprintf(`assert approval --fingerprint 8e568bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c --flow %s --api-token secret`, suite.flowName), - golden: cmdDeprecationLine("approval") + "Error: --org is not set\nUsage: kosli assert approval [IMAGE-NAME | FILE-PATH | DIR-PATH] [flags]\n", - }, - { - wantError: true, - name: "2 asserting approval for a non existing artifact fails", - cmd: fmt.Sprintf(`assert approval --fingerprint 8e568bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c --flow %s %s`, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: Artifact with fingerprint '8e568bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c' does not exist in flow 'assert-approval' belonging to organization 'docs-cmd-test-user'\n", - }, - { - wantError: true, - name: "3 asserting an existing artifact that does not have an approval (using --fingerprint) works and exits with non-zero code", - cmd: fmt.Sprintf(`assert approval --fingerprint %s --flow %s %s`, suite.fingerprint, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 has no approvals created\n", - }, - { - wantError: true, - name: "4 asserting approval of an existing artifact that does not have an approval (using --artifact-type) works and exits with non-zero code", - cmd: fmt.Sprintf(`assert approval %s --artifact-type file --flow %s %s`, suite.artifactPath, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 has no approvals created\n", - }, - { - name: "5 asserting approval of an existing artifact that has an approval (using --artifact-type) works and exits with zero code", - cmd: fmt.Sprintf(`assert approval %s --artifact-type file --flow %s %s`, suite.artifactPath, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 is approved (approval no. [1])\n", - additionalConfig: assertApprovalTestConfig{ - createApproval: true, - isRequest: false, - }, - }, - //The approval created in test 5 is valid for this test also - { - name: "6 asserting approval of an existing artifact that has an approval (using --fingerprint) works and exits with zero code", - cmd: fmt.Sprintf(`assert approval --fingerprint %s --flow %s %s`, suite.fingerprint, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 is approved (approval no. [1])\n", - }, - { - wantError: true, - name: "7 not providing --fingerprint nor --artifact-type fails", - cmd: fmt.Sprintf(`assert approval --flow %s %s`, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: docker image name or file/dir path is required when --fingerprint is not provided\nUsage: kosli assert approval [IMAGE-NAME | FILE-PATH | DIR-PATH] [flags]\n", - }, - { - wantError: true, - name: "8 providing both --fingerprint and --artifact-type fails", - cmd: fmt.Sprintf(`assert approval --artifact-type file --fingerprint %s --flow %s %s`, suite.fingerprint, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: only one of --fingerprint, --artifact-type is allowed\n", - }, - { - wantError: true, - name: "9 missing --flow fails", - cmd: fmt.Sprintf(`assert approval --fingerprint %s %s`, suite.fingerprint, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: required flag(s) \"flow\" not set\n", - }, - { - wantError: true, - name: "10 asserting approval of an unapproved existing artifact (using --artifact-type) works and exits with non-zero code", - cmd: fmt.Sprintf(`assert approval %s --artifact-type file --flow %s %s`, suite.artifactPath, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 is not approved\n", - additionalConfig: assertApprovalTestConfig{ - createApproval: true, - isRequest: true, - }, - }, - // The approval request created in test 9 is valid here too - { - wantError: true, - name: "11 asserting approval of an unapproved existing artifact (using --fingerprint) works and exits with non-zero code", - cmd: fmt.Sprintf(`assert approval --fingerprint %s --flow %s %s`, suite.fingerprint, suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: artifact with fingerprint fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 is not approved\n", - }, - } - - for _, t := range tests { - if t.additionalConfig != nil && t.additionalConfig.(assertApprovalTestConfig).createApproval { - CreateApproval(suite.flowName, suite.fingerprint, t.additionalConfig.(assertApprovalTestConfig).isRequest, suite.T()) - } - runTestCmd(suite.T(), []cmdTestCase{t}) - } -} - -// 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 TestAssertApprovalCommandTestSuite(t *testing.T) { - suite.Run(t, new(AssertApprovalCommandTestSuite)) -} diff --git a/cmd/kosli/get.go b/cmd/kosli/get.go index 5851bc6ac..cdfd7d5a3 100644 --- a/cmd/kosli/get.go +++ b/cmd/kosli/get.go @@ -19,7 +19,6 @@ func newGetCmd(out io.Writer) *cobra.Command { // Add subcommands cmd.AddCommand( newGetApiKeyCmd(out), - newGetApprovalCmd(out), newGetArtifactCmd(out), newGetEnvironmentCmd(out), newGetFlowCmd(out), diff --git a/cmd/kosli/getApproval.go b/cmd/kosli/getApproval.go deleted file mode 100644 index 792a9203a..000000000 --- a/cmd/kosli/getApproval.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - - "github.com/kosli-dev/cli/internal/output" - "github.com/kosli-dev/cli/internal/requests" - "github.com/spf13/cobra" -) - -const getApprovalShortDesc = `Get an approval from a specified flow.` - -const getApprovalLongDesc = getApprovalShortDesc + ` -EXPRESSION can be specified as follows: -- flowName - - the latest approval to flowName, at the time of the request - - e.g., **creator** -- flowName#N - - the Nth approval, counting from 1 - - e.g., **creator#453** -- flowName~N - - the Nth approval behind the latest, at the time of the request - - e.g., **creator~56** -` - -const getApprovalExample = ` -# get second behind the latest approval from a flow -kosli get approval flowName~1 \ - --api-token yourAPIToken \ - --org orgName - -# get the 10th approval from a flow -kosli get approval flowName#10 \ - --api-token yourAPIToken \ - --org orgName - -# get the latest approval from a flow -kosli get approval flowName \ - --api-token yourAPIToken \ - --org orgName` - -type getApprovalOptions struct { - output string -} - -func newGetApprovalCmd(out io.Writer) *cobra.Command { - o := new(getApprovalOptions) - cmd := &cobra.Command{ - Use: "approval EXPRESSION", - Short: getApprovalShortDesc, - Long: getApprovalLongDesc, - Example: getApprovalExample, - Args: cobra.ExactArgs(1), - Deprecated: deprecatedCommandMsg, - 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 { - return o.run(out, args) - }, - } - - cmd.Flags().StringVarP(&o.output, "output", "o", "table", outputFlag) - return cmd -} - -func (o *getApprovalOptions) run(out io.Writer, args []string) error { - flowName, id, err := handleExpressions(args[0]) - if err != nil { - return err - } - url, err := url.JoinPath(global.Host, "api/v2/approvals", global.Org, flowName, strconv.Itoa(id)) - if err != nil { - return err - } - - reqParams := &requests.RequestParams{ - Method: http.MethodGet, - URL: url, - Token: global.ApiToken, - } - response, err := kosliClient.Do(reqParams) - if err != nil { - return err - } - - return output.FormattedPrint(response.Body, o.output, out, 0, - map[string]output.FormatOutputFunc{ - "table": printApprovalAsTable, - "json": output.PrintJson, - }) -} - -func printApprovalAsTable(raw string, out io.Writer, page int) error { - var approval map[string]interface{} - err := json.Unmarshal([]byte(raw), &approval) - if err != nil { - return err - } - - rows := []string{} - rows = append(rows, fmt.Sprintf("ID:\t%d", int64(approval["release_number"].(float64)))) - rows = append(rows, fmt.Sprintf("Artifact fingerprint:\t%s", approval["base_artifact"].(string))) - rows = append(rows, fmt.Sprintf("Artifact name:\t%s", approval["artifact_name"].(string))) - rows = append(rows, fmt.Sprintf("State:\t%s", approval["state"].(string))) - lastModifiedAt, err := formattedTimestamp(approval["last_modified_at"], false) - if err != nil { - return err - } - rows = append(rows, fmt.Sprintf("Last modified at:\t%s", lastModifiedAt)) - reviews := approval["approvals"].([]interface{}) - if len(reviews) > 0 { - rows = append(rows, "Reviews:") - for _, review := range reviews { - convertedReview := review.(map[string]interface{}) - approvedBy := "Unknown" - if convertedReview["approved_by"] != nil { - approvedBy = convertedReview["approved_by"].(string) - } - createdAt, err := formattedTimestamp(convertedReview["timestamp"], true) - if err != nil { - return err - } - reviewRow := fmt.Sprintf("\t%s By: %s on %s", convertedReview["state"].(string), approvedBy, createdAt) - rows = append(rows, reviewRow) - } - } else { - rows = append(rows, "Reviews:\tNone") - } - - commits := approval["src_commit_list"].([]interface{}) - if len(reviews) > 0 { - rows = append(rows, "Changes:") - for _, commit := range commits { - convertedCommit := commit.(map[string]interface{}) - commitRow := fmt.Sprintf("\tGit commit: %s", convertedCommit["commit_sha"].(string)) - rows = append(rows, commitRow) - artifact_digests := convertedCommit["artifact_fingerprints"].([]interface{}) - if len(artifact_digests) == 0 { - commitRow = "\tNo artifacts produced from this commit" - rows = append(rows, commitRow) - } else { - commitRow = "\tProduced artifact fingerprint(s):" - rows = append(rows, commitRow) - for _, digest := range artifact_digests { - digestRow := fmt.Sprintf("\t\t%s", digest) - rows = append(rows, digestRow) - } - - } - } - } else { - rows = append(rows, "Changes:\tNone") - } - - tabFormattedPrint(out, []string{}, rows) - return nil -} diff --git a/cmd/kosli/getApproval_test.go b/cmd/kosli/getApproval_test.go deleted file mode 100644 index 7c0faf338..000000000 --- a/cmd/kosli/getApproval_test.go +++ /dev/null @@ -1,86 +0,0 @@ -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 GetApprovalCommandTestSuite struct { - suite.Suite - defaultKosliArguments string - flowName string - fingerprint string -} - -func (suite *GetApprovalCommandTestSuite) SetupTest() { - suite.flowName = "get-approval" - suite.fingerprint = "7a498bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c" - 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()) - CreateArtifact(suite.flowName, suite.fingerprint, "approved-artifact", suite.T()) - CreateApproval(suite.flowName, suite.fingerprint, false, suite.T()) - CreateApproval(suite.flowName, suite.fingerprint, false, suite.T()) -} - -func (suite *GetApprovalCommandTestSuite) TestGetApprovalCmd() { - tests := []cmdTestCase{ - { - name: "get latest approval works", - cmd: fmt.Sprintf("get approval %s %s", suite.flowName, suite.defaultKosliArguments), - goldenFile: "output/get/get-approval-latest.txt", - }, - { - name: "get an approval works with # expression", - cmd: fmt.Sprintf("get approval %s#1 %s", suite.flowName, suite.defaultKosliArguments), - goldenFile: "output/get/get-approval.txt", - }, - { - name: "get an approval works with ~ expression", - cmd: fmt.Sprintf("get approval %s~1 %s", suite.flowName, suite.defaultKosliArguments), - goldenFile: "output/get/get-approval.txt", - }, - { - wantError: true, - name: "get an approval with more than one argument fails", - cmd: fmt.Sprintf("get approval %s xxx %s", suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: accepts 1 arg(s), received 2\n", - }, - { - wantError: true, - name: "get approval on a non-existing flow fails", - cmd: "get approval get-approval-123#20" + suite.defaultKosliArguments, - golden: cmdDeprecationLine("approval") + "Error: Flow named 'get-approval-123' does not exist for organization 'docs-cmd-test-user'\n", - }, - { - wantError: true, - name: "get non-existing approval fails", - cmd: fmt.Sprintf("get approval %s#23 %s", suite.flowName, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approval") + "Error: Approval number '23' does not exist in flow 'get-approval' belonging to organization 'docs-cmd-test-user'\n", - }, - { - wantError: true, - name: "missing --org fails", - cmd: fmt.Sprintf("get approval %s --api-token secret", suite.flowName), - golden: cmdDeprecationLine("approval") + "Error: --org is not set\nUsage: kosli get approval EXPRESSION [flags]\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 TestGetApprovalCommandTestSuite(t *testing.T) { - suite.Run(t, new(GetApprovalCommandTestSuite)) -} diff --git a/cmd/kosli/list.go b/cmd/kosli/list.go index 992efd13c..44d665b85 100644 --- a/cmd/kosli/list.go +++ b/cmd/kosli/list.go @@ -34,7 +34,6 @@ func newListCmd(out io.Writer) *cobra.Command { // Add subcommands cmd.AddCommand( - newListApprovalsCmd(out), newListArtifactsCmd(out), newListEnvironmentsCmd(out), newListFlowsCmd(out), diff --git a/cmd/kosli/listApprovals.go b/cmd/kosli/listApprovals.go deleted file mode 100644 index ed125e5ca..000000000 --- a/cmd/kosli/listApprovals.go +++ /dev/null @@ -1,147 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - - "github.com/kosli-dev/cli/internal/output" - "github.com/kosli-dev/cli/internal/requests" - "github.com/spf13/cobra" -) - -const listApprovalsShortDesc = `List approvals in a flow.` -const listApprovalsLongDesc = listApprovalsShortDesc + ` -The results are paginated and ordered from latest to oldest. -By default, the page limit is 15 approvals per page. -` - -const listApprovalsExample = ` -# list the last 15 approvals for a flow: -kosli list approvals \ - --flow yourFlowName \ - --api-token yourAPIToken \ - --org yourOrgName - -# list the last 30 approvals for a flow: -kosli list approvals \ - --flow yourFlowName \ - --page-limit 30 \ - --api-token yourAPIToken \ - --org yourOrgName - -# list the last 30 approvals for a flow (in JSON): -kosli list approvals \ - --flow yourFlowName \ - --page-limit 30 \ - --api-token yourAPIToken \ - --org yourOrgName \ - --output json -` - -type listApprovalsOptions struct { - listOptions - flowName string -} - -func newListApprovalsCmd(out io.Writer) *cobra.Command { - o := new(listApprovalsOptions) - cmd := &cobra.Command{ - Use: "approvals", - Short: listApprovalsShortDesc, - Long: listApprovalsLongDesc, - Example: listApprovalsExample, - Args: cobra.NoArgs, - Deprecated: deprecatedCommandMsg, - PreRunE: func(cmd *cobra.Command, args []string) error { - err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - - return o.validate(cmd) - }, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run(out) - }, - } - - cmd.Flags().StringVarP(&o.flowName, "flow", "f", "", flowNameFlag) - addListFlags(cmd, &o.listOptions) - - err := RequireFlags(cmd, []string{"flow"}) - if err != nil { - logger.Error("failed to configure required flags: %v", err) - } - - return cmd -} - -func (o *listApprovalsOptions) run(out io.Writer) error { - base, err := url.JoinPath(global.Host, "api/v2/approvals", global.Org, o.flowName) - if err != nil { - return err - } - params := url.Values{} - params.Set("page", strconv.Itoa(o.pageNumber)) - params.Set("per_page", strconv.Itoa(o.pageLimit)) - reqURL := base + "?" + params.Encode() - - reqParams := &requests.RequestParams{ - Method: http.MethodGet, - URL: reqURL, - Token: global.ApiToken, - } - response, err := kosliClient.Do(reqParams) - if err != nil { - return err - } - - return output.FormattedPrint(response.Body, o.output, out, o.pageNumber, - map[string]output.FormatOutputFunc{ - "table": printApprovalListAsTable, - "json": output.PrintJson, - }) - -} - -func printApprovalListAsTable(raw string, out io.Writer, page int) error { - var approvals []map[string]interface{} - err := json.Unmarshal([]byte(raw), &approvals) - if err != nil { - return err - } - - if len(approvals) == 0 { - msg := "No approvals were found" - if page != 1 { - msg = fmt.Sprintf("%s at page number %d", msg, page) - } - logger.Info(msg + ".") - return nil - } - - header := []string{"ID", "ARTIFACT", "STATE", "LAST_MODIFIED_AT"} - rows := []string{} - for _, approval := range approvals { - approvalId := int(approval["release_number"].(float64)) - artifactName := approval["artifact_name"].(string) - approvalState := approval["state"].(string) - artifactDigest := approval["base_artifact"].(string) - lastModifiedAt, err := formattedTimestamp(approval["last_modified_at"], true) - if err != nil { - return err - } - row := fmt.Sprintf("%d\tName: %s\t%s\t%s", approvalId, artifactName, approvalState, lastModifiedAt) - rows = append(rows, row) - row = fmt.Sprintf("\tFingerprint: %s\t\t", artifactDigest) - rows = append(rows, row) - rows = append(rows, "\t\t\t") - } - tabFormattedPrint(out, header, rows) - - return nil -} diff --git a/cmd/kosli/listApprovals_test.go b/cmd/kosli/listApprovals_test.go deleted file mode 100644 index cd23f5261..000000000 --- a/cmd/kosli/listApprovals_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - "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 ListApprovalsCommandTestSuite struct { - suite.Suite - defaultKosliArguments string - flowName1 string - flowName2 string - artifactName string - artifactPath string - fingerprint string -} - -func (suite *ListApprovalsCommandTestSuite) SetupTest() { - suite.flowName1 = "list-approvals-empty" - suite.flowName2 = "list-approvals" - suite.artifactName = "arti" - suite.artifactPath = "testdata/folder1/hello.txt" - 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.flowName1, suite.T()) - CreateFlow(suite.flowName2, suite.T()) - fingerprintOptions := &fingerprintOptions{ - artifactType: "file", - } - var err error - suite.fingerprint, err = GetSha256Digest(suite.artifactPath, fingerprintOptions, logger) - require.NoError(suite.T(), err) - CreateArtifact(suite.flowName2, suite.fingerprint, suite.artifactName, suite.T()) - CreateApproval(suite.flowName2, suite.fingerprint, false, suite.T()) -} - -func (suite *ListApprovalsCommandTestSuite) TestListApprovalsCmd() { - tests := []cmdTestCase{ - { - wantError: true, - name: "missing --flow flag arg causes an error", - cmd: fmt.Sprintf(`list approvals %s`, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "Error: required flag(s) \"flow\" not set\n", - }, - { - wantError: true, - name: "non-existing flow causes an error", - cmd: fmt.Sprintf(`list approvals --flow non-existing %s`, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "Error: Flow named 'non-existing' does not exist for organization 'docs-cmd-test-user'\n", - }, - // TODO: the correct error is overwritten by the hack flag value check in root.go - { - wantError: true, - name: "negative page number causes an error", - cmd: fmt.Sprintf(`list approvals --flow foo --page -1 %s`, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "Error: flag '--page' has value '-1' which is illegal\n", - }, - { - wantError: true, - name: "negative page limit causes an error", - cmd: fmt.Sprintf(`list approvals --flow foo --page-limit -1 %s`, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "Error: flag '--page-limit' has value '-1' which is illegal\n", - }, - { - name: "listing approvals on an empty flow works", - cmd: fmt.Sprintf(`list approvals --flow %s %s`, suite.flowName1, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "No approvals were found.\n", - }, - { - name: "listing approvals on an empty flow with --output json works", - cmd: fmt.Sprintf(`list approvals --flow %s --output json %s`, suite.flowName1, suite.defaultKosliArguments), - golden: cmdDeprecationLine("approvals") + "[]", - }, - { - name: "listing approvals on a flow works", - cmd: fmt.Sprintf(`list approvals --flow %s %s`, suite.flowName2, suite.defaultKosliArguments), - goldenFile: "output/list/list-approvals.txt", - }, - } - - 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 TestListApprovalsCommandTestSuite(t *testing.T) { - suite.Run(t, new(ListApprovalsCommandTestSuite)) -} diff --git a/cmd/kosli/pipelineCommand_test.go b/cmd/kosli/pipelineCommand_test.go index 47d1f086f..ca6859045 100644 --- a/cmd/kosli/pipelineCommand_test.go +++ b/cmd/kosli/pipelineCommand_test.go @@ -88,23 +88,6 @@ func (suite *PipelineCommandTestSuite) TestPipelineCommandCmd() { cmd: "report artifact testdata/file1 --repo-root . --artifact-type file --git-commit " + headHash + defaultArtifactArguments + defaultKosliArguments, goldenRegex: "Error: failed to open git repository at .: repository does not exist\n", }, - - // TODO: decouple approval tests and make them independent - // Report approval - { - wantError: false, - name: "report approval", - cmd: "report approval --flow newFlow --oldest-commit HEAD~1 --fingerprint 847411c6124e719a4e8da2550ac5c116b7ff930493ce8a061486b48db8a5aaa0" + defaultKosliArguments + defaultRepoRoot, - golden: "", - }, - - // Request approval - { - wantError: false, - name: "request approval", - cmd: "request approval --flow newFlow --oldest-commit HEAD --fingerprint 4f09b9f4e4d354a42fd4599d0ef8e04daf278c967dea68741d127f21eaa1eeaf" + defaultKosliArguments + defaultRepoRoot, - golden: "", - }, } runTestCmd(suite.T(), tests) } diff --git a/cmd/kosli/report.go b/cmd/kosli/report.go index 8d28066eb..d0247b66c 100644 --- a/cmd/kosli/report.go +++ b/cmd/kosli/report.go @@ -19,7 +19,6 @@ func newReportCmd(out io.Writer) *cobra.Command { // Add subcommands cmd.AddCommand( newReportArtifactCmd(out), - newReportApprovalCmd(out), ) return cmd diff --git a/cmd/kosli/reportApproval.go b/cmd/kosli/reportApproval.go deleted file mode 100644 index 43a1f1ba1..000000000 --- a/cmd/kosli/reportApproval.go +++ /dev/null @@ -1,287 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - - "github.com/kosli-dev/cli/internal/gitview" - - "github.com/kosli-dev/cli/internal/requests" - "github.com/spf13/cobra" -) - -const ( - reportApprovalShortDesc = `Report an approval of deploying an artifact to an environment to Kosli. ` - reportApprovalLongDesc = reportApprovalShortDesc + ` -` + fingerprintDesc -) - -const reportApprovalExample = ` -# Report that an artifact with a provided fingerprint (sha256) has been approved for -# deployment to environment . -# The approval is for all git commits since the last approval to this environment. -kosli report approval \ - --api-token yourAPIToken \ - --description "An optional description for the approval" \ - --environment yourEnvironmentName \ - --approver username \ - --org yourOrgName \ - --flow yourFlowName \ - --fingerprint yourArtifactFingerprint - -# Report that a file type artifact has been approved for deployment to environment . -# The approval is for all git commits since the last approval to this environment. -kosli report approval FILE.tgz \ - --api-token yourAPIToken \ - --artifact-type file \ - --description "An optional description for the approval" \ - --environment yourEnvironmentName \ - --newest-commit HEAD \ - --approver username \ - --org yourOrgName \ - --flow yourFlowName - -# Report that an artifact with a provided fingerprint (sha256) has been approved for deployment. -# The approval is for all environments. -# The approval is for all commits since the git commit of origin/production branch. -kosli report approval \ - --api-token yourAPIToken \ - --description "An optional description for the approval" \ - --newest-commit HEAD \ - --oldest-commit origin/production \ - --approver username \ - --org yourOrgName \ - --flow yourFlowName \ - --fingerprint yourArtifactFingerprint -` - -type reportApprovalOptions struct { - fingerprintOptions *fingerprintOptions - flowName string - oldestSrcCommit string - newestSrcCommit string - srcRepoRoot string - userDataFile string - payload ApprovalPayload - approver string -} - -type ApprovalPayload struct { - ArtifactFingerprint string `json:"artifact_fingerprint"` - Environment string `json:"environment,omitempty"` - Description string `json:"description"` - CommitList []string `json:"src_commit_list"` - OldestCommit string `json:"oldest_commit,omitempty"` - Reviews []map[string]string `json:"approvals"` - UserData interface{} `json:"user_data"` -} - -func newReportApprovalCmd(out io.Writer) *cobra.Command { - o := new(reportApprovalOptions) - o.fingerprintOptions = new(fingerprintOptions) - cmd := &cobra.Command{ - Use: "approval [IMAGE-NAME | FILE-PATH | DIR-PATH]", - Short: reportApprovalShortDesc, - Long: reportApprovalLongDesc, - Example: reportApprovalExample, - Deprecated: deprecatedCommandMsg, - PreRunE: func(cmd *cobra.Command, args []string) error { - err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - - err = RequireAtLeastOneOfFlags(cmd, []string{"environment", "oldest-commit"}) - if err != nil { - return err - } - - err = ValidateArtifactArg(args, o.fingerprintOptions.artifactType, o.payload.ArtifactFingerprint, false) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - return ValidateRegistryFlags(cmd, o.fingerprintOptions) - }, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run(args, false) - }, - } - - cmd.Flags().StringVarP(&o.payload.ArtifactFingerprint, "fingerprint", "F", "", fingerprintFlag) - cmd.Flags().StringVarP(&o.payload.Environment, "environment", "e", "", approvalEnvironmentNameFlag) - cmd.Flags().StringVarP(&o.flowName, "flow", "f", "", flowNameFlag) - cmd.Flags().StringVarP(&o.payload.Description, "description", "d", "", approvalDescriptionFlag) - cmd.Flags().StringVarP(&o.userDataFile, "user-data", "u", "", approvalUserDataFlag) - cmd.Flags().StringVar(&o.oldestSrcCommit, "oldest-commit", "", oldestCommitFlag) - cmd.Flags().StringVar(&o.newestSrcCommit, "newest-commit", "HEAD", newestCommitFlag) - cmd.Flags().StringVar(&o.srcRepoRoot, "repo-root", ".", repoRootFlag) - cmd.Flags().StringVar(&o.approver, "approver", "", approverFlag) - addFingerprintFlags(cmd, o.fingerprintOptions) - addDryRunFlag(cmd) - - err := RequireFlags(cmd, []string{"flow"}) - if err != nil { - logger.Error("failed to configure required flags: %v", err) - } - - return cmd -} - -func (o *reportApprovalOptions) run(args []string, request bool) error { - var err error - o.payload.ArtifactFingerprint, err = o.payloadArtifactSHA256(args) - if err != nil { - return err - } - - o.payload.Reviews = o.payloadReviews(request) - - o.payload.UserData, err = LoadJsonData(o.userDataFile) - if err != nil { - return err - } - gitView, err := gitview.New(o.srcRepoRoot) - if err != nil { - return err - } - - o.newestSrcCommit, err = gitView.ResolveRevision(o.newestSrcCommit) - if err != nil { - return err - } - - if o.oldestSrcCommit != "" { - o.payload.OldestCommit, err = gitView.ResolveRevision(o.oldestSrcCommit) - if err != nil { - return err - } - o.payload.CommitList, err = o.payloadCommitList() - if err != nil { - return err - } - } else { - // Request last approved git commit from kosli server - url, err := url.JoinPath(global.Host, "api/v2/approvals", global.Org, o.flowName, "artifact-commit", o.payload.Environment) - if err != nil { - return err - } - - getLastApprovedGitCommitParams := &requests.RequestParams{ - Method: http.MethodGet, - URL: url, - DryRun: false, - Token: global.ApiToken, - } - - lastApprovedGitCommitResponse, err := kosliClient.Do(getLastApprovedGitCommitParams) - - if err != nil { - if !global.DryRun { - // error and not dry run -> print error message and return err - return err - } else { - // error and dry run -> set src_commit_list to o.newestCommit do not send oldestCommit - o.payload.CommitList = []string{o.newestSrcCommit} - } - } else { - var responseData map[string]interface{} - err = json.Unmarshal([]byte(lastApprovedGitCommitResponse.Body), &responseData) - if err != nil { - fmt.Println("unmarshal failed") - return err - } - - if responseData["commit_sha"] != nil { - // no error we get back a git commit -> call o.payloadCommitList() - o.oldestSrcCommit = responseData["commit_sha"].(string) - o.payload.OldestCommit = o.oldestSrcCommit - o.payload.CommitList, err = o.payloadCommitList() - if err != nil { - return err - } - } else { - // no error we get back None -> set src_commit_list to o.newestCommit do not send oldestCommit - o.payload.CommitList = []string{o.newestSrcCommit} - } - - } - } - - url, err := url.JoinPath(global.Host, "api/v2/approvals", global.Org, o.flowName) - if err != nil { - return err - } - - reqParams := &requests.RequestParams{ - Method: http.MethodPost, - URL: url, - Payload: o.payload, - DryRun: global.DryRun, - Token: global.ApiToken, - } - _, err = kosliClient.Do(reqParams) - if err == nil && !global.DryRun { - logger.Info("approval created for artifact: %s", o.payload.ArtifactFingerprint) - } - return err -} - -func (o *reportApprovalOptions) payloadArtifactSHA256(args []string) (string, error) { - if o.payload.ArtifactFingerprint == "" { - sha256, err := GetSha256Digest(args[0], o.fingerprintOptions, logger) - if err != nil { - return sha256, err - } - return sha256, nil - } - return o.payload.ArtifactFingerprint, nil -} - -func (o *reportApprovalOptions) payloadReviews(request bool) []map[string]string { - approver := "External" - if o.approver != "" { - approver = o.approver - } - if !request { - return []map[string]string{ - { - "state": "APPROVED", - "comment": o.payload.Description, - "approved_by": approver, - "approval_url": "undefined", - }, - } - } else { - return []map[string]string{} - } -} - -func (o *reportApprovalOptions) payloadCommitList() ([]string, error) { - commits, err := o.commitsHistory() - if err != nil { - return nil, err - } - - // Need this line to make sure an empty list is converted to [] and not null in SendPayload - commitList := make([]string, 0) - for _, commit := range commits { - commitList = append(commitList, commit.Sha1) - } - return commitList, nil -} - -func (o *reportApprovalOptions) commitsHistory() ([]*gitview.CommitInfo, error) { - gitView, err := gitview.New(o.srcRepoRoot) - if err != nil { - return nil, err - } - - commits, err := gitView.CommitsBetween(o.oldestSrcCommit, o.newestSrcCommit, logger) - if err != nil { - return nil, err - } - return commits, nil -} diff --git a/cmd/kosli/reportApproval_test.go b/cmd/kosli/reportApproval_test.go deleted file mode 100644 index 6a224d4b6..000000000 --- a/cmd/kosli/reportApproval_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -import ( - "fmt" - "testing" - - "github.com/kosli-dev/cli/internal/digest" - "github.com/kosli-dev/cli/internal/gitview" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" -) - -type ApprovalReportTestSuite struct { - suite.Suite - defaultKosliArguments string - artifactFingerprint string - flowName string - envName string - gitCommit string - artifactPath string -} - -type reportApprovalTestConfig struct { - createSnapshot bool -} - -func (suite *ApprovalReportTestSuite) SetupTest() { - 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) - suite.flowName = "approval-test" - suite.envName = "staging" - t := suite.T() - - gitView, err := gitview.New("../..") - require.NoError(t, err, "Failed to create gitview") - - suite.gitCommit, err = gitView.ResolveRevision("HEAD~5") - require.NoError(t, err, "Failed to get HEAD~5") - - suite.artifactPath = "testdata/report.xml" - // We cannot get the digest of the file by running the 'kosli fingerprint' command - // by using executeCommandC() because this function overwrites the global options - suite.artifactFingerprint, err = digest.FileSha256(suite.artifactPath, logger) - require.NoError(t, err, "Failed to calculate fingerprint") - - CreateFlow(suite.flowName, t) - CreateArtifactWithCommit(suite.flowName, suite.artifactFingerprint, suite.artifactPath, suite.gitCommit, t) - CreateEnv(global.Org, suite.envName, "server", t) -} - -func (suite *ApprovalReportTestSuite) TestApprovalReportCmd() { - tests := []cmdTestCase{ - { - name: "report approval with a range of commits works ", - cmd: `report approval --fingerprint ` + suite.artifactFingerprint + ` --flow ` + suite.flowName + ` --repo-root ../.. - --newest-commit HEAD --oldest-commit HEAD~3` + suite.defaultKosliArguments, - golden: cmdDeprecationLine("approval") + fmt.Sprintf("approval created for artifact: %s\n", suite.artifactFingerprint), - }, - { - name: "report approval with an environment name works", - cmd: `report approval --fingerprint ` + suite.artifactFingerprint + ` --flow ` + suite.flowName + ` --repo-root ../.. - --newest-commit HEAD --oldest-commit HEAD~3` + ` --environment staging` + suite.defaultKosliArguments, - golden: cmdDeprecationLine("approval") + fmt.Sprintf("approval created for artifact: %s\n", suite.artifactFingerprint), - }, - { - wantError: true, - name: "report approval with no environment name and no oldest commit fails", - cmd: `report approval --fingerprint ` + suite.artifactFingerprint + ` --flow ` + suite.flowName + ` --repo-root ../.. ` + - suite.defaultKosliArguments, - golden: cmdDeprecationLine("approval") + "Error: at least one of --environment, --oldest-commit is required\n", - }, - { - name: "report approval with an environment name and no oldest-commit and no newest-commit works", - cmd: `report approval --fingerprint ` + suite.artifactFingerprint + ` --flow ` + suite.flowName + ` --repo-root ../.. ` + - ` --environment ` + suite.envName + suite.defaultKosliArguments, - golden: cmdDeprecationLine("approval") + fmt.Sprintf("approval created for artifact: %s\n", suite.artifactFingerprint), - additionalConfig: reportApprovalTestConfig{ - createSnapshot: true, - }, - }, - } - for _, t := range tests { - if t.additionalConfig != nil && t.additionalConfig.(reportApprovalTestConfig).createSnapshot { - ReportServerArtifactToEnv([]string{suite.artifactPath}, suite.envName, suite.T()) - } - runTestCmd(suite.T(), []cmdTestCase{t}) - } -} - -func TestApprovalReportCommandTestSuite(t *testing.T) { - suite.Run(t, new(ApprovalReportTestSuite)) -} diff --git a/cmd/kosli/request.go b/cmd/kosli/request.go deleted file mode 100644 index 0f3cf4159..000000000 --- a/cmd/kosli/request.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "io" - - "github.com/spf13/cobra" -) - -const requestDesc = `All Kosli request commands.` - -func newRequestCmd(out io.Writer) *cobra.Command { - cmd := &cobra.Command{ - Use: "request", - Short: requestDesc, - Long: requestDesc, - Deprecated: deprecatedCommandMsg, - } - - // Add subcommands - cmd.AddCommand( - newRequestApprovalCmd(out), - ) - - return cmd -} diff --git a/cmd/kosli/requestApproval.go b/cmd/kosli/requestApproval.go deleted file mode 100644 index f15368473..000000000 --- a/cmd/kosli/requestApproval.go +++ /dev/null @@ -1,100 +0,0 @@ -package main - -import ( - "io" - - "github.com/spf13/cobra" -) - -const ( - requestApprovalShortDesc = `Request an approval of a deployment of an artifact to an environment in Kosli. ` - requestApprovalLongDesc = requestApprovalShortDesc + ` -The request should be reviewed in the Kosli UI. -` + fingerprintDesc -) - -const requestApprovalExample = ` -# Request an approval for an artifact with a provided fingerprint (sha256) -# for deployment to environment . -# The approval is for all git commits since the last approval to this environment. -kosli request approval \ - --api-token yourAPIToken \ - --description "An optional description for the approval" \ - --environment yourEnvironmentName \ - --org yourOrgName \ - --flow yourFlowName \ - --fingerprint yourArtifactFingerprint - -# Request that a file type artifact needs approval for deployment to environment . -# The approval is for all git commits since the last approval to this environment. -kosli request approval FILE.tgz \ - --api-token yourAPIToken \ - --artifact-type file \ - --description "An optional description for the requested approval" \ - --environment yourEnvironmentName \ - --newest-commit HEAD \ - --org yourOrgName \ - --flow yourFlowName - -# Request an approval for an artifact with a provided fingerprint (sha256). -# The approval is for all environments. -# The approval is for all commits since the git commit of origin/production branch. -kosli request approval \ - --api-token yourAPIToken \ - --description "An optional description for the requested approval" \ - --newest-commit HEAD \ - --oldest-commit origin/production \ - --org yourOrgName \ - --flow yourFlowName \ - --fingerprint yourArtifactFingerprint -` - -func newRequestApprovalCmd(out io.Writer) *cobra.Command { - o := new(reportApprovalOptions) - o.fingerprintOptions = new(fingerprintOptions) - cmd := &cobra.Command{ - Use: "approval [IMAGE-NAME | FILE-PATH | DIR-PATH]", - Short: requestApprovalShortDesc, - Long: requestApprovalLongDesc, - Example: requestApprovalExample, - Deprecated: deprecatedCommandMsg, - PreRunE: func(cmd *cobra.Command, args []string) error { - err := RequireGlobalFlags(global, []string{"Org", "ApiToken"}) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - - err = RequireAtLeastOneOfFlags(cmd, []string{"environment", "oldest-commit"}) - if err != nil { - return err - } - - err = ValidateArtifactArg(args, o.fingerprintOptions.artifactType, o.payload.ArtifactFingerprint, false) - if err != nil { - return ErrorBeforePrintingUsage(cmd, err.Error()) - } - return ValidateRegistryFlags(cmd, o.fingerprintOptions) - }, - RunE: func(cmd *cobra.Command, args []string) error { - return o.run(args, true) - }, - } - - cmd.Flags().StringVarP(&o.payload.ArtifactFingerprint, "fingerprint", "F", "", fingerprintFlag) - cmd.Flags().StringVarP(&o.payload.Environment, "environment", "e", "", approvalEnvironmentNameFlag) - cmd.Flags().StringVarP(&o.flowName, "flow", "f", "", flowNameFlag) - cmd.Flags().StringVarP(&o.payload.Description, "description", "d", "", approvalDescriptionFlag) - cmd.Flags().StringVarP(&o.userDataFile, "user-data", "u", "", approvalUserDataFlag) - cmd.Flags().StringVar(&o.oldestSrcCommit, "oldest-commit", "", oldestCommitFlag) - cmd.Flags().StringVar(&o.newestSrcCommit, "newest-commit", "HEAD", newestCommitFlag) - cmd.Flags().StringVar(&o.srcRepoRoot, "repo-root", ".", repoRootFlag) - addFingerprintFlags(cmd, o.fingerprintOptions) - addDryRunFlag(cmd) - - err := RequireFlags(cmd, []string{"flow"}) - if err != nil { - logger.Error("failed to configure required flags: %v", err) - } - - return cmd -} diff --git a/cmd/kosli/root.go b/cmd/kosli/root.go index 052e2c5db..c3fd77f7e 100644 --- a/cmd/kosli/root.go +++ b/cmd/kosli/root.go @@ -146,7 +146,6 @@ The ^.kosli_ignore^ will be treated as part of the artifact like any other file, apiKeyGracePeriodHoursFlag = "[optional] How many hours the old API key remains valid after rotation, to allow time to update dependent systems. Defaults to the server-side value when not set." apiKeyAssumeYesFlag = "[optional] Skip the confirmation prompt and delete the API key without asking. (alias: --yes)" environmentNameFlag = "The environment name." - approvalEnvironmentNameFlag = "[defaulted] The environment the artifact is approved for. (defaults to all environments)" pageNumberFlag = "[defaulted] The page number of a response." pageLimitFlag = "[defaulted] The number of elements per page." newEnvTypeFlag = "The type of environment. Valid types are: [" + validEnvTypesList + "]." @@ -161,7 +160,6 @@ The ^.kosli_ignore^ will be treated as part of the artifact like any other file, oldestCommitFlag = "[conditional] The source commit sha for the oldest change in the deployment. Can be any commit-ish. Only required if you don't specify '--environment'." newestCommitFlag = "[defaulted] The source commit sha for the newest change in the deployment. Can be any commit-ish." repoRootFlag = "[defaulted] The directory where the source git repository is available." - approvalDescriptionFlag = "[optional] The approval description." jiraBaseUrlFlag = "The base url for the jira project, e.g. 'https://kosli.atlassian.net'" jiraUsernameFlag = "Jira username (for Jira Cloud)" jiraAPITokenFlag = "Jira API token (for Jira Cloud)" @@ -178,7 +176,6 @@ The ^.kosli_ignore^ will be treated as part of the artifact like any other file, templateFileFlag = "[optional] The path to a yaml template file. Cannot be used together with --use-empty-template" templateFileSimpleFlag = "[optional] The path to a yaml template file." useEmptyTemplateFlag = "Use an empty template for the flow creation without specifying a file. Cannot be used together with --template or --template-file" - approvalUserDataFlag = "[optional] The path to a JSON file containing additional data you would like to attach to the approval." attestationUserDataFlag = "[optional] The path to a JSON file containing additional data you would like to attach to the attestation." trailUserDataFlag = "[optional] The path to a JSON file containing additional data you would like to attach to the flow trail." gitCommitFlag = "[defaulted] The git commit from which the artifact was created. (defaulted in some CIs: https://docs.kosli.com/integrations/ci_cd, otherwise defaults to HEAD )." @@ -259,7 +256,6 @@ The ^.kosli_ignore^ will be treated as part of the artifact like any other file, fingerprintFlag = "[conditional] The SHA256 fingerprint of the artifact. Only required if you don't specify '--artifact-type'." intervalFlag = "[optional] Expression to define specified snapshots range." showUnchangedArtifactsFlag = "[defaulted] Show the unchanged artifacts present in both snapshots within the diff output." - approverFlag = "[optional] The user approving an approval." attestationFingerprintFlag = "[conditional] The SHA256 fingerprint of the artifact to attach the attestation to. Only required if the attestation is for an artifact and --artifact-type and artifact name/path are not used." attestationCommitFlag = "[conditional] The git commit for which the attestation is associated to. Becomes required when reporting an attestation for an artifact before reporting it to Kosli. (defaulted in some CIs: https://docs.kosli.com/integrations/ci_cd )." attestationRedactCommitInfoFlag = "[optional] The list of commit info to be redacted before sending to Kosli. Allowed values are one or more of [author, message, branch]." @@ -459,7 +455,6 @@ func newRootCmd(out, errOut io.Writer, args []string) (*cobra.Command, error) { newArchiveCmd(out), newUnarchiveCmd(out), newSnapshotCmd(out), - newRequestCmd(out), newLogCmd(out), newDisableCmd(out), newEnableCmd(out), diff --git a/cmd/kosli/testHelpers.go b/cmd/kosli/testHelpers.go index 950239078..2036b82a3 100644 --- a/cmd/kosli/testHelpers.go +++ b/cmd/kosli/testHelpers.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "encoding/json" - "fmt" "io" "net/http" "net/url" @@ -23,13 +22,6 @@ import ( "github.com/stretchr/testify/require" ) -// cmdDeprecationLine returns the line Cobra prints before running a command -// whose Deprecated field is set. Used by tests to prepend the expected -// deprecation notice to golden strings. -func cmdDeprecationLine(cmd string) string { - return fmt.Sprintf("Command %q is deprecated, this command is deprecated and will be removed in a future release.\n", cmd) -} - type jsonCheck struct { Path string Want any @@ -461,25 +453,6 @@ func CreateArtifactWithCommit(flowName, artifactFingerprint, artifactName string require.NoError(t, err, "artifact should be created without error") } -// CreateApproval creates an approval for an artifact in a flow -// If isRequest is true, this creates an approval request -func CreateApproval(flowName, fingerprint string, isRequest bool, t *testing.T) { - t.Helper() - o := &reportApprovalOptions{ - payload: ApprovalPayload{ - ArtifactFingerprint: fingerprint, - Description: "some description", - }, - flowName: flowName, - oldestSrcCommit: "75690c740e7b222a3948f4f7618262a5254044e2", - newestSrcCommit: "cfbdba789edd14e5970405896c637dbf073ef831", - srcRepoRoot: "../..", - } - - err := o.run([]string{"filename"}, isRequest) - require.NoError(t, err, "approval should be created without error") -} - // EnableBeta enables beta features for the org func EnableBeta(t *testing.T) { t.Helper() diff --git a/cmd/kosli/testdata/output/get/get-approval-latest.txt b/cmd/kosli/testdata/output/get/get-approval-latest.txt deleted file mode 100644 index 084d549aa..000000000 --- a/cmd/kosli/testdata/output/get/get-approval-latest.txt +++ /dev/null @@ -1,13 +0,0 @@ -Command "approval" is deprecated, this command is deprecated and will be removed in a future release. -ID: 2 -Artifact fingerprint: 7a498bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c -Artifact name: approved-artifact -State: APPROVED -Last modified at: Sat, 16 Jan 2016 00:00:00 UTC • 2016-01-16 -Reviews: - APPROVED By: external://External on Sat, 16 Jan 2016 00:00:00 UTC -Changes: - Git commit: cfbdba789edd14e5970405896c637dbf073ef831 - No artifacts produced from this commit - Git commit: fc280c5dcb06598c49255b868f70b4a752e8840e - No artifacts produced from this commit \ No newline at end of file diff --git a/cmd/kosli/testdata/output/get/get-approval.txt b/cmd/kosli/testdata/output/get/get-approval.txt deleted file mode 100644 index d018b386a..000000000 --- a/cmd/kosli/testdata/output/get/get-approval.txt +++ /dev/null @@ -1,13 +0,0 @@ -Command "approval" is deprecated, this command is deprecated and will be removed in a future release. -ID: 1 -Artifact fingerprint: 7a498bd886069f1290def0caabc1e97ce0e7b80c105e611258b57d76fcef234c -Artifact name: approved-artifact -State: APPROVED -Last modified at: Sat, 16 Jan 2016 00:00:00 UTC • 2016-01-16 -Reviews: - APPROVED By: external://External on Sat, 16 Jan 2016 00:00:00 UTC -Changes: - Git commit: cfbdba789edd14e5970405896c637dbf073ef831 - No artifacts produced from this commit - Git commit: fc280c5dcb06598c49255b868f70b4a752e8840e - No artifacts produced from this commit \ No newline at end of file diff --git a/cmd/kosli/testdata/output/list/list-approvals.txt b/cmd/kosli/testdata/output/list/list-approvals.txt deleted file mode 100644 index 220af3600..000000000 --- a/cmd/kosli/testdata/output/list/list-approvals.txt +++ /dev/null @@ -1,5 +0,0 @@ -Command "approvals" is deprecated, this command is deprecated and will be removed in a future release. -ID ARTIFACT STATE LAST_MODIFIED_AT -1 Name: arti APPROVED Sat, 16 Jan 2016 00:00:00 UTC - Fingerprint: fcf33337634c2577a5d86fd7ecb0a25a7c1bb5d89c14fd236f546a5759252c02 - diff --git a/internal/docgen/mintlify.go b/internal/docgen/mintlify.go index 9a7dc0cf9..8de2da320 100644 --- a/internal/docgen/mintlify.go +++ b/internal/docgen/mintlify.go @@ -108,9 +108,7 @@ func (MintlifyFormatter) ExampleUseCases(commandName, example string) string { example = strings.TrimSpace(example) lines := strings.Split(example, "\n") - if commandName == "kosli report approval" || - commandName == "kosli request approval" || - commandName == "kosli snapshot server" { + if commandName == "kosli snapshot server" { fmt.Fprintf(&b, "```shell\n%s\n```\n\n", example) } else if lines[0][0] != '#' { fmt.Fprintf(&b, "```shell\n%s\n```\n\n", example)