move commonly used top-level commands to the top of --help

This adds a new annotation to commands that are known to be frequently
used, and allows setting a custom weight/order for these commands to
influence in what order they appear in the --help output.

I'm not entirely happy with the implementation (we could at least use
some helpers for this, and/or make it more generic to group commands
in output), but it could be a start.

For now, limiting this to only be used for the top-level --help, but
we can expand this to subcommands as well if we think it makes sense
to highlight "common" / "commonly used" commands.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2022-03-30 09:37:08 +02:00
parent a058f9774a
commit aaa912c9f7
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
13 changed files with 78 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
pluginmanager "github.com/docker/cli/cli-plugins/manager"
@ -12,6 +13,7 @@ import (
cliflags "github.com/docker/cli/cli/flags"
"github.com/docker/docker/pkg/homedir"
"github.com/docker/docker/registry"
"github.com/fvbommel/sortorder"
"github.com/moby/term"
"github.com/morikuni/aec"
"github.com/pkg/errors"
@ -30,9 +32,11 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *p
cobra.AddTemplateFunc("add", func(a, b int) int { return a + b })
cobra.AddTemplateFunc("hasSubCommands", hasSubCommands)
cobra.AddTemplateFunc("hasTopCommands", hasTopCommands)
cobra.AddTemplateFunc("hasManagementSubCommands", hasManagementSubCommands)
cobra.AddTemplateFunc("hasOrchestratorSubCommands", hasOrchestratorSubCommands)
cobra.AddTemplateFunc("hasInvalidPlugins", hasInvalidPlugins)
cobra.AddTemplateFunc("topCommands", topCommands)
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("orchestratorSubCommands", orchestratorSubCommands)
@ -250,12 +254,43 @@ func hasInvalidPlugins(cmd *cobra.Command) bool {
return len(invalidPlugins(cmd)) > 0
}
func hasTopCommands(cmd *cobra.Command) bool {
return len(topCommands(cmd)) > 0
}
func topCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
if cmd.Parent() != nil {
// for now, only use top-commands for the root-command, and skip
// for sub-commands
return cmds
}
for _, sub := range cmd.Commands() {
if isPlugin(sub) || !sub.IsAvailableCommand() {
continue
}
if _, ok := sub.Annotations["category-top"]; ok {
cmds = append(cmds, sub)
}
}
sort.SliceStable(cmds, func(i, j int) bool {
return sortorder.NaturalLess(cmds[i].Annotations["category-top"], cmds[j].Annotations["category-top"])
})
return cmds
}
func operationSubCommands(cmd *cobra.Command) []*cobra.Command {
cmds := []*cobra.Command{}
for _, sub := range cmd.Commands() {
if isPlugin(sub) {
continue
}
if _, ok := sub.Annotations["category-top"]; ok {
if cmd.Parent() == nil {
// for now, only use top-commands for the root-command
continue
}
}
if sub.IsAvailableCommand() && !sub.HasSubCommands() {
cmds = append(cmds, sub)
}
@ -378,6 +413,13 @@ Examples:
Options:
{{ wrappedFlagUsages . | trimRightSpace}}
{{- end}}
{{- end}}
{{- if hasTopCommands .}}
Common Commands:
{{- range topCommands .}}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}
{{- end}}
{{- end}}
{{- if hasManagementSubCommands . }}

View File

@ -52,6 +52,9 @@ func NewExecCommand(dockerCli command.Cli) *cobra.Command {
options.Command = args[1:]
return RunExec(dockerCli, options)
},
Annotations: map[string]string{
"category-top": "2",
},
}
flags := cmd.Flags()

View File

@ -37,6 +37,9 @@ func NewPsCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runPs(dockerCli, &options)
},
Annotations: map[string]string{
"category-top": "3",
},
}
flags := cmd.Flags()

View File

@ -44,6 +44,9 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
}
return runRun(dockerCli, cmd.Flags(), &opts, copts)
},
Annotations: map[string]string{
"category-top": "1",
},
}
flags := cmd.Flags()

View File

@ -105,6 +105,9 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
options.context = args[0]
return runBuild(dockerCli, options)
},
Annotations: map[string]string{
"category-top": "4",
},
}
flags := cmd.Flags()

View File

@ -37,6 +37,9 @@ func NewImagesCommand(dockerCli command.Cli) *cobra.Command {
}
return runImages(dockerCli, options)
},
Annotations: map[string]string{
"category-top": "7",
},
}
flags := cmd.Flags()

View File

@ -34,6 +34,9 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
opts.remote = args[0]
return RunPull(dockerCli, opts)
},
Annotations: map[string]string{
"category-top": "5",
},
}
flags := cmd.Flags()

View File

@ -35,6 +35,9 @@ func NewPushCommand(dockerCli command.Cli) *cobra.Command {
opts.remote = args[0]
return RunPush(dockerCli, opts)
},
Annotations: map[string]string{
"category-top": "6",
},
}
flags := cmd.Flags()

View File

@ -44,6 +44,9 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
}
return runLogin(dockerCli, opts)
},
Annotations: map[string]string{
"category-top": "8",
},
}
flags := cmd.Flags()

View File

@ -23,6 +23,9 @@ func NewLogoutCommand(dockerCli command.Cli) *cobra.Command {
}
return runLogout(dockerCli, serverAddress)
},
Annotations: map[string]string{
"category-top": "9",
},
}
return cmd

View File

@ -32,6 +32,9 @@ func NewSearchCommand(dockerCli command.Cli) *cobra.Command {
options.term = args[0]
return runSearch(dockerCli, options)
},
Annotations: map[string]string{
"category-top": "10",
},
}
flags := cmd.Flags()

View File

@ -54,6 +54,9 @@ func NewInfoCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runInfo(cmd, dockerCli, &opts)
},
Annotations: map[string]string{
"category-top": "12",
},
}
flags := cmd.Flags()

View File

@ -96,6 +96,9 @@ func NewVersionCommand(dockerCli command.Cli) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
return runVersion(dockerCli, &opts)
},
Annotations: map[string]string{
"category-top": "10",
},
}
flags := cmd.Flags()