Skip to content

Commit fc848df

Browse files
fix: Prevent usage error after successful workflow TUI execution (#1796)
* fix workflow * fix workflow * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 8125309 commit fc848df

File tree

7 files changed

+237
-18
lines changed

7 files changed

+237
-18
lines changed

NOTICE

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ APACHE 2.0 LICENSED DEPENDENCIES
5151

5252
- cloud.google.com/go/storage
5353
License: Apache-2.0
54-
URL: https://github.com/googleapis/google-cloud-go/blob/storage/v1.57.1/storage/LICENSE
54+
URL: https://github.com/googleapis/google-cloud-go/blob/storage/v1.57.2/storage/LICENSE
5555

5656
- cuelang.org/go
5757
License: Apache-2.0
@@ -481,6 +481,10 @@ APACHE 2.0 LICENSED DEPENDENCIES
481481
License: Apache-2.0
482482
URL: https://github.com/yaml/go-yaml/blob/v2.4.2/LICENSE
483483

484+
- go.yaml.in/yaml/v4
485+
License: Apache-2.0
486+
URL: https://github.com/yaml/go-yaml/blob/v4.0.0-rc.3/LICENSE
487+
484488
- gocloud.dev
485489
License: Apache-2.0
486490
URL: https://github.com/google/go-cloud/blob/v0.41.0/LICENSE
@@ -732,7 +736,7 @@ BSD LICENSED DEPENDENCIES
732736

733737
- golang.org/x/crypto
734738
License: BSD-3-Clause
735-
URL: https://cs.opensource.google/go/x/crypto/+/v0.43.0:LICENSE
739+
URL: https://cs.opensource.google/go/x/crypto/+/v0.44.0:LICENSE
736740

737741
- golang.org/x/exp
738742
License: BSD-3-Clause
@@ -744,7 +748,7 @@ BSD LICENSED DEPENDENCIES
744748

745749
- golang.org/x/net
746750
License: BSD-3-Clause
747-
URL: https://cs.opensource.google/go/x/net/+/v0.46.0:LICENSE
751+
URL: https://cs.opensource.google/go/x/net/+/v0.47.0:LICENSE
748752

749753
- golang.org/x/oauth2
750754
License: BSD-3-Clause
@@ -1422,7 +1426,7 @@ MIT LICENSED DEPENDENCIES
14221426

14231427
- github.com/mikefarah/yq/v4/pkg/yqlib
14241428
License: MIT
1425-
URL: https://github.com/mikefarah/yq/blob/v4.48.1/LICENSE
1429+
URL: https://github.com/mikefarah/yq/blob/v4.48.2/LICENSE
14261430

14271431
- github.com/mitchellh/copystructure
14281432
License: MIT

cmd/workflow.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ var workflowCmd = &cobra.Command{
2424
if err != nil {
2525
return err
2626
}
27+
// Return after TUI execution to prevent showing usage error.
28+
return nil
2729
}
2830

2931
// Get the --file flag value
@@ -35,6 +37,7 @@ var workflowCmd = &cobra.Command{
3537
if err != nil {
3638
return err
3739
}
40+
return nil
3841
}
3942

4043
// Execute the workflow command

cmd/workflow_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,23 @@ atmos describe component c1 -s test
4848
// Check if the output contains expected markdown content
4949
assert.Contains(t, output.String(), expectedOutput, "'atmos workflow' output should contain information about workflows")
5050
}
51+
52+
// TestWorkflowCmd_WithFileFlag tests that workflow execution with --file flag does not show usage error.
53+
func TestWorkflowCmd_WithFileFlag(t *testing.T) {
54+
_ = NewTestKit(t)
55+
56+
stacksPath := "../tests/fixtures/scenarios/complete"
57+
58+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
59+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
60+
61+
// Execute workflow with --file flag (test-1 has simple shell commands that will succeed)
62+
// Note: workflows.base_path in atmos.yaml is "stacks/workflows", so we just need the filename
63+
RootCmd.SetArgs([]string{"workflow", "test-1", "--file", "workflow1.yaml"})
64+
err := RootCmd.Execute()
65+
66+
// Workflow should execute successfully
67+
// The main fix is that when TUI is used (len(args)==0), it should return after execution
68+
// and NOT show "Incorrect Usage" message
69+
assert.NoError(t, err, "workflow should execute successfully with --file flag")
70+
}

go.mod

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.sum

Lines changed: 12 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/exec/workflow_test.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package exec
22

33
import (
4+
"path/filepath"
45
"testing"
56

7+
"github.com/spf13/cobra"
68
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
710

811
cfg "github.com/cloudposse/atmos/pkg/config"
912
"github.com/cloudposse/atmos/pkg/schema"
@@ -335,3 +338,188 @@ func TestCheckAndGenerateWorkflowStepNames(t *testing.T) {
335338
})
336339
}
337340
}
341+
342+
// TestExecuteWorkflowCmd tests the ExecuteWorkflowCmd function.
343+
func TestExecuteWorkflowCmd(t *testing.T) {
344+
// Create a helper to set up cobra command with workflow flags.
345+
createWorkflowCmd := func() *cobra.Command {
346+
cmd := &cobra.Command{
347+
Use: "workflow",
348+
}
349+
// Workflow-specific flags.
350+
cmd.PersistentFlags().StringP("file", "f", "", "Workflow file")
351+
cmd.PersistentFlags().Bool("dry-run", false, "Dry run")
352+
cmd.PersistentFlags().StringP("stack", "s", "", "Stack")
353+
cmd.PersistentFlags().String("from-step", "", "From step")
354+
cmd.PersistentFlags().String("identity", "", "Identity")
355+
356+
// Flags expected by ProcessCommandLineArgs.
357+
cmd.PersistentFlags().String("base-path", "", "Base path")
358+
cmd.PersistentFlags().StringSlice("config", []string{}, "Config files")
359+
cmd.PersistentFlags().StringSlice("config-path", []string{}, "Config paths")
360+
361+
return cmd
362+
}
363+
364+
t.Run("successful workflow execution", func(t *testing.T) {
365+
// Note: These tests are run from the module root, so use paths relative to module root.
366+
stacksPath := "../../tests/fixtures/scenarios/workflows"
367+
368+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
369+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
370+
371+
cmd := createWorkflowCmd()
372+
err := cmd.ParseFlags([]string{"--file", "test.yaml"})
373+
require.NoError(t, err)
374+
375+
// Execute with workflow name.
376+
args := []string{"shell-pass"}
377+
err = ExecuteWorkflowCmd(cmd, args)
378+
379+
// Should succeed.
380+
assert.NoError(t, err)
381+
})
382+
383+
t.Run("missing file flag", func(t *testing.T) {
384+
stacksPath := "../../tests/fixtures/scenarios/workflows"
385+
386+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
387+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
388+
389+
cmd := createWorkflowCmd()
390+
// Don't set --file flag.
391+
392+
args := []string{"shell-pass"}
393+
err := ExecuteWorkflowCmd(cmd, args)
394+
395+
// Should error with missing file flag message.
396+
assert.Error(t, err)
397+
assert.Contains(t, err.Error(), "'--file' flag is required")
398+
})
399+
400+
t.Run("file not found", func(t *testing.T) {
401+
// ExecuteWorkflowCmd calls CheckErrorPrintAndExit which exits the process.
402+
// We can't test this directly without mocking. Skip for now or refactor.
403+
// This test would require dependency injection to avoid the exit.
404+
t.Skip("Requires refactoring to avoid CheckErrorPrintAndExit")
405+
})
406+
407+
t.Run("absolute file path", func(t *testing.T) {
408+
stacksPath := "../../tests/fixtures/scenarios/workflows"
409+
410+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
411+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
412+
413+
// Use absolute path to workflow file.
414+
absPath, err := filepath.Abs("../../tests/fixtures/scenarios/workflows/stacks/workflows/test.yaml")
415+
require.NoError(t, err)
416+
417+
cmd := createWorkflowCmd()
418+
err = cmd.ParseFlags([]string{"--file", absPath})
419+
require.NoError(t, err)
420+
421+
args := []string{"shell-pass"}
422+
err = ExecuteWorkflowCmd(cmd, args)
423+
424+
assert.NoError(t, err)
425+
})
426+
427+
t.Run("file without extension", func(t *testing.T) {
428+
stacksPath := "../../tests/fixtures/scenarios/workflows"
429+
430+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
431+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
432+
433+
cmd := createWorkflowCmd()
434+
// Specify file without .yaml extension - should auto-add it.
435+
err := cmd.ParseFlags([]string{"--file", "test"})
436+
require.NoError(t, err)
437+
438+
args := []string{"shell-pass"}
439+
err = ExecuteWorkflowCmd(cmd, args)
440+
441+
assert.NoError(t, err)
442+
})
443+
444+
t.Run("dry-run flag", func(t *testing.T) {
445+
stacksPath := "../../tests/fixtures/scenarios/workflows"
446+
447+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
448+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
449+
450+
cmd := createWorkflowCmd()
451+
err := cmd.ParseFlags([]string{"--file", "test.yaml", "--dry-run"})
452+
require.NoError(t, err)
453+
454+
args := []string{"shell-pass"}
455+
err = ExecuteWorkflowCmd(cmd, args)
456+
457+
// Dry run should not error.
458+
assert.NoError(t, err)
459+
})
460+
461+
t.Run("stack override", func(t *testing.T) {
462+
stacksPath := "../../tests/fixtures/scenarios/workflows"
463+
464+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
465+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
466+
467+
cmd := createWorkflowCmd()
468+
err := cmd.ParseFlags([]string{"--file", "test.yaml", "--stack", "dev"})
469+
require.NoError(t, err)
470+
471+
// Use a workflow.
472+
args := []string{"shell-pass"}
473+
err = ExecuteWorkflowCmd(cmd, args)
474+
475+
// Should succeed with stack override.
476+
assert.NoError(t, err)
477+
})
478+
479+
t.Run("from-step flag", func(t *testing.T) {
480+
stacksPath := "../../tests/fixtures/scenarios/workflows"
481+
482+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
483+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
484+
485+
cmd := createWorkflowCmd()
486+
err := cmd.ParseFlags([]string{"--file", "test.yaml", "--from-step", "step1"})
487+
require.NoError(t, err)
488+
489+
args := []string{"shell-pass"}
490+
err = ExecuteWorkflowCmd(cmd, args)
491+
492+
// Should start from step1 (the only step in shell-pass workflow).
493+
assert.NoError(t, err)
494+
})
495+
496+
t.Run("identity flag", func(t *testing.T) {
497+
stacksPath := "../../tests/fixtures/scenarios/workflows"
498+
499+
t.Setenv("ATMOS_CLI_CONFIG_PATH", stacksPath)
500+
t.Setenv("ATMOS_BASE_PATH", stacksPath)
501+
502+
cmd := createWorkflowCmd()
503+
err := cmd.ParseFlags([]string{"--file", "test.yaml", "--identity", "test-identity"})
504+
require.NoError(t, err)
505+
506+
args := []string{"shell-pass"}
507+
err = ExecuteWorkflowCmd(cmd, args)
508+
509+
// Should error because identity doesn't exist (but flag was passed through correctly).
510+
assert.Error(t, err)
511+
assert.Contains(t, err.Error(), "test-identity")
512+
})
513+
514+
t.Run("invalid workflow manifest - no workflows key", func(t *testing.T) {
515+
// This will call CheckErrorPrintAndExit which exits the process.
516+
// Skip for now without dependency injection.
517+
t.Skip("Requires refactoring to avoid CheckErrorPrintAndExit")
518+
})
519+
520+
t.Run("workflow name not found in manifest", func(t *testing.T) {
521+
// This will call CheckErrorPrintAndExit which exits the process.
522+
// Skip for now without dependency injection.
523+
t.Skip("Requires refactoring to avoid CheckErrorPrintAndExit")
524+
})
525+
}

tests/fixtures/scenarios/workflows/stacks/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ workflows:
2626
echo "This should fail"
2727
exit 1
2828
type: shell
29+
2930
shell-command-not-found:
3031
description: |
3132
Run a shell command that doesn't exist.

0 commit comments

Comments
 (0)