Skip to content
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

Customizable error message prefix #2023

Merged
merged 9 commits into from
Sep 8, 2023
24 changes: 22 additions & 2 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ type Command struct {
// versionTemplate is the version template defined by user.
versionTemplate string

// errPrefix is the error message prefix defined by user.
errPrefix string

// inReader is a reader defined by the user that replaces stdin
inReader io.Reader
// outWriter is a writer defined by the user that replaces stdout
Expand Down Expand Up @@ -346,6 +349,11 @@ func (c *Command) SetVersionTemplate(s string) {
c.versionTemplate = s
}

// SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix.
func (c *Command) SetErrPrefix(s string) {
c.errPrefix = s
}

// SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands.
// The user should not have a cyclic dependency on commands.
func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string) flag.NormalizedName) {
Expand Down Expand Up @@ -595,6 +603,18 @@ func (c *Command) VersionTemplate() string {
`
}

// ErrPrefix return error message prefix for the command
func (c *Command) ErrPrefix() string {
if c.errPrefix != "" {
return c.errPrefix
}

if c.HasParent() {
return c.parent.ErrPrefix()
}
return "Error:"
}

func hasNoOptDefVal(name string, fs *flag.FlagSet) bool {
flag := fs.Lookup(name)
if flag == nil {
Expand Down Expand Up @@ -1050,7 +1070,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
c = cmd
}
if !c.SilenceErrors {
c.PrintErrln("Error:", err.Error())
c.PrintErrln(c.ErrPrefix(), err.Error())
c.PrintErrf("Run '%v --help' for usage.\n", c.CommandPath())
}
return c, err
Expand Down Expand Up @@ -1079,7 +1099,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
// If root command has SilenceErrors flagged,
// all subcommands should respect it
if !cmd.SilenceErrors && !c.SilenceErrors {
c.PrintErrln("Error:", err.Error())
c.PrintErrln(cmd.ErrPrefix(), err.Error())
}

// If root command has SilenceUsage flagged,
Expand Down
33 changes: 33 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,39 @@ func TestShorthandVersionTemplate(t *testing.T) {
checkStringContains(t, output, "customized version: 1.0.0")
}

func TestRootErrPrefixExecutedOnSubcommand(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
rootCmd.SetErrPrefix("root error prefix:")
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})

output, err := executeCommand(rootCmd, "sub", "--unknown-flag")
if err == nil {
t.Errorf("Expected error")
}

checkStringContains(t, output, "root error prefix: unknown flag: --unknown-flag")
}

func TestRootAndSubErrPrefix(t *testing.T) {
rootCmd := &Command{Use: "root", Run: emptyRun}
subCmd := &Command{Use: "sub", Run: emptyRun}
rootCmd.AddCommand(subCmd)
rootCmd.SetErrPrefix("root error prefix:")
subCmd.SetErrPrefix("sub error prefix:")

if output, err := executeCommand(rootCmd, "--unknown-root-flag"); err == nil {
t.Errorf("Expected error")
} else {
checkStringContains(t, output, "root error prefix: unknown flag: --unknown-root-flag")
}

if output, err := executeCommand(rootCmd, "sub", "--unknown-sub-flag"); err == nil {
t.Errorf("Expected error")
} else {
checkStringContains(t, output, "sub error prefix: unknown flag: --unknown-sub-flag")
}
}

func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
rootCmd := &Command{Use: "root", Version: "1.0.0"}
rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
Expand Down
6 changes: 6 additions & 0 deletions site/content/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,12 @@ Running an application with the '--version' flag will print the version to stdou
the version template. The template can be customized using the
`cmd.SetVersionTemplate(s string)` function.

## Error Message Prefix

Cobra prints an error message when receiving a non-nil error value.
The default error message is `Error: <error contents>`.
The Prefix, `Error:` can be customized using the `cmd.SetErrPrefix(s string)` function.

## PreRun and PostRun Hooks

It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order:
Expand Down