Repository navigation
feat: support dotenv files in !include - #1930
Conversation
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
📝 WalkthroughWalkthroughAdds structured env configuration and .env file support: new pkg/env loader, early .env injection during config load, EnvConfig schema (vars + files), and propagates case-sensitive env merging and per-directory .env merging into shell/terraform execution paths. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant ConfigLoader as Config Loader
participant EnvLoader as Env File Loader
participant ShellExec as Shell Executor
participant OS as OS Process
User->>ConfigLoader: Load atmos.yaml
ConfigLoader->>EnvLoader: loadEnvFilesEarly(env.files)
EnvLoader->>OS: Inject global .env vars into process env
ConfigLoader->>ConfigLoader: parseEnvConfig -> AtmosConfiguration.Env (EnvConfig)
User->>ShellExec: Run command (workflow/component)
ShellExec->>EnvLoader: LoadFromDirectory(component dir, patterns, parents)
EnvLoader->>ShellExec: Return merged component .env vars + file list
ShellExec->>ShellExec: Merge OS env + global env (GetCaseSensitiveEnvVars) + component env
ShellExec->>OS: Execute command with final environment
OS-->>User: Command output
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (7)
pkg/env/file.go (2)
104-108: Consider removing redundant perf tracking.
MapToSlicedelegates toConvertMapToSlice, which already has its ownperf.Track. This creates double tracking overhead for the same operation.🔎 Proposed fix
func MapToSlice(m map[string]string) []string { - defer perf.Track(nil, "env.MapToSlice")() - return ConvertMapToSlice(m) }
120-126: Silent skip of invalid glob patterns may hide configuration issues.When a pattern has invalid syntax (e.g.,
[invalid), it's silently skipped. Users won't know their pattern is malformed. Consider logging a warning.🔎 Proposed enhancement
for _, pattern := range patterns { fullPattern := filepath.Join(dir, pattern) matches, err := filepath.Glob(fullPattern) if err != nil { - // Invalid pattern - skip it but don't fail. + // Invalid pattern syntax - log warning but don't fail. + log.Debug("Invalid glob pattern", "pattern", pattern, "error", err) continue }This would require importing the log package.
pkg/schema/schema_test.go (1)
145-186: GetCaseSensitiveMap tests align with new EnvConfig semanticsThe new subtests exercise EnvConfig.Vars both with and without CaseMaps and cover the nil Vars case; this matches the updated GetCaseSensitiveMap / GetCaseSensitiveEnvVars behavior and preserves previous expectations for the
"env"path.If you want to harden coverage further, consider adding a small subtest that calls
GetCaseSensitiveMap("env.vars")explicitly to lock in the structured-path behavior, but the current suite is already functionally solid.cmd/cmd_utils.go (1)
551-612: Custom‑command env is wired correctly, but we now double‑merge global envUsing
atmosConfig.GetCaseSensitiveEnvVars()when seedingenvand switchingExecuteShellto&atmosConfigkeeps custom commands aligned with the new env handling (including case preservation and .env behavior).Right now
envalready includesos.Environ()+ global env, andExecuteShellrepeats that merge internally before applyingenvVars, so the same keys get processed twice. It’s harmless but a bit redundant. Longer‑term, it may be cleaner to treatenvhere as “overrides only” (commandConfig/env + auth) and letExecuteShellown the system/global/.env merge.pkg/schema/schema.go (1)
53-72: EnvConfig / EnvFilesConfig and case‑sensitive env access look coherentThe new
EnvFilesConfig+EnvConfigstructs, the switch toAtmosConfiguration.Env EnvConfig, and the updatedGetCaseSensitiveMap/GetCaseSensitiveEnvVarsall line up cleanly:
- Dual form is supported (flat
envvs structuredenv.vars/env.files) without fighting mapstructure.- Case preservation for env vars is centralized via
GetCaseSensitiveEnvVars()and the extendedcaseSensitivePaths("env","env.vars"), which matches how workflows, shell exec, and auth shells are now consuming env.- Returning the raw
Varsmap whenCaseMapsis nil preserves previous behavior.Only minor thought: if you ever care about distinguishing “unset” vs “empty map” when
CaseMapsis present, you might add an earlyif source == nil { return nil }before callingApplyCase, but as it stands this is fully workable.Also applies to: 113-114, 243-270, 1322-1323
pkg/config/load.go (1)
21-29: Early .env support and dual‑form env parsing are wired correctlyNice job threading the new env behavior through config loading:
parseEnvConfigcleanly supports both legacy flatenvand structuredenv.vars/env.fileswithout reintroducing the old mapstructure collision withCommand.Env.loadEnvFilesEarlyruns aftersetEnv(v)but before profile resolution, usesenv.files.enabled/env.files.paths, and injects only missing vars intoos.Environ, so ATMOS_* in.envcan influence profile selection and other config without clobbering explicit env.- UI feedback via
ui.Success("Loaded …")is consistent with the later working‑dir.envloading path.- Extending
caseSensitivePathswith"env"and"env.vars"completes the link soGetCaseSensitiveEnvVars()can rely on casemap for both flat and structured forms.One behavioral nuance to keep in mind (likely acceptable): early
.envloading will honorenv.files.*from the base config, not from profiles, since profiles are applied later. If you ever need profile‑specific.envbehavior at bootstrap time, that would require a follow‑up design, but this implementation is internally consistent.Also applies to: 218-237, 280-284, 1237-1317, 1321-1325
internal/exec/shell_utils.go (1)
18-26: Consider merging command env with MergeEnvSlices to avoid duplicate keysThe new layering in
ExecuteShellCommand—system env → global env → working‑dir.env→ command env—is the right shape, and usingGetCaseSensitiveEnvVars()keeps it aligned with the dual‑form env config.Right now the final step is:
cmdEnv = append(cmdEnv, env...)Since
envis already a full environment slice (fromprepareStepEnvironment), this can introduce duplicateKEY=valueentries and leaves which value “wins” up to the OS/env implementation. To make precedence explicit and avoid duplicates, you could merge the slices instead:cmdEnv = envpkg.MergeEnvSlices(cmdEnv, env)That keeps “command/env manager output” as the clear highest‑priority layer while still honoring global +
.envvalues.Also applies to: 51-76
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (13)
cmd/auth_exec.gocmd/cmd_utils.gogo.modinternal/exec/shell_utils.gointernal/exec/shell_utils_test.gointernal/exec/stack_processor_process_stacks.gointernal/exec/workflow_adapters.gointernal/exec/workflow_utils.gopkg/config/load.gopkg/env/file.gopkg/env/file_test.gopkg/schema/schema.gopkg/schema/schema_test.go
🧰 Additional context used
📓 Path-based instructions (5)
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file undercmd/directory
Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions
Provide meaningful feedback to users and include progress indicators for long-running operations in CLI commands
Files:
cmd/auth_exec.gocmd/cmd_utils.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context usingfmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: usegofmtandgoimportsto format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging
**/*.go: All comments must end with periods (enforced bygodotlinter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg,log,u,errUtils)
All errors MUST be wrapped using static errors defined inerrors/errors.go- useerrors.Joinfor combining errors,fmt.Errorfwith%wfor context, anderrors.Is()for error checking
Never manually create mocks - usego.uber.org/mock/mockgenwith//go:generatedirectives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use//revive:disable:file-length-limit
Use colors frompkg/ui/theme/colors.gofor all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, usefilepath.Join()instead of h...
Files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/env/file_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
**/{pkg,internal,cmd}/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Add
defer perf.Track(atmosConfig, "pkg.FuncName")()plus blank line to all public functions, usingnilif no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions
Files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/env/file_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Use table-driven tests for testing multiple scenarios in Go
Include integration tests for command flows and test CLI end-to-end when possible with test fixturesPrefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with
go.uber.org/mock/mockgen, use table-driven tests, target >80% coverage
Files:
pkg/schema/schema_test.gopkg/env/file_test.gointernal/exec/shell_utils_test.go
{go.mod,go.sum}
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies
Files:
go.mod
🧠 Learnings (64)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!env` is used to retrieve environment variables and assign them to sections in stack manifests. It supports both simple types (string, number, boolean) and complex types (JSON-encoded lists, maps, objects).
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
📚 Learning: 2025-12-13T06:10:25.156Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: internal/exec/workflow_utils.go:0-0
Timestamp: 2025-12-13T06:10:25.156Z
Learning: Atmos workflows: In internal/exec/workflow_utils.go ExecuteWorkflow, non-identity steps intentionally use baseWorkflowEnv, which is constructed from the parent environment with PATH modifications for the toolchain. Avoid appending os.Environ() again; prefer documenting this behavior and testing that standard environment variables are preserved.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/env/file_test.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gogo.modpkg/env/file.gointernal/exec/shell_utils.gointernal/exec/workflow_utils.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/schema/schema.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/schema/schema.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gogo.modpkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/schema/schema.gocmd/cmd_utils.gogo.modpkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.
Applied to files:
cmd/auth_exec.gopkg/schema/schema_test.gopkg/env/file_test.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/env/file_test.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/terraform_cli_args_utils.go:64-73
Timestamp: 2025-09-29T15:47:10.908Z
Learning: In the Atmos codebase, viper.BindEnv is required for CLI commands in the cmd/ package, but internal utilities can use os.Getenv directly when parsing environment variables for business logic purposes. The requirement to use viper is specific to the CLI interface layer, not all environment variable access throughout the codebase.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gointernal/exec/shell_utils.gointernal/exec/workflow_utils.go
📚 Learning: 2025-09-07T18:07:00.549Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1452
File: cmd/auth_login.go:43-44
Timestamp: 2025-09-07T18:07:00.549Z
Learning: In the atmos project, the identity flag is defined as a persistent flag on the auth root command (cmd/auth.go), making it available to all auth subcommands without needing to be redefined in each individual subcommand.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.
Applied to files:
cmd/auth_exec.gopkg/schema/schema.gocmd/cmd_utils.gointernal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-12-13T04:37:25.223Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/root.go:0-0
Timestamp: 2025-12-13T04:37:25.223Z
Learning: In Atmos cmd/root.go Execute(), after cfg.InitCliConfig, we must call both toolchainCmd.SetAtmosConfig(&atmosConfig) and toolchain.SetAtmosConfig(&atmosConfig) so the CLI wrapper and the toolchain package receive configuration; missing either can cause nil-pointer panics in toolchain path resolution.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.
Applied to files:
cmd/auth_exec.gopkg/schema/schema_test.gopkg/env/file_test.gointernal/exec/shell_utils_test.gopkg/env/file.gointernal/exec/shell_utils.go
📚 Learning: 2025-12-13T04:37:40.435Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/toolchain/get.go:23-40
Timestamp: 2025-12-13T04:37:40.435Z
Learning: In Go CLI command files using Cobra, constrain the subcommand to accept at most one positional argument (MaximumNArgs(1)) so it supports both listing all items (zero args) and fetching a specific item (one arg). Define and parse flags with a standard parser (e.g., flags.NewStandardParser()) and avoid binding flags to Viper (no viper.BindEnv/BindPFlag). This promotes explicit argument handling and predictable flag behavior across command files.
Applied to files:
cmd/auth_exec.gocmd/cmd_utils.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration.
Applied to files:
cmd/auth_exec.gointernal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/env/file_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2024-11-13T21:37:07.852Z
Learnt from: Cerebrovinny
Repo: cloudposse/atmos PR: 764
File: internal/exec/describe_stacks.go:289-295
Timestamp: 2024-11-13T21:37:07.852Z
Learning: In the `internal/exec/describe_stacks.go` file of the `atmos` project written in Go, avoid extracting the stack name handling logic into a helper function within the `ExecuteDescribeStacks` method, even if the logic appears duplicated.
Applied to files:
internal/exec/stack_processor_process_stacks.go
📚 Learning: 2025-12-13T03:21:35.786Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1813
File: cmd/terraform/shell.go:28-73
Timestamp: 2025-12-13T03:21:35.786Z
Learning: In Atmos, when calling cfg.InitCliConfig, you must first populate the schema.ConfigAndStacksInfo struct with global flag values using flags.ParseGlobalFlags(cmd, v) rather than passing an empty struct. The LoadConfig function (pkg/config/load.go) reads config selection fields (AtmosConfigFilesFromArg, AtmosConfigDirsFromArg, BasePath, ProfilesFromArg) directly from the ConfigAndStacksInfo struct, NOT from Viper. Passing an empty struct causes config selection flags (--base-path, --config, --config-path, --profile) to be silently ignored. Correct pattern: parse flags → populate struct → call InitCliConfig. See cmd/terraform/plan_diff.go for reference implementation.
Applied to files:
internal/exec/stack_processor_process_stacks.gopkg/schema/schema_test.gopkg/schema/schema.gocmd/cmd_utils.gointernal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-10-13T18:13:54.020Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1622
File: pkg/perf/perf.go:140-184
Timestamp: 2025-10-13T18:13:54.020Z
Learning: In pkg/perf/perf.go, the `trackWithSimpleStack` function intentionally skips ownership checks at call stack depth > 1 to avoid expensive `getGoroutineID()` calls on every nested function. This is a performance optimization for the common single-goroutine execution case (most Atmos commands), accepting the rare edge case of potential metric corruption if multi-goroutine execution occurs at depth > 1. The ~19× performance improvement justifies this trade-off.
Applied to files:
internal/exec/stack_processor_process_stacks.go
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.
Applied to files:
internal/exec/stack_processor_process_stacks.gogo.modinternal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 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/schema/schema_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gocmd/cmd_utils.gopkg/config/load.gointernal/exec/workflow_utils.go
📚 Learning: 2024-12-12T15:17:45.245Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos.d/atmos.d/tools/helmfile.yml:10-10
Timestamp: 2024-12-12T15:17:45.245Z
Learning: In `examples/demo-atmos.d/atmos.d/tools/helmfile.yml`, when suggesting changes to `kubeconfig_path`, ensure that the values use valid Go template syntax.
Applied to files:
pkg/schema/schema_test.go
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.
Applied to files:
pkg/schema/schema_test.go
📚 Learning: 2024-10-20T13:12:46.499Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 736
File: pkg/config/const.go:6-6
Timestamp: 2024-10-20T13:12:46.499Z
Learning: In `cmd/cmd_utils.go`, it's acceptable to have hardcoded references to `atmos.yaml` in logs, and it's not necessary to update them to use the `CliConfigFileName` constant.
Applied to files:
pkg/schema/schema_test.gopkg/schema/schema.gointernal/exec/workflow_adapters.gointernal/exec/shell_utils.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Use table-driven tests for testing multiple scenarios in Go
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Applied to files:
pkg/env/file_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Include integration tests for command flows and test CLI end-to-end when possible with test fixtures
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: The atmos codebase has a custom extension to *testing.T that provides a Chdir method, allowing test functions to call t.Chdir() to change working directories during tests. This is used consistently across test files in the codebase.
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Applied to files:
pkg/env/file_test.gopkg/schema/schema.gopkg/env/file.gopkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with `go.uber.org/mock/mockgen`, use table-driven tests, target >80% coverage
Applied to files:
pkg/env/file_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests. This is implemented through custom testing framework extensions and is used consistently throughout the test suite.
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests.
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method that can be called on *testing.T objects. This functionality is implemented through custom testing framework extensions and is used consistently throughout the test suite for changing working directories during tests.
Applied to files:
pkg/env/file_test.gointernal/exec/shell_utils_test.go
📚 Learning: 2024-12-25T20:28:47.526Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 887
File: internal/exec/stack_processor_utils.go:380-380
Timestamp: 2024-12-25T20:28:47.526Z
Learning: Windows path handling often requires `filepath.Join` to ensure correct separators and comparisons. Insufficient tests can break cross-platform compatibility, so migrating from `path.Join` to `filepath.Join` needs thorough testing on Windows before merging.
Applied to files:
pkg/env/file_test.go
📚 Learning: 2024-10-27T04:28:40.966Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:155-175
Timestamp: 2024-10-27T04:28:40.966Z
Learning: In the `CollectDirectoryObjects` function in `internal/exec/terraform_clean.go`, recursive search through all subdirectories is not needed.
Applied to files:
pkg/env/file_test.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/{pkg,internal,cmd}/**/*.go : Add `defer perf.Track(atmosConfig, "pkg.FuncName")()` plus blank line to all public functions, using `nil` if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions
Applied to files:
pkg/schema/schema.gopkg/env/file.gointernal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.
Applied to files:
pkg/schema/schema.gopkg/config/load.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
Applied to files:
pkg/schema/schema.gocmd/cmd_utils.gointernal/exec/workflow_utils.go
📚 Learning: 2025-01-25T15:21:40.413Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:8-8
Timestamp: 2025-01-25T15:21:40.413Z
Learning: In Atmos, when a directory is specified for configuration loading (e.g., in the `import` section of atmos.yaml), all files within that directory should be treated as Atmos configurations. Do not suggest restricting file extensions in directory-based glob patterns.
Applied to files:
pkg/schema/schema.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use Viper for managing configuration, environment variables, and flags in CLI commands
Applied to files:
pkg/schema/schema.gogo.modpkg/config/load.go
📚 Learning: 2024-11-16T17:30:52.893Z
Learnt from: pkbhowmick
Repo: cloudposse/atmos PR: 786
File: internal/exec/shell_utils.go:159-162
Timestamp: 2024-11-16T17:30:52.893Z
Learning: For the `atmos terraform shell` command in `internal/exec/shell_utils.go`, input validation for the custom shell prompt is not required, as users will use this as a CLI tool and any issues will impact themselves.
Applied to files:
internal/exec/workflow_adapters.gointernal/exec/shell_utils_test.gointernal/exec/shell_utils.go
📚 Learning: 2025-08-16T23:33:07.477Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1405
File: internal/exec/describe_dependents_test.go:651-652
Timestamp: 2025-08-16T23:33:07.477Z
Learning: In the cloudposse/atmos Go codebase, ExecuteDescribeDependents expects a pointer to AtmosConfiguration (*schema.AtmosConfiguration), so when calling it with a value returned by cfg.InitCliConfig (which returns schema.AtmosConfiguration), the address-of operator (&) is necessary: ExecuteDescribeDependents(&atmosConfig, ...).
Applied to files:
internal/exec/workflow_adapters.gocmd/cmd_utils.gointernal/exec/workflow_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to cmd/**/*_test.go : Always use `cmd.NewTestKit(t)` for cmd tests to auto-clean RootCmd state
Applied to files:
internal/exec/shell_utils_test.go
📚 Learning: 2025-12-10T18:32:51.237Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1808
File: cmd/terraform/backend/backend_delete_test.go:9-23
Timestamp: 2025-12-10T18:32:51.237Z
Learning: In cmd subpackages (e.g., cmd/terraform/backend/), tests cannot use cmd.NewTestKit(t) due to Go's test visibility rules (NewTestKit is in a parent package test file). These tests only need TestKit if they execute commands through RootCmd or modify RootCmd state. Structural tests that only verify command structure/flags without touching RootCmd don't require TestKit cleanup.
Applied to files:
internal/exec/shell_utils_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to {go.mod,go.sum} : Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies
Applied to files:
go.modpkg/env/file.go
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: Go version 1.23.0 was deliberately introduced by the maintainer (aknysh) in January 2025. While this might be a pre-release or development version of Go, it has been approved for use in this project.
Applied to files:
go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: The project uses Go version 1.23.0 which has been confirmed by the maintainer to be working in production for months. Do not flag this as an invalid Go version.
Applied to files:
go.mod
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.
Applied to files:
go.mod
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.
Applied to files:
go.mod
📚 Learning: 2025-03-12T21:38:42.699Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1139
File: pkg/config/go-homedir/homedir.go:183-196
Timestamp: 2025-03-12T21:38:42.699Z
Learning: The code in pkg/config/go-homedir is a direct fork of the mitchellh/go-homedir package and was intentionally imported as-is without modifications to maintain consistency with the original source. Security concerns or other improvements may be addressed in future PRs.
Applied to files:
go.mod
📚 Learning: 2025-04-10T20:48:22.687Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: pkg/config/load.go:0-0
Timestamp: 2025-04-10T20:48:22.687Z
Learning: In the `bindEnv` function in `pkg/config/load.go`, panic is used deliberately instead of returning errors because errors from `BindEnv` would only occur due to developer mistakes. Using panic helps with early detection of these developer errors during initialization.
Applied to files:
pkg/env/file.gopkg/config/load.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.
Applied to files:
internal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Use colors from `pkg/ui/theme/colors.go` for all UI theming in Go code
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: Applies to **/*.go : Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (`cfg`, `log`, `u`, `errUtils`)
Applied to files:
internal/exec/shell_utils.gopkg/config/load.go
📚 Learning: 2025-11-09T19:06:58.470Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1752
File: pkg/profile/list/formatter_table.go:27-29
Timestamp: 2025-11-09T19:06:58.470Z
Learning: In the cloudposse/atmos repository, performance tracking with `defer perf.Track()` is enforced on all functions via linting, including high-frequency utility functions, formatters, and renderers. This is a repository-wide policy to maintain consistency and avoid making case-by-case judgment calls about which functions should have profiling.
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2024-10-28T01:51:30.811Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:329-332
Timestamp: 2024-10-28T01:51:30.811Z
Learning: In the Atmos Go code, when deleting directories or handling file paths (e.g., in `terraform_clean.go`), always resolve the absolute path using `filepath.Abs` and use the logger `u.LogWarning` for logging messages instead of using `fmt.Printf`.
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2025-02-06T13:38:07.216Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 984
File: internal/exec/copy_glob.go:0-0
Timestamp: 2025-02-06T13:38:07.216Z
Learning: The `u.LogTrace` function in the `cloudposse/atmos` repository accepts `atmosConfig` as its first parameter, followed by the message string.
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2025-09-27T20:50:20.564Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1533
File: pkg/config/load.go:585-637
Timestamp: 2025-09-27T20:50:20.564Z
Learning: In the cloudposse/atmos repository, command merging prioritizes precedence over display ordering. Help commands are displayed lexicographically regardless of internal array order, so the mergeCommandArrays function focuses on ensuring the correct precedence chain (top-level file wins) rather than maintaining specific display order.
Applied to files:
internal/exec/shell_utils.go
📚 Learning: 2025-05-30T03:21:37.197Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1274
File: go.mod:63-63
Timestamp: 2025-05-30T03:21:37.197Z
Learning: The redis dependency (github.com/redis/go-redis/v9) in the atmos project is only used in tests, not in production code.
Applied to files:
pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.698Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.698Z
Learning: New config templates support Go templating with `FuncMap()` from `internal/exec/template_funcs.go`
Applied to files:
pkg/config/load.go
📚 Learning: 2025-09-23T04:43:31.857Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1430
File: pkg/config/config.go:98-107
Timestamp: 2025-09-23T04:43:31.857Z
Learning: In the Atmos codebase, NO_PAGER environment variable handling is intentionally kept as direct os.Getenv() access in pkg/config/config.go rather than using Viper binding, because adding no_pager to the config file would be confusing for users. This is an acknowledged exception to the normal Viper binding pattern for environment variables.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
Repo: cloudposse/atmos PR: 1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.
Applied to files:
internal/exec/workflow_utils.go
🧬 Code graph analysis (9)
cmd/auth_exec.go (1)
pkg/env/global.go (1)
MergeGlobalEnv(16-35)
pkg/schema/schema_test.go (1)
pkg/schema/schema.go (2)
AtmosConfiguration(75-120)EnvConfig(67-72)
pkg/env/file_test.go (1)
pkg/env/file.go (4)
LoadEnvFiles(19-27)LoadFromDirectory(33-69)MergeEnvMaps(72-82)MergeEnvSlices(85-100)
pkg/schema/schema.go (1)
pkg/config/casemap/casemap.go (1)
CaseMaps(20-22)
internal/exec/workflow_adapters.go (2)
pkg/perf/perf.go (1)
Track(121-138)internal/exec/shell_utils.go (1)
ExecuteShell(133-191)
cmd/cmd_utils.go (2)
pkg/env/global.go (1)
MergeGlobalEnv(16-35)internal/exec/shell_utils.go (1)
ExecuteShell(133-191)
pkg/env/file.go (2)
pkg/perf/perf.go (1)
Track(121-138)pkg/env/global.go (1)
ConvertMapToSlice(39-51)
internal/exec/shell_utils.go (2)
pkg/env/global.go (3)
MergeGlobalEnv(16-35)MergeSystemEnvWithGlobal(87-91)MergeSystemEnvSimpleWithGlobal(105-109)pkg/env/file.go (3)
LoadFromDirectory(33-69)MergeEnvSlices(85-100)MapToSlice(104-108)
internal/exec/workflow_utils.go (1)
internal/exec/shell_utils.go (1)
ExecuteShell(133-191)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Summary
🔇 Additional comments (21)
pkg/env/file.go (6)
19-27: LGTM.Clean delegation with proper empty pattern handling.
33-69: LGTM — parent directory walking logic is correct.The precedence model (repo root lowest, working dir highest) aligns with the expected behavior. Error handling propagates correctly.
72-82: LGTM.Simple and correct. Nil maps are handled gracefully.
85-100: LGTM.Properly handles values containing
=by splitting only at the first occurrence. Entries without=or with empty keys are silently skipped, which is reasonable.
164-213: LGTM — security boundary enforced correctly.The
isWithinOrEqualcheck at Line 187 prevents walking beyond repo root. Path normalization withfilepath.Absandfilepath.Cleanensures cross-platform compatibility.
216-231: LGTM — path containment check is robust.Adding the separator before the prefix check (Line 229) correctly prevents false positives like
/a/b/c-othermatching/a/b/c.pkg/env/file_test.go (4)
353-377: LGTM — comprehensive table-driven tests for path containment.Good coverage of edge cases including trailing slashes and similar prefixes. The hardcoded Unix paths work because
isWithinOrEqualusesfilepath.Cleanwhich normalizes separators.
12-125: LGTM — thorough test coverage for LoadEnvFiles.Tests cover key scenarios: single file, glob patterns, missing files, case preservation, empty patterns, values with equals, quoted values, and directory filtering.
127-230: LGTM — LoadFromDirectory tests validate parent traversal and security boundaries.The test at Line 172-200 correctly verifies that
.envfiles outside repo root are not loaded.
279-281: No issue here. ThesplitStringAtFirstOccurrencehelper is defined inpkg/env/env.goat line 55 and is accessible throughout the package.cmd/auth_exec.go (1)
111-111: LGTM — updated to use case-sensitive env vars.Consistent with the broader refactor to
GetCaseSensitiveEnvVars()across the codebase.internal/exec/shell_utils_test.go (2)
600-609: LGTM — nil atmosConfig is appropriate for basic shell tests.These tests verify shell execution mechanics, not Atmos-specific env var handling.
611-669: LGTM — remaining ExecuteShell test updates are consistent.All test cases correctly pass
nilas the first argument with appropriate comments.internal/exec/workflow_adapters.go (1)
34-40: LGTM — nil atmosConfig is intentional for workflow shell commands.Per the learning, workflow non-identity steps use
baseWorkflowEnv. The comment clearly documents the rationale: shell commands don't needatmosConfigfor basic execution.go.mod (1)
71-71: LGTM — godotenv promoted to direct dependency.This correctly reflects the new direct import in
pkg/env/file.go. v1.5.1 is the latest stable version.internal/exec/stack_processor_process_stacks.go (1)
211-215: LGTM — atmos.yaml env correctly positioned as lowest priority in merge chain.
GetCaseSensitiveEnvVars()provides case-preserved env vars fromatmos.yaml. The merge order ensures component-levelenvoverrides globalenv, which overridesatmos.yamlenv.internal/exec/workflow_utils.go (1)
324-334: Workflow env handling now correctly uses case‑preserving env accessWiring
prepareStepEnvironmenttoatmosConfig.GetCaseSensitiveEnvVars()and passing&atmosConfigintoExecuteShellkeeps workflow steps in line with the new EnvConfig / .env behavior and perf tracking. The change is consistent with how other call sites are being updated.internal/exec/shell_utils.go (3)
133-191: ExecuteShell updates correctly integrate global env and per‑dir .env supportPassing
*schema.AtmosConfigurationintoExecuteShelland merging:
os.Environ()- global env via
atmosConfig.GetCaseSensitiveEnvVars()- per‑directory
.envviaLoadFromDirectorybefore applying
envVarsgives shells the same enriched environment as workflows and other exec paths, while still allowing the caller‑supplied entries to override. TheatmosConfig == nilguard keeps tests and non‑Atmos usage safe.
210-305: Terraform shell now respects global env via GetCaseSensitiveEnvVarsSwitching
execTerraformShellCommandto buildmergedEnvwith:mergedEnv := envpkg.MergeSystemEnvWithGlobal(componentEnvList, atmosConfig.GetCaseSensitiveEnvVars())ensures both legacy flat
envand structuredenv.varsfeed into the Terraform shell’s environment with proper case restoration, while still letting the per‑component entries incomponentEnvListtake precedence. This keeps the Terraform shell consistent with the rest of the env pipeline.Also applies to: 297-304
361-419: Auth shell correctly layers global env under auth‑specific varsIn
ExecAuthShellCommand, usingMergeSystemEnvSimpleWithGlobal(authEnvList, atmosConfig.GetCaseSensitiveEnvVars())makes the auth shell’s environment:
- Start from the host env.
- Add global env from Atmos config (case‑preserved).
- Finally overlay the auth/env list (including ATMOS_IDENTITY and provider‑specific credentials).
That matches the documented precedence and keeps auth shells aligned with the new env model.
Also applies to: 402-403
pkg/schema/schema_test.go (1)
3-10: Import path resolves correctly —go.yaml.in/yaml/v3is declared as a direct dependency in go.mod, so no resolution issues here.The inconsistency you noticed is real (codebase mixes
go.yaml.in/yaml/v3andgopkg.in/yaml.v3), but both import paths are intentionally maintained as separate dependencies. If consistency across the codebase matters for maintenance, that's a separate refactoring conversation.Likely an incorrect or invalid review comment.
|
Warning Release Documentation RequiredThis PR is labeled
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
pkg/config/load.go (2)
1243-1275: Consider more robust structured form detection.The detection at lines 1259-1260 checks only for key existence, not value type. If a flat env map contains a key literally named
varsorfiles, it would be misinterpreted as structured form.♻️ More robust detection
- // Detect structured form by presence of "vars" or "files" keys. - _, hasVars := envMap["vars"] - _, hasFiles := envMap["files"] + // Detect structured form by presence of "vars" or "files" keys with map values. + varsVal, hasVars := envMap["vars"] + filesVal, hasFiles := envMap["files"] + + // Only treat as structured if the values are maps/objects, not simple strings. + if hasVars { + if _, ok := varsVal.(map[string]any); !ok { + hasVars = false + } + } + if hasFiles { + if _, ok := filesVal.(map[string]any); !ok { + hasFiles = false + } + }
1318-1320: Consider moving UI reporting to the caller.The
ui.Success()calls create side effects in the config loading function, which is called from many places. This could be noisy in test environments or when config is reloaded.Since the function already returns
loadedFiles, consider letting the caller handle UI reporting:// In LoadConfig (line 284): loadedFiles := loadEnvFilesEarly(v, v.GetString("base_path")) for _, file := range loadedFiles { ui.Success(fmt.Sprintf("Loaded %s", filepath.Base(file))) }Then remove the UI calls from inside
loadEnvFilesEarly. This separates concerns and makes the config loading function more testable.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
cmd/auth_exec.gocmd/cmd_utils.gogo.modinternal/exec/stack_processor_process_stacks.gopkg/config/load.go
🚧 Files skipped from review as they are similar to previous changes (2)
- internal/exec/stack_processor_process_stacks.go
- cmd/cmd_utils.go
🧰 Additional context used
📓 Path-based instructions (4)
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands, implementing each command in a separate file undercmd/directory
Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions
Provide meaningful feedback to users and include progress indicators for long-running operations in CLI commands
Files:
cmd/auth_exec.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context usingfmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: usegofmtandgoimportsto format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging
**/*.go: All comments must end with periods (enforced bygodotlinter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg,log,u,errUtils)
All errors MUST be wrapped using static errors defined inerrors/errors.go- useerrors.Joinfor combining errors,fmt.Errorfwith%wfor context, anderrors.Is()for error checking
Never manually create mocks - usego.uber.org/mock/mockgenwith//go:generatedirectives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use//revive:disable:file-length-limit
Use colors frompkg/ui/theme/colors.gofor all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, usefilepath.Join()instead of h...
Files:
cmd/auth_exec.gopkg/config/load.go
**/{pkg,internal,cmd}/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Add
defer perf.Track(atmosConfig, "pkg.FuncName")()plus blank line to all public functions, usingnilif no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions
Files:
cmd/auth_exec.gopkg/config/load.go
{go.mod,go.sum}
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies
Files:
go.mod
🧠 Learnings (37)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 0
File: :0-0
Timestamp: 2025-01-19T22:30:27.600Z
Learning: The Atmos YAML function `!env` is used to retrieve environment variables and assign them to sections in stack manifests. It supports both simple types (string, number, boolean) and complex types (JSON-encoded lists, maps, objects).
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.
Learnt from: RoseSecurity
Repo: cloudposse/atmos PR: 725
File: internal/exec/vendor_component_utils.go:55-62
Timestamp: 2024-10-15T17:36:08.040Z
Learning: In the 'atmos' project, when adding support for multiple file extensions, the preferred approach is to directly check for the existence of the files rather than modifying constants or adding helper functions.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: examples/demo-atmos-cli-imports/atmos.yaml:8-8
Timestamp: 2025-01-25T15:21:40.413Z
Learning: In Atmos, when a directory is specified for configuration loading (e.g., in the `import` section of atmos.yaml), all files within that directory should be treated as Atmos configurations. Do not suggest restricting file extensions in directory-based glob patterns.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1475
File: pkg/auth/providers/github/oidc.go:96-100
Timestamp: 2025-09-10T17:34:52.568Z
Learning: The ATMOS_ environment variable binding guideline applies to Atmos configuration variables, not external service-required environment variables like GitHub Actions OIDC variables (GITHUB_ACTIONS, ACTIONS_ID_TOKEN_*) which must use their standard names.
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code
📚 Learning: 2025-12-13T06:10:25.156Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: internal/exec/workflow_utils.go:0-0
Timestamp: 2025-12-13T06:10:25.156Z
Learning: Atmos workflows: In internal/exec/workflow_utils.go ExecuteWorkflow, non-identity steps intentionally use baseWorkflowEnv, which is constructed from the parent environment with PATH modifications for the toolchain. Avoid appending os.Environ() again; prefer documenting this behavior and testing that standard environment variables are preserved.
Applied to files:
cmd/auth_exec.gogo.mod
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-11-08T19:56:18.660Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1697
File: internal/exec/oci_utils.go:0-0
Timestamp: 2025-11-08T19:56:18.660Z
Learning: In the Atmos codebase, when a function receives an `*schema.AtmosConfiguration` parameter, it should read configuration values from `atmosConfig.Settings` fields rather than using direct `os.Getenv()` or `viper.GetString()` calls. The Atmos pattern is: viper.BindEnv in cmd/root.go binds environment variables → Viper unmarshals into atmosConfig.Settings via mapstructure → business logic reads from the Settings struct. This provides centralized config management, respects precedence, and enables testability. Example: `atmosConfig.Settings.AtmosGithubToken` instead of `os.Getenv("ATMOS_GITHUB_TOKEN")` in functions like `getGHCRAuth` in internal/exec/oci_utils.go.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Use `viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")` for environment variables - ATMOS_ prefix required in Go code
Applied to files:
cmd/auth_exec.gogo.modpkg/config/load.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1202
File: pkg/utils/yaml_func_exec.go:104-104
Timestamp: 2025-04-23T15:02:50.246Z
Learning: In the Atmos codebase, direct calls to `os.Getenv` should be avoided. Instead, use `viper.BindEnv` for environment variable access. This provides a consistent approach to configuration management across the codebase.
Applied to files:
cmd/auth_exec.gogo.modpkg/config/load.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2025-09-07T18:07:00.549Z
Learnt from: Benbentwo
Repo: cloudposse/atmos PR: 1452
File: cmd/auth_login.go:43-44
Timestamp: 2025-09-07T18:07:00.549Z
Learning: In the atmos project, the identity flag is defined as a persistent flag on the auth root command (cmd/auth.go), making it available to all auth subcommands without needing to be redefined in each individual subcommand.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
Repo: cloudposse/atmos PR: 844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-12-13T04:37:25.223Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/root.go:0-0
Timestamp: 2025-12-13T04:37:25.223Z
Learning: In Atmos cmd/root.go Execute(), after cfg.InitCliConfig, we must call both toolchainCmd.SetAtmosConfig(&atmosConfig) and toolchain.SetAtmosConfig(&atmosConfig) so the CLI wrapper and the toolchain package receive configuration; missing either can cause nil-pointer panics in toolchain path resolution.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-08-15T14:43:41.030Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1352
File: pkg/store/artifactory_store_test.go:108-113
Timestamp: 2025-08-15T14:43:41.030Z
Learning: In test files for the atmos project, it's acceptable to ignore errors from os.Setenv/Unsetenv operations during test environment setup and teardown, as these are controlled test scenarios.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2025-12-13T04:37:40.435Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: cmd/toolchain/get.go:23-40
Timestamp: 2025-12-13T04:37:40.435Z
Learning: In Go CLI command files using Cobra, constrain the subcommand to accept at most one positional argument (MaximumNArgs(1)) so it supports both listing all items (zero args) and fetching a specific item (one arg). Define and parse flags with a standard parser (e.g., flags.NewStandardParser()) and avoid binding flags to Viper (no viper.BindEnv/BindPFlag). This promotes explicit argument handling and predictable flag behavior across command files.
Applied to files:
cmd/auth_exec.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration.
Applied to files:
cmd/auth_exec.gopkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to {go.mod,go.sum} : Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies
Applied to files:
go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: Go version 1.23.0 was deliberately introduced by the maintainer (aknysh) in January 2025. While this might be a pre-release or development version of Go, it has been approved for use in this project.
Applied to files:
go.mod
📚 Learning: 2025-01-17T00:21:32.987Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:3-3
Timestamp: 2025-01-17T00:21:32.987Z
Learning: The project uses Go version 1.23.0 which has been confirmed by the maintainer to be working in production for months. Do not flag this as an invalid Go version.
Applied to files:
go.mod
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.
Applied to files:
go.mod
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.
Applied to files:
go.mod
📚 Learning: 2025-03-12T21:38:42.699Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1139
File: pkg/config/go-homedir/homedir.go:183-196
Timestamp: 2025-03-12T21:38:42.699Z
Learning: The code in pkg/config/go-homedir is a direct fork of the mitchellh/go-homedir package and was intentionally imported as-is without modifications to maintain consistency with the original source. Security concerns or other improvements may be addressed in future PRs.
Applied to files:
go.mod
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.
Applied to files:
go.modpkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use Viper for managing configuration, environment variables, and flags in CLI commands
Applied to files:
go.modpkg/config/load.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Applied to files:
pkg/config/load.go
📚 Learning: 2025-04-10T20:48:22.687Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1147
File: pkg/config/load.go:0-0
Timestamp: 2025-04-10T20:48:22.687Z
Learning: In the `bindEnv` function in `pkg/config/load.go`, panic is used deliberately instead of returning errors because errors from `BindEnv` would only occur due to developer mistakes. Using panic helps with early detection of these developer errors during initialization.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-12-13T03:21:35.786Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1813
File: cmd/terraform/shell.go:28-73
Timestamp: 2025-12-13T03:21:35.786Z
Learning: In Atmos, when calling cfg.InitCliConfig, you must first populate the schema.ConfigAndStacksInfo struct with global flag values using flags.ParseGlobalFlags(cmd, v) rather than passing an empty struct. The LoadConfig function (pkg/config/load.go) reads config selection fields (AtmosConfigFilesFromArg, AtmosConfigDirsFromArg, BasePath, ProfilesFromArg) directly from the ConfigAndStacksInfo struct, NOT from Viper. Passing an empty struct causes config selection flags (--base-path, --config, --config-path, --profile) to be silently ignored. Correct pattern: parse flags → populate struct → call InitCliConfig. See cmd/terraform/plan_diff.go for reference implementation.
Applied to files:
pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/{pkg,internal,cmd}/**/*.go : Add `defer perf.Track(atmosConfig, "pkg.FuncName")()` plus blank line to all public functions, using `nil` if no atmosConfig param - exceptions: trivial getters/setters, command constructors, simple factories, functions delegating to tracked functions
Applied to files:
pkg/config/load.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1466
File: toolchain/list.go:39-42
Timestamp: 2025-09-13T18:06:07.674Z
Learning: In the cloudposse/atmos repository, for UI messages in the toolchain package, use utils.PrintfMessageToTUI instead of log.Error or fmt.Fprintln(os.Stderr, ...). Import pkg/utils with alias "u" to follow the established pattern.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-05-30T03:21:37.197Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1274
File: go.mod:63-63
Timestamp: 2025-05-30T03:21:37.197Z
Learning: The redis dependency (github.com/redis/go-redis/v9) in the atmos project is only used in tests, not in production code.
Applied to files:
pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (`cfg`, `log`, `u`, `errUtils`)
Applied to files:
pkg/config/load.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: New config templates support Go templating with `FuncMap()` from `internal/exec/template_funcs.go`
Applied to files:
pkg/config/load.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 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/config/load.go
📚 Learning: 2025-09-23T04:43:31.857Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1430
File: pkg/config/config.go:98-107
Timestamp: 2025-09-23T04:43:31.857Z
Learning: In the Atmos codebase, NO_PAGER environment variable handling is intentionally kept as direct os.Getenv() access in pkg/config/config.go rather than using Viper binding, because adding no_pager to the config file would be confusing for users. This is an acknowledged exception to the normal Viper binding pattern for environment variables.
Applied to files:
pkg/config/load.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/terraform_cli_args_utils.go:64-73
Timestamp: 2025-09-29T15:47:10.908Z
Learning: In the Atmos codebase, viper.BindEnv is required for CLI commands in the cmd/ package, but internal utilities can use os.Getenv directly when parsing environment variables for business logic purposes. The requirement to use viper is specific to the CLI interface layer, not all environment variable access throughout the codebase.
Applied to files:
pkg/config/load.go
🧬 Code graph analysis (2)
cmd/auth_exec.go (1)
pkg/env/global.go (1)
MergeGlobalEnv(16-35)
pkg/config/load.go (3)
pkg/schema/schema.go (1)
AtmosConfiguration(75-121)pkg/env/file.go (1)
LoadEnvFiles(19-27)pkg/ui/formatter.go (1)
Success(204-211)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Summary
🔇 Additional comments (5)
go.mod (1)
74-74: Solid dependency addition. Movingjoho/godotenvto direct dependency is the right call since it's now a first-class feature. Version v1.5.1 is the latest stable release, so you're good to go.cmd/auth_exec.go (1)
113-113: LGTM! Proper use of case-sensitive env access.The switch to
GetCaseSensitiveEnvVars()correctly aligns with the new case-sensitive environment handling introduced in this PR.pkg/config/load.go (3)
22-22: LGTM! Imports properly organized.The new imports for
envanduipackages are correctly placed and follow the three-group organization pattern.Also applies to: 26-26
281-284: Correct placement for early .env loading.The placement before profile detection is essential and well-documented. This enables ATMOS_PROFILE and other ATMOS_* variables from .env files to influence Atmos behavior during initialization.
1328-1331: Good catch on dual-form case preservation.Adding both
env(flat form) andenv.vars(structured form) ensures environment variable names maintain correct casing regardless of which configuration format is used.
|
Warning Release Documentation RequiredThis PR is labeled
|
1 similar comment
|
Warning Release Documentation RequiredThis PR is labeled
|
|
Warning Release Documentation RequiredThis PR is labeled
|
|
Warning Release Documentation RequiredThis PR is labeled
|
|
Warning This PR exceeds the recommended limit of 1,000 lines.Large PRs are difficult to review and may be rejected due to their size. Please verify that this PR does not address multiple issues. |
- Add blog post announcing .env file support feature - Add milestone to DX initiative in roadmap - Link to PR #1930 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@pkg/config/load.go`:
- Around line 1286-1307: The early .env loader (loadEnvFilesEarly) currently
calls env.LoadEnvFiles(basePath, paths) which ignores the env.files.parents
flag; change it to call env.LoadFromDirectory(basePath, paths,
v.GetBool("env.files.parents"), v.GetString("repo_root")) so parent traversal is
honored during early loading and profile detection, ensuring it uses the same
repoRoot and parents flag as the main loader; preserve returned envVars,
loadedFiles and existing error handling (log.Debug and behavior) after the
switch.
- Around line 1251-1278: The code currently treats presence of "vars" or "files"
keys (via viper-lowercased envMap["vars"/"files"]) as indicating structured form
even when those keys are flat string values; update the detection logic to
verify the actual types before assuming structured form: check envMap["vars"] is
a map[string]any (or can be decoded by GetStringMapString) and envMap["files"]
is a map[string]any or a slice/struct expected by atmosConfig.Env.Files, only
then set hasVars/hasFiles true and use
GetStringMapString("env.vars")/GetBool/GetStringSlice; otherwise fall back to
the flat form and populate atmosConfig.Env.Vars from
v.GetStringMapString("env"). Ensure you reference and update the existing
symbols envRaw, envMap, envMap["vars"], envMap["files"], hasVars/hasFiles,
GetStringMapString("env.vars"), and atmosConfig.Env.Files handling so legacy
string values are not lost.
🧹 Nitpick comments (3)
pkg/schema/schema.go (1)
264-273: Fallback logic may be redundant.Both
GetCaseSensitiveMap("env.vars")andGetCaseSensitiveMap("env")returna.Env.Varsper lines 252-253. The fallback on line 272 would only differ if the casemap has different keys registered for each path. If that's the intent, it works. Otherwise, the fallback is effectively a no-op whenvarsis empty.Consider adding a brief comment explaining when the fallback would return different results, or simplify if both paths always return identical data.
website/blog/2025-01-15-dotenv-file-support.mdx (1)
37-56: Consider a brief note about.envsecrets and gitignore.
A short reminder to avoid committing.env/.env.localwould help readers.✏️ Optional doc tweak
Environment variables are now available to all Atmos commands including Terraform, Helmfile, workflows, and custom commands. + +Note: `.env` files often contain secrets. Add `.env.local` to `.gitignore` and avoid committing sensitive values.website/docs/cli/configuration/env.mdx (1)
126-209: Optional: add a brief note about missing files being skipped.
This matches the “load only when they exist” behavior and prevents confusion.✏️ Optional doc tweak
+ +Missing files are skipped silently; only existing matches are loaded. ```Enable loading in `atmos.yaml`: <File title="atmos.yaml"> ```yaml env: files: enabled: true paths: - .env
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
…support-for-env-files
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
…support-for-env-files # Conflicts: # examples/demo-localstack/stacks/mixins/localstack.yaml
…support-for-env-files
…support-for-env-files
…files per project Promote ATMOS_-prefixed keys from the base config `env:` section (e.g. via `env: !include .env`) into Atmos' own process environment during config load, before profile resolution. This lets a project pin ATMOS_PROFILE (and other ATMOS_* settings) in a committed `.env`. Exported env vars always win, and only ATMOS_*-prefixed keys are promoted; other keys still flow only to subprocesses. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TestLoadConfig_PinsAtmosProfileFromEnvSection asserted AWS_REGION was unset to prove non-ATMOS_ keys are not promoted, but CI runners (AWS) have AWS_REGION set in the ambient environment, so the assertion failed. Assert on a uniquely-named non-ATMOS_ key that cannot exist in the host environment instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Tip Atmos Pro
No affected stacks workflow was detected for this pull request. |
|
Warning Release Documentation RequiredThis PR is labeled
|
|
These changes were released in v1.222.0-rc.0. |
These nine carried `authors: [atmos]`, the generic team byline the changelog skill says to avoid. Attribution follows the pull request that implemented the feature, not the commit that added or later renamed the post file. That distinction mattered. Five of the nine appear in `git log --diff-filter=A` as added by #2753, a chronology-correction pass that renamed post files to match their publication dates. Following renames instead points at the real work: list-components-fix #1949 osterman chdir-config-isolation #1941 osterman introducing-atmos-lsp #2030 aknysh introducing-atmos-ai #2030 aknysh ci-comments-env-var #2300 osterman list-instances-matrix #2322 johncblandii terraform-all-dependency-order-wired-up #2486 thejrose1984 dotenv-include-support #1930 osterman toolchain-proxies #1687 osterman Each byline is the GitHub pull request author rather than the git commit author, because squash merges attribute the commit to whoever merged it. #2300 needed a judgment call. It was authored by `app/copilot-swe-agent`, a bot. The byline goes to osterman, who is the assignee and the human who drove the change. A bot is not a contributor byline, and the person who merged it (aknysh) did not do the work either. johncblandii and thejrose1984 were missing from `authors.yml` and are added here, which the changelog skill requires in the same change that references them. thejrose1984 publishes no display name on GitHub, so the login stands in rather than inventing one. Verified: all 263 posts now resolve to a real `authors.yml` entry, no post carries the generic byline, and the site builds with no author warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
Adds explicit dotenv file support to the existing
!includeYAML function. Dotenv files now resolve to maps, so they can be used directly in CLI and stackenvsections and with YAML merge keys.Dotenv files can also be layered with YAML merge sequences. This uses YAML's
<<merge-key syntax, the same YAML mechanism commonly used with anchors and aliases:YAML merge sequence precedence is earlier item wins, and inline keys under
envoverride all merged values.What Changed
.env,.env.*, and exact*.envfilenames as dotenv files when used with!includeenv: !include .envandenv: { <<: !include .env }/ block merge forms in stack config!includeinatmos.yamlenv, including merge sequences for layered dotenv files!include.rawbehavior for raw file contents.envrcandfoo.env.localunsupported/raw; Atmos does not auto-load or execute dotenv filesenv: !include .envsatisfies stack manifest schema rulesenvto document the!includestring formenvand stackenvdocs, including YAML merge-key behavior, include path resolution, and layered files!includesupportTests
cd examples/demo-localstack && ATMOS_IDENTITY=false go run ../.. describe component demo -s dev --format json --logs-level Off | jq '.providers.aws'cd examples/demo-localstack && ATMOS_IDENTITY=false go run ../.. validate stacks --logs-level Offgo test ./pkg/config ./pkg/validator ./pkg/filetypego test ./internal/exec -run 'TestGenerateProviderOverrides|TestGenerateProviderOverridesForAliases|TestProcessStackConfigProviderSection'go test ./pkg/config ./pkg/validator -coverprofile=.context/dotenv-include-coverage.outgo test ./pkg/utils -run 'TestInclude(Dotenv|ExtensionBased|RawFunction|WithNoExtension)'node -e "import('./website/src/data/roadmap.js').then(() => console.log('roadmap import ok'))"git diff --checkenv: !include .envvalidates againsttests/fixtures/schemas/atmos/atmos-manifest/1.0/atmos-manifest.jsonCloses DEV-2990