mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Support usage as plugin for tools like kubectl (#2018)
In this case the executable is `kubectl-plugin`, but we run it as: kubectl plugin And the help text should reflect the actual usage of the command. To create a plugin, add the cobra.CommandDisplayNameAnnotation: rootCmd := &cobra.Command{ Use: "plugin", Annotations: map[string]string{ cobra.CommandDisplayNameAnnotation: "kubectl plugin", } } Internally this change modifies CommandPath() for the root command to return the command display name instead of the command name. This is used for error messages, help text generation, and completions. CommandPath() is expected to have spaces and code using it already handle spaces (e.g replacing with _), so hopefully this does not break anything. Fixes: #2017 Signed-off-by: Nir Soffer <nsoffer@redhat.com>
This commit is contained in:
parent
48cea5c87b
commit
890302a35f
2 changed files with 38 additions and 2 deletions
10
command.go
10
command.go
|
@ -30,7 +30,10 @@ import (
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
const FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra"
|
const (
|
||||||
|
FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra"
|
||||||
|
CommandDisplayNameAnnotation = "cobra_annotation_command_display_name"
|
||||||
|
)
|
||||||
|
|
||||||
// FParseErrWhitelist configures Flag parse errors to be ignored
|
// FParseErrWhitelist configures Flag parse errors to be ignored
|
||||||
type FParseErrWhitelist flag.ParseErrorsWhitelist
|
type FParseErrWhitelist flag.ParseErrorsWhitelist
|
||||||
|
@ -99,7 +102,7 @@ type Command struct {
|
||||||
Deprecated string
|
Deprecated string
|
||||||
|
|
||||||
// Annotations are key/value pairs that can be used by applications to identify or
|
// Annotations are key/value pairs that can be used by applications to identify or
|
||||||
// group commands.
|
// group commands or set special options.
|
||||||
Annotations map[string]string
|
Annotations map[string]string
|
||||||
|
|
||||||
// Version defines the version for this command. If this value is non-empty and the command does not
|
// Version defines the version for this command. If this value is non-empty and the command does not
|
||||||
|
@ -1424,6 +1427,9 @@ func (c *Command) CommandPath() string {
|
||||||
if c.HasParent() {
|
if c.HasParent() {
|
||||||
return c.Parent().CommandPath() + " " + c.Name()
|
return c.Parent().CommandPath() + " " + c.Name()
|
||||||
}
|
}
|
||||||
|
if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok {
|
||||||
|
return displayName
|
||||||
|
}
|
||||||
return c.Name()
|
return c.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -366,6 +366,36 @@ func TestAliasPrefixMatching(t *testing.T) {
|
||||||
EnablePrefixMatching = defaultPrefixMatching
|
EnablePrefixMatching = defaultPrefixMatching
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestPlugin checks usage as plugin for another command such as kubectl. The
|
||||||
|
// executable is `kubectl-plugin`, but we run it as `kubectl plugin`. The help
|
||||||
|
// text should reflect the way we run the command.
|
||||||
|
func TestPlugin(t *testing.T) {
|
||||||
|
rootCmd := &Command{
|
||||||
|
Use: "plugin",
|
||||||
|
Args: NoArgs,
|
||||||
|
Annotations: map[string]string{
|
||||||
|
CommandDisplayNameAnnotation: "kubectl plugin",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
subCmd := &Command{Use: "sub [flags]", Args: NoArgs, Run: emptyRun}
|
||||||
|
rootCmd.AddCommand(subCmd)
|
||||||
|
|
||||||
|
rootHelp, err := executeCommand(rootCmd, "-h")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, rootHelp, "kubectl plugin [command]")
|
||||||
|
|
||||||
|
childHelp, err := executeCommand(rootCmd, "sub", "-h")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStringContains(t, childHelp, "kubectl plugin sub [flags]")
|
||||||
|
}
|
||||||
|
|
||||||
// TestChildSameName checks the correct behaviour of cobra in cases,
|
// TestChildSameName checks the correct behaviour of cobra in cases,
|
||||||
// when an application with name "foo" and with subcommand "foo"
|
// when an application with name "foo" and with subcommand "foo"
|
||||||
// is executed with args "foo foo".
|
// is executed with args "foo foo".
|
||||||
|
|
Loading…
Reference in a new issue