From 2d88c896bccaf7ae6cb393336503021ae88ad461 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 28 Jun 2022 10:17:50 +0200 Subject: [PATCH] cli: print full command as aliases in usage output The default output for Cobra aliases only shows the subcommand as alias, which is not very intuitive. This patch changes the output to print the full command as it would be called by the user. Note that there's still some improvements to be made; due to how aliases must be set-up in Cobra, aliases at different "levels" are still not shown. So for example, `docker ps --help` will not show `docker container ps` as alias, and vice-versa. This will require additional changes, and can possibly be resolved using custom metadata/annotations. Before this patch: docker container ls --help Usage: docker container ls [OPTIONS] List containers Aliases: ls, ps, list After this patch: docker container ls --help Usage: docker container ls [OPTIONS] List containers Aliases: docker container ls, docker container ps, docker container list Signed-off-by: Sebastiaan van Stijn --- cli/cobra.go | 18 +++++++++++++++++- cli/cobra_test.go | 8 ++++++++ e2e/stack/testdata/stack-deploy-help.golden | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/cli/cobra.go b/cli/cobra.go index cb1cf8527a..ae425adddd 100644 --- a/cli/cobra.go +++ b/cli/cobra.go @@ -37,6 +37,7 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *p cobra.AddTemplateFunc("hasSwarmSubCommands", hasSwarmSubCommands) cobra.AddTemplateFunc("hasInvalidPlugins", hasInvalidPlugins) cobra.AddTemplateFunc("topCommands", topCommands) + cobra.AddTemplateFunc("commandAliases", commandAliases) cobra.AddTemplateFunc("operationSubCommands", operationSubCommands) cobra.AddTemplateFunc("managementSubCommands", managementSubCommands) cobra.AddTemplateFunc("orchestratorSubCommands", orchestratorSubCommands) @@ -258,6 +259,21 @@ func hasTopCommands(cmd *cobra.Command) bool { return len(topCommands(cmd)) > 0 } +// commandAliases is a templating function to return aliases for the command, +// formatted as the full command as they're called (contrary to the default +// Aliases function, which only returns the subcommand). +func commandAliases(cmd *cobra.Command) string { + var parentPath string + if cmd.HasParent() { + parentPath = cmd.Parent().CommandPath() + " " + } + aliases := cmd.CommandPath() + for _, alias := range cmd.Aliases { + aliases += ", " + parentPath + alias + } + return aliases +} + func topCommands(cmd *cobra.Command) []*cobra.Command { cmds := []*cobra.Command{} if cmd.Parent() != nil { @@ -398,7 +414,7 @@ EXPERIMENTAL: {{- if gt .Aliases 0}} Aliases: - {{.NameAndAliases}} + {{ commandAliases . }} {{- end}} {{- if .HasExample}} diff --git a/cli/cobra_test.go b/cli/cobra_test.go index 18ce31ca2e..3349d18603 100644 --- a/cli/cobra_test.go +++ b/cli/cobra_test.go @@ -78,6 +78,14 @@ func TestInvalidPlugin(t *testing.T) { assert.DeepEqual(t, invalidPlugins(root), []*cobra.Command{sub1}, cmpopts.IgnoreUnexported(cobra.Command{})) } +func TestCommandAliases(t *testing.T) { + root := &cobra.Command{Use: "root"} + sub := &cobra.Command{Use: "subcommand", Aliases: []string{"alias1", "alias2"}} + root.AddCommand(sub) + + assert.Equal(t, commandAliases(sub), "root subcommand, root alias1, root alias2") +} + func TestDecoratedName(t *testing.T) { root := &cobra.Command{Use: "root"} topLevelCommand := &cobra.Command{Use: "pluginTopLevelCommand"} diff --git a/e2e/stack/testdata/stack-deploy-help.golden b/e2e/stack/testdata/stack-deploy-help.golden index fd8baec1af..6ca82f31aa 100644 --- a/e2e/stack/testdata/stack-deploy-help.golden +++ b/e2e/stack/testdata/stack-deploy-help.golden @@ -4,7 +4,7 @@ Usage: docker stack deploy [OPTIONS] STACK Deploy a new stack or update an existing stack Aliases: - deploy, up + docker stack deploy, docker stack up Options: -c, --compose-file strings Path to a Compose file, or "-" to read