Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reformat plugin's vendor position and add version on --help #1675

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions cli-plugins/manager/cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const (
// that plugin.
CommandAnnotationPluginVendor = "com.docker.cli.plugin.vendor"

// CommandAnnotationPluginVersion is added to every stub command
// added by AddPluginCommandStubs and contains the version of
// that plugin.
CommandAnnotationPluginVersion = "com.docker.cli.plugin.version"

// CommandAnnotationPluginInvalid is added to any stub command
// added by AddPluginCommandStubs for an invalid command (that
// is, one which failed it's candidate test) and contains the
Expand All @@ -37,8 +42,9 @@ func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error {
vendor = "unknown"
}
annotations := map[string]string{
CommandAnnotationPlugin: "true",
CommandAnnotationPluginVendor: vendor,
CommandAnnotationPlugin: "true",
CommandAnnotationPluginVendor: vendor,
CommandAnnotationPluginVersion: p.Version,
}
if p.Err != nil {
annotations[CommandAnnotationPluginInvalid] = p.Err.Error()
Expand Down
32 changes: 19 additions & 13 deletions cli/cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.ClientOptions, *p
flags.StringVar(&opts.ConfigDir, "config", cliconfig.Dir(), "Location of client config files")
opts.Common.InstallFlags(flags)

cobra.AddTemplateFunc("add", func(a, b int) int { return a + b })
cobra.AddTemplateFunc("hasSubCommands", hasSubCommands)
cobra.AddTemplateFunc("hasManagementSubCommands", hasManagementSubCommands)
cobra.AddTemplateFunc("hasInvalidPlugins", hasInvalidPlugins)
cobra.AddTemplateFunc("operationSubCommands", operationSubCommands)
cobra.AddTemplateFunc("managementSubCommands", managementSubCommands)
cobra.AddTemplateFunc("invalidPlugins", invalidPlugins)
cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("commandVendor", commandVendor)
cobra.AddTemplateFunc("isFirstLevelCommand", isFirstLevelCommand) // is it an immediate sub-command of the root
cobra.AddTemplateFunc("vendorAndVersion", vendorAndVersion)
cobra.AddTemplateFunc("invalidPluginReason", invalidPluginReason)
cobra.AddTemplateFunc("isPlugin", isPlugin)
cobra.AddTemplateFunc("decoratedName", decoratedName)

rootCmd.SetUsageTemplate(usageTemplate)
rootCmd.SetHelpTemplate(helpTemplate)
Expand Down Expand Up @@ -155,19 +157,23 @@ func wrappedFlagUsages(cmd *cobra.Command) string {
return cmd.Flags().FlagUsagesWrapped(width - 1)
}

func isFirstLevelCommand(cmd *cobra.Command) bool {
return cmd.Parent() == cmd.Root()
func decoratedName(cmd *cobra.Command) string {
decoration := " "
if isPlugin(cmd) {
decoration = "*"
}
return cmd.Name() + decoration
}

func commandVendor(cmd *cobra.Command) string {
width := 13
if v, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVendor]; ok {
if len(v) > width-2 {
v = v[:width-3] + "…"
func vendorAndVersion(cmd *cobra.Command) string {
if vendor, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVendor]; ok && isPlugin(cmd) {
version := ""
if v, ok := cmd.Annotations[pluginmanager.CommandAnnotationPluginVersion]; ok && v != "" {
version = ", " + v
}
return fmt.Sprintf("%-*s", width, "("+v+")")
return fmt.Sprintf("(%s%s)", vendor, version)
}
return strings.Repeat(" ", width)
return ""
}

func managementSubCommands(cmd *cobra.Command) []*cobra.Command {
Expand Down Expand Up @@ -230,7 +236,7 @@ Options:
Management Commands:

{{- range managementSubCommands . }}
{{rpad .Name .NamePadding }} {{ if isFirstLevelCommand .}}{{commandVendor .}} {{ end}}{{.Short}}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}{{ if isPlugin .}} {{vendorAndVersion .}}{{ end}}
{{- end}}

{{- end}}
Expand All @@ -239,7 +245,7 @@ Management Commands:
Commands:

{{- range operationSubCommands . }}
{{rpad .Name .NamePadding }} {{ if isFirstLevelCommand .}}{{commandVendor .}} {{ end}}{{.Short}}
{{rpad (decoratedName .) (add .NamePadding 1)}}{{.Short}}{{ if isPlugin .}} {{vendorAndVersion .}}{{ end}}
{{- end}}
{{- end}}

Expand Down
26 changes: 18 additions & 8 deletions cli/cobra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,29 @@ func TestVisitAll(t *testing.T) {
assert.DeepEqual(t, expected, visited)
}

func TestCommandVendor(t *testing.T) {
func TestVendorAndVersion(t *testing.T) {
// Non plugin.
assert.Equal(t, commandVendor(&cobra.Command{Use: "test"}), " ")
assert.Equal(t, vendorAndVersion(&cobra.Command{Use: "test"}), "")

// Plugins with various lengths of vendor.
for _, tc := range []struct {
vendor string
version string
expected string
}{
{vendor: "vendor", expected: "(vendor) "},
{vendor: "vendor12345", expected: "(vendor12345)"},
{vendor: "vendor123456", expected: "(vendor1234…)"},
{vendor: "vendor1234567", expected: "(vendor1234…)"},
{vendor: "vendor", expected: "(vendor)"},
{vendor: "vendor", version: "testing", expected: "(vendor, testing)"},
} {
t.Run(tc.vendor, func(t *testing.T) {
cmd := &cobra.Command{
Use: "test",
Annotations: map[string]string{
pluginmanager.CommandAnnotationPluginVendor: tc.vendor,
pluginmanager.CommandAnnotationPlugin: "true",
pluginmanager.CommandAnnotationPluginVendor: tc.vendor,
pluginmanager.CommandAnnotationPluginVersion: tc.version,
},
}
assert.Equal(t, commandVendor(cmd), tc.expected)
assert.Equal(t, vendorAndVersion(cmd), tc.expected)
})
}
}
Expand All @@ -76,3 +77,12 @@ func TestInvalidPlugin(t *testing.T) {

assert.DeepEqual(t, invalidPlugins(root), []*cobra.Command{sub1}, cmpopts.IgnoreUnexported(cobra.Command{}))
}

func TestDecoratedName(t *testing.T) {
root := &cobra.Command{Use: "root"}
topLevelCommand := &cobra.Command{Use: "pluginTopLevelCommand"}
root.AddCommand(topLevelCommand)
assert.Equal(t, decoratedName(topLevelCommand), "pluginTopLevelCommand ")
topLevelCommand.Annotations = map[string]string{pluginmanager.CommandAnnotationPlugin: "true"}
assert.Equal(t, decoratedName(topLevelCommand), "pluginTopLevelCommand*")
}
2 changes: 1 addition & 1 deletion e2e/cli-plugins/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestGlobalHelp(t *testing.T) {
// - The `badmeta` plugin under the "Invalid Plugins" heading.
//
// Regexps are needed because the width depends on `unix.TIOCGWINSZ` or similar.
helloworldre := regexp.MustCompile(`^ helloworld\s+\(Docker Inc\.\)\s+A basic Hello World plugin for tests$`)
helloworldre := regexp.MustCompile(`^ helloworld\*\s+A basic Hello World plugin for tests \(Docker Inc\., testing\)$`)
badmetare := regexp.MustCompile(`^ badmeta\s+invalid metadata: invalid character 'i' looking for beginning of object key string$`)
var helloworldcount, badmetacount int
for _, expected := range []*regexp.Regexp{
Expand Down