diff --git a/temporalcli/commands.gen.go b/temporalcli/commands.gen.go index 5821374b..4ef85844 100644 --- a/temporalcli/commands.gen.go +++ b/temporalcli/commands.gen.go @@ -563,9 +563,9 @@ func NewTemporalWorkflowCommand(cctx *CommandContext, parent *TemporalCommand) * s.Command.Use = "workflow" s.Command.Short = "Start, list, and operate on Workflows." if hasHighlighting { - s.Command.Long = "Workflow commands perform operations on \nWorkflow Executions.\n\nWorkflow commands use this syntax:\x1b[1mtemporal workflow COMMAND [ARGS]\x1b[0m." + s.Command.Long = "Workflow commands perform operations on Workflow Executions.\n\nWorkflow commands use this syntax: \x1b[1mtemporal workflow COMMAND [ARGS]\x1b[0m." } else { - s.Command.Long = "Workflow commands perform operations on \nWorkflow Executions.\n\nWorkflow commands use this syntax:`temporal workflow COMMAND [ARGS]`." + s.Command.Long = "Workflow commands perform operations on Workflow Executions.\n\nWorkflow commands use this syntax: `temporal workflow COMMAND [ARGS]`." } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalWorkflowCancelCommand(cctx, &s).Command) diff --git a/temporalcli/commands.go b/temporalcli/commands.go index 23e74fb4..c5291d7b 100644 --- a/temporalcli/commands.go +++ b/temporalcli/commands.go @@ -46,6 +46,10 @@ type CommandContext struct { Logger *slog.Logger JSONOutput bool JSONShorthandPayloads bool + + // Is set to true if any command actually started running. This is a hack to workaround the fact + // that cobra does not properly exit nonzero if an unknown command/subcommand is given. + ActuallyRanCommand bool } type CommandOptions struct { @@ -289,6 +293,10 @@ func Execute(ctx context.Context, options CommandOptions) { if err != nil { cctx.Options.Fail(err) } + // If no command ever actually got run, exit nonzero + if !cctx.ActuallyRanCommand { + cctx.Options.Fail(fmt.Errorf("unknown command")) + } } func (c *TemporalCommand) initCommand(cctx *CommandContext) { @@ -315,6 +323,7 @@ func (c *TemporalCommand) initCommand(cctx *CommandContext) { if cctx.JSONOutput { color.NoColor = true } + cctx.ActuallyRanCommand = true return res } c.Command.PersistentPostRun = func(*cobra.Command, []string) { diff --git a/temporalcli/commands_test.go b/temporalcli/commands_test.go index 0fc55da8..5cfdabcc 100644 --- a/temporalcli/commands_test.go +++ b/temporalcli/commands_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/google/uuid" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "go.temporal.io/api/enums/v1" @@ -496,3 +497,9 @@ func (w *concurrentWriter) Write(p []byte) (n int, err error) { defer w.wLock.Unlock() return w.w.Write(p) } + +func TestUnknownCommandExitsNonzero(t *testing.T) { + commandHarness := NewCommandHarness(t) + res := commandHarness.Execute("blerkflow") + assert.Contains(t, res.Err.Error(), "unknown command") +} diff --git a/temporalcli/commandsmd/commands.md b/temporalcli/commandsmd/commands.md index b2287c08..df3d6deb 100644 --- a/temporalcli/commandsmd/commands.md +++ b/temporalcli/commandsmd/commands.md @@ -255,10 +255,9 @@ Use the options listed below to modify what this command returns. ### temporal workflow: Start, list, and operate on Workflows. -[Workflow](/concepts/what-is-a-workflow) commands perform operations on -[Workflow Executions](/concepts/what-is-a-workflow-execution). +[Workflow](/concepts/what-is-a-workflow) commands perform operations on [Workflow Executions](/concepts/what-is-a-workflow-execution). -Workflow commands use this syntax:`temporal workflow COMMAND [ARGS]`. +Workflow commands use this syntax: `temporal workflow COMMAND [ARGS]`. #### Options set for client: