Skip to content

Improve ErrorWithExitCode #30

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

Merged
merged 2 commits into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions entrypoint/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,38 @@ func RunApp(app *cli.App) {
// If there is an error, display it in the console and exit with a non-zero exit code. Otherwise, exit 0.
// Note that if the GRUNTWORK_DEBUG environment variable is set, this will print out the stack trace.
func checkForErrorsAndExit(err error) {
exitCode := defaultSuccessExitCode
isDebugMode := os.Getenv(debugEnvironmentVarName) != ""
logError(err)
exitCode := getExitCode(err)
os.Exit(exitCode)
}

// logError will output an error message to stderr. This will output the stack trace if we are in debug mode.
func logError(err error) {
isDebugMode := os.Getenv(debugEnvironmentVarName) != ""
if err != nil {
errWithoutStackTrace := errors.Unwrap(err)
if isDebugMode {
logging.GetLogger("").WithError(err).Error(errors.PrintErrorWithStackTrace(err))
} else {
fmt.Fprintf(os.Stderr, "ERROR: %s\n", errors.Unwrap(err))
fmt.Fprintf(os.Stderr, "ERROR: %s\n", errWithoutStackTrace)
}
}
}

errorWithExitCode, isErrorWithExitCode := err.(errors.ErrorWithExitCode)
// getExitCode will return an exit code to use for the CLI app. This will either be:
// - defaultSuccessExitCode if there is no error.
// - defaultErrorExitCode if there is a standard error.
// - error exit code if there is an error that indicates an exit code.
func getExitCode(err error) int {
exitCode := defaultSuccessExitCode
if err != nil {
errWithoutStackTrace := errors.Unwrap(err)
errorWithExitCode, isErrorWithExitCode := errWithoutStackTrace.(errors.ErrorWithExitCode)
if isErrorWithExitCode {
exitCode = errorWithExitCode.ExitCode
} else {
exitCode = defaultErrorExitCode
}
}

os.Exit(exitCode)
return exitCode
}
43 changes: 42 additions & 1 deletion entrypoint/entrypoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,52 @@ package entrypoint

import (
"bytes"
"fmt"
"testing"

"github.com/gruntwork-io/gruntwork-cli/errors"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
"testing"
)

func TestEntrypointGetExitCode(t *testing.T) {
testCases := []struct {
name string
err error
expectedExitCode int
}{
{"TestNoError", nil, defaultSuccessExitCode},
{"TestNoErrorWithStackTrace", errors.WithStackTrace(nil), defaultSuccessExitCode},

{"TestBareError", fmt.Errorf("Broken"), defaultErrorExitCode},
{"TestBareErrorWithStackTrace", errors.WithStackTrace(fmt.Errorf("Broken")), defaultErrorExitCode},

{
"TestErrorWithExitCode",
errors.ErrorWithExitCode{
Err: fmt.Errorf("Broken"),
ExitCode: 127,
},
127,
},
{
"TestErrorWithExitCodeWithStackTrace",
errors.WithStackTrace(
errors.ErrorWithExitCode{
Err: fmt.Errorf("Broken"),
ExitCode: 127,
},
),
127,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, getExitCode(testCase.err), testCase.expectedExitCode)
})
}
}

func TestEntrypointNewAppWrapsAppHelpPrinter(t *testing.T) {
app := createSampleApp()
fakeStdout := bytes.NewBufferString("")
Expand Down
3 changes: 2 additions & 1 deletion errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package errors

import (
"fmt"

goerrors "github.com/go-errors/errors"
"github.com/urfave/cli"
)
Expand All @@ -13,7 +14,7 @@ type ErrorWithExitCode struct {
}

func (err ErrorWithExitCode) Error() string {
return fmt.Sprintf("ErrorWithExitCode{ Err = %v, ExitCode = %d }", err.Err, err.ExitCode)
return err.Err.Error()
}

// Wrap the given error in an Error type that contains the stack trace. If the given error already has a stack trace,
Expand Down