Skip to content

Commit ffa7f0a

Browse files
ostermanclaudeaknyshautofix-ci[bot]
authored
Add list affected command with spinner UI improvements (#1874)
* feat: Add list affected command with improved spinner UI and fix false positives - Implement new `atmos list affected` command to compare components between branches - Fix false positive affected components when using `-C` flag by computing relative paths from git root - Clear component config cache between branch comparisons to prevent contamination - Generalize spinner implementation from internal/exec to pkg/ui/spinner for reusability - Add FormatSuccess/FormatError to properly render markdown in toast messages - Add git worktree operations for isolated branch comparisons - Include documentation for false positive fix and new list affected command 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * test: Increase test coverage for list affected command Add comprehensive tests for multiple packages to improve coverage: - pkg/list/list_affected_test.go: Tests for column parsing, ref selection, filter/sorter building, and format-specific column handling - pkg/git/worktree_test.go: Tests for worktree creation, removal, and parent directory resolution - pkg/ui/spinner/spinner_test.go: Tests for dynamic and manual spinner models including Init, Update, and View methods - cmd/list/affected_test.go: Tests for CLI command structure, flag registration, and options handling - internal/exec/describe_affected_utils_test.go: Tests for error paths and excludeLocked functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeRabbit review comments - Add test case for excludeLocked=true to verify locked components are excluded (fix structure: locked goes in metadata, not settings.metadata) - Fix godot linter violations: add periods to comments on lines 521/527 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: Add more tests to improve coverage on affected lines - Add TestGetBasePathToUse to validate_component_test.go to cover getBasePathToUse function (9 lines covered) - Add comprehensive spinner tests for edge cases including: - TestSpinner_IsTTY for isTTY state verification - TestSpinner_AlreadyStopped for nil program safety - TestSpinnerModels_IgnoreNonQuitKeys for ignored key handling - TestSpinnerModelStyle for spinner initialization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeRabbit review comments - Fix excludeLocked test to use metadata.locked consistently (matches actual fixture usage in tests/fixtures/scenarios/) - Rename tests variable to testCases in worktree_test.go to avoid shadowing the imported tests package 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: Add edge case tests for list affected coverage Add additional edge case tests to improve test coverage: - pkg/list/list_affected_test.go: - TestBuildAffectedFilters_EdgeCases (multiple colons, spaces, special chars) - TestBuildAffectedSorters_EdgeCases (descending, multiple columns, empty) - TestParseAffectedColumnsFlag_EdgeCases (complex templates, unicode) - TestSelectRemoteRef_Precedence (SHA/ref precedence) - TestSetRefNames_Combinations (RepoPath override) - TestAffectedCommandOptions struct validation - cmd/list/affected_test.go: - TestAffectedOptions_FullOptions (all fields populated) - TestAffectedCommandSubcommand (command config) - TestAffectedFlagDefaults (default values) - TestAffectedFlagShorthands (shorthand configs) - TestAffectedCommandLong (descriptions) These tests increase overall coverage for the list affected command. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * address comments, add tests * [autofix.ci] apply automated fixes * fix: Add perf tracking to executeListAffectedCmd Add performance tracking to executeListAffectedCmd function per coding guidelines, addressing CodeRabbit review feedback. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * address comments, add tests --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com> Co-authored-by: aknysh <andriy.knysh@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent aafe982 commit ffa7f0a

38 files changed

+5281
-294
lines changed

cmd/list/affected.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package list
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/spf13/viper"
6+
7+
e "github.com/cloudposse/atmos/internal/exec"
8+
"github.com/cloudposse/atmos/pkg/flags"
9+
"github.com/cloudposse/atmos/pkg/flags/global"
10+
"github.com/cloudposse/atmos/pkg/list"
11+
"github.com/cloudposse/atmos/pkg/perf"
12+
)
13+
14+
var affectedParser *flags.StandardParser
15+
16+
// AffectedOptions contains parsed flags for the affected command.
17+
type AffectedOptions struct {
18+
global.Flags
19+
// Output format flags.
20+
Format string
21+
Columns []string
22+
Delimiter string
23+
Sort string
24+
25+
// Git comparison flags.
26+
Ref string
27+
SHA string
28+
RepoPath string
29+
SSHKeyPath string
30+
SSHKeyPassword string
31+
CloneTargetRef bool
32+
33+
// Content flags.
34+
IncludeDependents bool
35+
Stack string
36+
ExcludeLocked bool
37+
38+
// Processing flags.
39+
ProcessTemplates bool
40+
ProcessFunctions bool
41+
Skip []string
42+
}
43+
44+
// affectedCmd lists affected Atmos components and stacks.
45+
var affectedCmd = &cobra.Command{
46+
Use: "affected",
47+
Short: "List affected components and stacks",
48+
Long: "Display a table of affected components and stacks between Git commits.",
49+
Args: cobra.NoArgs,
50+
RunE: func(cmd *cobra.Command, args []string) error {
51+
// Parse flags using StandardParser with Viper precedence.
52+
v := viper.GetViper()
53+
54+
// Check Atmos configuration.
55+
if err := checkAtmosConfig(cmd, v); err != nil {
56+
return err
57+
}
58+
if err := affectedParser.BindFlagsToViper(cmd, v); err != nil {
59+
return err
60+
}
61+
62+
opts := &AffectedOptions{
63+
Flags: flags.ParseGlobalFlags(cmd, v),
64+
Format: v.GetString("format"),
65+
Columns: v.GetStringSlice("columns"),
66+
Delimiter: v.GetString("delimiter"),
67+
Sort: v.GetString("sort"),
68+
Ref: v.GetString("ref"),
69+
SHA: v.GetString("sha"),
70+
RepoPath: v.GetString("repo-path"),
71+
SSHKeyPath: v.GetString("ssh-key"),
72+
SSHKeyPassword: v.GetString("ssh-key-password"),
73+
CloneTargetRef: v.GetBool("clone-target-ref"),
74+
IncludeDependents: v.GetBool("include-dependents"),
75+
Stack: v.GetString("stack"),
76+
ExcludeLocked: v.GetBool("exclude-locked"),
77+
ProcessTemplates: v.GetBool("process-templates"),
78+
ProcessFunctions: v.GetBool("process-functions"),
79+
Skip: v.GetStringSlice("skip"),
80+
}
81+
82+
return executeListAffectedCmd(cmd, args, opts)
83+
},
84+
}
85+
86+
func init() {
87+
// Create parser using flag wrappers.
88+
affectedParser = NewListParser(
89+
WithFormatFlag,
90+
WithAffectedColumnsFlag,
91+
WithDelimiterFlag,
92+
WithSortFlag,
93+
WithRefFlag,
94+
WithSHAFlag,
95+
WithRepoPathFlag,
96+
WithSSHKeyFlag,
97+
WithSSHKeyPasswordFlag,
98+
WithCloneTargetRefFlag,
99+
WithIncludeDependentsFlag,
100+
WithStackFlag,
101+
WithExcludeLockedFlag,
102+
WithProcessTemplatesFlag,
103+
WithProcessFunctionsFlag,
104+
WithSkipFlag,
105+
)
106+
107+
// Register flags.
108+
affectedParser.RegisterFlags(affectedCmd)
109+
110+
// Bind flags to Viper for environment variable support.
111+
if err := affectedParser.BindToViper(viper.GetViper()); err != nil {
112+
panic(err)
113+
}
114+
}
115+
116+
func executeListAffectedCmd(cmd *cobra.Command, args []string, opts *AffectedOptions) error {
117+
defer perf.Track(nil, "list.executeListAffectedCmd")()
118+
119+
// Process and validate command line arguments.
120+
configAndStacksInfo, err := e.ProcessCommandLineArgs("list", cmd, args, nil)
121+
if err != nil {
122+
return err
123+
}
124+
configAndStacksInfo.Command = "list"
125+
configAndStacksInfo.SubCommand = "affected"
126+
127+
return list.ExecuteListAffectedCmd(&list.AffectedCommandOptions{
128+
Info: &configAndStacksInfo,
129+
Cmd: cmd,
130+
Args: args,
131+
ColumnsFlag: opts.Columns,
132+
FilterSpec: "", // Filter spec not yet exposed via flag.
133+
SortSpec: opts.Sort,
134+
Delimiter: opts.Delimiter,
135+
Ref: opts.Ref,
136+
SHA: opts.SHA,
137+
RepoPath: opts.RepoPath,
138+
SSHKeyPath: opts.SSHKeyPath,
139+
SSHKeyPassword: opts.SSHKeyPassword,
140+
CloneTargetRef: opts.CloneTargetRef,
141+
IncludeDependents: opts.IncludeDependents,
142+
Stack: opts.Stack,
143+
ProcessTemplates: opts.ProcessTemplates,
144+
ProcessFunctions: opts.ProcessFunctions,
145+
Skip: opts.Skip,
146+
ExcludeLocked: opts.ExcludeLocked,
147+
})
148+
}

0 commit comments

Comments
 (0)