Skip to content

[describe-stacks] Fix: switch --component-types to StringSlice to match []string and support multi-values#1432

Merged
aknysh merged 3 commits intocloudposse:mainfrom
dyer-oai:flag-fix
Sep 2, 2025
Merged

[describe-stacks] Fix: switch --component-types to StringSlice to match []string and support multi-values#1432
aknysh merged 3 commits intocloudposse:mainfrom
dyer-oai:flag-fix

Conversation

@dyer-oai
Copy link
Contributor

@dyer-oai dyer-oai commented Aug 29, 2025

what

  • Change describe stacks flag --component-types from a String to a StringSlice:
    • cmd/describe_stacks.go: String("component-types", "", ...)StringSlice("component-types", nil, ...)
  • Add a unit test to validate slice parsing (CSV supported by pflag):
    • cmd/describe_stacks_test.go: TestSetCliArgs_ComponentTypes_StringSlice asserts --component-types=terraform,helmfile[]string{"terraform","helmfile"}

why

  • Fix a flag type mismatch that caused: trying to get stringSlice value of flag of type string when --component-types was registered as a String, the command later read it as a []string, triggering the pflag runtime error.
  • Aligns the flag’s declared type with how it’s consumed ([]string in DescribeStacksArgs), eliminating the error for:
    atmos describe stacks --format=json --component-types=terraform
  • Improves UX by officially supporting multiple values via:
  • CSV: --component-types=terraform,helmfile
  • repeated flags: --component-types=terraform --component-types=helmfile
  • Keeps behavior consistent with other multi-valued flags (e.g., --sections).

Backwards compatibility: single-value usage (--component-types=terraform) continues to work. Scripts that previously passed comma-separated values still work because pflag’s StringSlice accepts CSV.

Atmos Breaking Change:

Commit: 8957ff6
Date: 2025-06-05T10:08:15-07:00
First release tag containing the commit: v1.179.0
Present in all subsequent releases checked, including v1.188.0.

references

  • Repro: atmos describe stacks --format=json --component-types=terraform on v1.188.0 (darwin/arm64) → pflag type error.
  • Implementation details:
  • Flag now declared as StringSlice to match []string in args struct.
  • New test validates CSV parsing populates args.ComponentTypes as expected.

Summary by CodeRabbit

  • New Features

    • The component-types CLI flag now accepts multiple values (comma-separated or repeated), e.g. --component-types=terraform,helmfile; when omitted it remains unset.
  • Bug Fixes

    • Merge behavior hardened to safely handle missing configuration and default to the existing "replace" list strategy to avoid crashes.
  • Tests

    • Added tests for multi-value component-types parsing and for merge behavior when configuration is absent.

@dyer-oai dyer-oai requested a review from a team as a code owner August 29, 2025 14:46
@mergify mergify bot added the triage Needs triage label Aug 29, 2025
@dyer-oai dyer-oai changed the title fix(describe-stacks): register --component-types as StringSlice to ma… fix(describe-stacks): make --component-types a String flag (CSV-supported) and normalize to []string downstream Aug 29, 2025
@dyer-oai dyer-oai changed the title fix(describe-stacks): make --component-types a String flag (CSV-supported) and normalize to []string downstream fix(describe-stacks): make --component-types a String flag (CSV-supported) and normalize to []string downstream Aug 29, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 29, 2025

📝 Walkthrough

Walkthrough

Changed the CLI --component-types flag from a single string to a string-slice and updated binding to populate exec.DescribeStacksArgs.ComponentTypes []string. Added unit tests for StringSlice parsing. Also hardened pkg/merge.Merge to handle a nil atmosConfig by defaulting list-merge strategy to "replace" and added a test for that behavior.

Changes

Cohort / File(s) Summary of Changes
CLI flag type update
cmd/describe_stacks.go
Switched --component-types flag from String to StringSlice (default nil) and changed retrieval to GetStringSlice, mapping into exec.DescribeStacksArgs.ComponentTypes []string.
CLI unit test
cmd/describe_stacks_test.go
Added TestSetCliArgs_ComponentTypes_StringSlice to assert --component-types=terraform,helmfile parses to []string{"terraform","helmfile"} and populates args.
Merge nil-safety refactor
pkg/merge/merge.go
Avoids direct mutation/dereference of atmosConfig.Settings.ListMergeStrategy; uses a local strategy variable defaulting to "replace" when atmosConfig or its setting is nil, and derives sliceDeepCopy / appendSlice from that local value.
Merge unit test
pkg/merge/merge_test.go
Added TestMerge_NilAtmosConfigDefaultsToReplace to verify Merge(nil, inputs) defaults to Replace and does not panic.

Sequence Diagram(s)

sequenceDiagram
    participant User as CLI user
    participant CLI as cmd/describe_stacks.go
    participant Flags as pflag.FlagSet
    participant Binder as setCliArgsForDescribeStackCli
    participant Exec as exec.DescribeStacksArgs

    Note over User,CLI: User runs `atmos describe-stacks --component-types=terraform,helmfile`
    User->>CLI: invoke command
    CLI->>Flags: define StringSlice "component-types"
    Flags->>CLI: parse args
    CLI->>Binder: call setCliArgsForDescribeStackCli(flags)
    Binder->>Flags: GetStringSlice("component-types")
    Flags-->>Binder: ["terraform","helmfile"]
    Binder->>Exec: set ComponentTypes = ["terraform","helmfile"]
    Note right of Exec: Args populated with slice
Loading
sequenceDiagram
    participant Caller as Merge caller
    participant Merge as pkg/merge.Merge
    participant Options as local strategy logic
    participant Merger as MergeWithOptions

    Caller->>Merge: Merge(atmosConfig=nil, inputs)
    Merge->>Options: compute strategy (nil -> "replace")
    Options-->>Merge: strategy = "replace"
    Merge->>Merger: MergeWithOptions(inputs, append=false, sliceDeepCopy=false)
    Merger-->>Caller: merged result (replace semantics)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

patch

Suggested reviewers

  • osterman
  • aknysh
  • milldr
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @auto-summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @auto-title anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6f99b9e and 0dfa609.

📒 Files selected for processing (2)
  • cmd/describe_stacks.go (1 hunks)
  • cmd/describe_stacks_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
cmd/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

cmd/*.go: Implement each Cobra command in a separate file under the cmd/ directory
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in command help
Provide meaningful feedback to users in command implementation
Include progress indicators for long-running operations
Provide clear error messages to users
Include troubleshooting hints when appropriate
Log detailed errors for debugging

Files:

  • cmd/describe_stacks_test.go
  • cmd/describe_stacks.go
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: Use Viper for managing configuration, environment variables, and flags
Use interfaces for external dependencies to facilitate mocking
All code must pass golangci-lint checks
Follow Go's error handling idioms
Use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider using a custom error type for domain-specific errors
Follow standard Go coding style
Use gofmt and goimports to format code
Prefer short, descriptive variable names
Use snake_case for environment variables
Document all exported functions, types, and methods
Document complex logic with inline comments
Follow Go's documentation conventions
Use Viper for configuration management
Support configuration via files, environment variables, and flags
Follow the precedence order: flags > environment variables > config file > defaults

Files:

  • cmd/describe_stacks_test.go
  • cmd/describe_stacks.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for testing multiple scenarios
Include integration tests for command flows
Test CLI end-to-end when possible
Use test fixtures for complex inputs
Consider using testify/mock for creating mock implementations

Files:

  • cmd/describe_stacks_test.go
🧠 Learnings (1)
📚 Learning: 2025-07-01T02:22:25.901Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-07-01T02:22:25.901Z
Learning: Applies to **/*_test.go : Test both happy paths and error conditions

Applied to files:

  • cmd/describe_stacks_test.go
🧬 Code graph analysis (1)
cmd/describe_stacks_test.go (1)
internal/exec/describe_stacks.go (1)
  • DescribeStacksArgs (18-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary

@dyer-oai dyer-oai changed the title fix(describe-stacks): make --component-types a String flag (CSV-supported) and normalize to []string downstream [describe-stacks] Fix: switch --component-types to StringSlice to match []string and support multi-values Aug 29, 2025
coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 29, 2025
@mergify mergify bot removed the triage Needs triage label Aug 29, 2025
@osterman osterman added the minor New features that do not break anything label Aug 29, 2025
@codecov
Copy link

codecov bot commented Aug 29, 2025

Codecov Report

❌ Patch coverage is 80.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.62%. Comparing base (c5c97fb) to head (d21019f).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/merge/merge.go 77.77% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1432   +/-   ##
=======================================
  Coverage   55.61%   55.62%           
=======================================
  Files         273      273           
  Lines       28620    28621    +1     
=======================================
+ Hits        15918    15919    +1     
+ Misses      10918    10916    -2     
- Partials     1784     1786    +2     
Flag Coverage Δ
unittests 55.62% <80.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@osterman
Copy link
Member

For some reason, we're getting this error on macos

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x104a5bb78]

goroutine 1081 [running]:
github.com/cloudposse/atmos/pkg/merge.Merge(0x107f10950?, {0x1400008ba60?, 0x1060197b2?, 0xb32?})
	/Users/runner/work/atmos/atmos/pkg/merge/merge.go:85 +0xa8
github.com/cloudposse/atmos/internal/exec.ProcessYAMLConfigFile(0x140046ecc88, {0x14000b399e0, 0x57}, {0x14001414000, 0x6b}, 0x140040dbf20, 0x0, 0x0, 0x0, 0x0, ...)
	/Users/runner/work/atmos/atmos/internal/exec/stack_processor_utils.go:323 +0x10b4
github.com/cloudposse/atmos/internal/exec.ProcessYAMLConfigFiles.func1(0x0, {0x14001414000, 0x6b})
	/Users/runner/work/atmos/atmos/internal/exec/stack_processor_utils.go:76 +0x2fc
created by github.com/cloudposse/atmos/internal/exec.ProcessYAMLConfigFiles in goroutine 1023
	/Users/runner/work/atmos/atmos/internal/exec/stack_processor_utils.go:61 +0xf8
FAIL	github.com/cloudposse/atmos/internal/exec	47.658s

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
pkg/merge/merge.go (2)

86-93: Polish the invalid-strategy error (no newline).

Drop the embedded newline to keep errors single-line and easier to wrap/log.

-		return nil, fmt.Errorf("invalid Atmos manifests list merge strategy '%s'.\n"+
-			"Supported list merge strategies are: %s.",
+		return nil, fmt.Errorf("invalid Atmos manifests list merge strategy %q. Supported list merge strategies are: %s.",
 			strategy,
 			fmt.Sprintf("%s, %s, %s", ListMergeStrategyReplace, ListMergeStrategyAppend, ListMergeStrategyMerge))

98-104: Tiny readability tweak: prefer switch.

A switch expresses the three discrete strategies a bit clearer.

-	if strategy == ListMergeStrategyMerge {
-		sliceDeepCopy = true
-	} else if strategy == ListMergeStrategyAppend {
-		appendSlice = true
-	}
+	switch strategy {
+	case ListMergeStrategyMerge:
+		sliceDeepCopy = true
+	case ListMergeStrategyAppend:
+		appendSlice = true
+	}
pkg/merge/merge_test.go (1)

26-38: Add an error-path test for invalid strategy.

Covers negative case per testing guidelines.

func TestMerge_InvalidStrategy_ReturnsError(t *testing.T) {
	atmosConfig := schema.AtmosConfiguration{
		Settings: schema.AtmosSettings{ListMergeStrategy: "bogus"},
	}
	_, err := Merge(&atmosConfig, []map[string]any{{"list": []string{"1"}}})
	assert.Error(t, err)
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0dfa609 and b01c7ba.

📒 Files selected for processing (2)
  • pkg/merge/merge.go (1 hunks)
  • pkg/merge/merge_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*.go: Use Viper for managing configuration, environment variables, and flags
Use interfaces for external dependencies to facilitate mocking
All code must pass golangci-lint checks
Follow Go's error handling idioms
Use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider using a custom error type for domain-specific errors
Follow standard Go coding style
Use gofmt and goimports to format code
Prefer short, descriptive variable names
Use snake_case for environment variables
Document all exported functions, types, and methods
Document complex logic with inline comments
Follow Go's documentation conventions
Use Viper for configuration management
Support configuration via files, environment variables, and flags
Follow the precedence order: flags > environment variables > config file > defaults

Files:

  • pkg/merge/merge_test.go
  • pkg/merge/merge.go
**/*_test.go

📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for testing multiple scenarios
Include integration tests for command flows
Test CLI end-to-end when possible
Use test fixtures for complex inputs
Consider using testify/mock for creating mock implementations

Files:

  • pkg/merge/merge_test.go
🧠 Learnings (2)
📓 Common learnings
Learnt from: aknysh
PR: cloudposse/atmos#1261
File: internal/exec/utils.go:639-640
Timestamp: 2025-05-22T15:42:10.906Z
Learning: In the Atmos codebase, when appending slices with `args := append(configAndStacksInfo.CliArgs, configAndStacksInfo.AdditionalArgsAndFlags...)`, it's intentional that the result is not stored back in the original slice. This pattern is used when the merged result serves a different purpose than the original slices, such as when creating a filtered version for component section assignments.
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
PR: cloudposse/atmos#1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.

Applied to files:

  • pkg/merge/merge.go
🧬 Code graph analysis (1)
pkg/merge/merge_test.go (1)
pkg/merge/merge.go (1)
  • Merge (77-105)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (2)
pkg/merge/merge.go (1)

81-84: Nil-safe default eliminates the panic.

Initializing strategy to replace and guarding atmosConfig prevents the nil deref reported in tests. LGTM.

pkg/merge/merge_test.go (1)

26-38: Good guardrail for nil atmosConfig.

Test clearly asserts default-to-replace and prevents regressions. Nice.

@aknysh aknysh added no-release Do not create a new release (wait for additional code changes) and removed minor New features that do not break anything labels Sep 2, 2025
Copy link
Member

@aknysh aknysh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @dyer-oai

@aknysh aknysh merged commit fd1399a into cloudposse:main Sep 2, 2025
54 of 55 checks passed
@github-actions
Copy link

github-actions bot commented Sep 2, 2025

These changes were released in v1.189.0-test.0.

osterman added a commit that referenced this pull request Sep 2, 2025
Resolve merge conflicts and integrate latest main branch changes:

✅ **errors/errors.go**: Added ErrMerge error for improved error handling
✅ **pkg/merge/merge.go**: Updated merge logic with better error wrapping and strategy handling
✅ **pkg/merge/merge_test.go**: Enhanced tests with proper error verification
✅ **cmd/describe_stacks.go**: Updated component types handling to support multi-values
✅ **cmd/describe_stacks_test.go**: Updated tests for new describe stacks functionality
✅ **website/docs/**: Fixed sample stack configuration

All conflicts resolved in favor of main branch improvements while preserving
our gotcha tool implementation and documentation changes.

Merged commits from main:
- 5e2f1c3 fix: improve error handling and code quality in merge package (#1440)
- fd1399a [describe-stacks] Fix: switch --component-types to StringSlice (#1432)
- c5c97fb Fix sample stacks/deploy/dev.yaml in documentation (#1434)
osterman pushed a commit that referenced this pull request Sep 23, 2025
…ch []string and support multi-values (#1432)

* fix(describe-stacks): register --component-types as StringSlice to match []string

* [merge] Fix: avoid nil-pointer panic when atmosConfig is nil in Merge

---------

Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-release Do not create a new release (wait for additional code changes)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants