mirror of https://github.com/spf13/cobra.git
Fix --version help and output for plugins (#2180)
* Fix --version help with CommandDisplayNameAnnotation When setting Command.Version, a --version option is added. The help message for the --version command did not consider the command display name: Flags: -h, --help help for kubectl plugin -v, --version version for kubectl-plugin With this change the help test is consistent with other flags: Flags: -h, --help help for kubectl plugin -v, --version version for kubectl plugin * Make command DisplayName() public This allows using the display name in templates or other code that want to use the same value. * Use display name in version template The version template used `{{.Name}}` but for plugins you want to use `{{.DisplayName}}` to be consistent with other help output. With this change will show: $ kubectl plugin --version kubectl plugin version 1.0.0
This commit is contained in:
parent
ff7c561cf7
commit
5bef9d8d87
32
command.go
32
command.go
|
@ -607,7 +607,7 @@ func (c *Command) VersionTemplate() string {
|
||||||
if c.HasParent() {
|
if c.HasParent() {
|
||||||
return c.parent.VersionTemplate()
|
return c.parent.VersionTemplate()
|
||||||
}
|
}
|
||||||
return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
|
return `{{with .DisplayName}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,7 +1190,7 @@ func (c *Command) InitDefaultHelpFlag() {
|
||||||
c.mergePersistentFlags()
|
c.mergePersistentFlags()
|
||||||
if c.Flags().Lookup("help") == nil {
|
if c.Flags().Lookup("help") == nil {
|
||||||
usage := "help for "
|
usage := "help for "
|
||||||
name := c.displayName()
|
name := c.DisplayName()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
usage += "this command"
|
usage += "this command"
|
||||||
} else {
|
} else {
|
||||||
|
@ -1216,7 +1216,7 @@ func (c *Command) InitDefaultVersionFlag() {
|
||||||
if c.Name() == "" {
|
if c.Name() == "" {
|
||||||
usage += "this command"
|
usage += "this command"
|
||||||
} else {
|
} else {
|
||||||
usage += c.Name()
|
usage += c.DisplayName()
|
||||||
}
|
}
|
||||||
if c.Flags().ShorthandLookup("v") == nil {
|
if c.Flags().ShorthandLookup("v") == nil {
|
||||||
c.Flags().BoolP("version", "v", false, usage)
|
c.Flags().BoolP("version", "v", false, usage)
|
||||||
|
@ -1240,7 +1240,7 @@ func (c *Command) InitDefaultHelpCmd() {
|
||||||
Use: "help [command]",
|
Use: "help [command]",
|
||||||
Short: "Help about any command",
|
Short: "Help about any command",
|
||||||
Long: `Help provides help for any command in the application.
|
Long: `Help provides help for any command in the application.
|
||||||
Simply type ` + c.displayName() + ` help [path to command] for full details.`,
|
Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,
|
||||||
ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
|
ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
|
||||||
var completions []string
|
var completions []string
|
||||||
cmd, _, e := c.Root().Find(args)
|
cmd, _, e := c.Root().Find(args)
|
||||||
|
@ -1431,10 +1431,12 @@ func (c *Command) CommandPath() string {
|
||||||
if c.HasParent() {
|
if c.HasParent() {
|
||||||
return c.Parent().CommandPath() + " " + c.Name()
|
return c.Parent().CommandPath() + " " + c.Name()
|
||||||
}
|
}
|
||||||
return c.displayName()
|
return c.DisplayName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) displayName() string {
|
// DisplayName returns the name to display in help text. Returns command Name()
|
||||||
|
// If CommandDisplayNameAnnoation is not set
|
||||||
|
func (c *Command) DisplayName() string {
|
||||||
if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok {
|
if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok {
|
||||||
return displayName
|
return displayName
|
||||||
}
|
}
|
||||||
|
@ -1444,7 +1446,7 @@ func (c *Command) displayName() string {
|
||||||
// UseLine puts out the full usage for a given command (including parents).
|
// UseLine puts out the full usage for a given command (including parents).
|
||||||
func (c *Command) UseLine() string {
|
func (c *Command) UseLine() string {
|
||||||
var useline string
|
var useline string
|
||||||
use := strings.Replace(c.Use, c.Name(), c.displayName(), 1)
|
use := strings.Replace(c.Use, c.Name(), c.DisplayName(), 1)
|
||||||
if c.HasParent() {
|
if c.HasParent() {
|
||||||
useline = c.parent.CommandPath() + " " + use
|
useline = c.parent.CommandPath() + " " + use
|
||||||
} else {
|
} else {
|
||||||
|
@ -1650,7 +1652,7 @@ func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) f
|
||||||
// to this command (local and persistent declared here and by all parents).
|
// to this command (local and persistent declared here and by all parents).
|
||||||
func (c *Command) Flags() *flag.FlagSet {
|
func (c *Command) Flags() *flag.FlagSet {
|
||||||
if c.flags == nil {
|
if c.flags == nil {
|
||||||
c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
if c.flagErrorBuf == nil {
|
if c.flagErrorBuf == nil {
|
||||||
c.flagErrorBuf = new(bytes.Buffer)
|
c.flagErrorBuf = new(bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
@ -1665,7 +1667,7 @@ func (c *Command) Flags() *flag.FlagSet {
|
||||||
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
|
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
|
||||||
persistentFlags := c.PersistentFlags()
|
persistentFlags := c.PersistentFlags()
|
||||||
|
|
||||||
out := flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
out := flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
c.LocalFlags().VisitAll(func(f *flag.Flag) {
|
c.LocalFlags().VisitAll(func(f *flag.Flag) {
|
||||||
if persistentFlags.Lookup(f.Name) == nil {
|
if persistentFlags.Lookup(f.Name) == nil {
|
||||||
out.AddFlag(f)
|
out.AddFlag(f)
|
||||||
|
@ -1680,7 +1682,7 @@ func (c *Command) LocalFlags() *flag.FlagSet {
|
||||||
c.mergePersistentFlags()
|
c.mergePersistentFlags()
|
||||||
|
|
||||||
if c.lflags == nil {
|
if c.lflags == nil {
|
||||||
c.lflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.lflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
if c.flagErrorBuf == nil {
|
if c.flagErrorBuf == nil {
|
||||||
c.flagErrorBuf = new(bytes.Buffer)
|
c.flagErrorBuf = new(bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
@ -1708,7 +1710,7 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
|
||||||
c.mergePersistentFlags()
|
c.mergePersistentFlags()
|
||||||
|
|
||||||
if c.iflags == nil {
|
if c.iflags == nil {
|
||||||
c.iflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.iflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
if c.flagErrorBuf == nil {
|
if c.flagErrorBuf == nil {
|
||||||
c.flagErrorBuf = new(bytes.Buffer)
|
c.flagErrorBuf = new(bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
@ -1737,7 +1739,7 @@ func (c *Command) NonInheritedFlags() *flag.FlagSet {
|
||||||
// PersistentFlags returns the persistent FlagSet specifically set in the current command.
|
// PersistentFlags returns the persistent FlagSet specifically set in the current command.
|
||||||
func (c *Command) PersistentFlags() *flag.FlagSet {
|
func (c *Command) PersistentFlags() *flag.FlagSet {
|
||||||
if c.pflags == nil {
|
if c.pflags == nil {
|
||||||
c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
if c.flagErrorBuf == nil {
|
if c.flagErrorBuf == nil {
|
||||||
c.flagErrorBuf = new(bytes.Buffer)
|
c.flagErrorBuf = new(bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
@ -1750,9 +1752,9 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
|
||||||
func (c *Command) ResetFlags() {
|
func (c *Command) ResetFlags() {
|
||||||
c.flagErrorBuf = new(bytes.Buffer)
|
c.flagErrorBuf = new(bytes.Buffer)
|
||||||
c.flagErrorBuf.Reset()
|
c.flagErrorBuf.Reset()
|
||||||
c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
c.flags.SetOutput(c.flagErrorBuf)
|
c.flags.SetOutput(c.flagErrorBuf)
|
||||||
c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
c.pflags.SetOutput(c.flagErrorBuf)
|
c.pflags.SetOutput(c.flagErrorBuf)
|
||||||
|
|
||||||
c.lflags = nil
|
c.lflags = nil
|
||||||
|
@ -1869,7 +1871,7 @@ func (c *Command) mergePersistentFlags() {
|
||||||
// If c.parentsPflags == nil, it makes new.
|
// If c.parentsPflags == nil, it makes new.
|
||||||
func (c *Command) updateParentsPflags() {
|
func (c *Command) updateParentsPflags() {
|
||||||
if c.parentsPflags == nil {
|
if c.parentsPflags == nil {
|
||||||
c.parentsPflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
|
c.parentsPflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
|
||||||
c.parentsPflags.SetOutput(c.flagErrorBuf)
|
c.parentsPflags.SetOutput(c.flagErrorBuf)
|
||||||
c.parentsPflags.SortFlags = false
|
c.parentsPflags.SortFlags = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,6 +372,7 @@ func TestAliasPrefixMatching(t *testing.T) {
|
||||||
func TestPlugin(t *testing.T) {
|
func TestPlugin(t *testing.T) {
|
||||||
cmd := &Command{
|
cmd := &Command{
|
||||||
Use: "kubectl-plugin",
|
Use: "kubectl-plugin",
|
||||||
|
Version: "1.0.0",
|
||||||
Args: NoArgs,
|
Args: NoArgs,
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
CommandDisplayNameAnnotation: "kubectl plugin",
|
CommandDisplayNameAnnotation: "kubectl plugin",
|
||||||
|
@ -386,12 +387,14 @@ func TestPlugin(t *testing.T) {
|
||||||
|
|
||||||
checkStringContains(t, cmdHelp, "kubectl plugin [flags]")
|
checkStringContains(t, cmdHelp, "kubectl plugin [flags]")
|
||||||
checkStringContains(t, cmdHelp, "help for kubectl plugin")
|
checkStringContains(t, cmdHelp, "help for kubectl plugin")
|
||||||
|
checkStringContains(t, cmdHelp, "version for kubectl plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPlugin checks usage as plugin with sub commands.
|
// TestPlugin checks usage as plugin with sub commands.
|
||||||
func TestPluginWithSubCommands(t *testing.T) {
|
func TestPluginWithSubCommands(t *testing.T) {
|
||||||
rootCmd := &Command{
|
rootCmd := &Command{
|
||||||
Use: "kubectl-plugin",
|
Use: "kubectl-plugin",
|
||||||
|
Version: "1.0.0",
|
||||||
Args: NoArgs,
|
Args: NoArgs,
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
CommandDisplayNameAnnotation: "kubectl plugin",
|
CommandDisplayNameAnnotation: "kubectl plugin",
|
||||||
|
@ -408,6 +411,7 @@ func TestPluginWithSubCommands(t *testing.T) {
|
||||||
|
|
||||||
checkStringContains(t, rootHelp, "kubectl plugin [command]")
|
checkStringContains(t, rootHelp, "kubectl plugin [command]")
|
||||||
checkStringContains(t, rootHelp, "help for kubectl plugin")
|
checkStringContains(t, rootHelp, "help for kubectl plugin")
|
||||||
|
checkStringContains(t, rootHelp, "version for kubectl plugin")
|
||||||
checkStringContains(t, rootHelp, "kubectl plugin [command] --help")
|
checkStringContains(t, rootHelp, "kubectl plugin [command] --help")
|
||||||
|
|
||||||
childHelp, err := executeCommand(rootCmd, "sub", "-h")
|
childHelp, err := executeCommand(rootCmd, "sub", "-h")
|
||||||
|
@ -1090,6 +1094,24 @@ func TestVersionFlagExecuted(t *testing.T) {
|
||||||
checkStringContains(t, output, "root version 1.0.0")
|
checkStringContains(t, output, "root version 1.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVersionFlagExecutedDiplayName(t *testing.T) {
|
||||||
|
rootCmd := &Command{
|
||||||
|
Use: "kubectl-plugin",
|
||||||
|
Version: "1.0.0",
|
||||||
|
Annotations: map[string]string{
|
||||||
|
CommandDisplayNameAnnotation: "kubectl plugin",
|
||||||
|
},
|
||||||
|
Run: emptyRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := executeCommand(rootCmd, "--version", "arg1")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, output, "kubectl plugin version 1.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
func TestVersionFlagExecutedWithNoName(t *testing.T) {
|
func TestVersionFlagExecutedWithNoName(t *testing.T) {
|
||||||
rootCmd := &Command{Version: "1.0.0", Run: emptyRun}
|
rootCmd := &Command{Version: "1.0.0", Run: emptyRun}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue