Repository navigation
feat: command-path aliases with default-flag injection - #2572
Erik Osterman (Cloud Posse) (osterman) wants to merge 20 commits into
Conversation
Add default arguments configurable per command in atmos.yaml via a path-derived `args:` list (top-level `args:` for global, `<command>.args` per command, most-specific wins). Default args are raw pass-through tokens spliced onto the command line before parsing — uniform across all commands, supporting any flag, repeated flag, or positional, with no per-command wiring. Precedence: CLI > ENV > command args > global args > built-in. A default is skipped when its flag is already on the CLI or its env var is set. Overridable by Atmos profiles, which merge into the same config. Implemented as a single argv preprocessor (flags.InjectDefaultArgs) run before Cobra parses, plus a captured merged-settings map (AtmosConfiguration.RawConfig) populated during config load. Includes PRD, changelog blog post, roadmap milestone, and docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Tip Atmos Pro
No affected stacks workflow was detected for this pull request. |
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughStores merged atmos.yaml as RawConfig, injects config-specified default CLI tokens into argv before Cobra parses, filters them when overridden by CLI or env, splices remaining defaults after the command path, and adds tests, PRD/docs/blog, and a roadmap entry. ChangesPer-command default args from atmos.yaml
Sequence DiagramsequenceDiagram
participant CLI as User CLI
participant Injector as InjectDefaultArgs
participant Cobra as Cobra (rootCmd)
participant Raw as RawConfig (merged settings)
participant Filter as filterDefaultArgs
participant Root as RootCmd
CLI->>Injector: args, rootCmd, rawConfig
Injector->>Cobra: rootCmd.Find(command path)
Injector->>Raw: collectDefaultArgs(command path)
Raw-->>Injector: default tokens
Injector->>Filter: filterDefaultArgs(defaults, remainingArgs)
Filter-->>Injector: filtered defaults
Injector->>Root: spliceDefaultArgs -> SetArgs(processedArgs)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/flags/arg_defaults_test.go`:
- Around line 72-119: Add a regression test in TestInjectDefaultArgs to cover
split-token defaults: create a raw config where describe.args is
[]any{"--identity","default"} and add a t.Run that calls InjectDefaultArgs(root,
raw, []string{"describe","component","vpc","--identity","me"}) and asserts the
result equals the input (both tokens removed/not injected). Also add a subcase
that sets the corresponding env var (e.g., t.Setenv("ATMOS_IDENTITY","me")) and
asserts InjectDefaultArgs(root, raw, []string{"describe","component","vpc"})
returns the input unchanged; this ensures InjectDefaultArgs correctly detects
and suppresses split-token defaults for both CLI and env wins.
In `@pkg/flags/arg_defaults.go`:
- Around line 119-127: filterDefaultArgs currently iterates defaults and, when
suppressing a flag (using flagNameFromArg/flagPresentInArgs/flagEnvIsSet), only
skips the flag token which leaves any following separate value token (e.g.
"--identity", "default") orphaned; change the loop in filterDefaultArgs to
iterate by index so when you decide to continue for a suppressed flag you also
check the next token and, if the current default is a standalone flag token (no
"=" form) and the next token exists and does not start with "-", increment the
index to skip that value token as well; use flagNameFromArg, flagPresentInArgs
and flagEnvIsSet to detect suppression and guard skipping the next token only
when appropriate.
In `@website/src/data/roadmap.js`:
- Line 230: The roadmap milestone object with label 'Per-command default args in
atmos.yaml' in website/src/data/roadmap.js is missing the required pr field; add
a pr: <number> property to that milestone object (the same object that has
status: 'shipped', quarter: 'q2-2026', changelog: 'per-command-default-args',
docs: '/cli/configuration/default-args', description: ..., benefits: ...) and
ensure you include the trailing comma/formatting consistent with other entries.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9ef715e3-6d8e-457a-b130-6ffec48898d3
📒 Files selected for processing (10)
cmd/root.godocs/prd/per-command-default-args.mdpkg/config/arg_defaults_test.gopkg/config/load.gopkg/flags/arg_defaults.gopkg/flags/arg_defaults_test.gopkg/schema/schema.gowebsite/blog/2026-06-05-per-command-default-args.mdxwebsite/docs/cli/configuration/default-args.mdxwebsite/src/data/roadmap.js
Codecov Report❌ Patch coverage is
❌ Your patch check has failed because the patch coverage (80.12%) is below the target coverage (85.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #2572 +/- ##
==========================================
+ Coverage 81.32% 81.34% +0.02%
==========================================
Files 1641 1642 +1
Lines 154729 154883 +154
==========================================
+ Hits 125830 125987 +157
+ Misses 21974 21962 -12
- Partials 6925 6934 +9
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…fault args filterDefaultArgs suppressed a default when the same flag was already set on the CLI or via env, but dropped only the flag token. For split-token defaults like `args: ["--identity", "default"]`, the bare "default" token was left behind and spliced onto the command line as a positional argument, silently corrupting the command. filterDefaultArgs now also drops the flag's paired space-separated value token. The pairing mirrors the existing NoOptDefVal preprocessor (a bare flag whose next token is a non-flag value), so it correctly handles NoOptDefVal flags such as `--identity` — unlike a NoOptDefVal-based check, which would misclassify them. Also adds regression tests for split-token suppression (CLI/ENV/not-suppressed), unit tests for the new helpers, and `pr: 2572` on the roadmap milestone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ide and positionals Remove the "Why Args Instead of a Typed Map" section from the blog post — it is internal design rationale (already covered in the PRD), not end-user content. Clarify two points that were unclear in the configuration reference: - Overriding a broader default at a deeper command path (most-specific wins via last-value-wins), with a concrete global-vs-subcommand example. - Flags vs. positional arguments: both are passed through as raw tokens, but positionals are never suppressed and are injected before typed args, so a defaulted positional adds to (rather than replaces) what you type. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The original feature request was about setting a list-valued flag. Add a dedicated "Repeated flags (list values)" section showing how to default a list by repeating the flag (e.g. `--skip`, Terraform `-var`), with the equivalent command line. Document the replace-not-extend behavior: passing an Atmos flag once on the command line suppresses all of its configured defaults. Tool-native flags (single-dash, e.g. `-var`) are not Atmos-suppressed — they pass straight through and the tool's own parsing decides how values combine. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Show defaulting list-command flags: `list.args: [--format=json]` applies across the whole `list` subtree (list stacks, list components, list values, …), with a subcommand-specific `list.components.args: [--max-columns=5]`, overridable on the command line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lags Verified the example end-to-end against examples/demo-stacks: `list.args: [--format=json]` injects across the whole list subtree (list stacks/components/ values), and CLI flags override it. The prior draft used `--max-columns` under `list.components`, which is invalid — that flag belongs to `list instances`/`list values`, and an injected flag the target subcommand does not define errors out. Switched the subcommand example to `--type=all` (a real `list components` flag) and added a note that injected flags must be valid for the targeted subcommand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Note Release Documentation Complete ✅
Thank you! |
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
Resource Changes Found for
|
…efault-args PRD The original per-command-default-args.md PRD was deleted wholesale when the implementation pivoted from a standalone args: config section to folding default-flag injection into the existing aliases: mechanism, leaving the concluded design undocumented. Documents the alias_expander.go mechanics and lists the abandoned args:-based approach as an alternative considered. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
…-defaults # Conflicts: # website/src/data/roadmap.js
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
…-defaults # Conflicts: # website/src/data/roadmap.js
|
💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏 |
what
atmos.yamlnow support multi-word command-path keys (e.g."terraform apply","describe component") in addition to single-word shortcuts, so an alias cantarget a subcommand, not just a top-level command.
terraform: terraform --identity=falserewritesatmos terraform ...toatmos terraform --identity=false ...before Cobra parses, so any commandcan get default flags without per-command wiring.
ATMOS_*env var) already sets thatflag, so precedence is CLI > ENV > alias-injected default > built-in.
cmd/internal/alias_expander.go:ExpandCommandAliases/AliasExpander.Expand) with longest-prefix matching, cycle detection, and amax expansion depth; no changes to flag parsing itself.
why
YAML-function processing by default, per command, or to vary it per environment.
args:/<command-path>.args:config section(
flags.InjectDefaultArgs), but that introduced a second config surface doing almost the same jobas
aliases:. Folding default-flag injection into the existing alias mechanism (same-namecommand-path aliases) gives one mental model for shortcuts and defaults, instead of two.
references
docs/prd/command-path-aliases.md/cli/configuration/aliasescommand-path-aliaseswebsite/src/data/roadmap.js(pr 2572, changelogcommand-path-aliases)Summary by CodeRabbit
New Features
Documentation
Tests