Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gh cache delete --all] Add --succeed-on-no-caches flag to return exit code 0 #10327

Merged
merged 12 commits into from
Feb 19, 2025
28 changes: 23 additions & 5 deletions pkg/cmd/cache/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ type DeleteOptions struct {
HttpClient func() (*http.Client, error)
IO *iostreams.IOStreams

DeleteAll bool
Identifier string
DeleteAll bool
SucceedOnNoCaches bool
Identifier string
}

func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command {
Expand All @@ -33,7 +34,7 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
}

cmd := &cobra.Command{
Use: "delete [<cache-id>| <cache-key> | --all]",
Use: "delete [<cache-id> | <cache-key> | --all]",
Short: "Delete GitHub Actions caches",
Long: heredoc.Docf(`
Delete GitHub Actions caches.
Expand All @@ -50,8 +51,11 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
# Delete a cache by id in a specific repo
$ gh cache delete 1234 --repo cli/cli

# Delete all caches
# Delete all caches (exit code 1 on no caches)
$ gh cache delete --all

# Delete all caches (exit code 0 on no caches)
$ gh cache delete --all --succeed-on-no-caches
`),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -65,6 +69,10 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
return err
}

if !opts.DeleteAll && opts.SucceedOnNoCaches {
return cmdutil.FlagErrorf("--succeed-on-no-caches must be used in conjunction with --all")
}

if !opts.DeleteAll && len(args) == 0 {
return cmdutil.FlagErrorf("must provide either cache id, cache key, or use --all")
}
Expand All @@ -82,6 +90,7 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
}

cmd.Flags().BoolVarP(&opts.DeleteAll, "all", "a", false, "Delete all caches")
cmd.Flags().BoolVar(&opts.SucceedOnNoCaches, "succeed-on-no-caches", false, "Return exit code 0 if no caches found. Must be used in conjunction with `--all`")

return cmd
}
Expand All @@ -100,12 +109,21 @@ func deleteRun(opts *DeleteOptions) error {

var toDelete []string
if opts.DeleteAll {
opts.IO.StartProgressIndicator()
caches, err := shared.GetCaches(client, repo, shared.GetCachesOptions{Limit: -1})
opts.IO.StopProgressIndicator()
if err != nil {
return err
}
if len(caches.ActionsCaches) == 0 {
return fmt.Errorf("%s No caches to delete", opts.IO.ColorScheme().FailureIcon())
if opts.SucceedOnNoCaches {
if opts.IO.IsStdoutTTY() {
fmt.Fprintf(opts.IO.Out, "%s No caches to delete\n", opts.IO.ColorScheme().SuccessIcon())
}
return nil
} else {
return fmt.Errorf("%s No caches to delete", opts.IO.ColorScheme().FailureIcon())
}
}
for _, cache := range caches.ActionsCaches {
toDelete = append(toDelete, strconv.Itoa(cache.Id))
Expand Down
77 changes: 77 additions & 0 deletions pkg/cmd/cache/delete/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ func TestNewCmdDelete(t *testing.T) {
cli: "--all",
wants: DeleteOptions{DeleteAll: true},
},
{
name: "delete all and succeed-on-no-caches flags",
cli: "--all --succeed-on-no-caches",
wants: DeleteOptions{DeleteAll: true, SucceedOnNoCaches: true},
},
{
name: "succeed-on-no-caches flag",
cli: "--succeed-on-no-caches",
wantsErr: "--succeed-on-no-caches must be used in conjunction with --all",
},
{
name: "succeed-on-no-caches flag and id argument",
cli: "--succeed-on-no-caches 123",
wantsErr: "--succeed-on-no-caches must be used in conjunction with --all",
},
{
name: "id argument and delete all flag",
cli: "1 --all",
Expand Down Expand Up @@ -72,6 +87,7 @@ func TestNewCmdDelete(t *testing.T) {
}
assert.NoError(t, err)
assert.Equal(t, tt.wants.DeleteAll, gotOpts.DeleteAll)
assert.Equal(t, tt.wants.SucceedOnNoCaches, gotOpts.SucceedOnNoCaches)
assert.Equal(t, tt.wants.Identifier, gotOpts.Identifier)
})
}
Expand Down Expand Up @@ -160,6 +176,19 @@ func TestDeleteRun(t *testing.T) {
tty: true,
wantStdout: "✓ Deleted 2 caches from OWNER/REPO\n",
},
{
name: "attempts to delete all caches but api errors",
opts: DeleteOptions{DeleteAll: true},
stubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/caches"),
httpmock.StatusStringResponse(500, ""),
)
},
tty: true,
wantErr: true,
wantErrMsg: "HTTP 500 (https://api.github.com/repos/OWNER/REPO/actions/caches?per_page=100)",
},
{
name: "displays delete error",
opts: DeleteOptions{Identifier: "123"},
Expand All @@ -186,6 +215,54 @@ func TestDeleteRun(t *testing.T) {
tty: true,
wantStdout: "✓ Deleted 1 cache from OWNER/REPO\n",
},
{
name: "no caches to delete when deleting all",
opts: DeleteOptions{DeleteAll: true},
stubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/caches"),
httpmock.JSONResponse(shared.CachePayload{
ActionsCaches: []shared.Cache{},
TotalCount: 0,
}),
)
},
tty: false,
wantErr: true,
wantErrMsg: "X No caches to delete",
},
{
name: "no caches to delete when deleting all but succeed on no cache tty",
opts: DeleteOptions{DeleteAll: true, SucceedOnNoCaches: true},
stubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/caches"),
httpmock.JSONResponse(shared.CachePayload{
ActionsCaches: []shared.Cache{},
TotalCount: 0,
}),
)
},
tty: true,
wantErr: false,
wantStdout: "✓ No caches to delete\n",
},
{
name: "no caches to delete when deleting all but succeed on no cache non-tty",
opts: DeleteOptions{DeleteAll: true, SucceedOnNoCaches: true},
stubs: func(reg *httpmock.Registry) {
reg.Register(
httpmock.REST("GET", "repos/OWNER/REPO/actions/caches"),
httpmock.JSONResponse(shared.CachePayload{
ActionsCaches: []shared.Cache{},
TotalCount: 0,
}),
)
},
tty: false,
wantErr: false,
wantStdout: "",
},
}

for _, tt := range tests {
Expand Down
Loading