-
-
Notifications
You must be signed in to change notification settings - Fork 135
feat: implement atmos version list and show commands with enhanced UI #1658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Refactor cmd/version.go → cmd/version/ package - Implement VersionCommandProvider for command registry - Add SetAtmosConfig() pattern to pass config from root - Add comprehensive unit tests This is Phase 0 of implementing version list/show/search. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements Phase 1 of the version list command feature,
adding comprehensive GitHub API integration for fetching releases.
Changes:
- Extended pkg/utils/github_utils.go with new functions:
- GetGitHubRepoReleases(): Fetch releases with pagination, prerelease
filtering, and date filtering
- GetGitHubReleaseByTag(): Fetch specific release by tag name
- GetGitHubLatestRelease(): Fetch latest stable release
- handleGitHubAPIError(): Convert API errors to descriptive messages
with rate limit information
- Helper functions: fetchAllReleases(), filterPrereleases(),
filterByDate(), applyPagination()
- Added GitHubReleasesOptions struct for flexible release fetching
- Added constants for GitHub API limits and logging field names
- Updated newGitHubClient() to support ATMOS_GITHUB_TOKEN (with
precedence over GITHUB_TOKEN)
- Added environment variable binding in cmd/root.go for
ATMOS_GITHUB_TOKEN and GITHUB_TOKEN
- Added ErrGitHubRateLimitExceeded error constant
- Handles GitHub API 1000-result limit gracefully
- Refactored for lower cognitive complexity per linting requirements
- Added comprehensive unit tests with precondition checks
- All tests pass with proper rate limit handling
Test coverage:
- TestGetGitHubRepoReleases: Tests pagination, filtering, offset
- TestGetGitHubReleaseByTag: Tests specific release fetching
- TestGetGitHubLatestRelease: Tests latest release fetching
- TestNewGitHubClientWithAtmosToken: Tests token precedence
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements the core functionality for version management
commands, allowing users to list and view Atmos releases from GitHub.
Commands Added:
- atmos version list: Browse releases with pagination and filtering
- Flags: --limit (1-100, default 10), --offset (default 0),
--since (YYYY-MM-DD), --include-prereleases, --format (text|json|yaml)
- Default output: simple text list with tag, date, and name
- Supports JSON and YAML output for scripting
- atmos version show <version>: View detailed release information
- Accepts version tag (e.g., v1.95.0) or "latest" keyword
- Shows release notes, assets, and download links
- Supports same output formats as list
Implementation:
- cmd/version/list.go: CLI command with flags and help
- cmd/version/show.go: CLI command for release details
- internal/exec/version_list.go: Business logic for listing releases
- internal/exec/version_show.go: Business logic for showing release details
- Output formatters for text, JSON, and YAML
- Comprehensive unit tests for command structure
- Static error constants in errors/errors.go
- Magic number constants for limits and byte conversions
Features:
- Pagination with limit and offset
- Date filtering with ISO 8601 format (YYYY-MM-DD)
- Prerelease filtering (excluded by default)
- Multiple output formats for automation
- "latest" keyword support in show command
- Clear error messages for invalid inputs
- Proper error wrapping with static errors
Testing:
- Manual end-to-end testing completed
- Unit tests for command flags and properties
- All tests passing
Examples:
atmos version list --limit 5
atmos version list --since 2025-01-01 --format json
atmos version show latest
atmos version show v1.95.0 --format yaml
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When a release title matches the version tag (e.g., "v1.194.1"), extract a more descriptive title from the release notes instead of showing the redundant version number. Changes: - Added extractFirstHeading() to extract meaningful titles from markdown - Looks for <summary> tags first (common in GitHub release notes) - Falls back to first H1/H2 heading if no summary found - Strips author/PR references from summary tags - getReleaseTitle() now provides smart fallback logic Example output before: v1.194.1 - 2025-10-13 - v1.194.1 Example output after: v1.194.1 - 2025-10-13 - Fix and Improve Performance Heatmap This makes the release list much more informative and easier to scan. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add borderless table with header separator for version list - Implement markdown rendering for release titles with ANSI colors - Add terminal width detection with minimum width validation - Style assets with muted file sizes and underlined links - Add spinner during GitHub API calls for better UX - Implement platform-specific asset filtering - Add debug logging for terminal width detection - Refactor version commands to self-contained cmd/version package - Create GitHubClient interface for testability - Update environment variable binding to use ATMOS_GITHUB_TOKEN fallback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
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. |
|
Warning Rate limit exceeded@aknysh has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 43 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughReplaces the single-file version command with a cmd/version package (provider, list, show, formatters, GitHub client), adds pkg/github releases and token-aware client, binds Changes
Sequence Diagram(s)sequenceDiagram
participant Root as cmd/root.go
participant CLI as CLI
participant Provider as cmd/version (provider)
participant Cmd as list/show Cmd
participant Spinner as Spinner/TUI
participant GH as pkg/github (GitHubClient)
participant GitHubAPI as GitHub API
participant Formatter as cmd/version/formatters.go
Root->>Provider: SetAtmosConfig(atmosConfig)
CLI->>Provider: invoke "version list" / "version show"
Provider->>Cmd: run command
alt TTY detected
Cmd->>Spinner: start spinner (async)
Spinner-->>GH: fetch releases/release (background)
else non-TTY
Cmd->>GH: fetch releases/release (sync)
end
GH->>GitHubAPI: API calls (paged)
GitHubAPI-->>GH: release data
GH-->>Cmd: releases/release
Cmd->>Formatter: formatReleaseList/Detail(releases)
Formatter-->>CLI: output (text/json/yaml)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
go.mod (1)
3-3: Use a valid Go directive (major.minor only).
go 1.24.8is invalid ingo.mod(patch versions aren’t allowed). Set togo 1.24(or the repo’s supported version).Apply:
-go 1.24.8 +go 1.24pkg/utils/github_utils.go (1)
45-62: Wrap errors; keep message context.Return contextual errors (and consider a NotFound sentinel if applicable) instead of bare GitHub errors. As per coding guidelines.
- release, _, err := client.Repositories.GetLatestRelease(ctx, owner, repo) - if err != nil { - return "", err - } + release, _, err := client.Repositories.GetLatestRelease(ctx, owner, repo) + if err != nil { + return "", fmt.Errorf("get latest release for %s/%s: %w", owner, repo, err) + }
🧹 Nitpick comments (14)
docs/prd/command-registry-pattern.md (1)
1280-1494: Fix fenced code block languages and minor terminology.Add languages to all triple‑backtick fences (e.g.,
text,bash, orgo) and standardize on “GitHub” capitalization and “prerelease” spelling throughout this section and the doc. This resolves MD040 and consistency nits.docs/prd/version-list-command.md (2)
151-191: Architecture inconsistency vs registry pattern doc.Here the diagram places version business logic in
internal/exec/*, while the registry-pattern doc proposes moving command-specific logic intocmd/version/*. To match our guidelines, keep Cobra/UI incmd/version/and implement reusable logic inpkg/version(orinternal/execif cross‑command). Please update the diagram and section text accordingly.As per coding guidelines.
1-612: Polish: code-fence languages, terminology, and punctuation.
- Add language to all code fences (MD040).
- Use “GitHub” capitalization; unify on “prerelease”.
- Prefer RFC3339 timestamps consistently in JSON examples.
- End list items and standalone sentences with punctuation.
cmd/version/formatters.go (4)
431-446: Standardize timestamp format in JSON/YAML detail outputs.List JSON uses RFC3339, but detail JSON/YAML use a custom format. Align on RFC3339 for machine readability.
Apply:
- Published: release.GetPublishedAt().Format("2006-01-02 15:04:05 MST"), + Published: release.GetPublishedAt().Format(time.RFC3339),Also applies to: 478-492
45-60: Make summary/heading extraction more robust.Support multiline and case-insensitive
<summary>tags, and prefer precompiled regex.- summaryRe := regexp.MustCompile(`<summary>(.+?)</summary>`) + summaryRe := regexp.MustCompile(`(?is)<summary>(.+?)</summary>`)
205-243: Consider measuring padding dynamically.
tableBorderPaddingis a fixed 8; style/padding changes can break width. Prefer computing from the table’s column styles or reduce optimistic width by a safer margin (e.g., 4) and let lipgloss wrap.
246-350: Optional: add perf tracking to critical paths.Add
defer perf.Track(nil, "version.format*")()at the start of formatter functions to aid profiling (blank line after call).As per coding guidelines.
Also applies to: 352-492
cmd/version/show_test.go (1)
9-23: Expand tests to cover behavior, not just flags.Add table-driven tests for:
- Arg parsing (
show <tag>vslatest, missing arg error).- JSON/YAML outputs shape (golden or schema validation).
- Error surfacing when release not found.
- Ensure TUI/text path writes to stderr, not stdout.
I can scaffold tests with a fake GitHub client and capture writers to assert destinations.
cmd/version/show.go (2)
131-155: Consider context-aware client calls.Plumb cmd.Context() through GitHubClient methods to enable cancellation/timeouts during API calls. This will make Ctrl+C responsive and avoids hanging on slow networks.
3-15: Imports: ensure grouping and sort within groups.Minor: keep stdlib, third-party, Atmos groups with alpha sort (bubbletea vs bubbles). No behavior change.
pkg/utils/github_utils.go (3)
32-39: Support GitHub Enterprise/base URL.Allow overriding API base via config/env (e.g., ATMOS_GITHUB_API_URL), using go-github’s NewEnterpriseClient. This aids enterprise users.
- return github.NewClient(tc) + base := viper.GetString("ATMOS_GITHUB_API_URL") + if base != "" { + // base should be like https://github.example.com/api/v3 + ent, err := github.NewEnterpriseClient(base, base, tc) + if err == nil { + return ent + } + // fall through on error + } + return github.NewClient(tc)Add BindEnv for ATMOS_GITHUB_API_URL in the config layer. As per coding guidelines.
101-124: Use timeouts on GitHub API calls.Guard API calls with context.WithTimeout to avoid indefinite waits. Keep timeout configurable (e.g., ATMOS_GITHUB_API_TIMEOUT).
- ctx := context.Background() + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel()Apply to RateLimit.Get, ListReleases, GetReleaseByTag, GetLatestRelease. As per coding guidelines.
Also applies to: 253-261, 239-245, 157-165
64-74: Typos in comments (“Github” → “GitHub”).Nit: fix brand capitalization in comment constants.
cmd/version/github.go (1)
11-24: Consider adding context to the interface.Add context.Context to GitHubClient methods to enable cancellation/timeouts from cmd.RunE. This future-proofs the API.
📜 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 (17)
cmd/root.go(4 hunks)cmd/version.go(0 hunks)cmd/version/formatters.go(1 hunks)cmd/version/github.go(1 hunks)cmd/version/list.go(1 hunks)cmd/version/list_test.go(1 hunks)cmd/version/show.go(1 hunks)cmd/version/show_test.go(1 hunks)cmd/version/version.go(1 hunks)cmd/version/version_test.go(1 hunks)docs/prd/command-registry-pattern.md(1 hunks)docs/prd/version-list-command.md(1 hunks)errors/errors.go(1 hunks)go.mod(1 hunks)pkg/utils/github_utils.go(4 hunks)pkg/utils/github_utils_test.go(1 hunks)website/blog/2025-10-17-version-list-command.md(1 hunks)
💤 Files with no reviewable changes (1)
- cmd/version.go
🧰 Additional context used
📓 Path-based instructions (13)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All Go comments must end with periods; applies to single-line, multi-line, inline, and documentation comments (golangci-lint godot).
Group imports into three sections (stdlib, 3rd-party, Atmos), separated by blank lines; sort alphabetically within each group; preserve existing aliases.
Configuration loading must use Viper with precedence CLI → ENV → files → defaults; bind config name atmos and add path, AutomaticEnv, and ATMOS prefix.
All errors must be wrapped using static errors (defined in errors/errors.go); use errors.Join for multiple errors; fmt.Errorf with %w for context; use errors.Is for checks; never compare error strings.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout; prefer utils.PrintfMessageToTUI for UI messages.
All new configurations must support Go templating using existing utilities and available template functions.
Prefer SDKs over external binaries for cross-platform support; use filepath/os/runtime for portability.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without user data.
80% minimum coverage on new/changed lines and include unit tests for new features; add integration tests for CLI using tests/ fixtures.
Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Use structured logging with levels (Fatal>Error>Warn>Debug>Trace); avoid string interpolation and ensure logging does not affect execution.
Prefer re...
Files:
errors/errors.gocmd/version/version.gocmd/version/show_test.gocmd/version/version_test.gocmd/root.gocmd/version/github.gopkg/utils/github_utils.gocmd/version/list.gocmd/version/formatters.gocmd/version/list_test.gopkg/utils/github_utils_test.gocmd/version/show.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track()to all public functions and critical private functions; include a blank line after the call; use package-prefixed names; pass atmosConfig when present, else nil.
Files:
errors/errors.gocmd/version/version.gocmd/root.gocmd/version/github.gopkg/utils/github_utils.gocmd/version/list.gocmd/version/formatters.gocmd/version/show.go
errors/errors.go
📄 CodeRabbit inference engine (CLAUDE.md)
Define all static errors centrally in errors/errors.go as package-level vars.
Files:
errors/errors.go
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use utils.PrintfMarkdown() to render embedded markdown content for CLI command help/examples.
One Cobra command per file in cmd/; keep files focused and small.
Files:
cmd/version/version.gocmd/version/show_test.gocmd/version/version_test.gocmd/root.gocmd/version/github.gocmd/version/list.gocmd/version/formatters.gocmd/version/list_test.gocmd/version/show.go
website/**
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use casesBefore committing documentation/site changes, run npm run build in website/ and fix errors, broken links, and missing images.
Files:
website/blog/2025-10-17-version-list-command.md
website/blog/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
website/blog/*.md: For PRs labeled minor or major, include a blog post in website/blog/YYYY-MM-DD-*.md following the template and include after the introduction.
Tag blog posts appropriately: user-facing (feature/enhancement/bugfix) or contributor (contributors) plus relevant technical tags.
Files:
website/blog/2025-10-17-version-list-command.md
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Use table-driven unit tests for pure functions and focus on behavior; co-locate tests; target >80% coverage for pkg/ and internal/exec/.
Always use t.Skipf() with a clear reason; never use t.Skip() or t.Skipf without a reason.
Files:
cmd/version/show_test.gocmd/version/version_test.gocmd/version/list_test.gopkg/utils/github_utils_test.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Command tests live under cmd/ alongside command implementations.
Files:
cmd/version/show_test.gocmd/version/version_test.gocmd/version/list_test.go
cmd/*/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Add tests for new commands under cmd//_test.go.
Files:
cmd/version/show_test.gocmd/version/version_test.gocmd/version/list_test.go
cmd/root.go
📄 CodeRabbit inference engine (CLAUDE.md)
cmd/root.go: Add a blank import for new commands in cmd/root.go to register via the command registry pattern.
Telemetry for standard Cobra commands is captured via RootCmd.ExecuteC() in cmd/root.go; avoid adding duplicate telemetry for these paths.
Files:
cmd/root.go
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/utils/github_utils.gopkg/utils/github_utils_test.go
pkg/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests for packages live under pkg/ alongside implementation files.
Files:
pkg/utils/github_utils_test.go
go.{mod,sum}
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
go.{mod,sum}: Manage dependencies with Go modules
Keep dependencies up to date
Files:
go.mod
🧠 Learnings (17)
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.
Applied to files:
website/blog/2025-10-17-version-list-command.md
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to cmd/*/*_test.go : Add tests for new commands under cmd/<command>/<command>_test.go.
Applied to files:
cmd/version/show_test.gocmd/version/version_test.gocmd/version/list_test.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to cmd/**/*_test.go : Command tests live under cmd/ alongside command implementations.
Applied to files:
cmd/version/show_test.gocmd/version/version_test.gocmd/version/list_test.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/show_test.gocmd/version/version_test.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to **/*.go : Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Applied to files:
cmd/root.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to **/*.go : Configuration loading must use Viper with precedence CLI → ENV → files → defaults; bind config name atmos and add path, AutomaticEnv, and ATMOS prefix.
Applied to files:
cmd/root.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for managing configuration, environment variables, and flags in the CLI
Applied to files:
cmd/root.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Applied to files:
cmd/root.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
PR: cloudposse/atmos#1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.
Applied to files:
cmd/root.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to internal/exec/**/*.go : Place command business logic in internal/exec/ (separate from cmd/ wiring).
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to pkg/**/*.go : Place business logic in pkg rather than in cmd
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Keep separation of concerns between CLI interface (cmd) and business logic
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Follow single responsibility; separate command interface from business logic
Applied to files:
docs/prd/command-registry-pattern.md
🧬 Code graph analysis (9)
cmd/version/version.go (4)
pkg/schema/schema.go (1)
AtmosConfiguration(27-65)internal/exec/version.go (1)
NewVersionExec(31-45)cmd/root.go (1)
Execute(444-494)cmd/internal/registry.go (1)
Register(41-52)
cmd/version/version_test.go (1)
cmd/version/version.go (1)
VersionCommandProvider(46-46)
cmd/root.go (2)
cmd/version/version.go (1)
SetAtmosConfig(20-22)pkg/logger/log.go (1)
Error(54-56)
cmd/version/github.go (1)
pkg/utils/github_utils.go (4)
GetGitHubRepoReleases(87-137)GitHubReleasesOptions(77-84)GetGitHubReleaseByTag(231-245)GetGitHubLatestRelease(248-262)
pkg/utils/github_utils.go (3)
pkg/logger/log.go (1)
Debug(24-26)pkg/perf/perf.go (1)
Track(121-138)errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
cmd/version/list.go (2)
cmd/version/github.go (3)
GitHubClient(12-16)ReleaseOptions(19-24)RealGitHubClient(27-27)errors/errors.go (2)
ErrInvalidLimit(46-46)ErrUnsupportedOutputFormat(47-47)
cmd/version/formatters.go (4)
internal/tui/templates/templater.go (1)
GetTerminalWidth(245-258)pkg/logger/log.go (3)
Errorf(59-61)Debug(24-26)Printf(159-161)errors/errors.go (1)
ErrTerminalTooNarrow(48-48)pkg/utils/markdown_utils.go (1)
PrintfMarkdown(80-84)
pkg/utils/github_utils_test.go (2)
tests/preconditions.go (1)
RequireGitHubAccess(206-230)pkg/utils/github_utils.go (4)
GitHubReleasesOptions(77-84)GetGitHubRepoReleases(87-137)GetGitHubReleaseByTag(231-245)GetGitHubLatestRelease(248-262)
cmd/version/show.go (2)
cmd/version/github.go (2)
GitHubClient(12-16)RealGitHubClient(27-27)errors/errors.go (1)
ErrUnsupportedOutputFormat(47-47)
🪛 LanguageTool
website/blog/2025-10-17-version-list-command.md
[typographical] ~27-~27: Consider using a typographic opening quote here.
Context: ...h --since (ISO dates or relative like "30d") - 📄 Pagination support - Brow...
(EN_QUOTES)
[typographical] ~27-~27: Consider using a typographic close quote here.
Context: ...-since` (ISO dates or relative like "30d") - 📄 Pagination support - Browse t...
(EN_QUOTES)
[style] ~390-~390: The verb “check out” can sound colloquial in this context. Consider using a more formal alternative.
Context: ... Contribute - Want to add features? Check out our [contribution guide](https://atmos....
(CHECK_OUT_OUR)
[grammar] ~390-~390: Please add a punctuation mark at the end of paragraph.
Context: ...d features? Check out our [contribution guide](https://atmos.tools/community/contribu...
(PUNCTUATION_PARAGRAPH_END)
docs/prd/version-list-command.md
[typographical] ~91-~91: Consider using a typographic opening quote here.
Context: ...nline) - Publication date (relative: "2 days ago") - Status indicators: ...
(EN_QUOTES)
[typographical] ~91-~91: Consider using a typographic close quote here.
Context: ... Publication date (relative: "2 days ago") - Status indicators: - `[Curre...
(EN_QUOTES)
[typographical] ~97-~97: Consider using a typographic opening quote here.
Context: ...ilable` indicator - Pagination info: "Showing 1-10 of 156 releases" 2. **Deta...
(EN_QUOTES)
[typographical] ~97-~97: Consider using a typographic close quote here.
Context: ...tion info: "Showing 1-10 of 156 releases" 2. Detail View (press Enter on rel...
(EN_QUOTES)
[style] ~215-~215: Since ownership is already implied, this phrasing may be redundant.
Context: ...organization** - Each command family in its own package - ✅ Type-safe interfaces - ...
(PRP_OWN)
[uncategorized] ~414-~414: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...ct: tag_name, name, body, published_at, prerelease, draft, assets - Transform to internal ...
(EN_WORD_COHERENCY)
[uncategorized] ~419-~419: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...s excluded (not published releases) - Prereleases: Excluded by default, included with `...
(EN_WORD_COHERENCY)
[uncategorized] ~427-~427: The official name of this software platform is spelled with a capital “H”.
Context: ...%+ coverage) 1. GitHub API Client (pkg/utils/github_utils_test.go) - Mock GitHub API re...
(GITHUB)
[uncategorized] ~433-~433: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ... scenarios - Test filtering (drafts, prereleases) 2. Business Logic (`internal/exec...
(EN_WORD_COHERENCY)
[grammar] ~461-~461: Please add a punctuation mark at the end of paragraph.
Context: ...with real data - Skip if rate limits low 2. End-to-End CLI (`tests/version_...
(PUNCTUATION_PARAGRAPH_END)
[typographical] ~500-~500: Consider using typographic quotation marks here.
Context: ...ls - Add GetGitHubLatestRelease() for "latest" keyword (stable releases only) - Enviro...
(EN_QUOTES)
[uncategorized] ~504-~504: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...ests with mocked GitHub client - Test prerelease filtering (included/excluded) - Test ...
(EN_WORD_COHERENCY)
[uncategorized] ~528-~528: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...es with caching support - Filter drafts/prereleases based on flags - **Date filtering imple...
(EN_WORD_COHERENCY)
[typographical] ~541-~541: Consider using typographic quotation marks here.
Context: ...- Fetch single release details - Handle "latest" keyword special case - Reuse TUI detail...
(EN_QUOTES)
[grammar] ~590-~590: Please add a punctuation mark at the end of paragraph.
Context: ...` - Verify 80%+ coverage on new/changed lines Total Estimated Time: 22-30 hours ...
(PUNCTUATION_PARAGRAPH_END)
[uncategorized] ~600-~600: Do not mix variants of the same word (‘prerelease’ and ‘pre-release’) within a single text.
Context: ...ude-prereleases` flag excludes/includes prereleases - ✅ Release notes render with markdown ...
(EN_WORD_COHERENCY)
[uncategorized] ~601-~601: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ereleases - ✅ Release notes render with markdown formatting - ✅ Artifacts displayed with...
(MARKDOWN_NNP)
🪛 markdownlint-cli2 (0.18.1)
website/blog/2025-10-17-version-list-command.md
19-19: Dollar signs used before commands without showing output
(MD014, commands-show-output)
37-37: Dollar signs used before commands without showing output
(MD014, commands-show-output)
59-59: Dollar signs used before commands without showing output
(MD014, commands-show-output)
146-146: Dollar signs used before commands without showing output
(MD014, commands-show-output)
docs/prd/version-list-command.md
153-153: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
221-221: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
301-301: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
364-364: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
375-375: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
383-383: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
592-592: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
docs/prd/command-registry-pattern.md
1447-1447: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
1457-1457: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (macos-latest, macos)
- GitHub Check: Run pre-commit hooks
- GitHub Check: website-deploy-preview
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: Summary
🔇 Additional comments (20)
cmd/version/version_test.go (3)
9-15: LGTM!Provider interface tests correctly verify the registry pattern wiring.
17-26: LGTM!Flag presence and shorthand verification are appropriate.
28-36: LGTM!Basic property tests validate command configuration.
cmd/version/list_test.go (2)
9-29: LGTM!Flag testing is comprehensive with proper default value verification.
31-37: LGTM!Basic property tests follow established patterns.
cmd/root.go (2)
451-452: LGTM!Configuration injection timing is correct, enabling the version command to access runtime config before execution.
631-635: LGTM!Environment variable binding follows project guidelines with appropriate token precedence and error handling.
Based on coding guidelines.
errors/errors.go (1)
45-48: LGTM!New error sentinels follow established patterns with clear, actionable messages.
Based on coding guidelines.
cmd/version/list.go (2)
31-68: LGTM!Bubble Tea model implementation correctly handles spinner state and messages.
70-110: LGTM!Spinner logic correctly handles TTY detection and background fetching. Type assertion at line 100 is safe in this controlled context.
cmd/version/version.go (2)
18-22: LGTM!Configuration setter provides clean injection point for runtime config.
45-61: LGTM!Provider implementation correctly exposes command metadata for the registry pattern.
pkg/utils/github_utils_test.go (4)
296-393: LGTM!Comprehensive test coverage for GetGitHubRepoReleases with proper rate limit awareness and pagination validation.
395-419: LGTM!Tag lookup tests cover both success and error cases appropriately.
421-435: LGTM!Latest release test correctly validates stable release properties.
437-450: Token precedence test is minimal but acceptable.The test verifies client creation doesn't panic with both tokens set. Testing actual precedence would require viper mocking. Consider adding integration tests if precedence logic becomes critical.
website/blog/2025-10-17-version-list-command.md (1)
1-394: LGTM!Blog post comprehensively documents the new version commands with clear examples and usage guidance. Static analysis warnings (dollar signs in code blocks, typographical quotes) align with established project conventions.
Based on learnings.
pkg/utils/github_utils.go (1)
214-228: applyPagination logic is correct.Offsets and bounds are handled cleanly. Nice.
cmd/version/github.go (2)
51-80: Mock looks good.Simple, predictable behavior; useful for tests.
29-49: Add perf.Track to public methods.Required on public funcs; helps profiling hot paths even though utils already tracks. As per coding guidelines.
func (c *RealGitHubClient) GetReleases(owner, repo string, opts ReleaseOptions) ([]*github.RepositoryRelease, error) { + defer perf.Track(nil, "version.RealGitHubClient.GetReleases")() return utils.GetGitHubRepoReleases(utils.GitHubReleasesOptions{ Owner: owner, Repo: repo, Limit: opts.Limit, Offset: opts.Offset, IncludePrereleases: opts.IncludePrereleases, Since: opts.Since, }) } func (c *RealGitHubClient) GetRelease(owner, repo, tag string) (*github.RepositoryRelease, error) { + defer perf.Track(nil, "version.RealGitHubClient.GetRelease")() return utils.GetGitHubReleaseByTag(owner, repo, tag) } func (c *RealGitHubClient) GetLatestRelease(owner, repo string) (*github.RepositoryRelease, error) { + defer perf.Track(nil, "version.RealGitHubClient.GetLatestRelease")() return utils.GetGitHubLatestRelease(owner, repo) }Add import:
import ( "time" "github.com/google/go-github/v59/github" "github.com/cloudposse/atmos/pkg/utils" + "github.com/cloudposse/atmos/pkg/perf" )⛔ Skipped due to learnings
Learnt from: CR PR: cloudposse/atmos#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-16T15:18:00.319Z Learning: Applies to **/!(*_test).go : Add `defer perf.Track()` to all public functions and critical private functions; include a blank line after the call; use package-prefixed names; pass atmosConfig when present, else nil.Learnt from: osterman PR: cloudposse/atmos#1599 File: pkg/ui/markdown/renderer.go:247-259 Timestamp: 2025-10-11T19:06:16.131Z Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1658 +/- ##
==========================================
+ Coverage 66.12% 66.41% +0.28%
==========================================
Files 344 350 +6
Lines 38817 39606 +789
==========================================
+ Hits 25669 26303 +634
- Misses 11158 11293 +135
- Partials 1990 2010 +20
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
- Remove references to interactive TUI (implemented simple text tables) - Change token instructions to use 'gh auth token' - Remove CI/CD Integration section - Remove 'What's Coming Next' section - Update features to match actual implementation - Simplify examples and remove unsupported features
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 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 (1)
website/blog/2025-10-17-version-list-command.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
website/**
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use casesBefore committing documentation/site changes, run npm run build in website/ and fix errors, broken links, and missing images.
Files:
website/blog/2025-10-17-version-list-command.md
website/blog/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
website/blog/*.md: For PRs labeled minor or major, include a blog post in website/blog/YYYY-MM-DD-*.md following the template and include after the introduction.
Tag blog posts appropriately: user-facing (feature/enhancement/bugfix) or contributor (contributors) plus relevant technical tags.
Files:
website/blog/2025-10-17-version-list-command.md
🧠 Learnings (1)
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.
Applied to files:
website/blog/2025-10-17-version-list-command.md
🪛 LanguageTool
website/blog/2025-10-17-version-list-command.md
[uncategorized] ~40-~40: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...s: - Full release notes rendered in markdown with colors preserved - **Release metad...
(MARKDOWN_NNP)
[style] ~266-~266: The verb “check out” can sound colloquial in this context. Consider using a more formal alternative.
Context: ... Contribute - Want to add features? Check out our [contribution guide](https://atmos....
(CHECK_OUT_OUR)
[grammar] ~266-~266: Please add a punctuation mark at the end of paragraph.
Context: ...d features? Check out our [contribution guide](https://atmos.tools/community/contribu...
(PUNCTUATION_PARAGRAPH_END)
🪛 markdownlint-cli2 (0.18.1)
website/blog/2025-10-17-version-list-command.md
19-19: Dollar signs used before commands without showing output
(MD014, commands-show-output)
36-36: Dollar signs used before commands without showing output
(MD014, commands-show-output)
120-120: Dollar signs used before commands without showing output
(MD014, commands-show-output)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (macos-latest, macos)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Analyze (go)
- GitHub Check: website-deploy-preview
- GitHub Check: Lint (golangci)
- GitHub Check: Summary
🔇 Additional comments (4)
website/blog/2025-10-17-version-list-command.md (4)
1-10: Blog post structure and formatting look good. Front matter, title, authors, tags, and truncate marker are all in place following the blog template. The introduction clearly summarizes the new functionality.
19-19: Note: MD014 violations in code examples. Lines with$ atmos ...commands without showing output trigger markdownlint's MD014. However, based on learnings from the Atmos repo convention (noted in PR #1466), CLI documentation files incmd/markdown/intentionally follow this format and skip compliance with MD014. If this blog post should align with that project convention, these violations are acceptable. If not, consider reformatting to show example output or removing the$prefix.Please confirm whether blog posts in
website/blog/should follow the same$ atmos commandformat convention as CLI documentation files incmd/markdown/.Also applies to: 36-36, 120-120
243-245: Verify website documentation links.The blog post references
atmos.tools/cli/commands/version/listand other CLI docs. Per the coding guidelines, CLI help text and website documentation must stay in sync. Confirm that corresponding pages are being added/updated to thewebsite/directory in this PR.
240-270: Content quality is solid. The blog post covers features comprehensively with clear examples, use cases for different personas (platform engineers, teams, contributors), and implementation details. The "Try It Now" section encourages immediate adoption, and links to further resources are well-placed.
- Move GitHub API functions from pkg/utils to pkg/github - Create pkg/github/client.go for authentication - Create pkg/github/releases.go for release operations - Move tests to pkg/github/releases_test.go - Update pkg/utils/github_utils.go to provide deprecated wrappers for backward compatibility - All existing callers continue to work through wrapper functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
pkg/github/client.go (1)
30-50: Fix token retrieval to use correct viper keys.The code reads from incorrect viper keys. According to
setEnv()inpkg/config/load.go, environment variables are bound to"settings.atmos_github_token"and"settings.github_token", but this code reads from"ATMOS_GITHUB_TOKEN"and"GITHUB_TOKEN"directly, which bypasses viper's configuration precedence.Apply this diff:
- // Check for ATMOS_GITHUB_TOKEN first, then fall back to GITHUB_TOKEN. - githubToken := viper.GetString("ATMOS_GITHUB_TOKEN") + // Check for ATMOS_GITHUB_TOKEN first, then fall back to GITHUB_TOKEN. + githubToken := viper.GetString("settings.atmos_github_token") if githubToken == "" { - githubToken = viper.GetString("GITHUB_TOKEN") + githubToken = viper.GetString("settings.github_token") }Based on coding guidelines.
🧹 Nitpick comments (1)
docs/prd/version-list-command.md (1)
140-140: Consider adding language specifiers to fenced code blocks.Several code blocks throughout the document are missing language identifiers. Adding them improves syntax highlighting and readability in rendered markdown.
For example:
- Line 140: Add
textorasciifor the ASCII diagram- Line 213: Add language identifier for the package structure
- Line 238: Add
textfor the example output- Lines 314, 326, 331: Add
textfor error message examplesAlso applies to: 213-213, 238-238, 314-314, 326-326, 331-331
📜 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)
docs/prd/version-list-command.md(1 hunks)pkg/github/client.go(1 hunks)pkg/github/releases.go(1 hunks)pkg/github/releases_test.go(11 hunks)pkg/utils/github_utils.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/github/client.gopkg/github/releases.gopkg/utils/github_utils.gopkg/github/releases_test.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All Go comments must end with periods; applies to single-line, multi-line, inline, and documentation comments (golangci-lint godot).
Group imports into three sections (stdlib, 3rd-party, Atmos), separated by blank lines; sort alphabetically within each group; preserve existing aliases.
Configuration loading must use Viper with precedence CLI → ENV → files → defaults; bind config name atmos and add path, AutomaticEnv, and ATMOS prefix.
All errors must be wrapped using static errors (defined in errors/errors.go); use errors.Join for multiple errors; fmt.Errorf with %w for context; use errors.Is for checks; never compare error strings.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout; prefer utils.PrintfMessageToTUI for UI messages.
All new configurations must support Go templating using existing utilities and available template functions.
Prefer SDKs over external binaries for cross-platform support; use filepath/os/runtime for portability.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without user data.
80% minimum coverage on new/changed lines and include unit tests for new features; add integration tests for CLI using tests/ fixtures.
Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Use structured logging with levels (Fatal>Error>Warn>Debug>Trace); avoid string interpolation and ensure logging does not affect execution.
Prefer re...
Files:
pkg/github/client.gopkg/github/releases.gopkg/utils/github_utils.gopkg/github/releases_test.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track()to all public functions and critical private functions; include a blank line after the call; use package-prefixed names; pass atmosConfig when present, else nil.
Files:
pkg/github/client.gopkg/github/releases.gopkg/utils/github_utils.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Use table-driven unit tests for pure functions and focus on behavior; co-locate tests; target >80% coverage for pkg/ and internal/exec/.
Always use t.Skipf() with a clear reason; never use t.Skip() or t.Skipf without a reason.
Files:
pkg/github/releases_test.go
pkg/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests for packages live under pkg/ alongside implementation files.
Files:
pkg/github/releases_test.go
🧠 Learnings (4)
📚 Learning: 2024-12-05T02:48:53.818Z
Learnt from: aknysh
PR: cloudposse/atmos#809
File: cmd/cmd_utils.go:470-477
Timestamp: 2024-12-05T02:48:53.818Z
Learning: The function `GetLatestGitHubRepoRelease` in the Go codebase already uses a context with a timeout, so wrapping it with an additional context is unnecessary.
Applied to files:
pkg/utils/github_utils.gopkg/github/releases_test.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#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:
pkg/utils/github_utils.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to **/*.go : Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Applied to files:
pkg/utils/github_utils.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
PR: cloudposse/atmos#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:
pkg/utils/github_utils.go
🧬 Code graph analysis (4)
pkg/github/client.go (2)
pkg/perf/perf.go (1)
Track(121-138)errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
pkg/github/releases.go (3)
pkg/perf/perf.go (1)
Track(121-138)pkg/logger/log.go (2)
Debug(24-26)Errorf(59-61)errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
pkg/utils/github_utils.go (1)
pkg/github/releases.go (5)
GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleases(49-99)GetReleaseByTag(193-207)GetLatestReleaseInfo(210-224)
pkg/github/releases_test.go (2)
pkg/github/releases.go (5)
GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleases(49-99)GetReleaseByTag(193-207)GetLatestReleaseInfo(210-224)tests/preconditions.go (1)
RequireGitHubAccess(206-230)
🪛 LanguageTool
docs/prd/version-list-command.md
[grammar] ~86-~86: Please add a punctuation mark at the end of paragraph.
Context: ...) - Automatic word wrapping for long titles 2. Detail View (`atmos version sho...
(PUNCTUATION_PARAGRAPH_END)
[style] ~206-~206: Since ownership is already implied, this phrasing may be redundant.
Context: ...organization** - Each command family in its own package - ✅ Type-safe interfaces - ...
(PRP_OWN)
[uncategorized] ~412-~412: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...releases - ✅ Release titles render with markdown formatting and colors - ✅ Current insta...
(MARKDOWN_NNP)
🪛 markdownlint-cli2 (0.18.1)
docs/prd/version-list-command.md
140-140: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
213-213: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
238-238: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
314-314: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
326-326: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
331-331: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Lint (golangci)
- GitHub Check: Analyze (go)
- GitHub Check: Run pre-commit hooks
- GitHub Check: website-deploy-preview
- GitHub Check: Summary
🔇 Additional comments (4)
pkg/github/releases_test.go (1)
296-450: Excellent test coverage for new GitHub release functions.The new tests comprehensively cover pagination, prerelease filtering, tag-based retrieval, and latest release fetching. All tests properly use
t.Skipfwith clear reasons and follow table-driven patterns where appropriate.pkg/utils/github_utils.go (1)
9-35: Clean deprecation approach.The deprecated wrappers maintain backward compatibility while clearly directing users to the new
pkg/githubpackage. The type alias forGitHubReleasesOptionsensures a smooth transition.pkg/github/releases.go (1)
1-224: Well-structured GitHub releases API implementation.This implementation demonstrates solid engineering practices:
- Proactive rate limit checking before making requests
- Proper error wrapping with context throughout
- Defensive pagination logic that handles GitHub's 1000-result limit
- Consistent use of performance tracking and debug logging
- Clean separation of concerns with focused helper functions
pkg/github/client.go (1)
3-14: Fix import grouping.Imports should be grouped into three sections (stdlib, 3rd-party, Atmos) separated by blank lines, as per coding guidelines.
Apply this diff:
import ( "context" "fmt" "time" "github.com/google/go-github/v59/github" "github.com/spf13/viper" "golang.org/x/oauth2" errUtils "github.com/cloudposse/atmos/errors" "github.com/cloudposse/atmos/pkg/perf" )⛔ Skipped due to learnings
Learnt from: CR PR: cloudposse/atmos#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-16T15:18:00.319Z Learning: Applies to **/*.go : Group imports into three sections (stdlib, 3rd-party, Atmos), separated by blank lines; sort alphabetically within each group; preserve existing aliases.Learnt from: aknysh PR: cloudposse/atmos#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.
- Remove ambiguous 'win' pattern from Windows matching to prevent false positives with 'darwin' - Add perf.Track() to all version command RunE handlers for performance telemetry - Fix spinner UI to use stderr instead of stdout for proper data piping - Add type assertion safety checks with comma-ok idiom - Wrap all errors with contextual information using fmt.Errorf - Check for nil models before type assertions - Create static errors in errors/errors.go to fix err113 linting warnings - Refactor fetchReleaseWithSpinner to reduce cognitive complexity - Fix test expectation to match actual Use string ([version] not <version>)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
cmd/version/show.go (1)
75-92: UI stream and TTY detection are correct.Spinner renders to stderr and checks TTY on stderr. Nice.
🧹 Nitpick comments (6)
cmd/version/version.go (1)
21-23: Track the exported setter for completeness.Add perf tracking to SetAtmosConfig; pass the provided config.
func SetAtmosConfig(config *schema.AtmosConfiguration) { + defer perf.Track(config, "cmd.version.SetAtmosConfig")() + atmosConfigPtr = config }As per coding guidelines.
cmd/version/list.go (3)
75-124: Track the spinner fetch helper; use package‑prefixed name.This is a critical private path; add perf.Track and pass atmosConfig.
func fetchReleasesWithSpinner(client GitHubClient, opts ReleaseOptions) ([]*github.RepositoryRelease, error) { + defer perf.Track(atmosConfigPtr, "cmd.version.list.fetchReleasesWithSpinner")() + // Check if we have a TTY for the spinner. //nolint:nestif // Spinner logic requires nested conditions for TTY check.As per coding guidelines.
131-133: Use atmosConfig and standard name in RunE tracking.Minor consistency tweak.
- defer perf.Track(nil, "version.list.RunE")() + defer perf.Track(atmosConfigPtr, "cmd.version.list")()As per coding guidelines.
134-137: Validate offset.Guard against negative offsets; use a shared sentinel.
// Validate limit. if listLimit < 1 || listLimit > listMaxLimit { return fmt.Errorf("%w: got %d", errUtils.ErrInvalidLimit, listLimit) } + + // Validate offset. + if listOffset < 0 { + return fmt.Errorf("%w: offset must be >= 0 (got %d)", errUtils.ErrInvalidFlag, listOffset) + }As per coding guidelines.
cmd/version/show.go (2)
71-75: Align helper tracking name and context.Name should be package‑prefixed and pass atmosConfig.
func fetchReleaseWithSpinner(client GitHubClient, versionArg string) (*github.RepositoryRelease, error) { - defer perf.Track(nil, "version.fetchReleaseWithSpinner")() + defer perf.Track(atmosConfigPtr, "cmd.version.show.fetchReleaseWithSpinner")()As per coding guidelines.
63-69: Defensive: treat empty version as latest here too.Makes the helper robust even if callers forget to set the default.
func fetchRelease(client GitHubClient, versionArg string) (*github.RepositoryRelease, error) { - if strings.ToLower(versionArg) == "latest" { + if versionArg == "" || strings.ToLower(versionArg) == "latest" { return client.GetLatestRelease("cloudposse", "atmos") } return client.GetRelease("cloudposse", "atmos", versionArg) }
📜 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 (6)
cmd/version/formatters.go(1 hunks)cmd/version/list.go(1 hunks)cmd/version/show.go(1 hunks)cmd/version/show_test.go(1 hunks)cmd/version/version.go(1 hunks)errors/errors.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- cmd/version/show_test.go
- cmd/version/formatters.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
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use utils.PrintfMarkdown() to render embedded markdown content for CLI command help/examples.
One Cobra command per file in cmd/; keep files focused and small.
Files:
cmd/version/version.gocmd/version/show.gocmd/version/list.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All Go comments must end with periods; applies to single-line, multi-line, inline, and documentation comments (golangci-lint godot).
Group imports into three sections (stdlib, 3rd-party, Atmos), separated by blank lines; sort alphabetically within each group; preserve existing aliases.
Configuration loading must use Viper with precedence CLI → ENV → files → defaults; bind config name atmos and add path, AutomaticEnv, and ATMOS prefix.
All errors must be wrapped using static errors (defined in errors/errors.go); use errors.Join for multiple errors; fmt.Errorf with %w for context; use errors.Is for checks; never compare error strings.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout; prefer utils.PrintfMessageToTUI for UI messages.
All new configurations must support Go templating using existing utilities and available template functions.
Prefer SDKs over external binaries for cross-platform support; use filepath/os/runtime for portability.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without user data.
80% minimum coverage on new/changed lines and include unit tests for new features; add integration tests for CLI using tests/ fixtures.
Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Use structured logging with levels (Fatal>Error>Warn>Debug>Trace); avoid string interpolation and ensure logging does not affect execution.
Prefer re...
Files:
cmd/version/version.gocmd/version/show.goerrors/errors.gocmd/version/list.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track()to all public functions and critical private functions; include a blank line after the call; use package-prefixed names; pass atmosConfig when present, else nil.
Files:
cmd/version/version.gocmd/version/show.goerrors/errors.gocmd/version/list.go
errors/errors.go
📄 CodeRabbit inference engine (CLAUDE.md)
Define all static errors centrally in errors/errors.go as package-level vars.
Files:
errors/errors.go
🧠 Learnings (4)
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to **/!(*_test).go : Add `defer perf.Track()` to all public functions and critical private functions; include a blank line after the call; use package-prefixed names; pass atmosConfig when present, else nil.
Applied to files:
cmd/version/version.gocmd/version/list.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
Applied to files:
cmd/version/version.gocmd/version/list.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to **/*.go : Most text UI must go to stderr; only data/results to stdout; prefer utils.PrintfMessageToTUI for UI messages.
Applied to files:
cmd/version/show.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.
Applied to files:
cmd/version/show.go
🧬 Code graph analysis (3)
cmd/version/version.go (5)
pkg/schema/schema.go (1)
AtmosConfiguration(27-65)pkg/perf/perf.go (1)
Track(121-138)internal/exec/version.go (1)
NewVersionExec(31-45)cmd/root.go (1)
Execute(444-494)cmd/internal/registry.go (1)
Register(41-52)
cmd/version/show.go (4)
cmd/version/github.go (2)
GitHubClient(12-16)RealGitHubClient(27-27)pkg/github/releases.go (1)
GetLatestRelease(26-46)pkg/perf/perf.go (1)
Track(121-138)errors/errors.go (3)
ErrSpinnerReturnedNilModel(49-49)ErrSpinnerUnexpectedModelType(50-50)ErrUnsupportedOutputFormat(47-47)
cmd/version/list.go (3)
cmd/version/github.go (3)
GitHubClient(12-16)ReleaseOptions(19-24)RealGitHubClient(27-27)errors/errors.go (4)
ErrSpinnerReturnedNilModel(49-49)ErrSpinnerUnexpectedModelType(50-50)ErrInvalidLimit(46-46)ErrUnsupportedOutputFormat(47-47)pkg/perf/perf.go (1)
Track(121-138)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: Run pre-commit hooks
- GitHub Check: website-deploy-preview
- GitHub Check: Summary
🔇 Additional comments (1)
errors/errors.go (1)
45-50: New error sentinels look good.Good centralization and clear messages. Use errors.Is for checks and wrap with %w when propagating.
Add extensive test coverage for version list/show commands to improve patch coverage from 19.74% to 74.2%, meeting the 80-90% target requirement. New test files: - cmd/version/formatters_test.go: Tests for formatting functions including markdown rendering, platform filtering (validates the Windows "win" fix), table creation, and JSON/YAML/text output formatting with refactored helper function to reduce code duplication - cmd/version/github_test.go: Tests for GitHub client interface including mock client methods and real client integration tests Enhanced existing test files: - cmd/version/list_test.go: Added tests for Bubbletea Update method with success, error, and default message handling - cmd/version/show_test.go: Added tests for fetchRelease, fetchReleaseWithSpinner, and Update method variations - cmd/version/version_test.go: Added SetAtmosConfig test Test highlights: - Table-driven tests for comprehensive scenario coverage - Mock client testing to avoid network dependencies - Integration tests with Short mode skip for CI - Bubbletea model lifecycle testing (Init/Update/View) - Output capture testing with helper function to avoid duplication - Platform-specific asset filtering validation Coverage results: - Total coverage: 74.2% (up from 19.74%) - Formatters: 85-100% coverage on most functions - GitHub client methods: 100% coverage - Bubbletea models: 66-100% coverage - Command registration: 100% coverage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…mit handling
Split the TestRealGitHubClient_Integration test into sub-tests so each
API call can skip independently when rate limited. This prevents wasting
API quota on subsequent tests after the first one hits the rate limit.
Before: Single test that would skip after first error, but structure
made it try all three API calls before skipping
After: Three sub-tests that each skip independently on error
This improves CI reliability when GitHub API rate limits are hit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add isRateLimitError helper function and use it to skip tests instead of failing when GitHub API rate limits are hit. This improves CI reliability when running integration tests without a GITHUB_TOKEN or when quota is low. Changes: - Add isRateLimitError() helper to detect rate limit errors - Check for rate limit errors after each API call - Skip test with helpful message instead of failing - Tests now skip gracefully: "Skipping due to GitHub API rate limit: ..." This complements the existing tests.RequireGitHubAccess() precondition check by handling the case where rate limits drop between the check and the actual API call. The GitHub client already supports ATMOS_GITHUB_TOKEN and GITHUB_TOKEN environment variables (via viper binding in cmd/root.go), so CI can set these to increase rate limits. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (9)
cmd/version/version_test.go (2)
17-26: Consider table-driven approach for flag testing.The test correctly verifies flag registration, but could be more maintainable with a table-driven structure if you add more flags in the future.
Optional refactor:
-func TestVersionCommand_Flags(t *testing.T) { - cmd := versionCmd - - checkFlagLookup := cmd.Flags().Lookup("check") - assert.NotNil(t, checkFlagLookup) - assert.Equal(t, "c", checkFlagLookup.Shorthand) - - formatFlagLookup := cmd.Flags().Lookup("format") - assert.NotNil(t, formatFlagLookup) -} +func TestVersionCommand_Flags(t *testing.T) { + cmd := versionCmd + + tests := []struct { + name string + shorthand string + }{ + {"check", "c"}, + {"format", ""}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + flag := cmd.Flags().Lookup(tt.name) + assert.NotNil(t, flag) + if tt.shorthand != "" { + assert.Equal(t, tt.shorthand, flag.Shorthand) + } + }) + } +}
38-48: Remove duplicate SetAtmosConfig call.Line 40 redundantly calls
SetAtmosConfig(nil)before theNotPanicsassertion that does the same thing.Apply this diff:
func TestSetAtmosConfig(t *testing.T) { - // Test that SetAtmosConfig accepts a nil pointer without panic. - SetAtmosConfig(nil) - // SetAtmosConfig should complete without error. // Note: We can't easily test the side effect without refactoring, // but we verify it doesn't panic. assert.NotPanics(t, func() { SetAtmosConfig(nil) }) }pkg/github/releases_test.go (2)
168-186: Consider removing or enhancing this test.This test only verifies
os.Getenvbehavior rather than testing how the client uses the token. Token handling is already covered indirectly by other tests that create authenticated clients.
462-475: Test doesn't verify the intended precedence behavior.As the comment notes, this test can't verify that
ATMOS_GITHUB_TOKENtakes precedence without mocking viper. Consider enhancing this with proper mocking or removing it since it only verifies the client doesn't panic during creation.cmd/version/list_test.go (1)
20-39: Remove or use the hasDefault field.The
hasDefaultfield is defined in each test case but never used in the test logic. Either remove it to keep the test focused, or add assertions to validate the default values.If you want to validate defaults, apply this diff:
func TestListCommand_Flags(t *testing.T) { tests := []struct { name string flagName string hasDefault bool + defaultVal string }{ - {name: "limit flag exists", flagName: "limit", hasDefault: true}, - {name: "offset flag exists", flagName: "offset", hasDefault: true}, - {name: "since flag exists", flagName: "since", hasDefault: false}, - {name: "include-prereleases flag exists", flagName: "include-prereleases", hasDefault: true}, - {name: "format flag exists", flagName: "format", hasDefault: true}, + {name: "limit flag exists", flagName: "limit", hasDefault: true, defaultVal: "10"}, + {name: "offset flag exists", flagName: "offset", hasDefault: true, defaultVal: "0"}, + {name: "since flag exists", flagName: "since", hasDefault: false, defaultVal: ""}, + {name: "include-prereleases flag exists", flagName: "include-prereleases", hasDefault: true, defaultVal: "false"}, + {name: "format flag exists", flagName: "format", hasDefault: true, defaultVal: "text"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { flag := listCmd.Flags().Lookup(tt.flagName) assert.NotNil(t, flag, "flag %s should exist", tt.flagName) + if tt.hasDefault { + assert.Equal(t, tt.defaultVal, flag.DefValue, "flag %s should have correct default", tt.flagName) + } }) } }Or simplify by removing the unused field:
func TestListCommand_Flags(t *testing.T) { tests := []struct { name string flagName string - hasDefault bool }{ - {name: "limit flag exists", flagName: "limit", hasDefault: true}, - {name: "offset flag exists", flagName: "offset", hasDefault: true}, - {name: "since flag exists", flagName: "since", hasDefault: false}, - {name: "include-prereleases flag exists", flagName: "include-prereleases", hasDefault: true}, - {name: "format flag exists", flagName: "format", hasDefault: true}, + {name: "limit flag exists", flagName: "limit"}, + {name: "offset flag exists", flagName: "offset"}, + {name: "since flag exists", flagName: "since"}, + {name: "include-prereleases flag exists", flagName: "include-prereleases"}, + {name: "format flag exists", flagName: "format"}, }cmd/version/formatters_test.go (4)
190-238: Use the captureStdout helper for consistency.This test manually captures stdout, but the
captureStdouthelper (defined at lines 240-257) exists for exactly this purpose. Using it would make the test more concise and consistent with other tests in this file.Apply this diff:
func TestFormatReleaseListText(t *testing.T) { publishedAt := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC) tests := []struct { name string releases []*github.RepositoryRelease - wantErr bool }{ { name: "formats releases as table", releases: []*github.RepositoryRelease{ { TagName: github.String("v1.0.0"), Name: github.String("Release 1.0.0"), PublishedAt: &github.Timestamp{Time: publishedAt}, Prerelease: github.Bool(false), }, }, - wantErr: false, }, { name: "handles empty release list", releases: []*github.RepositoryRelease{}, - wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - err := formatReleaseListText(tt.releases) - - w.Close() - os.Stdout = oldStdout - - var buf bytes.Buffer - _, _ = io.Copy(&buf, r) - - if tt.wantErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } + output := captureStdout(t, func() error { + return formatReleaseListText(tt.releases) + }) + assert.NotEmpty(t, output) }) } }
297-331: Use the captureStdout helper for consistency.Like
TestFormatReleaseListText, this test manually captures stdout instead of using thecaptureStdouthelper. For consistency and maintainability, use the helper.Apply this diff:
func TestFormatReleaseDetailText(t *testing.T) { publishedAt := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC) size := int(1048576) // 1 MB release := &github.RepositoryRelease{ TagName: github.String("v1.0.0"), Name: github.String("Release 1.0.0"), Body: github.String("Release notes with **markdown**"), PublishedAt: &github.Timestamp{Time: publishedAt}, HTMLURL: github.String("https://github.com/cloudposse/atmos/releases/tag/v1.0.0"), Assets: []*github.ReleaseAsset{ { Name: github.String("atmos_1.0.0_" + runtime.GOOS + "_" + runtime.GOARCH + ".tar.gz"), Size: &size, BrowserDownloadURL: github.String("https://github.com/cloudposse/atmos/releases/download/v1.0.0/atmos.tar.gz"), }, }, } - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - formatReleaseDetailText(release) - - w.Close() - os.Stdout = oldStdout - - var buf bytes.Buffer - _, _ = io.Copy(&buf, r) - output := buf.String() + output := captureStdout(t, func() error { + formatReleaseDetailText(release) + return nil + }) assert.Contains(t, output, "v1.0.0") assert.Contains(t, output, "Release 1.0.0") }
381-403: Strengthen test assertions.The test only verifies that
isCurrentVersiondoesn't panic, which is minimal coverage. Additionally, thewantErrfield is defined but never used. Consider adding assertions to verify the boolean return value against expected results.Apply this diff:
func TestIsCurrentVersion(t *testing.T) { + // Get the actual current version from the build + currentVer := version // This should be the package-level version variable + tests := []struct { name string tag string - wantErr bool + want bool }{ { - name: "checks version tag", - tag: "v1.0.0", + name: "matches current version", + tag: currentVer, + want: true, }, { name: "handles non-matching version", tag: "v999.999.999", + want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Just verify the function doesn't panic - _ = isCurrentVersion(tt.tag) + got := isCurrentVersion(tt.tag) + assert.Equal(t, tt.want, got) }) } }
405-429: Consider stronger assertions if possible.The test uses weak assertions (
GreaterOrEqual) because the actual current version affects the result. If the implementation details allow, consider adding more specific test cases that don't depend on the runtime version.For example, if you can control or mock the current version, you could test:
- Adding current version when it's missing
- Not duplicating when it's already present
- Proper sorting/ordering after insertion
This would provide better confidence in the function's behavior.
📜 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 (6)
cmd/version/formatters_test.go(1 hunks)cmd/version/github_test.go(1 hunks)cmd/version/list_test.go(1 hunks)cmd/version/show_test.go(1 hunks)cmd/version/version_test.go(1 hunks)pkg/github/releases_test.go(12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cmd/version/show_test.go
🧰 Additional context used
📓 Path-based instructions (7)
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use utils.PrintfMarkdown() to render embedded markdown content for CLI command help/examples.
One Cobra command per file in cmd/; keep files focused and small.
Files:
cmd/version/version_test.gocmd/version/formatters_test.gocmd/version/list_test.gocmd/version/github_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Use table-driven unit tests for pure functions and focus on behavior; co-locate tests; target >80% coverage for pkg/ and internal/exec/.
Always use t.Skipf() with a clear reason; never use t.Skip() or t.Skipf without a reason.
Files:
cmd/version/version_test.gocmd/version/formatters_test.gopkg/github/releases_test.gocmd/version/list_test.gocmd/version/github_test.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All Go comments must end with periods; applies to single-line, multi-line, inline, and documentation comments (golangci-lint godot).
Group imports into three sections (stdlib, 3rd-party, Atmos), separated by blank lines; sort alphabetically within each group; preserve existing aliases.
Configuration loading must use Viper with precedence CLI → ENV → files → defaults; bind config name atmos and add path, AutomaticEnv, and ATMOS prefix.
All errors must be wrapped using static errors (defined in errors/errors.go); use errors.Join for multiple errors; fmt.Errorf with %w for context; use errors.Is for checks; never compare error strings.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; never use logging for UI.
Most text UI must go to stderr; only data/results to stdout; prefer utils.PrintfMessageToTUI for UI messages.
All new configurations must support Go templating using existing utilities and available template functions.
Prefer SDKs over external binaries for cross-platform support; use filepath/os/runtime for portability.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without user data.
80% minimum coverage on new/changed lines and include unit tests for new features; add integration tests for CLI using tests/ fixtures.
Always bind environment variables with viper.BindEnv and provide ATMOS_ alternatives for every env var.
Use structured logging with levels (Fatal>Error>Warn>Debug>Trace); avoid string interpolation and ensure logging does not affect execution.
Prefer re...
Files:
cmd/version/version_test.gocmd/version/formatters_test.gopkg/github/releases_test.gocmd/version/list_test.gocmd/version/github_test.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Command tests live under cmd/ alongside command implementations.
Files:
cmd/version/version_test.gocmd/version/formatters_test.gocmd/version/list_test.gocmd/version/github_test.go
cmd/*/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Add tests for new commands under cmd//_test.go.
Files:
cmd/version/version_test.gocmd/version/formatters_test.gocmd/version/list_test.gocmd/version/github_test.go
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/github/releases_test.go
pkg/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Unit tests for packages live under pkg/ alongside implementation files.
Files:
pkg/github/releases_test.go
🧠 Learnings (4)
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to cmd/*/*_test.go : Add tests for new commands under cmd/<command>/<command>_test.go.
Applied to files:
cmd/version/version_test.gocmd/version/list_test.gocmd/version/github_test.go
📚 Learning: 2025-10-16T15:18:00.319Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-16T15:18:00.319Z
Learning: Applies to cmd/**/*_test.go : Command tests live under cmd/ alongside command implementations.
Applied to files:
cmd/version/version_test.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/version_test.gocmd/version/github_test.go
📚 Learning: 2024-12-05T02:48:53.818Z
Learnt from: aknysh
PR: cloudposse/atmos#809
File: cmd/cmd_utils.go:470-477
Timestamp: 2024-12-05T02:48:53.818Z
Learning: The function `GetLatestGitHubRepoRelease` in the Go codebase already uses a context with a timeout, so wrapping it with an additional context is unnecessary.
Applied to files:
pkg/github/releases_test.go
🧬 Code graph analysis (4)
cmd/version/version_test.go (1)
cmd/version/version.go (2)
VersionCommandProvider(49-49)SetAtmosConfig(21-23)
pkg/github/releases_test.go (2)
pkg/github/releases.go (5)
GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleases(49-99)GetReleaseByTag(193-207)GetLatestReleaseInfo(210-224)tests/preconditions.go (1)
RequireGitHubAccess(206-230)
cmd/version/list_test.go (1)
cmd/version/github.go (2)
MockGitHubClient(52-56)ReleaseOptions(19-24)
cmd/version/github_test.go (2)
cmd/version/github.go (3)
MockGitHubClient(52-56)ReleaseOptions(19-24)RealGitHubClient(27-27)pkg/github/releases.go (2)
GetReleases(49-99)GetLatestRelease(26-46)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build (macos-latest, macos)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Analyze (go)
- GitHub Check: website-deploy-preview
- GitHub Check: Lint (golangci)
- GitHub Check: Summary
🔇 Additional comments (5)
cmd/version/version_test.go (2)
9-15: Clean provider interface test.This test properly verifies the provider contract. The assertions confirm the expected name, group, and command initialization.
28-36: Solid command structure verification.The test properly validates the command's basic properties, ensuring all required fields are populated and RunE is wired correctly.
pkg/github/releases_test.go (2)
1-13: Package structure looks good.The package declaration and imports are properly organized following Go conventions.
306-460: Comprehensive test coverage for new APIs.These tests provide good coverage of
GetReleases,GetReleaseByTag, andGetLatestReleaseInfowith multiple scenarios including pagination, filtering, and error handling. Once theisRateLimitErrorhelper is fixed (see comment on lines 15-22), these tests will have proper error checking.cmd/version/github_test.go (1)
109-149: Good integration test structure.The integration test properly uses
testing.Short()to skip in short mode and has clear skip messages for API errors. The subtests provide good coverage of the real GitHub client methods.
Complete the rate limit error handling for all GitHub API integration tests. This ensures all tests skip gracefully instead of failing when rate limits are hit, improving CI reliability. Tests updated: - TestGetLatestRelease (all sub-tests) - TestGetLatestReleaseWithAuthentication - TestGetReleaseByTag - TestGetLatestReleaseInfo All tests now check for rate limit errors after API calls and skip with a helpful message instead of failing. Combined with the existing tests.RequireGitHubAccess() precondition checks, this provides robust rate limit handling. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
cmd/version/formatters.go (1)
245-496: Consider adding performance tracking to critical format functions.The formatting functions (
formatReleaseListText,formatReleaseListJSON,formatReleaseListYAML,formatReleaseDetailText,formatReleaseDetailJSON,formatReleaseDetailYAML) are critical to the version command execution path. Per guidelines, critical private functions should includedefer perf.Track()at the start.Example:
func formatReleaseListText(releases []*github.RepositoryRelease) error { defer perf.Track(nil, "version.formatReleaseListText")() // Add current version if it's not in the list. releases = addCurrentVersionIfMissing(releases) ... }This would provide visibility into formatting performance during command execution.
pkg/github/releases_test.go (4)
186-203: Remove tautological test of standard library behavior.This test verifies that
t.Setenvandos.Getenvwork together, which tests Go's standard library rather than your production code. The guideline advises removing tautological tests.Consider removing this test or replacing it with a test that verifies
newGitHubClientactually uses the token from the environment:-// TestGitHubTokenHandling tests token handling from environment. -func TestGitHubTokenHandling(t *testing.T) { - t.Run("reads token from GITHUB_TOKEN env var", func(t *testing.T) { - // Test with token - testToken := "ghp_test_123" - t.Setenv("GITHUB_TOKEN", testToken) - - // Verify token is read - token := os.Getenv("GITHUB_TOKEN") - assert.Equal(t, testToken, token) - }) - - t.Run("handles empty token", func(t *testing.T) { - // Test without token - t.Setenv("GITHUB_TOKEN", "") - token := os.Getenv("GITHUB_TOKEN") - assert.Empty(t, token) - }) -}As per coding guidelines.
275-284: Replace implementation-detail check with behavior test.Asserting that
client.Repositoriesis initialized tests the internal structure of thegithub.Clienttype rather than behavior. The guideline recommends behavior-focused tests.Replace this with a test that verifies the client works by making an actual API call (or remove if redundant with other tests):
-// TestGitHubClientConfiguration tests client configuration options. -func TestGitHubClientConfiguration(t *testing.T) { - t.Run("client is properly configured", func(t *testing.T) { - ctx := context.Background() - client := newGitHubClient(ctx) - - assert.NotNil(t, client) - assert.NotNil(t, client.Repositories, "Repositories service should be initialized") - }) -}As per coding guidelines.
286-321: Add assertions to verify concurrent call behavior.This test launches concurrent API calls but doesn't verify correctness, thread-safety, or results. It only confirms the goroutines complete without panicking.
Add assertions to verify behavior:
for _, r := range repos { go func(owner, repo string) { - _, err := GetLatestRelease(owner, repo) - // Don't assert on error - could be rate limited. - _ = err + tag, err := GetLatestRelease(owner, repo) + if err == nil { + // If successful, verify we got a valid tag + if tag == "" { + t.Errorf("Expected non-empty tag for %s/%s", owner, repo) + } + } done <- true }(r.owner, r.repo) }As per coding guidelines.
485-498: Consider enhancing or removing this weak test.The test only verifies that client creation doesn't panic and acknowledges it "can't directly test precedence without mocking viper." This doesn't verify the documented ATMOS_GITHUB_TOKEN precedence behavior.
Options to improve this:
- Use dependency injection to test token precedence without global viper state
- Make the token selection logic testable by extracting it to a pure function
- Remove the test if it doesn't verify meaningful behavior
- Keep as-is if it serves as a basic smoke test
📜 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 (7)
CLAUDE.md(1 hunks)cmd/root.go(4 hunks)cmd/version/formatters.go(1 hunks)cmd/version/formatters_test.go(1 hunks)cmd/version/list_test.go(1 hunks)pkg/github/client_test.go(1 hunks)pkg/github/releases_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cmd/version/list_test.go
🧰 Additional context used
📓 Path-based instructions (8)
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/github/client_test.gopkg/github/releases_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Write behavior-focused tests (verify inputs/outputs) rather than implementation details.
Avoid tautological tests and tests of stub functions; remove always-skipped tests.
Use dependency injection to avoid hard dependencies on os.Exit or interactive/system calls in tests.
Call production code in tests; do not duplicate production logic inside tests.
Use t.Skipf with a clear reason instead of t.Skip when skipping tests.
Co-locate tests alongside implementation files (use _test.go in same package directories).
Use mockgen for interface mocks; prefer //go:generate mockgen directives in test files; do not write manual mocks.
Files:
pkg/github/client_test.gopkg/github/releases_test.gocmd/version/formatters_test.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All comments must be complete sentences ending with periods.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines, sorted alphabetically within each group; preserve existing aliases.
Wrap all returned errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; use fmt.Errorf with %w for adding context; check with errors.Is; never compare err.Error().
Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Prefer interfaces for multi-provider capabilities and generate mocks for them; use provider registry pattern.
Ensure cross-platform compatibility: use stdlib (filepath, os.PathSeparator), avoid platform-specific binaries when SDKs exist, and guard OS-specific logic with runtime.GOOS.
Files:
pkg/github/client_test.gopkg/github/releases_test.gocmd/version/formatters_test.gocmd/version/formatters.gocmd/root.go
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use embedded markdown for cobra command Long/Examples via //go:embed and render with utils.PrintfMarkdown().
Telemetry is captured automatically via RootCmd.ExecuteC; for non-standard paths call telemetry.CaptureCmd/CaptureCmdString explicitly.
Files:
cmd/version/formatters_test.gocmd/version/formatters.gocmd/root.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use cmd.NewTestKit(t) in all tests touching RootCmd (Execute, SetArgs, or commands using RootCmd), including subtests.
Files:
cmd/version/formatters_test.go
cmd/**
📄 CodeRabbit inference engine (CLAUDE.md)
One command per file in cmd/; keep files small and focused.
Files:
cmd/version/formatters_test.gocmd/version/formatters.gocmd/root.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()at the start of all public and critical private functions, followed by a blank line.
Files:
cmd/version/formatters.gocmd/root.go
cmd/root.go
📄 CodeRabbit inference engine (CLAUDE.md)
When adding a new command package, add a blank import in cmd/root.go (e.g., _ "github.com/cloudposse/atmos/cmd/mycommand").
Files:
cmd/root.go
🧠 Learnings (14)
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Applied to files:
cmd/version/formatters.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Applied to files:
cmd/version/formatters.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#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:
cmd/version/formatters.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Applied to files:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-09-10T17:34:52.568Z
Learnt from: Benbentwo
PR: cloudposse/atmos#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.
Applied to files:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Configuration precedence should be CLI flags → environment variables → config files → defaults (use Viper).
Applied to files:
CLAUDE.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for managing configuration, environment variables, and flags in the CLI
Applied to files:
cmd/root.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to cmd/root.go : When adding a new command package, add a blank import in cmd/root.go (e.g., _ "github.com/cloudposse/atmos/cmd/mycommand").
Applied to files:
cmd/root.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Applied to files:
cmd/root.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
PR: cloudposse/atmos#1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.
Applied to files:
cmd/root.go
🧬 Code graph analysis (3)
pkg/github/releases_test.go (3)
errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)tests/preconditions.go (1)
RequireGitHubAccess(207-231)pkg/github/releases.go (5)
GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleases(49-99)GetReleaseByTag(193-207)GetLatestReleaseInfo(210-224)
cmd/version/formatters.go (4)
internal/tui/templates/templater.go (1)
GetTerminalWidth(245-258)pkg/logger/log.go (2)
Errorf(59-61)Debug(24-26)errors/errors.go (1)
ErrTerminalTooNarrow(48-48)pkg/utils/markdown_utils.go (1)
PrintfMarkdownToTUI(89-93)
cmd/root.go (2)
cmd/version/version.go (1)
SetAtmosConfig(21-23)pkg/logger/log.go (1)
Error(54-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: website-deploy-preview
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: Summary
🔇 Additional comments (7)
cmd/root.go (1)
681-686: LGTM! Environment variable binding now correct.The
viper.BindEnvcall now properly checks bothATMOS_GITHUB_TOKEN(first) andGITHUB_TOKEN(fallback), giving correct precedence. The three-argument form ensures Viper checks the key name first, then falls back to the alternate environment variable.CLAUDE.md (1)
928-936: LGTM! Documentation clearly explains correct pattern.The updated examples show both the incorrect single-argument form and the correct multi-argument form of
viper.BindEnv. This will help prevent similar mistakes in the future.cmd/version/formatters_test.go (1)
1-546: LGTM! Comprehensive and well-structured tests.This test file demonstrates excellent practices:
- Behavior-focused tests that verify inputs/outputs
- Table-driven tests for multiple scenarios
- Good edge case coverage (empty inputs, platform variations, markdown parsing)
- Calls production code rather than duplicating logic
- Proper use of
t.Helper()in the capture helpercmd/version/formatters.go (2)
352-403: LGTM! Proper separation of UI and data output.The formatter correctly routes all UI elements (release info, assets) to
os.Stderrand usesu.PrintfMarkdownToTUIfor markdown rendering. This follows the guidelines for output separation, ensuring piping works correctly.
205-243: LGTM! Terminal width validation and error handling.The table creation properly validates terminal width and returns a well-contextualized
ErrTerminalTooNarrowerror when the terminal is too narrow. Debug logging provides useful troubleshooting information.pkg/github/releases_test.go (2)
62-483: Comprehensive integration test coverage.The integration tests for GitHub API operations are well-structured with proper precondition checks, rate limit handling, and coverage of both success and error paths. Good use of
tests.RequireGitHubAccessto gate network-dependent tests and graceful skipping when rate-limited.
500-691: Well-structured unit tests for filter and pagination helpers.The table-driven tests for
filterPrereleases,filterByDate, andapplyPaginationprovide thorough coverage with clear test cases, edge cases (empty slices, boundary conditions), and proper assertions verifying the filtering logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
♻️ Duplicate comments (2)
docs/prd/command-registry-pattern.md (1)
1280-1494: Guidance still conflicts with established layering rules.This section recommends placing command-specific business logic in
cmd/[command]/, but our coding guidelines require keeping business logic inpkg/orinternal/exec/and limitingcmd/to CLI wiring and I/O.The decision framework (lines 1282-1298) narrows
internal/exec/to "cross-command orchestration logic" only, which contradicts the broader pattern established across the codebase whereinternal/exec/houses command business logic.Recommend aligning this section with existing learnings:
cmd/packages should contain only Cobra command definitions, flag parsing, and calls to business logic- Business logic belongs in
pkg/(reusable) orinternal/exec/(command orchestration)- Self-contained command packages are acceptable for truly isolated features, but the general pattern remains separation of concerns
As per coding guidelines.
pkg/github/client_test.go (1)
50-59: Use error type checking instead of string matching.The test validates errors by matching substrings in error messages, which violates the coding guideline against comparing error strings. For the rate-limit case that wraps
errUtils.ErrGitHubRateLimitExceeded, useerrors.Isorassert.ErrorIsto verify error semantics.As per coding guidelines.
Apply this diff:
+ "errors" + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := handleGitHubAPIError(tt.err, tt.resp) if tt.wantErr { assert.Error(t, err) - assert.Contains(t, err.Error(), tt.errString) + if tt.name == "rate limit exceeded with response" { + assert.ErrorIs(t, err, errUtils.ErrGitHubRateLimitExceeded) + } else { + assert.Contains(t, err.Error(), tt.errString) + } } else { assert.NoError(t, err) } }) }
🧹 Nitpick comments (11)
cmd/version/list_test.go (1)
33-38: Also assert default values for flags.You already verify presence; add quick checks for defaults to guard regressions.
Apply this diff inside the loop after the NotNil assertion:
flag := listCmd.Flags().Lookup(tt.flagName) assert.NotNil(t, flag, "flag %s should exist", tt.flagName) + if tt.hasDefault { + assert.NotEmpty(t, flag.DefValue, "flag %s should have a default", tt.flagName) + }cmd/version/list.go (3)
131-134: Pass atmos config and use package-prefixed tracker name.Use atmosConfigPtr and a consistent name per convention.
As per coding guidelines.
- defer perf.Track(nil, "version.list.RunE")() + defer perf.Track(atmosConfigPtr, "cmd.version.list.RunE")()
75-124: Instrument fetchReleasesWithSpinner for perf telemetry.Low-frequency, critical private path; safe to track. Avoid tracking listModel.Update/View (high-frequency).
Based on learnings.
func fetchReleasesWithSpinner(client GitHubClient, opts ReleaseOptions) ([]*github.RepositoryRelease, error) { + defer perf.Track(atmosConfigPtr, "cmd.version.fetchReleasesWithSpinner")()
47-55: Quit-on-any-key may be too aggressive.Consider restricting to Ctrl+C, q, or Esc so stray keys don’t exit the spinner.
- case tea.KeyMsg: - return m, tea.Quit + case tea.KeyMsg: + switch strings.ToLower(msg.String()) { + case "q", "esc", "ctrl+c": + return m, tea.Quit + default: + return m, nil + }cmd/version/version.go (1)
33-35: Align perf tracker label with convention.Use a package-prefixed name.
As per coding guidelines.
- defer perf.Track(atmosConfigPtr, "version.RunE")() + defer perf.Track(atmosConfigPtr, "cmd.version.RunE")()pkg/github/releases_test.go (2)
445-453: Avoid brittle hard-coded tag.Using a fixed tag can flake if removed/renamed. Prefer fetching a known recent tag or skipping when not found.
Example approach:
- Get latest release, then fetch by that tag and assert round-trip.
- Or gate by env (e.g., TEST_KNOWN_TAG) and skip if unset.
295-321: Optional: bound concurrency to respect rate limits.Limit goroutines with a small worker pool to reduce 429 risks on CI.
pkg/utils/github_utils.go (1)
10-11: Fix deprecation comments to reference internal pkg/github (not google/go-github).Current “Use github.*” is ambiguous. Point to our internal package or the gh alias to avoid confusion.
-// Deprecated: Use github.GetLatestRelease instead. +// Deprecated: Use pkg/github.GetLatestRelease (gh.GetLatestRelease) instead. -// Deprecated: Use github.ReleasesOptions instead. +// Deprecated: Use pkg/github.ReleasesOptions (gh.ReleasesOptions) instead. -// Deprecated: Use github.GetReleases instead. +// Deprecated: Use pkg/github.GetReleases (gh.GetReleases) instead. -// Deprecated: Use github.GetReleaseByTag instead. +// Deprecated: Use pkg/github.GetReleaseByTag (gh.GetReleaseByTag) instead. -// Deprecated: Use github.GetLatestReleaseInfo instead. +// Deprecated: Use pkg/github.GetLatestReleaseInfo (gh.GetLatestReleaseInfo) instead.Also applies to: 15-17, 19-23, 25-29, 31-35
cmd/version/formatters_test.go (2)
223-244: DRY stderr capture and prevent descriptor leaksSeveral tests duplicate stderr capture logic and never close r. Extract a captureStderr helper mirroring captureStdout and use it in those tests to avoid FD leaks and make failures safe.
Add this helper near captureStdout:
+// captureStderr captures stderr for a function call and returns the output. +func captureStderr(t *testing.T, fn func() error) (string, error) { + t.Helper() + oldStderr := os.Stderr + r, w, _ := os.Pipe() + os.Stderr = w + defer func() { os.Stderr = oldStderr }() + defer r.Close() + err := fn() + _ = w.Close() + var buf bytes.Buffer + _, _ = io.Copy(&buf, r) + return buf.String(), err +}Then, for example in TestFormatReleaseListText:
out, err := captureStderr(t, func() error { return formatReleaseListText(tt.releases) }) if tt.wantErr { assert.Error(t, err) } else { assert.NoError(t, err) } _ = out // assert on it if desiredAlso applies to: 322-338, 495-514, 516-546, 547-573
517-545: Fragile substring check for prerelease labelAsserting "Pre-release" is brittle (casing/hyphenization may vary). Prefer case-insensitive contains or assert on the beta tag plus a stable label token.
Example:
require.Contains(t, strings.ToLower(output), "v2.0.0-beta") require.Contains(t, strings.ToLower(output), "pre")Remember to import "strings".
pkg/github/releases.go (1)
25-46: Ambiguous “not found” return for GetLatestReleaseReturning "", nil makes it hard for callers to distinguish “no release” vs success. Consider returning a sentinel error (e.g., errUtils.ErrGitHubReleaseNotFound) or document that empty string equals “not found”.
📜 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 (27)
CLAUDE.md(1 hunks)cmd/root.go(4 hunks)cmd/version.go(0 hunks)cmd/version/formatters.go(1 hunks)cmd/version/formatters_test.go(1 hunks)cmd/version/github.go(1 hunks)cmd/version/github_test.go(1 hunks)cmd/version/list.go(1 hunks)cmd/version/list_test.go(1 hunks)cmd/version/markdown/atmos_version_list_usage.md(1 hunks)cmd/version/markdown/atmos_version_show_usage.md(1 hunks)cmd/version/show.go(1 hunks)cmd/version/show_test.go(1 hunks)cmd/version/version.go(1 hunks)cmd/version/version_test.go(1 hunks)docs/prd/command-registry-pattern.md(1 hunks)docs/prd/version-list-command.md(1 hunks)errors/errors.go(1 hunks)go.mod(1 hunks)pkg/config/cache_lock_unix.go(2 hunks)pkg/github/client.go(1 hunks)pkg/github/client_test.go(1 hunks)pkg/github/releases.go(1 hunks)pkg/github/releases_test.go(1 hunks)pkg/utils/github_utils.go(1 hunks)pkg/utils/github_utils_test.go(0 hunks)website/blog/2025-10-17-version-list-command.md(1 hunks)
💤 Files with no reviewable changes (2)
- cmd/version.go
- pkg/utils/github_utils_test.go
🧰 Additional context used
🧠 Learnings (24)
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Applied to files:
cmd/version/formatters.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Applied to files:
cmd/version/formatters.go
📚 Learning: 2025-09-13T18:06:07.674Z
Learnt from: samtholiya
PR: cloudposse/atmos#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:
cmd/version/formatters.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/!(*_test).go : Add `defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()` at the start of all public and critical private functions, followed by a blank line.
Applied to files:
cmd/version/show.gocmd/version/list.gocmd/version/version.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/*.go : Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Applied to files:
CLAUDE.mdcmd/root.gopkg/utils/github_utils.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.gopkg/utils/github_utils.go
📚 Learning: 2025-04-23T15:02:50.246Z
Learnt from: osterman
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.gopkg/utils/github_utils.go
📚 Learning: 2025-09-29T15:47:10.908Z
Learnt from: aknysh
PR: cloudposse/atmos#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:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-09-10T17:34:52.568Z
Learnt from: Benbentwo
PR: cloudposse/atmos#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.
Applied to files:
CLAUDE.mdcmd/root.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Configuration precedence should be CLI flags → environment variables → config files → defaults (use Viper).
Applied to files:
CLAUDE.md
📚 Learning: 2025-09-13T16:39:20.007Z
Learnt from: samtholiya
PR: cloudposse/atmos#1466
File: cmd/markdown/atmos_toolchain_aliases.md:2-4
Timestamp: 2025-09-13T16:39:20.007Z
Learning: In the cloudposse/atmos repository, CLI documentation files in cmd/markdown/ follow a specific format that uses " $ atmos command" (with leading space and dollar sign prompt) in code blocks. This is the established project convention and should not be changed to comply with standard markdownlint rules MD040 and MD014.
Applied to files:
cmd/version/markdown/atmos_version_list_usage.mdcmd/version/markdown/atmos_version_show_usage.md
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
Applied to files:
cmd/version/list.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#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/version/version.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Keep separation of concerns between CLI interface (cmd) and business logic
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Follow single responsibility; separate command interface from business logic
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Cobra's recommended command structure with a root command and subcommands
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to internal/exec/**/*.go : Place business logic for commands in internal/exec/ (e.g., internal/exec/mycommand.go).
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to pkg/**/*.go : Place business logic in pkg rather than in cmd
Applied to files:
docs/prd/command-registry-pattern.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/version_test.gocmd/version/show_test.go
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#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/root.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to cmd/root.go : When adding a new command package, add a blank import in cmd/root.go (e.g., _ "github.com/cloudposse/atmos/cmd/mycommand").
Applied to files:
cmd/root.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for managing configuration, environment variables, and flags in the CLI
Applied to files:
cmd/root.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to cmd/**/*.go : Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Applied to files:
cmd/root.go
📚 Learning: 2025-08-16T23:32:40.412Z
Learnt from: aknysh
PR: cloudposse/atmos#1405
File: internal/exec/describe_dependents_test.go:455-456
Timestamp: 2025-08-16T23:32:40.412Z
Learning: In the cloudposse/atmos Go codebase, `InitCliConfig` returns a `schema.AtmosConfiguration` value (not a pointer), while `ExecuteDescribeDependents` expects a `*schema.AtmosConfiguration` pointer parameter. Therefore, when passing the result of `InitCliConfig` to `ExecuteDescribeDependents`, use `&atmosConfig` to pass the address of the value.
Applied to files:
cmd/root.go
🪛 LanguageTool
docs/prd/version-list-command.md
[grammar] ~86-~86: Please add a punctuation mark at the end of paragraph.
Context: ...) - Automatic word wrapping for long titles 2. Detail View (`atmos version sho...
(PUNCTUATION_PARAGRAPH_END)
[style] ~206-~206: Since ownership is already implied, this phrasing may be redundant.
Context: ...organization** - Each command family in its own package - ✅ Type-safe interfaces - ...
(PRP_OWN)
[uncategorized] ~412-~412: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...releases - ✅ Release titles render with markdown formatting and colors - ✅ Current insta...
(MARKDOWN_NNP)
🪛 markdownlint-cli2 (0.18.1)
cmd/version/markdown/atmos_version_list_usage.md
3-3: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
4-4: Dollar signs used before commands without showing output
(MD014, commands-show-output)
9-9: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
10-10: Dollar signs used before commands without showing output
(MD014, commands-show-output)
15-15: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
16-16: Dollar signs used before commands without showing output
(MD014, commands-show-output)
21-21: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
22-22: Dollar signs used before commands without showing output
(MD014, commands-show-output)
27-27: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
28-28: Dollar signs used before commands without showing output
(MD014, commands-show-output)
website/blog/2025-10-17-version-list-command.md
13-13: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
74-74: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Acceptance Tests (windows-latest, windows)
- GitHub Check: Acceptance Tests (ubuntu-latest, linux)
- GitHub Check: Acceptance Tests (macos-latest, macos)
- GitHub Check: Summary
🔇 Additional comments (23)
pkg/config/cache_lock_unix.go (1)
26-28: No issues—the 500ms retry approach is sound for non-critical cache operations.The lock acquisition is bounded and graceful: if the lock can't be acquired within 500ms of retries, the operation fails cleanly with a clear error instead of blocking indefinitely. The cache itself is documented as non-critical to functionality, and the retry logic includes appropriate comments explaining the strategy. The change improves robustness without introducing problematic latency.
cmd/version/formatters.go (13)
1-40: LGTM—clean package setup.Imports follow the three-group convention, constants are well-named, and styling variables use lipgloss consistently.
41-63: LGTM—heading extraction logic is solid.Correctly handles both summary tags and markdown headings with appropriate cleanup.
65-91: LGTM—version handling is robust.Proper normalization and fallback logic for release titles.
93-128: LGTM—synthetic current version logic is sound.Correctly checks for existing version and prepends synthetic release when needed.
130-178: LGTM—platform filtering is correct.Pattern maps are explicit and avoid false positives. Matching logic properly filters by both OS and architecture.
180-203: LGTM—markdown rendering with graceful fallback.Proper error handling and ANSI color preservation.
205-243: LGTM—table creation with width validation.Properly checks terminal width and returns sentinel error when too narrow. Styling matches design requirements.
245-285: LGTM—text formatter routes to stderr correctly.As per guidelines, UI output goes to stderr (lines 251, 283). Logic properly handles empty results and formats releases.
287-318: LGTM—JSON formatter routes data to stdout.Correctly uses os.Stdout for structured data output. Fields are comprehensive.
320-350: LGTM—YAML formatter routes data to stdout.Consistent with JSON formatter, correctly using stdout for structured output.
352-403: LGTM—detail formatter uses TUI helpers and stderr correctly.All UI output routed to stderr, markdown rendering uses utils.PrintfMarkdownToTUI per guidelines (line 377). Platform filtering applied appropriately.
405-450: LGTM—JSON detail formatter routes to stdout.Properly structured output with platform-filtered assets.
452-496: LGTM—YAML detail formatter routes to stdout.Consistent with JSON, properly structured.
go.mod (1)
66-66: LGTM—dependency promoted to direct usage.Correctly moves go-isatty to direct dependency to reflect its usage in version command TTY detection.
docs/prd/version-list-command.md (1)
1-450: LGTM—comprehensive design document.PRD thoroughly documents command design, architecture, output formats, error handling, and testing strategy. Aligns well with the implementation in cmd/version/.
errors/errors.go (1)
45-50: LGTM—new error sentinels are well-defined.Static errors follow the established pattern and support the version command's error handling needs.
cmd/version/show.go (1)
1-171: LGTM—show command implementation is solid.All previous review feedback has been addressed:
- perf.Track added correctly (lines 73, 134)
- TTY detection uses stderr (line 76)
- Spinner renders to stderr (line 91)
- Safe type assertion with nil check (lines 110-117)
- Default version handling works correctly (line 137)
- Errors are properly wrapped and propagated
Clean implementation with good separation of concerns.
cmd/version/github_test.go (1)
1-149: LGTM—comprehensive test coverage.Tests properly exercise both mock and real clients. Good use of skip conditions for integration tests and graceful handling of API errors.
CLAUDE.md (1)
928-936: LGTM—environment variable binding guidance is correct.The updated example properly demonstrates the three-argument BindEnv pattern for fallback behavior: check ATMOS_GITHUB_TOKEN first, then fall back to GITHUB_TOKEN. This aligns with the project's environment variable conventions.
cmd/version/version_test.go (1)
1-48: LGTM!The test coverage is solid for the version command provider, flags, and basic properties. The SetAtmosConfig test appropriately verifies nil handling.
cmd/root.go (1)
501-502: LGTM!Exposing the Atmos configuration to the version command via
SetAtmosConfigis the right approach for early configuration access.cmd/version/show_test.go (1)
1-183: LGTM!Comprehensive test coverage for the show command, including flags, fetch logic, spinner behavior, and model state transitions. Well done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
♻️ Duplicate comments (3)
cmd/version/formatters_test.go (2)
518-547: Use defer to guarantee stderr cleanup.Ensure cleanup happens even on test failure by using defer statements.
Apply this diff:
func TestFormatReleaseDetailText_Prerelease(t *testing.T) { // ... setup ... oldStderr := os.Stderr r, w, _ := os.Pipe() os.Stderr = w + defer func() { os.Stderr = oldStderr }() + defer r.Close() err := formatReleaseDetailText(release) - w.Close() - os.Stderr = oldStderr + _ = w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r)
196-244: Use defer to guarantee stderr cleanup even on test failure.If the test fails or panics before line 231-232,
os.Stderrwon't be restored and the pipe won't be closed, potentially affecting subsequent tests. Follow the same pattern ascaptureStdout(lines 254-255) and use defer statements.Apply this diff:
func TestFormatReleaseListText(t *testing.T) { // ... test cases ... for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { oldStderr := os.Stderr r, w, _ := os.Pipe() os.Stderr = w + defer func() { os.Stderr = oldStderr }() + defer r.Close() err := formatReleaseListText(tt.releases) - w.Close() - os.Stderr = oldStderr + _ = w.Close() var buf bytes.Buffer _, _ = io.Copy(&buf, r)pkg/github/client_test.go (1)
52-69: Nice: switched to error semantics over string matching.
This aligns with the repo guideline. Nothing else to change here.
🧹 Nitpick comments (6)
cmd/version/formatters_test.go (2)
390-412: Consider strengthening version check test.The test only verifies that
isCurrentVersiondoesn't panic. Consider adding assertions to verify the actual boolean return value for known version comparisons.
226-226: Consider checking or documenting os.Pipe() errors.Multiple tests ignore the error from
os.Pipe(). While it rarely fails in practice, explicitly checking or documenting why it's safe to ignore would follow defensive coding practices.Example pattern:
r, w, err := os.Pipe() require.NoError(t, err, "os.Pipe should not fail")Also applies to: 251-251, 325-325, 500-500, 532-532, 563-563
pkg/github/releases_test.go (2)
19-33: Drop string fallback once prod normalizes errors; rely on errors.Is only.After normalizing GetLatestRelease to use handleGitHubAPIError, this helper can be simplified to strict type checks.
-func isRateLimitError(err error) bool { - if err == nil { - return false - } - // Check for our wrapped error type first. - if errors.Is(err, errUtils.ErrGitHubRateLimitExceeded) { - return true - } - // Fallback to checking error message for GitHub API rate limit errors. - // This handles errors from API calls that don't use handleGitHubAPIError. - errMsg := err.Error() - return strings.Contains(errMsg, "rate limit exceeded") || - strings.Contains(errMsg, "API rate limit") -} +func isRateLimitError(err error) bool { + return errors.Is(err, errUtils.ErrGitHubRateLimitExceeded) +}
445-453: Avoid brittle fixed tag assertions.Using a pinned tag can fail as history evolves. Prefer fetching the latest tag first and then asserting GetReleaseByTag returns the same release.
- release, err := GetReleaseByTag("cloudposse", "atmos", "v1.50.0") + latest, err := GetLatestRelease("cloudposse", "atmos") + if isRateLimitError(err) { + t.Skipf("Skipping due to GitHub API rate limit: %v", err) + } + require.NoError(t, err) + require.NotEmpty(t, latest) + + release, err := GetReleaseByTag("cloudposse", "atmos", latest) if isRateLimitError(err) { t.Skipf("Skipping due to GitHub API rate limit: %v", err) } require.NoError(t, err) assert.NotNil(t, release) - assert.Equal(t, "v1.50.0", release.GetTagName()) + assert.Equal(t, latest, release.GetTagName())cmd/version/github.go (1)
11-16: Consider adding context to the interface for cancellation/timeouts.Plumb context.Context through methods to support CLI-level timeouts and cancellation.
pkg/github/releases.go (1)
15-23: Clarify options semantics in docs.Document that limit<=0 means “no limit” and negative offsets are clamped to 0 to match applyPagination.
-// ReleasesOptions contains options for fetching GitHub releases. +// ReleasesOptions contains options for fetching GitHub releases. +// Limit <= 0 means no upper bound (fetch all pages). Offset < 0 is treated as 0. type ReleasesOptions struct {
📜 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 (8)
cmd/version/formatters_test.go(1 hunks)cmd/version/github.go(1 hunks)cmd/version/list.go(1 hunks)errors/errors.go(1 hunks)pkg/github/client.go(1 hunks)pkg/github/client_test.go(1 hunks)pkg/github/releases.go(1 hunks)pkg/github/releases_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- cmd/version/list.go
- pkg/github/client.go
🧰 Additional context used
📓 Path-based instructions (7)
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/github/client_test.gopkg/github/releases_test.gopkg/github/releases.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Write behavior-focused tests (verify inputs/outputs) rather than implementation details.
Avoid tautological tests and tests of stub functions; remove always-skipped tests.
Use dependency injection to avoid hard dependencies on os.Exit or interactive/system calls in tests.
Call production code in tests; do not duplicate production logic inside tests.
Use t.Skipf with a clear reason instead of t.Skip when skipping tests.
Co-locate tests alongside implementation files (use _test.go in same package directories).
Use mockgen for interface mocks; prefer //go:generate mockgen directives in test files; do not write manual mocks.
Files:
pkg/github/client_test.gopkg/github/releases_test.gocmd/version/formatters_test.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All comments must be complete sentences ending with periods.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines, sorted alphabetically within each group; preserve existing aliases.
Wrap all returned errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; use fmt.Errorf with %w for adding context; check with errors.Is; never compare err.Error().
Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Prefer interfaces for multi-provider capabilities and generate mocks for them; use provider registry pattern.
Ensure cross-platform compatibility: use stdlib (filepath, os.PathSeparator), avoid platform-specific binaries when SDKs exist, and guard OS-specific logic with runtime.GOOS.
Files:
pkg/github/client_test.gopkg/github/releases_test.gocmd/version/github.gocmd/version/formatters_test.gopkg/github/releases.goerrors/errors.go
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use embedded markdown for cobra command Long/Examples via //go:embed and render with utils.PrintfMarkdown().
Telemetry is captured automatically via RootCmd.ExecuteC; for non-standard paths call telemetry.CaptureCmd/CaptureCmdString explicitly.
Files:
cmd/version/github.gocmd/version/formatters_test.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()at the start of all public and critical private functions, followed by a blank line.
Files:
cmd/version/github.gopkg/github/releases.goerrors/errors.go
cmd/**
📄 CodeRabbit inference engine (CLAUDE.md)
One command per file in cmd/; keep files small and focused.
Files:
cmd/version/github.gocmd/version/formatters_test.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use cmd.NewTestKit(t) in all tests touching RootCmd (Execute, SetArgs, or commands using RootCmd), including subtests.
Files:
cmd/version/formatters_test.go
🧠 Learnings (1)
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/formatters_test.go
🧬 Code graph analysis (4)
pkg/github/client_test.go (1)
errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
pkg/github/releases_test.go (3)
errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)tests/preconditions.go (1)
RequireGitHubAccess(207-231)pkg/github/releases.go (5)
GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleases(49-99)GetReleaseByTag(195-209)GetLatestReleaseInfo(212-226)
cmd/version/github.go (1)
pkg/github/releases.go (5)
GetReleases(49-99)GetLatestRelease(26-46)ReleasesOptions(16-23)GetReleaseByTag(195-209)GetLatestReleaseInfo(212-226)
pkg/github/releases.go (3)
pkg/perf/perf.go (1)
Track(121-138)pkg/logger/log.go (1)
Debug(24-26)errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: website-deploy-preview
- GitHub Check: Lint (golangci)
- GitHub Check: Analyze (go)
- GitHub Check: Run pre-commit hooks
- GitHub Check: Summary
🔇 Additional comments (5)
cmd/version/formatters_test.go (4)
3-51: Imports and markdown tests look solid.The import organization follows Go conventions, and the table-driven test for
renderMarkdownInlinecovers the expected cases well.
53-117: Platform filtering tests are well structured.Good use of
runtime.GOOSandruntime.GOARCHto make tests platform-aware, and the coverage includes edge cases like Windows variants.
119-194: Table and structured format tests look good.These tests appropriately use the
captureStdouthelper and verify expected fields in the output.
440-496: Heading extraction tests are thorough.Comprehensive coverage of different markdown heading formats and edge cases.
cmd/version/github.go (1)
29-49: Add perf.Track to exported methods.Keep perf consistent with pkg APIs and profiling guidance.
+import ( + "time" + + go_github "github.com/google/go-github/v59/github" + + cpgithub "github.com/cloudposse/atmos/pkg/github" + "github.com/cloudposse/atmos/pkg/perf" +) @@ func (c *RealGitHubClient) GetReleases(owner, repo string, opts ReleaseOptions) ([]*go_github.RepositoryRelease, error) { - return cpgithub.GetReleases(cpgithub.ReleasesOptions{ + defer perf.Track(nil, "version.RealGitHubClient.GetReleases")() + return cpgithub.GetReleases(cpgithub.ReleasesOptions{ @@ func (c *RealGitHubClient) GetRelease(owner, repo, tag string) (*go_github.RepositoryRelease, error) { - return cpgithub.GetReleaseByTag(owner, repo, tag) + defer perf.Track(nil, "version.RealGitHubClient.GetRelease")() + return cpgithub.GetReleaseByTag(owner, repo, tag) } @@ func (c *RealGitHubClient) GetLatestRelease(owner, repo string) (*go_github.RepositoryRelease, error) { - return cpgithub.GetLatestReleaseInfo(owner, repo) + defer perf.Track(nil, "version.RealGitHubClient.GetLatestRelease")() + return cpgithub.GetLatestReleaseInfo(owner, repo) }⛔ Skipped due to learnings
Learnt from: CR PR: cloudposse/atmos#0 File: CLAUDE.md:0-0 Timestamp: 2025-10-19T19:05:16.583Z Learning: Applies to **/!(*_test).go : Add `defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()` at the start of all public and critical private functions, followed by a blank line.Learnt from: osterman PR: cloudposse/atmos#1599 File: pkg/ui/markdown/renderer.go:247-259 Timestamp: 2025-10-11T19:06:16.131Z Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.Learnt from: osterman PR: cloudposse/atmos#1599 File: pkg/ui/markdown/renderer.go:143-182 Timestamp: 2025-10-11T19:12:23.475Z Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (2)
pkg/github/releases.go (2)
172-188: Pagination clamp looks solid.Negative offsets clamped, and limit<=0 treated as unbounded. This aligns with prior feedback.
35-39: Consistent API error normalization.Using handleGitHubAPIError with the response is correct and consistent with other funcs.
🧹 Nitpick comments (5)
cmd/version/formatters_test.go (1)
415-439: Non-deterministic test with weak assertion.The test admits the length "might vary based on actual current version" and uses
GreaterOrEqual, which doesn't verify specific behavior. Consider mocking the version or asserting specific properties of the result.Example improvement:
func TestAddCurrentVersionIfMissing(t *testing.T) { publishedAt := time.Date(2025, 1, 15, 10, 30, 0, 0, time.UTC) tests := []struct { name string releases []*github.RepositoryRelease checkContains string }{ { name: "does not duplicate if already present", releases: []*github.RepositoryRelease{ {TagName: github.String(version.Version), PublishedAt: &github.Timestamp{Time: publishedAt}}, }, checkContains: version.Version, }, { name: "adds current version when missing", releases: []*github.RepositoryRelease{}, checkContains: version.Version, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := addCurrentVersionIfMissing(tt.releases) found := false for _, r := range result { if r.GetTagName() == tt.checkContains { found = true break } } assert.True(t, found, "Expected to find version %s", tt.checkContains) }) } }pkg/github/releases.go (4)
52-58: Improve traceability and error context in GetReleases.
- Add since to the debug log.
- Wrap the returned error with context per guidelines.
log.Debug("Fetching releases from GitHub API", logFieldOwner, opts.Owner, logFieldRepo, opts.Repo, "limit", opts.Limit, "offset", opts.Offset, - "includePrereleases", opts.IncludePrereleases, + "includePrereleases", opts.IncludePrereleases, + "since", opts.Since, )allReleases, err := fetchAllReleases(ctx, client, opts) if err != nil { - return nil, err + return nil, fmt.Errorf("github.GetReleases: fetchAllReleases %s/%s: %w", opts.Owner, opts.Repo, err) }Also applies to: 88-91
106-107: Preallocate slice capacity for fewer reallocations.Tiny perf win when limit>0; falls back to one page otherwise.
-startPage := (opts.Offset / githubAPIMaxPerPage) + 1 -allReleases := make([]*github.RepositoryRelease, 0) +startPage := (opts.Offset / githubAPIMaxPerPage) + 1 +capHint := opts.Limit +if capHint <= 0 { + capHint = githubAPIMaxPerPage +} +allReleases := make([]*github.RepositoryRelease, 0, capHint)
25-46: Prefer context‑aware public APIs (add WithContext variants).Expose ctx on exported functions for cancellation and deadlines. Keep current funcs as thin wrappers to avoid breaking callers.
Example additions (new functions):
// Context-aware variants. func GetLatestReleaseWithContext(ctx context.Context, owner, repo string) (string, error) { /* move body here */ } func GetReleasesWithContext(ctx context.Context, opts ReleasesOptions) ([]*github.RepositoryRelease, error) { /* move body here */ } func GetReleaseByTagWithContext(ctx context.Context, owner, repo, tag string) (*github.RepositoryRelease, error) { /* move body here */ } func GetLatestReleaseInfoWithContext(ctx context.Context, owner, repo string) (*github.RepositoryRelease, error) { /* move body here */ } // Back-compat wrappers. func GetLatestRelease(owner, repo string) (string, error) { return GetLatestReleaseWithContext(context.Background(), owner, repo) } func GetReleases(opts ReleasesOptions) ([]*github.RepositoryRelease, error) { return GetReleasesWithContext(context.Background(), opts) } func GetReleaseByTag(owner, repo, tag string) (*github.RepositoryRelease, error) { return GetReleaseByTagWithContext(context.Background(), owner, repo, tag) } func GetLatestReleaseInfo(owner, repo string) (*github.RepositoryRelease, error) { return GetLatestReleaseInfoWithContext(context.Background(), owner, repo) }Alternatively, switch signatures now if call sites are contained.
Also applies to: 48-99, 190-205, 207-222
122-129: Early-stop optimization is valid; add when releases page is fully older than Since.The releases endpoint returns newest-first (sorted by created_at in descending order), so the suggested optimization is sound. Once you encounter a release older than
Since, all subsequent pages will also be older, making early termination safe.allReleases = append(allReleases, releases...) + // Optional early stop when everything on this page is older than 'since'. + if opts.Since != nil && len(releases) > 0 { + if last := releases[len(releases)-1]; last != nil { + if last.GetPublishedAt().Time.Before(*opts.Since) { + break + } + } + } + // Stop early only when a positive limit is satisfied. if opts.Limit > 0 && len(allReleases) >= opts.Offset+opts.Limit { break }
📜 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 (4)
cmd/version/formatters_test.go(1 hunks)cmd/version/list.go(1 hunks)cmd/version/show.go(1 hunks)pkg/github/releases.go(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use embedded markdown for cobra command Long/Examples via //go:embed and render with utils.PrintfMarkdown().
Telemetry is captured automatically via RootCmd.ExecuteC; for non-standard paths call telemetry.CaptureCmd/CaptureCmdString explicitly.
Files:
cmd/version/list.gocmd/version/formatters_test.gocmd/version/show.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All comments must be complete sentences ending with periods.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines, sorted alphabetically within each group; preserve existing aliases.
Wrap all returned errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; use fmt.Errorf with %w for adding context; check with errors.Is; never compare err.Error().
Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Prefer interfaces for multi-provider capabilities and generate mocks for them; use provider registry pattern.
Ensure cross-platform compatibility: use stdlib (filepath, os.PathSeparator), avoid platform-specific binaries when SDKs exist, and guard OS-specific logic with runtime.GOOS.
Files:
cmd/version/list.gocmd/version/formatters_test.gopkg/github/releases.gocmd/version/show.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()at the start of all public and critical private functions, followed by a blank line.
Files:
cmd/version/list.gopkg/github/releases.gocmd/version/show.go
cmd/**
📄 CodeRabbit inference engine (CLAUDE.md)
One command per file in cmd/; keep files small and focused.
Files:
cmd/version/list.gocmd/version/formatters_test.gocmd/version/show.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Write behavior-focused tests (verify inputs/outputs) rather than implementation details.
Avoid tautological tests and tests of stub functions; remove always-skipped tests.
Use dependency injection to avoid hard dependencies on os.Exit or interactive/system calls in tests.
Call production code in tests; do not duplicate production logic inside tests.
Use t.Skipf with a clear reason instead of t.Skip when skipping tests.
Co-locate tests alongside implementation files (use _test.go in same package directories).
Use mockgen for interface mocks; prefer //go:generate mockgen directives in test files; do not write manual mocks.
Files:
cmd/version/formatters_test.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use cmd.NewTestKit(t) in all tests touching RootCmd (Execute, SetArgs, or commands using RootCmd), including subtests.
Files:
cmd/version/formatters_test.go
pkg/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Place business logic in pkg rather than in cmd
Files:
pkg/github/releases.go
🧠 Learnings (3)
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/!(*_test).go : Add `defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()` at the start of all public and critical private functions, followed by a blank line.
Applied to files:
cmd/version/list.gocmd/version/show.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
Applied to files:
cmd/version/list.go
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/formatters_test.go
🧬 Code graph analysis (3)
cmd/version/list.go (4)
cmd/version/github.go (3)
GitHubClient(12-16)ReleaseOptions(19-24)RealGitHubClient(27-27)pkg/github/releases.go (1)
GetReleases(49-99)errors/errors.go (5)
ErrSpinnerReturnedNilModel(50-50)ErrSpinnerUnexpectedModelType(51-51)ErrInvalidLimit(46-46)ErrInvalidOffset(47-47)ErrUnsupportedOutputFormat(48-48)pkg/perf/perf.go (1)
Track(121-138)
pkg/github/releases.go (3)
pkg/perf/perf.go (1)
Track(121-138)pkg/logger/log.go (1)
Debug(24-26)errors/errors.go (1)
ErrGitHubRateLimitExceeded(45-45)
cmd/version/show.go (3)
cmd/version/github.go (2)
GitHubClient(12-16)RealGitHubClient(27-27)pkg/perf/perf.go (1)
Track(121-138)errors/errors.go (3)
ErrSpinnerReturnedNilModel(50-50)ErrSpinnerUnexpectedModelType(51-51)ErrUnsupportedOutputFormat(48-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build (ubuntu-latest, linux)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Analyze (go)
- GitHub Check: Lint (golangci)
- GitHub Check: website-deploy-preview
- GitHub Check: Summary
🔇 Additional comments (5)
cmd/version/show.go (1)
1-171: Implementation looks solid.All past review feedback has been addressed: perf tracking is in place for both RunE and the fetch helper, TTY detection uses stderr, spinner output goes to stderr, type assertions are safe, and errors are properly wrapped. The code follows the guidelines and maintains consistency with the command patterns.
cmd/version/formatters_test.go (4)
246-265: Cleanup pattern correctly implemented.The
captureStdouthelper now properly uses defer to restore stdout and close pipe FDs even on test failure. Well done addressing the previous feedback.
305-341: Cleanup pattern correctly implemented.Proper use of defer ensures
os.Stderris restored and pipe FDs are closed even on failure. Good fix.
498-518: Cleanup pattern correctly implemented.Proper use of defer ensures cleanup happens even on failure. Good fix.
551-578: Cleanup pattern correctly implemented.Proper use of defer for resource cleanup. Good fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
cmd/version/list.go (3)
171-180: Accept “yml” alias and add shell completion for --format.Small UX win: support yml and guide users with completions.
Apply these diffs:
@@ switch strings.ToLower(listFormat) { case "text": return formatReleaseListText(releases) case "json": return formatReleaseListJSON(releases) - case "yaml": + case "yaml", "yml": return formatReleaseListYAML(releases)@@ func init() { @@ listCmd.Flags().StringVar(&listFormat, "format", "text", "Output format: text, json, yaml") + // Shell completion for --format. + _ = listCmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"text", "json", "yaml", "yml"}, cobra.ShellCompDirectiveNoFileComp + }) + versionCmd.AddCommand(listCmd) }Also applies to: 184-192
128-133: Render help via embedded markdown for Long/Examples.You already embed markdown for examples. Consider setting Long to embedded markdown and/or rendering help with utils.PrintfMarkdown() for consistent formatting across commands. This aligns with cmd guidelines.
As per coding guidelines.
185-189: Clarify UTC semantics in --since help.time.Parse without location yields UTC. Add “(UTC)” to avoid confusion across time zones.
Apply this diff:
- listCmd.Flags().StringVar(&listSince, "since", "", "Only show releases published after this date (ISO 8601 format: YYYY-MM-DD)") + listCmd.Flags().StringVar(&listSince, "since", "", "Only show releases published after this date (ISO 8601 format: YYYY-MM-DD, interpreted in UTC).")
📜 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 (2)
cmd/version/formatters_test.go(1 hunks)cmd/version/list.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- cmd/version/formatters_test.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
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use embedded markdown for cobra command Long/Examples via //go:embed and render with utils.PrintfMarkdown().
Telemetry is captured automatically via RootCmd.ExecuteC; for non-standard paths call telemetry.CaptureCmd/CaptureCmdString explicitly.
Files:
cmd/version/list.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All comments must be complete sentences ending with periods.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines, sorted alphabetically within each group; preserve existing aliases.
Wrap all returned errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; use fmt.Errorf with %w for adding context; check with errors.Is; never compare err.Error().
Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Prefer interfaces for multi-provider capabilities and generate mocks for them; use provider registry pattern.
Ensure cross-platform compatibility: use stdlib (filepath, os.PathSeparator), avoid platform-specific binaries when SDKs exist, and guard OS-specific logic with runtime.GOOS.
Files:
cmd/version/list.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()at the start of all public and critical private functions, followed by a blank line.
Files:
cmd/version/list.go
cmd/**
📄 CodeRabbit inference engine (CLAUDE.md)
One command per file in cmd/; keep files small and focused.
Files:
cmd/version/list.go
🧠 Learnings (2)
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/!(*_test).go : Add `defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()` at the start of all public and critical private functions, followed by a blank line.
Applied to files:
cmd/version/list.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
Applied to files:
cmd/version/list.go
🧬 Code graph analysis (1)
cmd/version/list.go (4)
cmd/version/github.go (3)
GitHubClient(12-16)ReleaseOptions(19-24)RealGitHubClient(27-27)pkg/perf/perf.go (1)
Track(121-138)pkg/github/releases.go (1)
GetReleases(49-99)errors/errors.go (5)
ErrSpinnerReturnedNilModel(50-50)ErrSpinnerUnexpectedModelType(51-51)ErrInvalidLimit(46-46)ErrInvalidOffset(47-47)ErrUnsupportedOutputFormat(48-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build (macos-latest, macos)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Lint (golangci)
- GitHub Check: Analyze (go)
- GitHub Check: website-deploy-preview
- GitHub Check: Summary
🔇 Additional comments (1)
cmd/version/list.go (1)
75-85: Nice: UI to stderr, non‑TTY fallback, and sentinel errors.Spinner output is correctly routed to stderr, non‑TTY path bypasses the spinner, and you use sentinel errors for spinner edge cases. Looks solid.
Also applies to: 100-126
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
cmd/version/show_test.go (1)
164-248: Model lifecycle tests are well-structured.The tests cover Init, View, and Update paths (success, error, default) with good state verification. The table-driven approach in
TestShowModel_Viewis clean.Consider adding an integration test that executes the full show command via
showCmd.RunEto verify end-to-end behavior, but the current unit test coverage is solid.cmd/version/list.go (4)
54-56: Don’t quit on any key; restrict to explicit quit keys.Avoid accidental termination while the spinner is running.
- case tea.KeyMsg: - return m, tea.Quit + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "q", "esc": + return m, tea.Quit + default: + return m, nil + }
96-96: Remove unnecessary nolint if not required.The block isn’t nested; consider dropping //nolint:nestif to keep lints meaningful.
- //nolint:nestif // Spinner logic requires nested conditions for TTY check. + // Spinner logic for TTY check.
83-84: Centralize owner/repo to avoid duplication.Define package constants and reuse in both calls. Reduces typos and eases future moves.
@@ const ( listDefaultLimit = 10 listMaxLimit = 100 + ghOwner = "cloudposse" + ghRepo = "atmos" ) @@ - releases, err := client.GetReleases("cloudposse", "atmos", opts) + releases, err := client.GetReleases(ghOwner, ghRepo, opts) @@ - return client.GetReleases("cloudposse", "atmos", opts) + return client.GetReleases(ghOwner, ghRepo, opts)Also applies to: 131-131, 23-26
106-111: Consider a sentinel for spinner run failures.For consistency with other spinner-related errors, wrap the Run error with a static sentinel (e.g., ErrSpinnerRunFailed).
- finalModel, err := p.Run() - if err != nil { - return nil, fmt.Errorf("spinner execution failed: %w", err) - } + finalModel, err := p.Run() + if err != nil { + return nil, fmt.Errorf("%w: %v", errUtils.ErrSpinnerRunFailed, err) + }Add sentinel (in errors/errors.go):
+// Spinner program failed to run. +ErrSpinnerRunFailed = errors.New("spinner execution failed")As per coding guidelines.
Also applies to: 112-121
📜 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 (4)
cmd/version/list.go(1 hunks)cmd/version/list_test.go(1 hunks)cmd/version/show.go(1 hunks)cmd/version/show_test.go(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- cmd/version/show.go
- cmd/version/list_test.go
🧰 Additional context used
📓 Path-based instructions (6)
cmd/**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate
cmd/**/*.go: Use embedded markdown for cobra command Long/Examples via //go:embed and render with utils.PrintfMarkdown().
Telemetry is captured automatically via RootCmd.ExecuteC; for non-standard paths call telemetry.CaptureCmd/CaptureCmdString explicitly.
Files:
cmd/version/show_test.gocmd/version/list.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios
**/*_test.go: Write behavior-focused tests (verify inputs/outputs) rather than implementation details.
Avoid tautological tests and tests of stub functions; remove always-skipped tests.
Use dependency injection to avoid hard dependencies on os.Exit or interactive/system calls in tests.
Call production code in tests; do not duplicate production logic inside tests.
Use t.Skipf with a clear reason instead of t.Skip when skipping tests.
Co-locate tests alongside implementation files (use _test.go in same package directories).
Use mockgen for interface mocks; prefer //go:generate mockgen directives in test files; do not write manual mocks.
Files:
cmd/version/show_test.go
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments
**/*.go: All comments must be complete sentences ending with periods.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines, sorted alphabetically within each group; preserve existing aliases.
Wrap all returned errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; use fmt.Errorf with %w for adding context; check with errors.Is; never compare err.Error().
Use viper.BindEnv for environment variable binding; every env var must have an ATMOS_ alternative.
Distinguish structured logging from UI output: UI prompts/status/errors to stderr; data/results to stdout; do not use logging for UI.
Most text UI must go to stderr; only data/results go to stdout. Prefer utils.PrintfMessageToTUI for UI messages.
Prefer interfaces for multi-provider capabilities and generate mocks for them; use provider registry pattern.
Ensure cross-platform compatibility: use stdlib (filepath, os.PathSeparator), avoid platform-specific binaries when SDKs exist, and guard OS-specific logic with runtime.GOOS.
Files:
cmd/version/show_test.gocmd/version/list.go
cmd/**/*_test.go
📄 CodeRabbit inference engine (CLAUDE.md)
Use cmd.NewTestKit(t) in all tests touching RootCmd (Execute, SetArgs, or commands using RootCmd), including subtests.
Files:
cmd/version/show_test.go
cmd/**
📄 CodeRabbit inference engine (CLAUDE.md)
One command per file in cmd/; keep files small and focused.
Files:
cmd/version/show_test.gocmd/version/list.go
**/!(*_test).go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Document all exported functions, types, and methods with Go doc comments
Add
defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()at the start of all public and critical private functions, followed by a blank line.
Files:
cmd/version/list.go
🧠 Learnings (3)
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests
Applied to files:
cmd/version/show_test.go
📚 Learning: 2025-10-19T19:05:16.583Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T19:05:16.583Z
Learning: Applies to **/!(*_test).go : Add `defer perf.Track(<atmosConfig or nil>, "packagename.FunctionName")()` at the start of all public and critical private functions, followed by a blank line.
Applied to files:
cmd/version/list.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.
Applied to files:
cmd/version/list.go
🧬 Code graph analysis (2)
cmd/version/show_test.go (1)
cmd/version/github.go (1)
MockGitHubClient(52-56)
cmd/version/list.go (4)
cmd/version/github.go (3)
GitHubClient(12-16)ReleaseOptions(19-24)RealGitHubClient(27-27)pkg/github/releases.go (1)
GetReleases(49-99)pkg/perf/perf.go (1)
Track(121-138)errors/errors.go (5)
ErrSpinnerReturnedNilModel(50-50)ErrSpinnerUnexpectedModelType(51-51)ErrInvalidLimit(46-46)ErrInvalidOffset(47-47)ErrUnsupportedOutputFormat(48-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build (windows-latest, windows)
- GitHub Check: Lint (golangci)
- GitHub Check: website-deploy-preview
- GitHub Check: Analyze (go)
- GitHub Check: Summary
🔇 Additional comments (9)
cmd/version/show_test.go (5)
1-10: Imports look solid.Clean import structure with appropriate testing and GitHub client dependencies.
28-90: Fetch function tests cover the bases well.Both happy and error paths are tested with proper mock usage and assertions.
92-135: fetchReleaseCmd test structure is solid.Good use of subtests to separate success and error paths, with safe type assertions and clear expectations.
137-162: Init test is reasonable for a Batch command.The comment acknowledges the limitation of testing
tea.Batchinternals. Verifying the command is callable and returns a message is a pragmatic approach for Bubbletea components.
12-26: Approved—no changes needed.These property-check tests don't execute, set args, or touch RootCmd, so
cmd.NewTestKit(t)isn't required per the guideline. The tests safely verify immutable command properties (flag defaults, Use, Short, Long, Example, RunE, Args) without state isolation concerns. No other tests in the file mutateshowCmd, so there's no cross-test pollution risk.cmd/version/list.go (4)
106-107: Good TTY-aware spinner to stderr.Using tea.WithOutput(os.Stderr) and TTY checks is correct; UI stays on stderr while data can go to stdout. Nice.
Also applies to: 104-105
176-186: Verify formatter I/O separation.Confirm that:
- formatReleaseListText/JSON/YAML write data to stdout only.
- All user-facing messages/errors go to stderr.
190-197: Bind flags to Viper (if not already bound elsewhere).To honor config/env precedence (flags > env > config), bind these flags to Viper in init or a central binder.
Example:
+// After flag definitions: +viper.BindPFlag("version.list.limit", listCmd.Flags().Lookup("limit")) +viper.BindPFlag("version.list.offset", listCmd.Flags().Lookup("offset")) +viper.BindPFlag("version.list.since", listCmd.Flags().Lookup("since")) +viper.BindPFlag("version.list.include_prereleases", listCmd.Flags().Lookup("include-prereleases")) +viper.BindPFlag("version.list.format", listCmd.Flags().Lookup("format"))As per coding guidelines.
142-150: Input validation looks good.Bounds-checks for limit and non-negative offset align with sentinels. Nice.
|
These changes were released in v1.195.0-rc.1. |
what
why
references
Summary by CodeRabbit
New Features
Authentication
Errors
Documentation
Tests
Chores