From d8aa00a766ad7c7c4e21a54953405dd37051b6c3 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Thu, 15 Apr 2021 12:43:18 +0200 Subject: [PATCH] wrap compose cobra command to set exitcode according to metrics status Signed-off-by: Nicolas De Loof --- cli/cmd/compose/build.go | 6 +++--- cli/cmd/compose/compose.go | 29 ++++++++++++++++++++++++++--- cli/cmd/compose/convert.go | 6 +++--- cli/cmd/compose/create.go | 7 ++++--- cli/cmd/compose/down.go | 8 +++++--- cli/cmd/compose/events.go | 6 +++--- cli/cmd/compose/exec.go | 6 +++--- cli/cmd/compose/images.go | 6 +++--- cli/cmd/compose/kill.go | 6 +++--- cli/cmd/compose/list.go | 6 +++--- cli/cmd/compose/logs.go | 6 +++--- cli/cmd/compose/pause.go | 12 ++++++------ cli/cmd/compose/port.go | 6 +++--- cli/cmd/compose/ps.go | 6 +++--- cli/cmd/compose/pull.go | 6 +++--- cli/cmd/compose/push.go | 6 +++--- cli/cmd/compose/remove.go | 6 +++--- cli/cmd/compose/restart.go | 6 +++--- cli/cmd/compose/run.go | 6 +++--- cli/cmd/compose/start.go | 6 +++--- cli/cmd/compose/stop.go | 6 ++++-- cli/cmd/compose/top.go | 6 +++--- cli/cmd/compose/up.go | 10 ++++++---- cli/main.go | 6 +++--- docs/yaml/main/generate.go | 2 +- main.go | 14 +++++++++++--- 26 files changed, 117 insertions(+), 79 deletions(-) diff --git a/cli/cmd/compose/build.go b/cli/cmd/compose/build.go index ecacacbd..bc2bb583 100644 --- a/cli/cmd/compose/build.go +++ b/cli/cmd/compose/build.go @@ -46,7 +46,7 @@ func buildCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "build [SERVICE...]", Short: "Build or rebuild services", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if opts.memory != "" { fmt.Println("WARNING --memory is ignored as not supported in buildkit.") } @@ -57,8 +57,8 @@ func buildCommand(p *projectOptions, backend compose.Service) *cobra.Command { } os.Stdout = devnull } - return runBuild(cmd.Context(), backend, opts, args) - }, + return runBuild(ctx, backend, opts, args) + }), } cmd.Flags().BoolVarP(&opts.quiet, "quiet", "q", false, "Don't print anything to STDOUT") cmd.Flags().BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image.") diff --git a/cli/cmd/compose/compose.go b/cli/cmd/compose/compose.go index da105b9c..6722527a 100644 --- a/cli/cmd/compose/compose.go +++ b/cli/cmd/compose/compose.go @@ -17,12 +17,14 @@ package compose import ( + "context" "fmt" "os" "strings" "github.com/compose-spec/compose-go/cli" "github.com/compose-spec/compose-go/types" + dockercli "github.com/docker/cli/cli" "github.com/morikuni/aec" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -34,6 +36,24 @@ import ( "github.com/docker/compose-cli/cli/metrics" ) +//Command defines a compose CLI command as a func with args +type Command func(context.Context, []string) error + +//Adapt a Command func to cobra library +func Adapt(fn Command) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + err := fn(cmd.Context(), args) + var composeErr metrics.ComposeError + if errors.As(err, &composeErr) { + err = dockercli.StatusError{ + StatusCode: composeErr.GetMetricsFailureCategory().ExitCode, + Status: err.Error(), + } + } + return err + } +} + // Warning is a global warning to be displayed to user on command failure var Warning string @@ -105,8 +125,8 @@ func (o *projectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.Proj cli.WithName(o.ProjectName))...) } -// Command returns the compose command with its child commands -func Command(contextType string, backend compose.Service) *cobra.Command { +// RootCommand returns the compose command with its child commands +func RootCommand(contextType string, backend compose.Service) *cobra.Command { opts := projectOptions{} var ansi string var noAnsi bool @@ -120,7 +140,10 @@ func Command(contextType string, backend compose.Service) *cobra.Command { return cmd.Help() } _ = cmd.Help() - return fmt.Errorf("unknown docker command: %q", "compose "+args[0]) + return dockercli.StatusError{ + StatusCode: metrics.CommandSyntaxFailure.ExitCode, + Status: fmt.Sprintf("unknown docker command: %q", "compose "+args[0]), + } }, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { parent := cmd.Root() diff --git a/cli/cmd/compose/convert.go b/cli/cmd/compose/convert.go index 01b0fbe5..359bef47 100644 --- a/cli/cmd/compose/convert.go +++ b/cli/cmd/compose/convert.go @@ -58,7 +58,7 @@ func convertCommand(p *projectOptions, backend compose.Service) *cobra.Command { Aliases: []string{"config"}, Use: "convert SERVICES", Short: "Converts the compose file to platform's canonical format", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if opts.quiet { devnull, err := os.Open(os.DevNull) if err != nil { @@ -79,8 +79,8 @@ func convertCommand(p *projectOptions, backend compose.Service) *cobra.Command { return runProfiles(opts, args) } - return runConvert(cmd.Context(), backend, opts, args) - }, + return runConvert(ctx, backend, opts, args) + }), } flags := cmd.Flags() flags.StringVar(&opts.Format, "format", "yaml", "Format the output. Values: [yaml | json]") diff --git a/cli/cmd/compose/create.go b/cli/cmd/compose/create.go index ef608085..8d790ca2 100644 --- a/cli/cmd/compose/create.go +++ b/cli/cmd/compose/create.go @@ -17,6 +17,7 @@ package compose import ( + "context" "fmt" "github.com/spf13/cobra" @@ -37,14 +38,14 @@ func createCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "create [SERVICE...]", Short: "Creates containers for a service.", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if opts.Build && opts.noBuild { return fmt.Errorf("--build and --no-build are incompatible") } if opts.forceRecreate && opts.noRecreate { return fmt.Errorf("--force-recreate and --no-recreate are incompatible") } - return runCreateStart(cmd.Context(), backend, upOptions{ + return runCreateStart(ctx, backend, upOptions{ composeOptions: &composeOptions{ projectOptions: p, Build: opts.Build, @@ -54,7 +55,7 @@ func createCommand(p *projectOptions, backend compose.Service) *cobra.Command { forceRecreate: opts.forceRecreate, noRecreate: opts.noRecreate, }, args) - }, + }), } flags := cmd.Flags() flags.BoolVar(&opts.Build, "build", false, "Build images before starting containers.") diff --git a/cli/cmd/compose/down.go b/cli/cmd/compose/down.go index 07e37744..ba6dac25 100644 --- a/cli/cmd/compose/down.go +++ b/cli/cmd/compose/down.go @@ -45,15 +45,17 @@ func downCommand(p *projectOptions, contextType string, backend compose.Service) downCmd := &cobra.Command{ Use: "down", Short: "Stop and remove containers, networks", - RunE: func(cmd *cobra.Command, args []string) error { + PreRun: func(cmd *cobra.Command, args []string) { opts.timeChanged = cmd.Flags().Changed("timeout") + }, + RunE: Adapt(func(ctx context.Context, args []string) error { if opts.images != "" { if opts.images != "all" && opts.images != "local" { return fmt.Errorf("invalid value for --rmi: %q", opts.images) } } - return runDown(cmd.Context(), backend, opts) - }, + return runDown(ctx, backend, opts) + }), } flags := downCmd.Flags() flags.BoolVar(&opts.removeOrphans, "remove-orphans", false, "Remove containers for services not defined in the Compose file.") diff --git a/cli/cmd/compose/events.go b/cli/cmd/compose/events.go index da496d0d..a6648687 100644 --- a/cli/cmd/compose/events.go +++ b/cli/cmd/compose/events.go @@ -40,9 +40,9 @@ func eventsCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "events [options] [--] [SERVICE...]", Short: "Receive real time events from containers.", - RunE: func(cmd *cobra.Command, args []string) error { - return runEvents(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runEvents(ctx, backend, opts, args) + }), } cmd.Flags().BoolVar(&opts.json, "json", false, "Output events as a stream of json objects") diff --git a/cli/cmd/compose/exec.go b/cli/cmd/compose/exec.go index 4592448e..c2a5b908 100644 --- a/cli/cmd/compose/exec.go +++ b/cli/cmd/compose/exec.go @@ -52,13 +52,13 @@ func execCommand(p *projectOptions, backend compose.Service) *cobra.Command { Use: "exec [options] [-e KEY=VAL...] [--] SERVICE COMMAND [ARGS...]", Short: "Execute a command in a running container.", Args: cobra.MinimumNArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if len(args) > 1 { opts.command = args[1:] } opts.service = args[0] - return runExec(cmd.Context(), backend, opts) - }, + return runExec(ctx, backend, opts) + }), } runCmd.Flags().BoolVarP(&opts.detach, "detach", "d", false, "Detached mode: Run command in the background.") diff --git a/cli/cmd/compose/images.go b/cli/cmd/compose/images.go index 072a6a08..39520cbe 100644 --- a/cli/cmd/compose/images.go +++ b/cli/cmd/compose/images.go @@ -46,9 +46,9 @@ func imagesCommand(p *projectOptions, backend compose.Service) *cobra.Command { imgCmd := &cobra.Command{ Use: "images [SERVICE...]", Short: "List images used by the created containers", - RunE: func(cmd *cobra.Command, args []string) error { - return runImages(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runImages(ctx, backend, opts, args) + }), } imgCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") return imgCmd diff --git a/cli/cmd/compose/kill.go b/cli/cmd/compose/kill.go index 97cb9c9d..986dce0f 100644 --- a/cli/cmd/compose/kill.go +++ b/cli/cmd/compose/kill.go @@ -36,9 +36,9 @@ func killCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "kill [options] [SERVICE...]", Short: "Force stop service containers.", - RunE: func(cmd *cobra.Command, args []string) error { - return runKill(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runKill(ctx, backend, opts, args) + }), } flags := cmd.Flags() diff --git a/cli/cmd/compose/list.go b/cli/cmd/compose/list.go index b75887d0..bcf8d364 100644 --- a/cli/cmd/compose/list.go +++ b/cli/cmd/compose/list.go @@ -43,9 +43,9 @@ func listCommand(contextType string, backend compose.Service) *cobra.Command { lsCmd := &cobra.Command{ Use: "ls", Short: "List running compose projects", - RunE: func(cmd *cobra.Command, args []string) error { - return runList(cmd.Context(), backend, opts) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runList(ctx, backend, opts) + }), } lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs.") diff --git a/cli/cmd/compose/logs.go b/cli/cmd/compose/logs.go index e2249721..f89b13b4 100644 --- a/cli/cmd/compose/logs.go +++ b/cli/cmd/compose/logs.go @@ -44,9 +44,9 @@ func logsCommand(p *projectOptions, contextType string, backend compose.Service) logsCmd := &cobra.Command{ Use: "logs [service...]", Short: "View output from containers", - RunE: func(cmd *cobra.Command, args []string) error { - return runLogs(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runLogs(ctx, backend, opts, args) + }), } flags := logsCmd.Flags() flags.BoolVarP(&opts.follow, "follow", "f", false, "Follow log output.") diff --git a/cli/cmd/compose/pause.go b/cli/cmd/compose/pause.go index 0265b4ea..13287f9a 100644 --- a/cli/cmd/compose/pause.go +++ b/cli/cmd/compose/pause.go @@ -36,9 +36,9 @@ func pauseCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "pause [SERVICE...]", Short: "pause services", - RunE: func(cmd *cobra.Command, args []string) error { - return runPause(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runPause(ctx, backend, opts, args) + }), } return cmd } @@ -68,9 +68,9 @@ func unpauseCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "unpause [SERVICE...]", Short: "unpause services", - RunE: func(cmd *cobra.Command, args []string) error { - return runUnPause(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runUnPause(ctx, backend, opts, args) + }), } return cmd } diff --git a/cli/cmd/compose/port.go b/cli/cmd/compose/port.go index ecb8c8e5..1d00b9c1 100644 --- a/cli/cmd/compose/port.go +++ b/cli/cmd/compose/port.go @@ -40,13 +40,13 @@ func portCommand(p *projectOptions, backend compose.Service) *cobra.Command { Use: "port [options] [--] SERVICE PRIVATE_PORT", Short: "Print the public port for a port binding.", Args: cobra.MinimumNArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { port, err := strconv.Atoi(args[1]) if err != nil { return err } - return runPort(cmd.Context(), backend, opts, args[0], port) - }, + return runPort(ctx, backend, opts, args[0], port) + }), } cmd.Flags().StringVar(&opts.protocol, "protocol", "tcp", "tcp or udp") cmd.Flags().IntVar(&opts.index, "index", 1, "index of the container if service has multiple replicas") diff --git a/cli/cmd/compose/ps.go b/cli/cmd/compose/ps.go index 985b16c3..20e99c32 100644 --- a/cli/cmd/compose/ps.go +++ b/cli/cmd/compose/ps.go @@ -46,9 +46,9 @@ func psCommand(p *projectOptions, backend compose.Service) *cobra.Command { psCmd := &cobra.Command{ Use: "ps", Short: "List containers", - RunE: func(cmd *cobra.Command, args []string) error { - return runPs(cmd.Context(), backend, opts) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runPs(ctx, backend, opts) + }), } psCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") psCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") diff --git a/cli/cmd/compose/pull.go b/cli/cmd/compose/pull.go index 9fb4df13..8917da74 100644 --- a/cli/cmd/compose/pull.go +++ b/cli/cmd/compose/pull.go @@ -46,12 +46,12 @@ func pullCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "pull [SERVICE...]", Short: "Pull service images", - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if opts.noParallel { fmt.Fprint(os.Stderr, aec.Apply("option '--no-parallel' is DEPRECATED and will be ignored.\n", aec.RedF)) } - return runPull(cmd.Context(), backend, opts, args) - }, + return runPull(ctx, backend, opts, args) + }), } flags := cmd.Flags() flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Pull without printing progress information") diff --git a/cli/cmd/compose/push.go b/cli/cmd/compose/push.go index 3f1fb6e2..91531793 100644 --- a/cli/cmd/compose/push.go +++ b/cli/cmd/compose/push.go @@ -39,9 +39,9 @@ func pushCommand(p *projectOptions, backend compose.Service) *cobra.Command { pushCmd := &cobra.Command{ Use: "push [SERVICE...]", Short: "Push service images", - RunE: func(cmd *cobra.Command, args []string) error { - return runPush(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runPush(ctx, backend, opts, args) + }), } pushCmd.Flags().BoolVar(&opts.Ignorefailures, "ignore-push-failures", false, "Push what it can and ignores images with push failures") diff --git a/cli/cmd/compose/remove.go b/cli/cmd/compose/remove.go index 786e0fee..2757f9fc 100644 --- a/cli/cmd/compose/remove.go +++ b/cli/cmd/compose/remove.go @@ -48,9 +48,9 @@ By default, anonymous volumes attached to containers will not be removed. You can override this with -v. To list all volumes, use "docker volume ls". Any data which is not in a volume will be lost.`, - RunE: func(cmd *cobra.Command, args []string) error { - return runRemove(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runRemove(ctx, backend, opts, args) + }), } f := cmd.Flags() f.BoolVarP(&opts.force, "force", "f", false, "Don't ask to confirm removal") diff --git a/cli/cmd/compose/restart.go b/cli/cmd/compose/restart.go index b6dd7dc0..f1e031af 100644 --- a/cli/cmd/compose/restart.go +++ b/cli/cmd/compose/restart.go @@ -38,9 +38,9 @@ func restartCommand(p *projectOptions, backend compose.Service) *cobra.Command { restartCmd := &cobra.Command{ Use: "restart", Short: "Restart containers", - RunE: func(cmd *cobra.Command, args []string) error { - return runRestart(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runRestart(ctx, backend, opts, args) + }), } flags := restartCmd.Flags() flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds") diff --git a/cli/cmd/compose/run.go b/cli/cmd/compose/run.go index 79028e6e..ca2582cc 100644 --- a/cli/cmd/compose/run.go +++ b/cli/cmd/compose/run.go @@ -109,7 +109,7 @@ func runCommand(p *projectOptions, backend compose.Service) *cobra.Command { Use: "run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]", Short: "Run a one-off command on a service.", Args: cobra.MinimumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: Adapt(func(ctx context.Context, args []string) error { if len(args) > 1 { opts.Command = args[1:] } @@ -117,8 +117,8 @@ func runCommand(p *projectOptions, backend compose.Service) *cobra.Command { if len(opts.publish) > 0 && opts.servicePorts { return fmt.Errorf("--service-ports and --publish are incompatible") } - return runRun(cmd.Context(), backend, opts) - }, + return runRun(ctx, backend, opts) + }), } flags := cmd.Flags() flags.BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID") diff --git a/cli/cmd/compose/start.go b/cli/cmd/compose/start.go index f6632a7b..3e8b0b4e 100644 --- a/cli/cmd/compose/start.go +++ b/cli/cmd/compose/start.go @@ -36,9 +36,9 @@ func startCommand(p *projectOptions, backend compose.Service) *cobra.Command { startCmd := &cobra.Command{ Use: "start [SERVICE...]", Short: "Start services", - RunE: func(cmd *cobra.Command, args []string) error { - return runStart(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runStart(ctx, backend, opts, args) + }), } return startCmd } diff --git a/cli/cmd/compose/stop.go b/cli/cmd/compose/stop.go index 494ac907..73e81156 100644 --- a/cli/cmd/compose/stop.go +++ b/cli/cmd/compose/stop.go @@ -39,10 +39,12 @@ func stopCommand(p *projectOptions, backend compose.Service) *cobra.Command { cmd := &cobra.Command{ Use: "stop [SERVICE...]", Short: "Stop services", - RunE: func(cmd *cobra.Command, args []string) error { + PreRun: func(cmd *cobra.Command, args []string) { opts.timeChanged = cmd.Flags().Changed("timeout") - return runStop(cmd.Context(), backend, opts, args) }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runStop(ctx, backend, opts, args) + }), } flags := cmd.Flags() flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds") diff --git a/cli/cmd/compose/top.go b/cli/cmd/compose/top.go index cd5a12bc..1d6518ea 100644 --- a/cli/cmd/compose/top.go +++ b/cli/cmd/compose/top.go @@ -41,9 +41,9 @@ func topCommand(p *projectOptions, backend compose.Service) *cobra.Command { topCmd := &cobra.Command{ Use: "top", Short: "Display the running processes", - RunE: func(cmd *cobra.Command, args []string) error { - return runTop(cmd.Context(), backend, opts, args) - }, + RunE: Adapt(func(ctx context.Context, args []string) error { + return runTop(ctx, backend, opts, args) + }), } return topCmd } diff --git a/cli/cmd/compose/up.go b/cli/cmd/compose/up.go index b6df226d..6c926fdb 100644 --- a/cli/cmd/compose/up.go +++ b/cli/cmd/compose/up.go @@ -148,8 +148,10 @@ func upCommand(p *projectOptions, contextType string, backend compose.Service) * upCmd := &cobra.Command{ Use: "up [SERVICE...]", Short: "Create and start containers", - RunE: func(cmd *cobra.Command, args []string) error { + PreRun: func(cmd *cobra.Command, args []string) { opts.timeChanged = cmd.Flags().Changed("timeout") + }, + RunE: Adapt(func(ctx context.Context, args []string) error { switch contextType { case store.LocalContextType, store.DefaultContextType, store.EcsLocalSimulationContextType: if opts.exitCodeFrom != "" { @@ -167,11 +169,11 @@ func upCommand(p *projectOptions, contextType string, backend compose.Service) * if opts.recreateDeps && opts.noRecreate { return fmt.Errorf("--always-recreate-deps and --no-recreate are incompatible") } - return runCreateStart(cmd.Context(), backend, opts, args) + return runCreateStart(ctx, backend, opts, args) default: - return runUp(cmd.Context(), backend, opts, args) + return runUp(ctx, backend, opts, args) } - }, + }), } flags := upCmd.Flags() flags.StringArrayVarP(&opts.Environment, "environment", "e", []string{}, "Environment variables") diff --git a/cli/main.go b/cli/main.go index ae6ab7c1..ffcdc64f 100644 --- a/cli/main.go +++ b/cli/main.go @@ -218,7 +218,7 @@ func main() { root.AddCommand( run.Command(ctype), - compose.Command(ctype, service.ComposeService()), + compose.RootCommand(ctype, service.ComposeService()), volume.Command(ctype), ) @@ -294,7 +294,7 @@ func exit(ctx string, err error, ctype string) { if errors.Is(err, errdefs.ErrNotImplemented) { name := metrics.GetCommand(os.Args[1:]) - fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s)\n", name, ctx) + fmt.Fprintf(os.Stderr, "RootCommand %q not available in current context (%s)\n", name, ctx) os.Exit(1) } @@ -314,7 +314,7 @@ func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string dockerCommand := string(submatch[1]) if mobycli.IsDefaultContextCommand(dockerCommand) { - fmt.Fprintf(os.Stderr, "Command %q not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext) + fmt.Fprintf(os.Stderr, "RootCommand %q not available in current context (%s), you can use the \"default\" context to run this command\n", dockerCommand, currentContext) metrics.Track(contextType, os.Args[1:], metrics.FailureStatus) os.Exit(1) } diff --git a/docs/yaml/main/generate.go b/docs/yaml/main/generate.go index 4ca4a16b..19353dc7 100644 --- a/docs/yaml/main/generate.go +++ b/docs/yaml/main/generate.go @@ -35,7 +35,7 @@ const descriptionSourcePath = "docs/reference/" func generateCliYaml(opts *options) error { cmd := &cobra.Command{Use: "docker"} - cmd.AddCommand(compose.Command("local", nil)) + cmd.AddCommand(compose.RootCommand("local", nil)) disableFlagsInUseLine(cmd) source := filepath.Join(opts.source, descriptionSourcePath) if err := loadLongDescription(cmd, source); err != nil { diff --git a/main.go b/main.go index fa801fa6..1686408e 100644 --- a/main.go +++ b/main.go @@ -19,14 +19,16 @@ package main import ( "strings" - "github.com/spf13/cobra" - + dockercli "github.com/docker/cli/cli" "github.com/docker/cli/cli-plugins/manager" "github.com/docker/cli/cli-plugins/plugin" "github.com/docker/cli/cli/command" + "github.com/spf13/cobra" + api "github.com/docker/compose-cli/api/compose" "github.com/docker/compose-cli/api/context/store" "github.com/docker/compose-cli/cli/cmd/compose" + "github.com/docker/compose-cli/cli/metrics" "github.com/docker/compose-cli/internal" impl "github.com/docker/compose-cli/local/compose" ) @@ -36,7 +38,7 @@ func main() { lazyInit := api.ServiceDelegator{ Delegate: api.NoImpl{}, } - cmd := compose.Command(store.DefaultContextType, &lazyInit) + cmd := compose.RootCommand(store.DefaultContextType, &lazyInit) originalPreRun := cmd.PersistentPreRunE cmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { if err := plugin.PersistentPreRunE(cmd, args); err != nil { @@ -48,6 +50,12 @@ func main() { } return nil } + cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { + return dockercli.StatusError{ + StatusCode: metrics.CommandSyntaxFailure.ExitCode, + Status: err.Error(), + } + }) return cmd }, manager.Metadata{