From deb34d6456d14efe73ccd61fcb88e063da5f4794 Mon Sep 17 00:00:00 2001 From: bagtoad <47394200+BagToad@users.noreply.github.com> Date: Sat, 23 Nov 2024 16:59:49 -0700 Subject: [PATCH] Refactor error handling for missing "workflow" scope in createRelease --- pkg/cmd/release/create/create.go | 15 +++++++++++++++ pkg/cmd/release/create/create_test.go | 9 +++++---- pkg/cmd/release/create/http.go | 18 +++++++++++------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 0b7c99b23..8e77546d0 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -477,6 +477,21 @@ func createRun(opts *CreateOptions) error { } newRelease, err := createRelease(httpClient, baseRepo, params) + + var errMissingRequiredWorkflowScope *errMissingRequiredWorkflowScope + if errors.As(err, &errMissingRequiredWorkflowScope) { + host := errMissingRequiredWorkflowScope.Hostname + refreshInstructions := fmt.Sprintf("gh auth refresh -h %[1]s -s workflow", host) + cs := opts.IO.ColorScheme() + + var sb strings.Builder + sb.WriteString(fmt.Sprintf("%s Failed to create release, \"workflow\" scope may be required.\n", cs.WarningIcon())) + sb.WriteString(fmt.Sprintf("To request it, run:\n%s\n", cs.Bold(refreshInstructions))) + fmt.Fprint(opts.IO.ErrOut, sb.String()) + + return cmdutil.SilentError + } + if err != nil { return err } diff --git a/pkg/cmd/release/create/create_test.go b/pkg/cmd/release/create/create_test.go index aded1bea9..c9e9a8c8a 100644 --- a/pkg/cmd/release/create/create_test.go +++ b/pkg/cmd/release/create/create_test.go @@ -1102,10 +1102,12 @@ func Test_createRun(t *testing.T) { httpmock.REST("POST", "repos/OWNER/REPO/releases"), httpmock.StatusScopesResponder(404, `repo,read:org`)) }, - wantErr: heredoc.Doc(` - HTTP 404: Failed to create release, "workflow" scope may be required - To request it, run gh auth refresh -h github.com -s workflow + wantStderr: heredoc.Doc(` + ! Failed to create release, "workflow" scope may be required. + To request it, run: + gh auth refresh -h github.com -s workflow `), + wantErr: cmdutil.SilentError.Error(), }, { name: "API returns 404, OAuth token has workflow scope", @@ -1182,7 +1184,6 @@ func Test_createRun(t *testing.T) { err := createRun(&tt.opts) if tt.wantErr != "" { require.EqualError(t, err, tt.wantErr) - return } else { require.NoError(t, err) } diff --git a/pkg/cmd/release/create/http.go b/pkg/cmd/release/create/http.go index 1162e7080..3bb55f39e 100644 --- a/pkg/cmd/release/create/http.go +++ b/pkg/cmd/release/create/http.go @@ -11,7 +11,6 @@ import ( "slices" "strings" - "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghinstance" "github.com/cli/cli/v2/internal/ghrepo" @@ -32,6 +31,14 @@ type releaseNotes struct { var notImplementedError = errors.New("not implemented") +type errMissingRequiredWorkflowScope struct { + Hostname string +} + +func (e errMissingRequiredWorkflowScope) Error() string { + return "workflow scope may be required" +} + func remoteTagExists(httpClient *http.Client, repo ghrepo.Interface, tagName string) (bool, error) { gql := api.NewClientFromHTTP(httpClient) qualifiedTagName := fmt.Sprintf("refs/tags/%s", tagName) @@ -192,12 +199,9 @@ func createRelease(httpClient *http.Client, repo ghrepo.Interface, params map[st // https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps#available-scopes if resp.StatusCode == http.StatusNotFound && !tokenHasWorkflowScope(resp) { normalizedHostname := ghauth.NormalizeHostname(resp.Request.URL.Hostname()) - errMissingRequiredWorkflowScope := errors.New(heredoc.Docf(` - HTTP 404: Failed to create release, "workflow" scope may be required - To request it, run gh auth refresh -h %[1]s -s workflow - `, normalizedHostname)) - - return nil, errMissingRequiredWorkflowScope + return nil, &errMissingRequiredWorkflowScope{ + Hostname: normalizedHostname, + } } success := resp.StatusCode >= 200 && resp.StatusCode < 300