diff --git a/cmd/gh/main.go b/cmd/gh/main.go index a0eba09a5..adfa28f90 100644 --- a/cmd/gh/main.go +++ b/cmd/gh/main.go @@ -148,6 +148,12 @@ func main() { rootCmd.SetArgs(expandedArgs) if cmd, err := rootCmd.ExecuteC(); err != nil { + if err == cmdutil.SilentError { + os.Exit(1) + } else if cmdutil.IsUserCancellation(err) { + os.Exit(2) + } + printError(stderr, err, cmd, hasDebug) var httpErr api.HTTPError @@ -177,10 +183,6 @@ func main() { } func printError(out io.Writer, err error, cmd *cobra.Command, debug bool) { - if err == cmdutil.SilentError { - return - } - var dnsError *net.DNSError if errors.As(err, &dnsError) { fmt.Fprintf(out, "error connecting to %s\n", dnsError.Name) diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index 7cba14800..3c16f1a16 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -177,7 +177,7 @@ func editRun(opts *EditOptions) error { case "Submit": stop = true case "Cancel": - return cmdutil.SilentError + return cmdutil.CancelError } if stop { diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index 3d6b5b25c..0bd8dabc9 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -249,7 +249,7 @@ func createRun(opts *CreateOptions) (err error) { if action == prShared.CancelAction { fmt.Fprintln(opts.IO.ErrOut, "Discarding.") - err = cmdutil.SilentError + err = cmdutil.CancelError return } } else { diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 18b8c1e99..2dc7045ff 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -299,7 +299,7 @@ func createRun(opts *CreateOptions) (err error) { if action == shared.CancelAction { fmt.Fprintln(opts.IO.ErrOut, "Discarding.") - err = cmdutil.SilentError + err = cmdutil.CancelError return } @@ -542,7 +542,7 @@ func NewCreateContext(opts *CreateOptions) (*CreateContext, error) { } else if pushOptions[selectedOption] == "Skip pushing the branch" { isPushEnabled = false } else if pushOptions[selectedOption] == "Cancel" { - return nil, cmdutil.SilentError + return nil, cmdutil.CancelError } else { // "Create a fork of ..." if baseRepo.IsPrivate { diff --git a/pkg/cmd/pr/merge/merge.go b/pkg/cmd/pr/merge/merge.go index 67498b726..5981b330f 100644 --- a/pkg/cmd/pr/merge/merge.go +++ b/pkg/cmd/pr/merge/merge.go @@ -228,7 +228,7 @@ func mergeRun(opts *MergeOptions) error { } if action == shared.CancelAction { fmt.Fprintln(opts.IO.ErrOut, "Cancelled.") - return cmdutil.SilentError + return cmdutil.CancelError } } diff --git a/pkg/cmd/pr/shared/preserve.go b/pkg/cmd/pr/shared/preserve.go index 44b8fa183..6d3c32965 100644 --- a/pkg/cmd/pr/shared/preserve.go +++ b/pkg/cmd/pr/shared/preserve.go @@ -2,11 +2,9 @@ package shared import ( "encoding/json" - "errors" "fmt" "os" - "github.com/AlecAivazis/survey/v2/terminal" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" ) @@ -21,7 +19,7 @@ func PreserveInput(io *iostreams.IOStreams, state *IssueMetadataState, createErr return } - if errors.Is(*createErr, cmdutil.SilentError) || errors.Is(*createErr, terminal.InterruptErr) { + if cmdutil.IsUserCancellation(*createErr) { // these errors are user-initiated cancellations return } diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 9b87b8845..fd94a511a 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -262,7 +262,7 @@ func createRun(opts *CreateOptions) error { case "Save as draft": opts.Draft = true case "Cancel": - return cmdutil.SilentError + return cmdutil.CancelError default: return fmt.Errorf("invalid action: %v", opts.SubmitAction) } diff --git a/pkg/cmd/release/delete/delete.go b/pkg/cmd/release/delete/delete.go index fde3fbcee..c880f9d58 100644 --- a/pkg/cmd/release/delete/delete.go +++ b/pkg/cmd/release/delete/delete.go @@ -78,7 +78,7 @@ func deleteRun(opts *DeleteOptions) error { } if !confirmed { - return cmdutil.SilentError + return cmdutil.CancelError } } diff --git a/pkg/cmdutil/errors.go b/pkg/cmdutil/errors.go index 77ca58340..aa33e98ef 100644 --- a/pkg/cmdutil/errors.go +++ b/pkg/cmdutil/errors.go @@ -1,6 +1,10 @@ package cmdutil -import "errors" +import ( + "errors" + + "github.com/AlecAivazis/survey/v2/terminal" +) // FlagError is the kind of error raised in flag processing type FlagError struct { @@ -17,3 +21,10 @@ func (fe FlagError) Unwrap() error { // SilentError is an error that triggers exit code 1 without any error messaging var SilentError = errors.New("SilentError") + +// CancelError signals user-initiated cancellation +var CancelError = errors.New("CancelError") + +func IsUserCancellation(err error) bool { + return errors.Is(err, CancelError) || errors.Is(err, terminal.InterruptErr) +}