Skip to content

Commit f78032f

Browse files
author
Ian Campbell
committed
Ensure that plugins are only listed once in help outputs.
They were listed twice in `docker --help` (but not `docker help`), since the stubs were added in both `tryRunPluginHelp` and the `setHelpFunc` closure. Calling `AddPluginStubCommands` earlier in `setHelpFunc` before the call to `tryRunPluginHelp` is sufficient. Also it is no longer necessary to add just valid plugins (`tryRunPluginHelp` handles invalid plugins correctly) so remove that logic (which was in any case broken for e.g. `docker --help`). Update the e2e test to check for duplicate entries and also to test `docker --help` which was previously missed. Signed-off-by: Ian Campbell <ijc@docker.com>
1 parent c8f1f1e commit f78032f

3 files changed

Lines changed: 47 additions & 24 deletions

File tree

cli-plugins/manager/cobra.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,15 @@ const (
2323
CommandAnnotationPluginInvalid = "com.docker.cli.plugin-invalid"
2424
)
2525

26-
// AddPluginCommandStubs adds a stub cobra.Commands for each plugin
27-
// (optionally including invalid ones). The command stubs will have
28-
// several annotations added, see `CommandAnnotationPlugin*`.
29-
func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command, includeInvalid bool) error {
26+
// // AddPluginCommandStubs adds a stub cobra.Commands for each valid and invalid
27+
// plugin. The command stubs will have several annotations added, see
28+
// `CommandAnnotationPlugin*`.
29+
func AddPluginCommandStubs(dockerCli command.Cli, cmd *cobra.Command) error {
3030
plugins, err := ListPlugins(dockerCli, cmd)
3131
if err != nil {
3232
return err
3333
}
3434
for _, p := range plugins {
35-
if !includeInvalid && p.Err != nil {
36-
continue
37-
}
3835
vendor := p.Vendor
3936
if vendor == "" {
4037
vendor = "unknown"

cmd/docker/docker.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ func setupHelpCommand(dockerCli *command.DockerCli, rootCmd, helpCmd *cobra.Comm
146146

147147
func tryRunPluginHelp(dockerCli command.Cli, ccmd *cobra.Command, cargs []string) error {
148148
root := ccmd.Root()
149-
pluginmanager.AddPluginCommandStubs(dockerCli, root, false)
150149

151150
cmd, _, err := root.Traverse(cargs)
152151
if err != nil {
@@ -169,6 +168,17 @@ func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.
169168
ccmd.Println(err)
170169
return
171170
}
171+
172+
// Add a stub entry for every plugin so they are
173+
// included in the help output and so that
174+
// `tryRunPluginHelp` can find them or if we fall
175+
// through they will be included in the default help
176+
// output.
177+
if err := pluginmanager.AddPluginCommandStubs(dockerCli, ccmd.Root()); err != nil {
178+
ccmd.Println(err)
179+
return
180+
}
181+
172182
if len(args) >= 1 {
173183
err := tryRunPluginHelp(dockerCli, ccmd, args)
174184
if err == nil { // Successfully ran the plugin
@@ -189,16 +199,6 @@ func setHelpFunc(dockerCli *command.DockerCli, cmd *cobra.Command, flags *pflag.
189199
return
190200
}
191201

192-
// Add a stub entry for every plugin so they are
193-
// included in the help output. If we have no args
194-
// then this is being used for `docker help` and we
195-
// want to include broken plugins, otherwise this is
196-
// `help «foo»` and we do not.
197-
if err := pluginmanager.AddPluginCommandStubs(dockerCli, ccmd.Root(), len(args) == 0); err != nil {
198-
ccmd.Println(err)
199-
return
200-
}
201-
202202
defaultHelpFunc(ccmd, args)
203203
})
204204
}

e2e/cli-plugins/help_test.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,55 @@ func TestGlobalHelp(t *testing.T) {
3434
// - The `badmeta` plugin under the "Invalid Plugins" heading.
3535
//
3636
// Regexps are needed because the width depends on `unix.TIOCGWINSZ` or similar.
37+
helloworldre := regexp.MustCompile(`^ helloworld\s+\(Docker Inc\.\)\s+A basic Hello World plugin for tests$`)
38+
badmetare := regexp.MustCompile(`^ badmeta\s+invalid metadata: invalid character 'i' looking for beginning of object key string$`)
39+
var helloworldcount, badmetacount int
3740
for _, expected := range []*regexp.Regexp{
3841
regexp.MustCompile(`^A self-sufficient runtime for containers$`),
3942
regexp.MustCompile(`^Management Commands:$`),
4043
regexp.MustCompile(`^ container\s+Manage containers$`),
4144
regexp.MustCompile(`^Commands:$`),
4245
regexp.MustCompile(`^ create\s+Create a new container$`),
43-
regexp.MustCompile(`^ helloworld\s+\(Docker Inc\.\)\s+A basic Hello World plugin for tests$`),
46+
helloworldre,
4447
regexp.MustCompile(`^ ps\s+List containers$`),
4548
regexp.MustCompile(`^Invalid Plugins:$`),
46-
regexp.MustCompile(`^ badmeta\s+invalid metadata: invalid character 'i' looking for beginning of object key string$`),
49+
badmetare,
50+
nil, // scan to end of input rather than stopping at badmetare
4751
} {
4852
var found bool
4953
for scanner.Scan() {
50-
if expected.MatchString(scanner.Text()) {
54+
text := scanner.Text()
55+
if helloworldre.MatchString(text) {
56+
helloworldcount++
57+
}
58+
if badmetare.MatchString(text) {
59+
badmetacount++
60+
}
61+
62+
if expected != nil && expected.MatchString(text) {
5163
found = true
5264
break
5365
}
5466
}
55-
assert.Assert(t, found, "Did not find match for %q in `docker help` output", expected)
67+
assert.Assert(t, expected == nil || found, "Did not find match for %q in `docker help` output", expected)
5668
}
69+
// We successfully scanned all the input
70+
assert.Assert(t, scanner.Scan() == false)
71+
assert.NilError(t, scanner.Err())
72+
// Plugins should only be listed once.
73+
assert.Assert(t, is.Equal(helloworldcount, 1))
74+
assert.Assert(t, is.Equal(badmetacount, 1))
75+
76+
// Running with `--help` should produce the same.
77+
res2 := icmd.RunCmd(run("--help"))
78+
res2.Assert(t, icmd.Expected{
79+
ExitCode: 0,
80+
})
81+
assert.Assert(t, is.Equal(res2.Stdout(), res.Stdout()))
82+
assert.Assert(t, is.Equal(res2.Stderr(), ""))
5783

58-
// Running just `docker` (without help) should produce the same thing, except on Stderr
59-
res2 := icmd.RunCmd(run())
84+
// Running just `docker` (without `help` nor `--help`) should produce the same thing, except on Stderr.
85+
res2 = icmd.RunCmd(run())
6086
res2.Assert(t, icmd.Expected{
6187
ExitCode: 0,
6288
})

0 commit comments

Comments
 (0)