From 2ebdde1ddd0b0887b92ba3f3fc4b59082bb7498c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 2 Mar 2021 13:48:44 +0100 Subject: [PATCH] Exit with status code "2" on user cancellation errors This also stops printing "interrupt" after Ctrl-C is pressed. --- cmd/gh/main.go | 10 ++++++---- pkg/cmd/gist/edit/edit.go | 2 +- pkg/cmd/issue/create/create.go | 2 +- pkg/cmd/pr/create/create.go | 4 ++-- pkg/cmd/pr/merge/merge.go | 2 +- pkg/cmd/pr/shared/preserve.go | 4 +--- pkg/cmd/release/create/create.go | 2 +- pkg/cmd/release/delete/delete.go | 2 +- pkg/cmdutil/errors.go | 13 ++++++++++++- 9 files changed, 26 insertions(+), 15 deletions(-) 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) +}