diff --git a/commands/ci/delete/delete.go b/commands/ci/delete/delete.go index 8c1020d62f9392d4729530dcd70fdd024c7f4055..8a0b824fdaffbfdb048908043a3d15fac56b8c70 100644 --- a/commands/ci/delete/delete.go +++ b/commands/ci/delete/delete.go @@ -9,7 +9,6 @@ import ( "gitlab.com/gitlab-org/cli/api" "gitlab.com/gitlab-org/cli/commands/cmdutils" - "gitlab.com/gitlab-org/cli/pkg/utils" "github.com/MakeNowJust/heredoc" "github.com/spf13/cobra" @@ -47,42 +46,48 @@ func NewCmdDelete(f *cmdutils.Factory) *cobra.Command { return err } + var pipelineIDs []int + if m, _ := cmd.Flags().GetString("status"); m != "" { - l := &gitlab.ListProjectPipelinesOptions{} - l.Status = gitlab.BuildState(gitlab.BuildStateValue(m)) - pipes, err := api.ListProjectPipelines(apiClient, repo.FullName(), l) + pipes, err := api.ListProjectPipelines(apiClient, repo.FullName(), &gitlab.ListProjectPipelinesOptions{ + Status: gitlab.BuildState(gitlab.BuildStateValue(m)), + }) if err != nil { return err } + for _, item := range pipes { - err := api.DeletePipeline(apiClient, repo.FullName(), item.ID) + pipelineIDs = append(pipelineIDs, item.ID) + } + } else { + for _, stringID := range strings.Split(strings.Trim(args[0], "[] "), ",") { + id, err := strconv.Atoi(stringID) if err != nil { return err } - - fmt.Fprintln(f.IO.StdOut, c.RedCheck(), "Pipeline #"+strconv.Itoa(item.ID)+" deleted successfully") + pipelineIDs = append(pipelineIDs, id) } + } - } else { - pipelineID := args[0] - - arrIds := strings.Split(strings.Trim(pipelineID, "[] "), ",") - for _, i2 := range arrIds { - fmt.Fprintln(f.IO.StdOut, "Deleting pipeline #"+i2) - err := api.DeletePipeline(apiClient, repo.FullName(), utils.StringToInt(i2)) + for _, id := range pipelineIDs { + if dryRun, _ := cmd.Flags().GetBool("dry-run"); dryRun { + fmt.Fprintf(f.IO.StdOut, "%s Pipeline #%d will be deleted\n", c.DotWarnIcon(), id) + } else { + err := api.DeletePipeline(apiClient, repo.FullName(), id) if err != nil { return err } - fmt.Fprintln(f.IO.StdOut, c.RedCheck(), "Pipeline #"+i2+" deleted successfully") + fmt.Fprintf(f.IO.StdOut, "%s Pipeline #%d deleted successfully\n", c.RedCheck(), id) } - fmt.Println() } + fmt.Println() return nil }, } + pipelineDeleteCmd.Flags().BoolP("dry-run", "", false, "simulate process, but do not delete anything") pipelineDeleteCmd.Flags().StringP("status", "s", "", "delete pipelines by status: {running|pending|success|failed|canceled|skipped|created|manual}") return pipelineDeleteCmd diff --git a/commands/ci/delete/delete_test.go b/commands/ci/delete/delete_test.go index 169c5626dd05e9e39c1b1c06ee63639665441cf6..f4302d550e2b4e38f1e7a1c61099ffab18ba7371 100644 --- a/commands/ci/delete/delete_test.go +++ b/commands/ci/delete/delete_test.go @@ -44,7 +44,6 @@ func TestCiDelete(t *testing.T) { out := output.String() assert.Equal(t, heredoc.Doc(` - Deleting pipeline #11111111 ✓ Pipeline #11111111 deleted successfully `), out) assert.Empty(t, output.Stderr()) @@ -150,10 +149,75 @@ func TestCiDeleteMultiple(t *testing.T) { out := output.String() assert.Equal(t, heredoc.Doc(` - Deleting pipeline #11111111 ✓ Pipeline #11111111 deleted successfully - Deleting pipeline #22222222 ✓ Pipeline #22222222 deleted successfully `), out) assert.Empty(t, output.Stderr()) } + +func TestCiDryRunDeleteNothing(t *testing.T) { + fakeHTTP := httpmock.New() + defer fakeHTTP.Verify(t) + + args := "--dry-run 11111111,22222222" + output, err := runCommand(fakeHTTP, args) + if err != nil { + t.Errorf("error running command `ci delete %s`: %v", args, err) + } + + out := output.String() + + assert.Equal(t, heredoc.Doc(` + • Pipeline #11111111 will be deleted + • Pipeline #22222222 will be deleted + `), out) + assert.Empty(t, output.Stderr()) +} + +func TestCiDeletedDryRunWithFilterDoesNotDelete(t *testing.T) { + fakeHTTP := httpmock.New() + fakeHTTP.MatchURL = httpmock.PathAndQuerystring + defer fakeHTTP.Verify(t) + + fakeHTTP.RegisterResponder(http.MethodGet, "/api/v4/projects/OWNER/REPO/pipelines?status=success", + httpmock.NewStringResponse(http.StatusOK, ` + [ + { + "id": 11111111, + "iid": 3, + "project_id": 5, + "sha": "c366255c71600e17519e802850ddcf7105d3cf66", + "ref": "refs/merge-requests/1107/merge", + "status": "success", + "source": "merge_request_event", + "created_at": "2020-12-01T01:15:50.559Z", + "updated_at": "2020-12-01T01:36:41.737Z", + "web_url": "https://gitlab.com/OWNER/REPO/-/pipelines/710046436" + }, + { + "id": 22222222, + "iid": 4, + "project_id": 5, + "sha": "c9a7c0d9351cd1e71d1c2ad8277f3bc7e3c47d1f", + "ref": "main", + "status": "success", + "source": "push", + "created_at": "2020-11-30T18:20:47.571Z", + "updated_at": "2020-11-30T18:39:40.092Z", + "web_url": "https://gitlab.com/OWNER/REPO/-/pipelines/709793838" + } + ] + `)) + + args := "--dry-run --status=success" + output, err := runCommand(fakeHTTP, args) + require.NoError(t, err) + + out := output.String() + + assert.Equal(t, heredoc.Doc(` + • Pipeline #11111111 will be deleted + • Pipeline #22222222 will be deleted + `), out) + assert.Empty(t, output.Stderr()) +} diff --git a/docs/source/ci/delete.md b/docs/source/ci/delete.md index bd5e8d08af754160cafdb436e1eb8bbc12541813..3d7a3c64e9ad8197d20fe283d1131aa79103b336 100644 --- a/docs/source/ci/delete.md +++ b/docs/source/ci/delete.md @@ -29,6 +29,7 @@ glab ci delete --status=failed ## Options ```plaintext + --dry-run simulate process, but do not delete anything -s, --status string delete pipelines by status: {running|pending|success|failed|canceled|skipped|created|manual} ```