From 95f2f73ed97e57387762620175ccdc277a8597a0 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Fri, 28 Feb 2020 13:13:40 -0500 Subject: [PATCH] Add short version flag -v when not otherwise set (#996) Signed-off-by: Dave Henderson --- command.go | 9 +++- command_test.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/command.go b/command.go index dc6775329..55ddc50fa 100644 --- a/command.go +++ b/command.go @@ -84,7 +84,8 @@ type Command struct { // Version defines the version for this command. If this value is non-empty and the command does not // define a "version" flag, a "version" boolean flag will be added to the command and, if specified, - // will print content of the "Version" variable. + // will print content of the "Version" variable. A shorthand "v" flag will also be added if the + // command does not define one. Version string // The *Run functions are executed in the following order: @@ -1033,7 +1034,11 @@ func (c *Command) InitDefaultVersionFlag() { } else { usage += c.Name() } - c.Flags().Bool("version", false, usage) + if c.Flags().ShorthandLookup("v") == nil { + c.Flags().BoolP("version", "v", false, usage) + } else { + c.Flags().Bool("version", false, usage) + } } } diff --git a/command_test.go b/command_test.go index 05a3c0f27..121559374 100644 --- a/command_test.go +++ b/command_test.go @@ -921,6 +921,52 @@ func TestVersionFlagExecuted(t *testing.T) { checkStringContains(t, output, "root version 1.0.0") } +func TestVersionFlagExecutedWithNoName(t *testing.T) { + rootCmd := &Command{Version: "1.0.0", Run: emptyRun} + + output, err := executeCommand(rootCmd, "--version", "arg1") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "version 1.0.0") +} + +func TestShortAndLongVersionFlagInHelp(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "-v, --version") +} + +func TestLongVersionFlagOnlyInHelpWhenShortPredefined(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + rootCmd.Flags().StringP("foo", "v", "", "not a version flag") + + output, err := executeCommand(rootCmd, "--help") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringOmits(t, output, "-v, --version") + checkStringContains(t, output, "--version") +} + +func TestShorthandVersionFlagExecuted(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + + output, err := executeCommand(rootCmd, "-v", "arg1") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "root version 1.0.0") +} + func TestVersionTemplate(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) @@ -933,6 +979,18 @@ func TestVersionTemplate(t *testing.T) { checkStringContains(t, output, "customized version: 1.0.0") } +func TestShorthandVersionTemplate(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + rootCmd.SetVersionTemplate(`customized version: {{.Version}}`) + + output, err := executeCommand(rootCmd, "-v", "arg1") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "customized version: 1.0.0") +} + func TestVersionFlagExecutedOnSubcommand(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0"} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) @@ -945,6 +1003,18 @@ func TestVersionFlagExecutedOnSubcommand(t *testing.T) { checkStringContains(t, output, "root version 1.0.0") } +func TestShorthandVersionFlagExecutedOnSubcommand(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0"} + rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) + + output, err := executeCommand(rootCmd, "-v", "sub") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + checkStringContains(t, output, "root version 1.0.0") +} + func TestVersionFlagOnlyAddedToRoot(t *testing.T) { rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) @@ -957,6 +1027,18 @@ func TestVersionFlagOnlyAddedToRoot(t *testing.T) { checkStringContains(t, err.Error(), "unknown flag: --version") } +func TestShortVersionFlagOnlyAddedToRoot(t *testing.T) { + rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun} + rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun}) + + _, err := executeCommand(rootCmd, "sub", "-v") + if err == nil { + t.Errorf("Expected error") + } + + checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") +} + func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { rootCmd := &Command{Use: "root", Run: emptyRun} @@ -967,6 +1049,39 @@ func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { checkStringContains(t, err.Error(), "unknown flag: --version") } +func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun} + + _, err := executeCommand(rootCmd, "-v") + if err == nil { + t.Errorf("Expected error") + } + checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") +} + +func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"} + rootCmd.Flags().StringP("notversion", "v", "", "not a version flag") + + _, err := executeCommand(rootCmd, "-v") + if err == nil { + t.Errorf("Expected error") + } + check(t, rootCmd.Flags().ShorthandLookup("v").Name, "notversion") + checkStringContains(t, err.Error(), "flag needs an argument: 'v' in -v") +} + +func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined(t *testing.T) { + rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"} + rootCmd.Flags().Bool("version", false, "a different kind of version flag") + + _, err := executeCommand(rootCmd, "-v") + if err == nil { + t.Errorf("Expected error") + } + checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v") +} + func TestUsageIsNotPrintedTwice(t *testing.T) { var cmd = &Command{Use: "root"} var sub = &Command{Use: "sub"}