diff --git a/cmd/root.go b/cmd/root.go index a6b72d2..54ff0ea 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,6 +1,8 @@ package cmd import ( + "os" + "github.com/amp-labs/cli/flags" "github.com/amp-labs/cli/logger" "github.com/spf13/cobra" @@ -21,7 +23,7 @@ var rootCmd = &cobra.Command{ //nolint:gochecknoglobals func Execute() { err := rootCmd.Execute() if err != nil { - return + os.Exit(1) } } diff --git a/cmd/root_test.go b/cmd/root_test.go new file mode 100644 index 0000000..7b90c3e --- /dev/null +++ b/cmd/root_test.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "errors" + "os" + "os/exec" + "strings" + "testing" +) + +const executeUnknownCommandEnv = "AMP_TEST_EXECUTE_UNKNOWN_COMMAND" + +func TestExecuteExitsWithFailureForUnknownCommand(t *testing.T) { + t.Parallel() + + if os.Getenv(executeUnknownCommandEnv) == "1" { + os.Args = []string{"amp", "definitely-not-a-command"} + + Execute() + + return + } + + // This test intentionally executes the current test binary. + //nolint:gosec + command := exec.CommandContext( + t.Context(), os.Args[0], "-test.run=^TestExecuteExitsWithFailureForUnknownCommand$", + ) + + command.Env = append(os.Environ(), executeUnknownCommandEnv+"=1") + + output, err := command.CombinedOutput() + if err == nil { + t.Fatalf("Execute() exited successfully for an unknown command: %s", output) + } + + var exitError *exec.ExitError + if !errors.As(err, &exitError) { + t.Fatalf("Execute() returned %T, want an exit error", err) + } + + if exitError.ExitCode() != 1 { + t.Fatalf("Execute() returned exit code %d, want 1", exitError.ExitCode()) + } + + if !strings.Contains(string(output), `unknown command "definitely-not-a-command"`) { + t.Fatalf("Execute() output = %q, want unknown command error", output) + } +}