diff --git a/cmd/docker/cloud.go b/cmd/docker/cloud.go index f2a127bb4219..72a37bd44d5b 100644 --- a/cmd/docker/cloud.go +++ b/cmd/docker/cloud.go @@ -199,7 +199,17 @@ func cloudHelpRequest(rootCmd *cobra.Command, args []string) (bool, error) { if err != nil || cmd == rootCmd || pluginmanager.IsPluginCommand(cmd) { // Plugin flags are opaque. Only recognize help immediately after the // plugin name; deeper help is available through "docker help PLUGIN". - return len(args) > 1 && (args[1] == "--help" || args[1] == "-h" || args[1] == "--help=true"), nil + return len(args) > 1 && isHelpFlag(args[1]), nil + } + + // "build", "bake", "builder", and "image build" are builtin commands that + // processAliases may still rewrite into a call to the builder plugin + // (buildx) after cloud resolution runs, so their flag set here is only the + // legacy builder's and does not reflect what will actually parse the + // remaining args. Treat them like a plugin command above: only recognize + // help immediately after the resolved command path. + if _, _, _, forwarded := forwardBuilder(builderDefaultPlugin, args, args); forwarded { + return len(remaining) > 0 && isHelpFlag(remaining[0]), nil } cmd.InitDefaultHelpFlag() @@ -226,6 +236,12 @@ func cloudHelpRequest(rootCmd *cobra.Command, args []string) (bool, error) { return help, nil } +// isHelpFlag reports whether arg requests help, in any of the forms pflag +// accepts for a boolean flag. +func isHelpFlag(arg string) bool { + return arg == "--help" || arg == "-h" || arg == "--help=true" +} + // cloudPluginArgs only rewrites the global prefix, leaving subcommand arguments // untouched. Parsing also distinguishes --cloud from another flag's value. func cloudPluginArgs(cmd *cobra.Command, osArgs []string, contextName string) ([]string, error) { diff --git a/cmd/docker/cloud_test.go b/cmd/docker/cloud_test.go index f1ce8a60a840..9f6b1ab463d5 100644 --- a/cmd/docker/cloud_test.go +++ b/cmd/docker/cloud_test.go @@ -62,6 +62,11 @@ func TestCloudHelpRequest(t *testing.T) { {name: "container help", args: []string{"run", "alpine", "--help"}}, {name: "flag value", args: []string{"run", "--name", "--help", "alpine"}}, {name: "help disabled", args: []string{"run", "--help=false", "alpine"}}, + {name: "build help", args: []string{"build", "--help"}, help: true}, + {name: "build buildkit-only flag", args: []string{"build", "--secret", "id=s,src=./s", "."}}, + {name: "image build buildkit-only flag", args: []string{"image", "build", "--push", "."}}, + {name: "builder build buildkit-only flag", args: []string{"builder", "build", "--ssh", "default", "."}}, + {name: "bake help", args: []string{"bake", "--help"}, help: true}, } { t.Run(tc.name, func(t *testing.T) { dockerCli, err := command.NewDockerCli()