Skip to content

Commit 8951259

Browse files
ankddevBagToad
andauthored
Add --force flag to gh run cancel (cli#11513)
* feat: add --force flag to run cancel command Signed-off-by: Andrey <andrekabatareika@gmail.com> * docs: use less prescriptive docs for --force flag Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com> * chore: remove short flag Signed-off-by: Andrey <andrekabatareika@gmail.com> --------- Signed-off-by: Andrey <andrekabatareika@gmail.com> Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com>
1 parent d43d7a1 commit 8951259

2 files changed

Lines changed: 69 additions & 4 deletions

File tree

pkg/cmd/run/cancel/cancel.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type CancelOptions struct {
2323
Prompt bool
2424

2525
RunID string
26+
Force bool
2627
}
2728

2829
func NewCmdCancel(f *cmdutil.Factory, runF func(*CancelOptions) error) *cobra.Command {
@@ -56,6 +57,8 @@ func NewCmdCancel(f *cmdutil.Factory, runF func(*CancelOptions) error) *cobra.Co
5657
},
5758
}
5859

60+
cmd.Flags().BoolVar(&opts.Force, "force", false, "Force cancel a workflow run")
61+
5962
return cmd
6063
}
6164

@@ -115,7 +118,9 @@ func runCancel(opts *CancelOptions) error {
115118
}
116119
}
117120

118-
err = cancelWorkflowRun(client, repo, fmt.Sprintf("%d", run.ID))
121+
force := opts.Force
122+
123+
err = cancelWorkflowRun(client, repo, fmt.Sprintf("%d", run.ID), force)
119124
if err != nil {
120125
var httpErr api.HTTPError
121126
if errors.As(err, &httpErr) {
@@ -127,13 +132,22 @@ func runCancel(opts *CancelOptions) error {
127132
return err
128133
}
129134

130-
fmt.Fprintf(opts.IO.Out, "%s Request to cancel workflow %s submitted.\n", cs.SuccessIcon(), runID)
135+
if force {
136+
fmt.Fprintf(opts.IO.Out, "%s Request to force cancel workflow %s submitted.\n", cs.SuccessIcon(), runID)
137+
} else {
138+
fmt.Fprintf(opts.IO.Out, "%s Request to cancel workflow %s submitted.\n", cs.SuccessIcon(), runID)
139+
}
131140

132141
return nil
133142
}
134143

135-
func cancelWorkflowRun(client *api.Client, repo ghrepo.Interface, runID string) error {
136-
path := fmt.Sprintf("repos/%s/actions/runs/%s/cancel", ghrepo.FullName(repo), runID)
144+
func cancelWorkflowRun(client *api.Client, repo ghrepo.Interface, runID string, force bool) error {
145+
var path string
146+
if force {
147+
path = fmt.Sprintf("repos/%s/actions/runs/%s/force-cancel", ghrepo.FullName(repo), runID)
148+
} else {
149+
path = fmt.Sprintf("repos/%s/actions/runs/%s/cancel", ghrepo.FullName(repo), runID)
150+
}
137151

138152
err := client.REST(repo.RepoHost(), "POST", path, nil, nil)
139153
if err != nil {

pkg/cmd/run/cancel/cancel_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ func TestNewCmdCancel(t *testing.T) {
4141
cli: "1234",
4242
wants: CancelOptions{
4343
RunID: "1234",
44+
Force: false,
45+
},
46+
},
47+
{
48+
name: "with arg and force flag",
49+
cli: "1234 --force",
50+
wants: CancelOptions{
51+
RunID: "1234",
52+
Force: true,
4453
},
4554
},
4655
}
@@ -78,6 +87,7 @@ func TestNewCmdCancel(t *testing.T) {
7887
assert.NoError(t, err)
7988

8089
assert.Equal(t, tt.wants.RunID, gotOpts.RunID)
90+
assert.Equal(t, tt.wants.Force, gotOpts.Force)
8191
})
8292
}
8393
}
@@ -213,6 +223,47 @@ func TestRunCancel(t *testing.T) {
213223
wantErr: true,
214224
errMsg: "invalid run-id \"12\\n34\"",
215225
},
226+
{
227+
name: "force cancel run",
228+
opts: &CancelOptions{
229+
RunID: "1234",
230+
Force: true,
231+
},
232+
wantErr: false,
233+
httpStubs: func(reg *httpmock.Registry) {
234+
reg.Register(
235+
httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/1234"),
236+
httpmock.JSONResponse(inProgressRun))
237+
reg.Register(
238+
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
239+
httpmock.JSONResponse(shared.TestWorkflow))
240+
reg.Register(
241+
httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/force-cancel"),
242+
httpmock.StatusStringResponse(202, "{}"))
243+
},
244+
wantOut: "✓ Request to force cancel workflow 1234 submitted.\n",
245+
},
246+
{
247+
name: "force and completed",
248+
opts: &CancelOptions{
249+
RunID: "4567",
250+
Force: true,
251+
},
252+
wantErr: true,
253+
errMsg: "Cannot cancel a workflow run that is completed",
254+
httpStubs: func(reg *httpmock.Registry) {
255+
reg.Register(
256+
httpmock.REST("GET", "repos/OWNER/REPO/actions/runs/4567"),
257+
httpmock.JSONResponse(completedRun))
258+
reg.Register(
259+
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
260+
httpmock.JSONResponse(shared.TestWorkflow))
261+
reg.Register(
262+
httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/4567/force-cancel"),
263+
httpmock.StatusStringResponse(409, ""),
264+
)
265+
},
266+
},
216267
}
217268

218269
for _, tt := range tests {

0 commit comments

Comments
 (0)