fix: Fix Aqua registry factory and add darwin_all pattern support#1948
fix: Fix Aqua registry factory and add darwin_all pattern support#1948
Conversation
…urus from 3.6.3 to 3.9.2 (#1926)
- Fix nil registry factory by injecting real Aqua registry factory - Load configured registries from atmos.yaml in NewInstaller() - Add Asset field to AquaPackage for github_release types - Support platform-specific asset patterns (e.g., darwin_all) - Add test for replicated darwin_all override pattern - Move test fixtures to proper testdata directories - Clean up unnecessary aqua config files - Refactor FindTool to reduce complexity and improve logging Co-Authored-By: Claude Haiku 4.5 <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. |
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
Remove toolchain/installer/atmos/ which was accidentally committed alongside the proper test fixture at toolchain/installer/testdata/atmos/. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRefactors toolchain into a new installer package with exported APIs and options; adds platform-specific overrides, OS/Arch replacements, multi-file and .pkg extraction; extends Aqua/Atmos registry parsing and fixtures; updates many call sites, tests, snapshots, docs, and a CI workflow comment. (34 words) Changes
Sequence Diagram(s)sequenceDiagram
participant User as CLI/User
participant CLI as atmos CLI
participant Installer as Installer
participant ConfigReg as Configured Registry (atmos.yaml)
participant LegacyReg as Legacy Registries (Aqua/Atmos)
participant Override as Platform Override Logic
participant Fetch as Downloader/Extractor
User->>CLI: atmos toolchain install owner/repo@version
CLI->>Installer: New(...) / Install(owner,repo,version)
Installer->>Installer: ParseToolSpec / FindTool
Installer->>ConfigReg: search configured registry
alt found in configured registry
ConfigReg-->>Installer: tool metadata
else not found
Installer->>LegacyReg: search legacy registries
LegacyReg-->>Installer: tool metadata or error
end
Installer->>Override: ApplyPlatformOverrides(tool)
Override-->>Installer: tool (asset/format/files/replacements)
Installer->>Installer: BuildAssetURL(tool, version)
Installer->>Fetch: download asset -> extract (zip/tar/pkg) -> extractFilesFromDir
Fetch-->>Installer: installed binary path
Installer-->>User: success / failure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (9)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used📓 Path-based instructions (2)**/*.go📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Files:
**/*_test.go📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
Files:
🧠 Learnings (24)📓 Common learnings📚 Learning: 2025-09-08T01:25:44.958ZApplied to files:
📚 Learning: 2025-09-08T01:25:44.958ZApplied to files:
📚 Learning: 2025-12-21T04:10:29.030ZApplied to files:
📚 Learning: 2025-02-21T20:56:05.539ZApplied to files:
📚 Learning: 2025-02-21T20:56:20.761ZApplied to files:
📚 Learning: 2026-01-04T00:55:21.720ZApplied to files:
📚 Learning: 2025-11-24T17:35:37.209ZApplied to files:
📚 Learning: 2025-11-10T23:23:39.771ZApplied to files:
📚 Learning: 2025-12-13T06:10:13.688ZApplied to files:
📚 Learning: 2025-11-24T17:35:37.209ZApplied to files:
📚 Learning: 2025-12-10T18:32:51.237ZApplied to files:
📚 Learning: 2026-01-04T00:55:21.720ZApplied to files:
📚 Learning: 2025-11-24T17:35:37.209ZApplied to files:
📚 Learning: 2026-01-04T00:55:21.720ZApplied to files:
📚 Learning: 2025-11-11T03:47:59.576ZApplied to files:
📚 Learning: 2025-05-30T03:21:37.197ZApplied to files:
📚 Learning: 2025-11-11T03:47:45.878ZApplied to files:
📚 Learning: 2025-05-23T19:51:47.091ZApplied to files:
📚 Learning: 2025-05-23T19:51:47.091ZApplied to files:
📚 Learning: 2025-09-08T01:25:44.958ZApplied to files:
📚 Learning: 2025-05-23T19:51:47.091ZApplied to files:
📚 Learning: 2025-05-23T19:51:47.091ZApplied to files:
📚 Learning: 2024-10-23T20:13:23.054ZApplied to files:
🧬 Code graph analysis (1)toolchain/installer/installer_test.go (1)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (15)
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 |
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Add parseOverrides() to parse platform-specific asset/format overrides in atmos inline registry (goos/goarch matching with custom asset templates) - Fix toolchain info command to show correct registry name from tool metadata instead of always showing "aqua-public" - Add debug/warning logging when loading registries from atmos.yaml to help diagnose registry configuration issues - Add comprehensive test fixture with all supported package types (github_release, http) and formats (tar.gz, zip, pkg, raw) - Add CLI test cases for toolchain help, info, registry search, and error handling - Fix lint errors in pkg/template/ast.go and pkg/utils/git_test.go Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests were using SetAtmosConfig() but then calling installer.New() which doesn't read from the config. This caused binaries to be installed to the current directory (toolchain/installer/atmos/) instead of temp directories. Fixed by: - Using WithBinDir(tempDir) when creating the installer - Using separate src/bin directories to avoid filename conflicts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add sanitize rules to replace dynamic version numbers and dates with stable placeholders (X.X.X and YYYY-MM-DD) in toolchain info tests. This prevents test failures when new tool versions are released. Affected tests: - atmos toolchain info shows atmos-inline registry - atmos toolchain info http type tool - atmos toolchain info tar.gz format tool - atmos toolchain info raw format tool - atmos toolchain info yaml output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The aqua/ folder was accidentally deleted, causing CI failures with "gofumpt: command not found" in the autofix workflow. The aqua-installer action needs aqua.yaml to know which tools to install. Restored: - aqua/aqua.yaml - Main Aqua config - aqua/imports/gofumpt.yaml - gofumpt v0.7.0 definition - aqua/aqua-checksums.json - Security checksums Added: - aqua/README.md - Documentation explaining the folder's purpose Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Important Cloud Posse Engineering Team Review RequiredThis pull request modifies files that require Cloud Posse's review. Please be patient, and a core maintainer will review your changes. To expedite this process, reach out to us on Slack in the |
1. Custom command integration tests: Rename `--verbose/-v` flag to `--detailed/-d` to avoid conflicts with the new global `--verbose` flag registered on RootCmd. 2. Regenerate CLI snapshots to include new debug logs from toolchain registry loading: - "Loading toolchain registries from atmos.yaml" - "Successfully loaded configured registry from atmos.yaml" 3. Update toolchain info snapshot for CI environment (no versions installed). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The verbose->detailed flag rename is being handled in a separate branch: osterman/fix-custom-cmd-flag-conflict Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Remove TestCustomCommandIntegration_BooleanFlagDefaults and TestCustomCommandIntegration_BooleanFlagTemplatePatterns tests that use --verbose flag which conflicts with global --verbose flag. (Being handled in osterman/fix-custom-cmd-flag-conflict branch) 2. Add ignore_trailing_whitespace to toolchain info test - lipgloss table padding varies by platform/terminal width 3. Add platform sanitization (darwin/linux_arm64/amd64 -> linux_amd64) to toolchain info yaml output test 4. Regenerate toolchain snapshots with proper sanitization Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
website/docs/cli/commands/toolchain/usage.mdx (3)
193-207: Doc-structure: add an explicit “Usage” section heading to satisfy website/docs CLI doc requirements.
This page has the required frontmatter/Intro/Screengrab and<dl>sections, but it’s missing an explicit## Usagesection (per repo guidelines forwebsite/docs/cli/commands/**/*.mdx).Proposed outline insertion
## Quick Start + +## Usage + +```bash +atmos toolchain <subcommand> [args] +```
688-697: Cache path example looks out of date vs XDG behavior — update the snippet.
The tree shows~/.cache/atmos/toolchain/, but the toolchain cache moved to XDG locations (${XDG_CACHE_HOME}/atmos-toolchainwith~/.cache/atmos-toolchainfallback). Based on learnings, this doc snippet should be updated so users can actually find/clean caches.Proposed doc tweak
-~/.cache/atmos/toolchain/ +${XDG_CACHE_HOME:-~/.cache}/atmos-toolchain/ ├── registries/ # Cached registry YAML files ├── downloads/ # Downloaded tool archives └── temp/ # Temporary extraction directory
90-96: Clarify that.pkgsupport extracts payloads only (no installer scripts).Line 94 reads "macOS installer packages" which could be misunderstood as full package installation. The implementation only extracts payloads using
pkgutil --expand-fulland requires macOS. Suggest:- `.pkg` - macOS installer packages (uses `pkgutil --expand-full`) + `.pkg` - macOS installer packages (payload extraction only; uses `pkgutil --expand-full`)toolchain/registry/atmos/atmos.go (2)
54-76: Normalize the tool map key (current code can make valid tools “not found”).
parseToolID()trims whitespace, butparseToolDefinitions()stores the tool under the originaltoolIDstring, whileGetTool()looks upowner/repo. If the config key contains whitespace (or other normalization differences), parsing succeeds but lookup fails.Proposed fix.
diff --git a/toolchain/registry/atmos/atmos.go b/toolchain/registry/atmos/atmos.go @@ for toolID, toolConfigRaw := range toolsConfig { // Parse tool identifier (owner/repo format). owner, repo, err := parseToolID(toolID) if err != nil { return nil, fmt.Errorf("invalid tool ID %q: %w", toolID, err) } + normalizedKey := fmt.Sprintf("%s/%s", owner, repo) @@ - tools[toolID] = tool + tools[normalizedKey] = tool }Also applies to: 214-218
169-208: Don’t silently ignore malformedoverrides(and consider supportingurlas an alias).Right now
parseOverrides()drops non-map entries and can append empty overrides, with no error surfaced to the user—making misconfigurations hard to spot. Also, users may reasonably writeurl(like other registry YAMLs) rather thanasset; if that’s expected, this parser should accept both.If you want to keep
parseOptionalFields()“optional”, I’d still recommend plumbing an error up from overrides parsing so broken config fails fast.One way to plumb validation without changing external behavior much.
diff --git a/toolchain/registry/atmos/atmos.go b/toolchain/registry/atmos/atmos.go @@ -func parseToolConfig(owner, repo string, config map[string]any) (*registry.Tool, error) { +func parseToolConfig(owner, repo string, config map[string]any) (*registry.Tool, error) { @@ - // Parse optional fields. - parseOptionalFields(tool, config) + // Parse optional fields. + if err := parseOptionalFields(tool, config); err != nil { + return nil, err + } return tool, nil } @@ -func parseOptionalFields(tool *registry.Tool, config map[string]any) { +func parseOptionalFields(tool *registry.Tool, config map[string]any) error { if format, ok := config["format"].(string); ok { tool.Format = format } @@ // Parse platform-specific overrides. if overridesRaw, ok := config["overrides"].([]any); ok { - tool.Overrides = parseOverrides(overridesRaw) + overrides, err := parseOverrides(overridesRaw) + if err != nil { + return err + } + tool.Overrides = overrides } + return nil } // parseOverrides parses platform-specific override configurations. -func parseOverrides(overridesRaw []any) []registry.Override { +func parseOverrides(overridesRaw []any) ([]registry.Override, error) { var overrides []registry.Override - for _, overrideRaw := range overridesRaw { + for i, overrideRaw := range overridesRaw { overrideMap, ok := overrideRaw.(map[string]any) if !ok { - continue + return nil, fmt.Errorf("%w: overrides[%d] must be a map, got %T", ErrInvalidToolConfig, i, overrideRaw) } override := registry.Override{} @@ - if asset, ok := overrideMap["asset"].(string); ok { - override.Asset = asset - } + if asset, ok := overrideMap["asset"].(string); ok && asset != "" { + override.Asset = asset + } else if url, ok := overrideMap["url"].(string); ok && url != "" { + override.Asset = url + } @@ + if override.GOOS == "" && override.GOARCH == "" && override.Asset == "" && override.Format == "" { + return nil, fmt.Errorf("%w: overrides[%d] is empty", ErrInvalidToolConfig, i) + } overrides = append(overrides, override) } - return overrides + return overrides, nil }toolchain/installer/extract.go (2)
80-96: Harden Files-based extraction: prevent path escape + avoid chmod’ing non-binaries.
extractFilesFromDirshould enforce thatfile.Srcresolves undertempDir(similar tovalidatePath/isSafePath) to avoid../escapes, and it shouldn’t mark every extracted file executable (manyFilesentries are likely config/docs). Also, relying on “first file is primary” is a hidden contract—consider validating thattool.Files[0]is intended as the primary binary (or selecting byBinaryName).Proposed diff (safe path check + chmod only primary)
func (i *Installer) extractFilesFromDir(tempDir, binaryPath string, tool *registry.Tool) error { @@ for idx, file := range tool.Files { srcPath := file.Src if srcPath == "" { srcPath = file.Name // Default src to name if not specified. } - src := filepath.Join(tempDir, srcPath) + // Ensure srcPath can't escape tempDir (e.g. via "../"). + src := filepath.Join(tempDir, srcPath) + cleanTemp := filepath.Clean(tempDir) + string(os.PathSeparator) + if !strings.HasPrefix(filepath.Clean(src), cleanTemp) { + return fmt.Errorf("%w: illegal file path in files config: %s", ErrFileOperation, srcPath) + } var dst string if idx == 0 { @@ - // Make the file executable. - if err := os.Chmod(dst, defaultMkdirPermissions); err != nil { - return fmt.Errorf("%w: failed to make file executable: %w", ErrFileOperation, err) - } + // Make only the primary binary executable; leave other files as-is. + if idx == 0 { + if err := os.Chmod(dst, defaultMkdirPermissions); err != nil { + return fmt.Errorf("%w: failed to make file executable: %w", ErrFileOperation, err) + } + } }Also applies to: 98-126, 175-226, 405-432
434-470: Add timeout/context + clearer “pkgutil missing” handling for .pkg extraction.
exec.Command("pkgutil", ...)without a timeout can hang CI/users indefinitely; also, ifpkgutilisn’t in PATH, the error could be made more actionable. Considerexec.CommandContextwith a reasonable timeout and a targeted hint whenexec.ErrNotFoundoccurs.toolchain/info_test.go (1)
287-340: Replace silent "tool not found" bypass with deterministic httptest mock.
TestInfoCommand_AquaRegistryToolstreats registry lookup failures as success via early return. This silently passes the test even when tool resolution fails due to network unavailability or missing entries, masking potential regressions.Per prior learnings and the established pattern in
toolchain/registry/aqua/aqua_test.go, inject anhttptestserver URL usingWithGitHubBaseURLto make the test deterministic and network-independent. You can pass a mockRegistryFactorytoNewInstaller(WithRegistryFactory(...))that returns anAquaRegistryconfigured with the httptest server, eliminating network flakiness and ensuring real behavior is tested.
🤖 Fix all issues with AI agents
In
@tests/snapshots/TestCLICommands_atmos_toolchain_info_non-existent_tool.stderr.golden:
- Around line 1-9: The snapshot for
TestCLICommands_atmos_toolchain_info_non-existent_tool is wrong (shows
"Incorrect Usage") and must be regenerated to reflect the actual lookup error
and hints; run the test suite for that case with the -regenerate-snapshots flag
so the golden file is re-created from the real CLI output for the command "atmos
toolchain info <tool>", confirm the CLI emits a "tool not found" / registry
lookup message with suggested hints (search registries, check network, verify
registry config), and do not manually edit the snapshot file or its contents.
In
@tests/snapshots/TestCLICommands_atmos_toolchain_info_shows_atmos-inline_registry.stderr.golden:
- Line 5: The failing snapshot for the 'Available Versions' table is out of
sync; run the test that owns the golden file
TestCLICommands_atmos_toolchain_info_shows_atmos-inline_registry with the
snapshot regeneration flag to update the file instead of editing it manually —
e.g. execute: go test ./tests/... -run
TestCLICommands_atmos_toolchain_info_shows_atmos-inline_registry
-regenerate-snapshots to regenerate
tests/snapshots/TestCLICommands_atmos_toolchain_info_shows_atmos-inline_registry.stderr.golden
so the table alignment matches the CLI output.
In @toolchain/clean_test.go:
- Around line 18-21: Update the comment to reference the actual constant
identifier: change "DefaultMkdirPermissions" in the comment to
"defaultMkdirPermissions" so the docline matches the declared constant name
(defaultMkdirPermissions) used in the file; ensure the descriptive text remains
the same and only the identifier casing is corrected.
In @toolchain/setup.go:
- Around line 14-19: Update the comments to match the actual package-scoped
constant names: change the comment text to refer to "defaultDirPermissions" (not
DefaultDirPermissions) and "versionPrefix" (not VersionPrefix) so the
documentation matches the identifiers in toolchain/set.go and toolchain/info.go;
do not change the constants' visibility or export status.
🧹 Nitpick comments (8)
website/docs/cli/commands/toolchain/usage.mdx (1)
97-112: These bullets aren’t “Template Functions” — split into “Template Functions” vs “Advanced Resolution/Extraction”.
Lines 109-111 read like capabilities (platform overrides, arch mapping, nested extraction), not template functions; mixing them makes it harder to know what’s actually callable in templates vs what the installer does..github/workflows/autofix.yml (1)
40-40: Minor: Verify the aqua.yaml path in the comment.The comment references "aqua/aqua.yaml" but the standard location for Aqua configuration is typically "aqua.yaml" in the repository root. Verify this path is accurate for your setup.
📝 Suggested correction if aqua.yaml is in root
- # gofumpt (installed via aqua from aqua/aqua.yaml) + # gofumpt (installed via aqua from aqua.yaml)pkg/template/ast.go (1)
20-24: Remove perf.Track from trivial string join.
FieldRef.String()only performsstrings.Join(f.Path, ".")- a trivial O(1) operation. Per coding guidelines, perf.Track should NOT be added to trivial getters/setters where the tracking overhead exceeds the actual operation time.♻️ Remove unnecessary perf.Track
// String returns the dot-separated path of the field reference. func (f FieldRef) String() string { - defer perf.Track(nil, "template.FieldRef.String")() - return strings.Join(f.Path, ".") }Based on coding guidelines for perf.Track exceptions.
toolchain/registry/atmos/atmos.go (1)
13-20: These error sentinels are atmos-specific—no canonical equivalents exist, but consider the registry pattern.No existing canonical errors match
ErrInvalidToolConfigorErrMissingRequiredFieldintoolchain/registry/registry.go. However, compare this against the pattern used by other registries (aqua reuses canonical errors). If these errors are specific to atmos registry validation, keeping them local is fine—just document why they diverge from the canonical pattern. If they're fundamental to registry configuration validation more broadly, consider promoting them totoolchain/registry/registry.goand re-exporting intoolchain/errors.gofor consistency with the architecture shown in the learning materials.toolchain/info_test.go (1)
12-30: Good shift to exercising public APIs (ParseToolSpec/FindTool); tighten test isolation.
Swapping toinstaller.ParseToolSpec/installer.FindToolis the right direction for coverage of the exported surface. Consider settingSetAtmosConfig(&schema.AtmosConfiguration{})consistently in tests that constructNewInstaller()to avoid any coupling to package-global config state.Also applies to: 32-49, 51-68, 124-148, 191-199
tests/test-cases/toolchain.yaml (1)
1-224: Verify these snapshots are fully offline/deterministic (avoid GitHub/Aqua lookups during CI).
The sanitizers help, but iftoolchain info/registry searchtriggers network calls in some environments, these will still be flaky. If any path is remote-dependent, consider adding a fixture-backed mock endpoint (or explicit skip/gating) so CI doesn’t depend on outbound access.toolchain/installer/override_test.go (1)
1-321: Override tests look solid and align with “first match wins”.
Table-driven coverage of exact/wildcard mismatches plusApplyPlatformOverridesbehavior is on point. Optional: addt.Parallel()where safe to speed up the package test suite.toolchain/installer/installer_test.go (1)
316-340: Consider using testify assertions consistently.This test uses manual
t.Errorfwhile other tests in this file useassert/require. Minor consistency nit.♻️ Optional: Use testify assertions for consistency
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { owner, repo, err := installer.GetResolver().Resolve(tt.toolName) if tt.wantErr { - if err == nil { - t.Errorf("resolveToolName() expected error but got none") - } + assert.Error(t, err, "resolveToolName() expected error") return } - if err != nil { - t.Errorf("resolveToolName() unexpected error: %v", err) - return - } - - if owner != tt.wantOwner { - t.Errorf("resolveToolName() owner = %v, want %v", owner, tt.wantOwner) - } - - if repo != tt.wantRepo { - t.Errorf("resolveToolName() repo = %v, want %v", repo, tt.wantRepo) - } + require.NoError(t, err) + assert.Equal(t, tt.wantOwner, owner) + assert.Equal(t, tt.wantRepo, repo) }) }
tests/snapshots/TestCLICommands_atmos_toolchain_info_non-existent_tool.stderr.golden
Outdated
Show resolved
Hide resolved
tests/snapshots/TestCLICommands_atmos_toolchain_info_shows_atmos-inline_registry.stderr.golden
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
toolchain/registry/registry.go (1)
260-271: Consider consolidating AquaOverride with Override.Both
AquaOverrideandOverridehave nearly identical fields. The only difference isAquaOverrideincludes aURLfield.This duplication may lead to drift over time. Consider either:
- Embedding
OverrideinAquaOverrideand adding theURLfield.- Adding
URLtoOverrideif it's generally applicable.If the separation is intentional for strict Aqua format parsing, the current approach is acceptable—just worth noting for future maintenance.
toolchain/types.go (1)
51-84: NewInstaller logic is sound, with one suggestion.The function correctly:
- Derives
binDirfrom config.- Injects
realRegistryFactoryas default.- Loads configured registries from
atmos.yaml.- Allows user options to override base options.
One minor point: the error from
NewRegistryis logged but swallowed. This is reasonable for graceful degradation, but consider whether a debug log of the specific error would help troubleshooting.💡 Optional: Include error details in debug log
if reg, err := NewRegistry(config); err != nil { - log.Warn("Failed to load configured registry from atmos.yaml", "error", err) + log.Warn("Failed to load configured registry from atmos.yaml", + "error", err, + "registryCount", len(config.Toolchain.Registries))
📜 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)
toolchain/registry/registry.gotoolchain/types.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context usingfmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: usegofmtandgoimportsto format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging
**/*.go: All comments must end with periods (enforced bygodotlinter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg,log,u,errUtils)
All errors MUST be wrapped using static errors defined inerrors/errors.go- useerrors.Joinfor combining errors,fmt.Errorfwith%wfor context, anderrors.Is()for error checking
Never manually create mocks - usego.uber.org/mock/mockgenwith//go:generatedirectives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use//revive:disable:file-length-limit
Use colors frompkg/ui/theme/colors.gofor all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, usefilepath.Join()instead of h...
Files:
toolchain/types.gotoolchain/registry/registry.go
🧠 Learnings (19)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).
Applied to files:
toolchain/types.gotoolchain/registry/registry.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).
Applied to files:
toolchain/types.gotoolchain/registry/registry.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
Applied to files:
toolchain/types.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : Never manually create mocks - use `go.uber.org/mock/mockgen` with `//go:generate` directives in Go code
Applied to files:
toolchain/types.gotoolchain/registry/registry.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with `go.uber.org/mock/mockgen`, use table-driven tests, target >80% coverage
Applied to files:
toolchain/types.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
Applied to files:
toolchain/types.go
📚 Learning: 2024-11-23T00:13:22.004Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 801
File: examples/quick-start-advanced/Dockerfile:9-9
Timestamp: 2024-11-23T00:13:22.004Z
Learning: When updating the `ATMOS_VERSION` in Dockerfiles, the team prefers to pin to the next future version when the PR merges, even if the version is not yet released.
Applied to files:
toolchain/types.go
📚 Learning: 2025-07-05T20:59:02.914Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1363
File: internal/exec/template_utils.go:18-18
Timestamp: 2025-07-05T20:59:02.914Z
Learning: In the Atmos project, gomplate v4 is imported with a blank import (`_ "github.com/hairyhenderson/gomplate/v4"`) alongside v3 imports to resolve AWS SDK version conflicts. V3 uses older AWS SDK versions that conflict with newer AWS modules used by Atmos. A full migration to v4 requires extensive refactoring due to API changes and should be handled in a separate PR.
Applied to files:
toolchain/types.go
📚 Learning: 2025-12-13T06:10:13.688Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.
Applied to files:
toolchain/types.go
📚 Learning: 2025-01-08T19:01:56.978Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 899
File: examples/tests/test-vendor/vendor.yaml:39-43
Timestamp: 2025-01-08T19:01:56.978Z
Learning: In example code and test fixtures, using 'latest' version tag is acceptable as it's for demonstration purposes only. This is different from production code where specific version pinning is recommended.
Applied to files:
toolchain/types.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to {go.mod,go.sum} : Manage dependencies with Go modules and keep dependencies up to date while minimizing external dependencies
Applied to files:
toolchain/types.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.
Applied to files:
toolchain/types.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*.go : All comments must end with periods (enforced by `godot` linter) in Go code
Applied to files:
toolchain/types.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Document complex logic with inline comments in Go code
Applied to files:
toolchain/types.go
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.
Applied to files:
toolchain/types.gotoolchain/registry/registry.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Follow multi-provider registry pattern: define interface, implement per provider, register implementations, generate mocks - see `pkg/store/` example
Applied to files:
toolchain/types.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration.
Applied to files:
toolchain/types.gotoolchain/registry/registry.go
📚 Learning: 2025-09-29T02:20:11.636Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1540
File: internal/exec/validate_component.go:117-118
Timestamp: 2025-09-29T02:20:11.636Z
Learning: The ValidateComponent function in internal/exec/validate_component.go had its componentSection parameter type refined from `any` to `map[string]any` without adding new parameters. This is a type safety improvement, not a signature change requiring call site updates.
Applied to files:
toolchain/registry/registry.go
🧬 Code graph analysis (2)
toolchain/types.go (4)
toolchain/installer/installer.go (13)
Installer(98-107)ToolResolver(44-46)DefaultToolResolver(55-57)RegistryFactory(110-112)Option(115-115)WithBinDir(118-124)WithRegistryFactory(155-161)WithConfiguredRegistry(145-152)New(174-208)NewInstallerWithResolver(212-219)WithResolver(136-142)WithCacheDir(127-133)BuiltinAliases(50-52)toolchain/registry/aqua/aqua.go (1)
NewAquaRegistry(84-113)toolchain/registry/registry.go (1)
ToolRegistry(64-88)toolchain/setup.go (2)
GetInstallPath(56-81)GetAtmosConfig(37-41)
toolchain/registry/registry.go (1)
toolchain/types.go (1)
File(20-20)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Summary
🔇 Additional comments (10)
toolchain/registry/registry.go (3)
59-60: LGTM on mockgen directive.Correctly uses
go.uber.org/mock/mockgen@v0.6.0withgo:generateper coding guidelines. Output destination and package are appropriate for test usage.
213-219: Override struct expansion looks solid.Added
FormatandReplacementsfields to support platform-specific format overrides and OS/Arch string mappings. YAML tags are consistent with the rest of the codebase.
239-251: AquaPackage enhancements are well-documented.The new
Asset,Files,Overrides, andReplacementsfields align with Aqua registry semantics. Inline comments clarify each field's purpose.toolchain/types.go (7)
3-4: Mockgen directive is correct.Uses pinned version and follows the established pattern. Generates mock for
ToolRegistryinterface into test file.
5-13: Import organization follows guidelines.Three groups properly separated: stdlib (
path/filepath), third-party (charmbracelet/log), and atmos packages. Sorted alphabetically within groups.
24-39: Type aliases maintain backward compatibility.Clean approach for exposing
installerpackage types while allowing existing code to continue usingtoolchainimports.
41-49: realRegistryFactory injection resolves the nil registry issue.This addresses the PR objective of fixing the broken registry lookups. The factory delegates to
NewAquaRegistry()which properly constructs the registry with all dependencies.
86-96: Deprecation handled correctly.Delegates to
NewInstallerensuring therealRegistryFactoryinjection happens. The deprecation comment guides users to the preferred approach.
98-131: Option wrappers are consistent.Each wrapper includes
perf.Trackand delegates to the correspondinginstallerfunction. This maintains observability while providing backward compatibility.
133-142: BuiltinAliases and NewInstallerWithBinDir look good.
BuiltinAliasesre-export is clean.NewInstallerWithBinDiris a sensible convenience wrapper for testing.
|
@coderabbitai full review please |
|
@aknysh, I'll perform a full review of all the changes in this PR. 🧠 Learnings used✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
toolchain/installer/installer_test.go (1)
621-647: This test needs proper registry mocking—it's hitting external services without isolation.
FindToolwithout configuration defaults to real external registries (GitHub, HashiCorp releases), making the test non-deterministic. The skip handles missing tools gracefully, but doesn't prevent flakiness from registry behavior changes or network issues.The codebase already has
mockToolResolverinTestNewInstaller—use a similar pattern to inject a mock registry factory intoNew()or provide a way to override the registry configuration for testing. This aligns with howAquaRegistrytests should use dependency injection (WithGitHubBaseURL patterns) to make tests deterministic and reliable.
🧹 Nitpick comments (4)
toolchain/installer/installer_test.go (3)
94-118: Consider using testify assertions for consistency.This test uses manual
t.Errorfchecks while the rest of the file uses testify. Mixing styles can make the codebase harder to maintain.Optional refactor to use testify
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { owner, repo, err := installer.ParseToolSpec(tt.tool) if tt.wantErr { - if err == nil { - t.Errorf("parseToolSpec() expected error but got none") - } + assert.Error(t, err, "parseToolSpec() expected error") return } - if err != nil { - t.Errorf("parseToolSpec() unexpected error: %v", err) - return - } - - if owner != tt.wantOwner { - t.Errorf("parseToolSpec() owner = %v, want %v", owner, tt.wantOwner) - } - - if repo != tt.wantRepo { - t.Errorf("parseToolSpec() repo = %v, want %v", repo, tt.wantRepo) - } + require.NoError(t, err) + assert.Equal(t, tt.wantOwner, owner) + assert.Equal(t, tt.wantRepo, repo) }) }
203-247: Test bypasses the New() constructor.This test creates an
Installerstruct directly instead of usingNew()orNewInstallerWithResolver(). While this works for testing specific fields, it doesn't exercise the actual constructor logic being tested.Suggested fix to use the constructor
func TestNewInstaller(t *testing.T) { mockResolver := &mockToolResolver{ mapping: map[string][2]string{ "terraform": {"hashicorp", "terraform"}, "opentofu": {"opentofu", "opentofu"}, "kubectl": {"kubernetes", "kubectl"}, "helm": {"helm", "helm"}, "helmfile": {"helmfile", "helmfile"}, }, } - customRegistries := []string{"mock-remote-registry", "mock-local-registry"} - installer := &Installer{ - binDir: "./.tools/bin", - registries: customRegistries, - resolver: mockResolver, - } + tmpDir := t.TempDir() + installer := New( + WithBinDir(tmpDir), + WithResolver(mockResolver), + ) - if installer.binDir != "./.tools/bin" { - t.Errorf("New() binDir = %v, want ./.tools/bin", installer.binDir) - } + assert.Equal(t, tmpDir, installer.binDir, "binDir should match") + assert.NotNil(t, installer.resolver, "resolver should be set")
315-339: Same assertion style inconsistency.Consider using testify assertions here as well for consistency with the rest of the file.
toolchain/installer/extract_test.go (1)
482-505: Invalid mode test uses negative value.Line 500 uses
Mode: -1which tests invalid mode handling. This is a good edge case, though documenting why -1 is invalid could help future readers.Add clarifying comment
t.Run("rejects invalid mode", func(t *testing.T) { tmpDir := t.TempDir() targetPath := filepath.Join(tmpDir, "newdir") + // Mode -1 is invalid as file mode bits must be non-negative. header := &tar.Header{Mode: -1} err := extractDir(targetPath, header) assert.Error(t, err) assert.ErrorIs(t, err, ErrFileOperation) })
📜 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)
tests/snapshots/TestCLICommands_atmos_toolchain_--help.stdout.goldentests/snapshots/TestCLICommands_atmos_toolchain_info_--help.stdout.goldentests/snapshots/TestCLICommands_atmos_toolchain_install_--help.stdout.goldentoolchain/installer/extract_test.gotoolchain/installer/installer_test.go
✅ Files skipped from review due to trivial changes (2)
- tests/snapshots/TestCLICommands_atmos_toolchain_info_--help.stdout.golden
- tests/snapshots/TestCLICommands_atmos_toolchain_--help.stdout.golden
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/snapshots/TestCLICommands_atmos_toolchain_install_--help.stdout.golden
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*.go: Use Viper for managing configuration, environment variables, and flags in CLI commands
Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
All code must pass golangci-lint checks
Follow Go's error handling idioms: use meaningful error messages, wrap errors with context usingfmt.Errorf("context: %w", err), and consider using custom error types for domain-specific errors
Follow standard Go coding style: usegofmtandgoimportsto format code, prefer short descriptive variable names, use kebab-case for command-line flags, and snake_case for environment variables
Document all exported functions, types, and methods following Go's documentation conventions
Document complex logic with inline comments in Go code
Support configuration via files, environment variables, and flags following the precedence order: flags > environment variables > config file > defaults
Provide clear error messages to users, include troubleshooting hints when appropriate, and log detailed errors for debugging
**/*.go: All comments must end with periods (enforced bygodotlinter) in Go code
Organize imports into three groups separated by blank lines, sorted alphabetically: Go stdlib, 3rd-party (NOT cloudposse/atmos), then Atmos packages with maintained aliases (cfg,log,u,errUtils)
All errors MUST be wrapped using static errors defined inerrors/errors.go- useerrors.Joinfor combining errors,fmt.Errorfwith%wfor context, anderrors.Is()for error checking
Never manually create mocks - usego.uber.org/mock/mockgenwith//go:generatedirectives in Go code
Keep files small and focused - under 600 lines with one cmd/impl per file, co-locate tests, never use//revive:disable:file-length-limit
Use colors frompkg/ui/theme/colors.gofor all UI theming in Go code
Code must be compatible with Linux, macOS, and Windows - use SDKs over binaries, usefilepath.Join()instead of h...
Files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
**/*_test.go
📄 CodeRabbit inference engine (.cursor/rules/atmos-rules.mdc)
**/*_test.go: Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Use table-driven tests for testing multiple scenarios in Go
Include integration tests for command flows and test CLI end-to-end when possible with test fixturesPrefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with
go.uber.org/mock/mockgen, use table-driven tests, target >80% coverage
Files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
🧠 Learnings (28)
📓 Common learnings
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).
Learnt from: Listener430
Repo: cloudposse/atmos PR: 934
File: tests/fixtures/scenarios/docs-generate/README.md.gotmpl:99-118
Timestamp: 2025-01-25T03:51:57.689Z
Learning: For the cloudposse/atmos repository, changes to template contents should be handled in dedicated PRs and are typically considered out of scope for PRs focused on other objectives.
Learnt from: aknysh
Repo: cloudposse/atmos PR: 944
File: go.mod:206-206
Timestamp: 2025-01-17T00:18:57.769Z
Learning: For indirect dependencies with license compliance issues in the cloudposse/atmos repository, the team prefers to handle them in follow-up PRs rather than blocking the current changes, as these issues often require deeper investigation of the dependency tree.
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain has been updated to follow XDG Base Directory Specification with helper functions GetXDGCacheDir() and GetXDGTempCacheDir() in toolchain/xdg_cache.go, using XDG_CACHE_HOME when set and falling back to ~/.cache/atmos-toolchain, making it consistent with atmos core's XDG compliance.
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Every new feature must include comprehensive unit tests targeting >80% code coverage for all packages
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: The atmos toolchain XDG compliance implementation is complete with GetXDGCacheDir() and GetXDGTempCacheDir() functions in toolchain/xdg_cache.go, updated installer.go and toolchain_clean.go to use these helpers, and changed cache paths from ~/.cache/tools-cache to ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain when XDG_CACHE_HOME is not set).
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Include integration tests for command flows and test CLI end-to-end when possible with test fixtures
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: XDG Base Directory Specification compliance implementation for atmos toolchain is complete: created toolchain/xdg_cache.go with GetXDGCacheDir() and GetXDGTempCacheDir() functions, updated toolchain/installer.go and cmd/toolchain_clean.go to use these XDG helpers, and changed all cache paths from hardcoded ~/.cache/tools-cache to XDG-compliant ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback).
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to **/*_test.go : Prefer unit tests with mocks over integration tests - use interfaces and dependency injection for testability, generate mocks with `go.uber.org/mock/mockgen`, use table-driven tests, target >80% coverage
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2024-10-23T20:13:23.054Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 731
File: pkg/utils/file_utils.go:198-202
Timestamp: 2024-10-23T20:13:23.054Z
Learning: In `pkg/utils/file_utils.go`, the current implementation of the `IsURL` function is considered sufficient; avoid suggesting more complex URL validation in future reviews.
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2024-12-02T21:26:32.337Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 808
File: pkg/config/config.go:478-483
Timestamp: 2024-12-02T21:26:32.337Z
Learning: In the 'atmos' project, when reviewing Go code like `pkg/config/config.go`, avoid suggesting file size checks after downloading remote configs if such checks aren't implemented elsewhere in the codebase.
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2025-12-13T06:10:13.688Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: errors/errors.go:184-203
Timestamp: 2025-12-13T06:10:13.688Z
Learning: cloudposse/atmos: For toolchain work, duplicate/unused error sentinels in errors/errors.go should be cleaned up in a separate refactor PR and not block feature PRs; canonical toolchain sentinels live under toolchain/registry with re-exports in toolchain/errors.go.
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-04-04T02:03:23.676Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1185
File: internal/exec/yaml_func_store.go:26-26
Timestamp: 2025-04-04T02:03:23.676Z
Learning: The Atmos codebase currently uses `log.Fatal` for error handling in multiple places. The maintainers are aware this isn't an ideal pattern (should only be used in main() or init() functions) and plan to address it comprehensively in a separate PR. CodeRabbit should not flag these issues or push for immediate changes until that refactoring is complete.
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
Repo: cloudposse/atmos PR: 1195
File: internal/exec/terraform_clean.go:99-99
Timestamp: 2025-04-26T15:54:10.506Z
Learning: The error variable `ErrRelPath` is defined in `internal/exec/terraform_clean_util.go` and is used across files in the `exec` package, including in `terraform_clean.go`. This is part of an approach to standardize error handling in the codebase.
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2024-10-28T01:51:30.811Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 727
File: internal/exec/terraform_clean.go:329-332
Timestamp: 2024-10-28T01:51:30.811Z
Learning: In the Atmos Go code, when deleting directories or handling file paths (e.g., in `terraform_clean.go`), always resolve the absolute path using `filepath.Abs` and use the logger `u.LogWarning` for logging messages instead of using `fmt.Printf`.
Applied to files:
toolchain/installer/extract_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: The atmos codebase has a custom extension to *testing.T that provides a Chdir method, allowing test functions to call t.Chdir() to change working directories during tests. This is used consistently across test files in the codebase.
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*_test.go : Use table-driven tests for testing multiple scenarios in Go
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-12-21T04:10:29.030Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1891
File: internal/exec/describe_affected.go:468-468
Timestamp: 2025-12-21T04:10:29.030Z
Learning: In Go, package-level declarations (constants, variables, types, and functions) are visible to all files in the same package without imports. During reviews in cloudposse/atmos (and similar Go codebases), before suggesting to declare a new identifier, first check if it already exists in another file of the same package. If it exists, you can avoid adding a new declaration; if not, proceed with a proper package-level declaration.
Applied to files:
toolchain/installer/extract_test.gotoolchain/installer/installer_test.go
📚 Learning: 2025-11-10T23:23:39.771Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/registry/aqua/aqua_test.go:417-442
Timestamp: 2025-11-10T23:23:39.771Z
Learning: In Atmos toolchain AquaRegistry, tests should not hit real GitHub. Use the options pattern via WithGitHubBaseURL to inject an httptest server URL and make GetLatestVersion/GetAvailableVersions deterministic.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-11-24T17:35:37.209Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-11-24T17:35:37.209Z
Learning: Applies to **/*.go : Use interfaces for external dependencies to facilitate mocking and consider using testify/mock for creating mock implementations
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Follow multi-provider registry pattern: define interface, implement per provider, register implementations, generate mocks - see `pkg/store/` example
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-11-11T03:47:59.576Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/which_test.go:166-223
Timestamp: 2025-11-11T03:47:59.576Z
Learning: In the cloudposse/atmos repo, tests that manipulate environment variables should use testing.T.Setenv for automatic setup/teardown instead of os.Setenv/Unsetenv.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-05-30T03:21:37.197Z
Learnt from: aknysh
Repo: cloudposse/atmos PR: 1274
File: go.mod:63-63
Timestamp: 2025-05-30T03:21:37.197Z
Learning: The redis dependency (github.com/redis/go-redis/v9) in the atmos project is only used in tests, not in production code.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-11-11T03:47:45.878Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1686
File: toolchain/add_test.go:67-77
Timestamp: 2025-11-11T03:47:45.878Z
Learning: In the cloudposse/atmos codebase, tests should prefer t.Setenv for environment variable setup/teardown instead of os.Setenv/Unsetenv to ensure test-scoped isolation.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2026-01-04T00:55:21.720Z
Learnt from: CR
Repo: cloudposse/atmos PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-04T00:55:21.720Z
Learning: Applies to cmd/**/*_test.go : Always use `cmd.NewTestKit(t)` for cmd tests to auto-clean RootCmd state
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-12-10T18:32:51.237Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1808
File: cmd/terraform/backend/backend_delete_test.go:9-23
Timestamp: 2025-12-10T18:32:51.237Z
Learning: In cmd subpackages (e.g., cmd/terraform/backend/), tests cannot use cmd.NewTestKit(t) due to Go's test visibility rules (NewTestKit is in a parent package test file). These tests only need TestKit if they execute commands through RootCmd or modify RootCmd state. Structural tests that only verify command structure/flags without touching RootCmd don't require TestKit cleanup.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests. This is implemented through custom testing framework extensions and is used consistently throughout the test suite.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-09-08T01:25:44.958Z
Learnt from: osterman
Repo: cloudposse/atmos PR: 1466
File: website/docs/cli/commands/toolchain/usage.mdx:117-121
Timestamp: 2025-09-08T01:25:44.958Z
Learning: Final XDG Base Directory Specification implementation for atmos toolchain is complete and verified: toolchain/xdg_cache.go provides GetXDGCacheDir() and GetXDGTempCacheDir() functions, all hardcoded ~/.cache/tools-cache paths have been replaced with XDG-compliant paths using ${XDG_CACHE_HOME}/atmos-toolchain (or ~/.cache/atmos-toolchain fallback), and tests have been updated to expect the new path structure.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method that can be called on *testing.T objects. This functionality is implemented through custom testing framework extensions and is used consistently throughout the test suite for changing working directories during tests.
Applied to files:
toolchain/installer/installer_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
Repo: cloudposse/atmos PR: 1255
File: cmd/describe_affected_test.go:15-15
Timestamp: 2025-05-23T19:51:47.091Z
Learning: In the atmos codebase, t.Chdir() is a valid method call on *testing.T objects and works correctly for changing directories in tests.
Applied to files:
toolchain/installer/installer_test.go
🧬 Code graph analysis (2)
toolchain/installer/extract_test.go (2)
toolchain/registry/registry.go (4)
Tool(185-203)ErrToolNotFound(14-14)ErrFileOperation(38-38)File(206-209)toolchain/installer/extract.go (3)
Unzip(230-247)MoveFile(474-492)ExtractTarGz(319-349)
toolchain/installer/installer_test.go (1)
toolchain/installer/installer.go (6)
NewInstallerWithResolver(212-219)New(174-208)WithBinDir(118-124)WithCacheDir(127-133)WithResolver(136-142)WithRegistryFactory(155-161)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Acceptance Tests (macos)
- GitHub Check: Acceptance Tests (linux)
- GitHub Check: Acceptance Tests (windows)
- GitHub Check: Summary
🔇 Additional comments (14)
toolchain/installer/installer_test.go (4)
1-16: Imports look clean and properly organized.Good separation with stdlib, third-party (testify), and internal packages (schema, registry). Aligns with the coding guidelines for import organization.
199-201: Skipped test with clear reasoning.Good practice to document why tests are skipped rather than deleting them. This indicates the functionality exists elsewhere.
484-514: Good test setup with separate directories.Using separate
srcDirandbinDirprevents path conflicts and makes the test more robust.
964-1013: Solid test coverage for the options pattern.These tests verify all the constructor options work correctly. Good coverage of the functional options pattern introduced in the refactor.
toolchain/installer/extract_test.go (10)
1-16: Imports well-organized for test file.All necessary packages for comprehensive extraction testing are included.
18-77: Good MIME type testing approach.Creating actual gzip content to test detection is the right approach. This ensures the test validates real behavior.
233-272: Path traversal security testing included.Good coverage of the path validation function with traversal attack scenarios. This is critical for secure archive extraction.
309-350: Comprehensive binary discovery tests.Tests cover root directory, subdirectories, and Windows
.exeextension handling. Error case for missing binary also covered.
439-480: Size limit test validates decompression bomb protection.Testing the limit enforcement is important for security. The error message check at line 478 validates proper error reporting.
507-550: Test helpers properly use t.Helper().Both
createTestZipArchiveandcreateTestTarGzArchivecorrectly callt.Helper()for accurate error line reporting.
623-672: Tests cover both simple and Files config extraction.The second subtest at line 646 validates the
Filesconfiguration feature for extracting specific files from archives. This aligns with the PR's support for multi-file extraction.
822-889: Magic bytes detection tests are thorough.Testing extraction by magic bytes (without relying on file extension) ensures robust file type handling. Good coverage of zip, gzip, and binary octet-stream types.
891-945: Error cases properly tested.Tests include empty
Filesslice and missing source file scenarios. This validates the function fails gracefully with clear errors.
149-191: The test setup is necessary. TheisTarGzFilefunction at line 77 oftoolchain/installer/extract.goactively callsmime.Is("application/x-tar")as a fallback check. Passingnilas suggested would cause a nil pointer dereference panic. The MIME detection serves a real purpose beyond filename extension checking.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
toolchain/install_test.go (1)
226-256: Test will hit real GitHub when resolving "latest" version.
RunInstall("terraform@latest", ...)triggersresolveLatestVersionWithSpinner→registry.GetLatestVersion()→ real HTTP calls to GitHub API. The AquaRegistry supportsWithGitHubBaseURL()option to inject an httptest server, but the test currently doesn't use it. Either:
- Refactor
resolveLatestVersionWithSpinnerto accept a registry parameter and update test to inject a mocked registry viahttptestandWithGitHubBaseURL, or- Mark this as an integration test and skip in CI when network is unavailable.
toolchain/info_test.go (1)
287-339: Use httptest to mock GitHub requests in AquaRegistry test.The test calls
installer.FindTool()which accesses a real GitHub endpoint via the AquaRegistry client. Per PR 1686 learnings, inject an httptest server usingWithGitHubBaseURL()like the pattern intoolchain/registry/aqua/aqua_test.goto ensure the test is deterministic and doesn't depend on network availability.Consider refactoring
NewAquaRegistry()intoolchain/aqua_registry.goto acceptRegistryOptionparameters so tests can inject the mock URL through the existing wrapper.toolchain/installer/installer_test.go (1)
621-647: Mock the registry factory instead of relying on skip fallback.The test calls
New()without options, which initializes a realdefaultRegistryFactorythat makes HTTP calls tohttps://raw.githubusercontent.com/aquaproj/aqua-registry/main/pkgs. Whilet.Skipfprevents test failure if the tool isn't found, it doesn't prevent network calls when the tool exists. UseWithRegistryFactorywith a mock that injects anhttptestserver (likeaqua_test.godemonstrates) to ensure the test stays isolated and deterministic.
🤖 Fix all issues with AI agents
In @toolchain/registry/aqua/aqua_test.go:
- Around line 844-864: Consolidate the multiple
TestAquaRegistry_parseRegistryFile_* functions into one table-driven test named
e.g. TestAquaRegistry_parseRegistryFile: create a slice of scenarios each with
fields (name, inputFile, expected values such as ExpectedName,
ExpectedRepoOwner, ExpectedRepoName,
ExpectedFiles/ExpectedReplacements/ExpectedOverrides), loop over scenarios and
call t.Run(s.name, func(t *testing.T){ ar := NewAquaRegistry(); data :=
os.ReadFile(s.inputFile); tool, err := ar.parseRegistryFile(data);
assert/require checks using s.expected values }), and remove the individual test
functions; keep references to parseRegistryFile and NewAquaRegistry to locate
logic and reuse existing testdata files (e.g., "testdata/aws-cli-files.yaml").
In @toolchain/registry/aqua/testdata/aws-cli-full.yaml:
- Around line 1-23: The download URLs use the v-prefixed template variable
{{.Version}} which yields values like "v2.13.0" but AWS CLI expects a bare
semver; update both url entries (the top-level url and the darwin override url
in the package definition) to use either {{.SemVer}} or {{trimV .Version}}
instead of {{.Version}} so the generated URLs omit the leading "v".
🧹 Nitpick comments (18)
aqua/README.md (1)
38-42: Consider clarifying the working directory context.The command
aqua installis documented here, but it's unclear whether users should run it from the repository root or theaqua/directory. If Aqua requires configuration in the repo root or specific path flags, consider adding a note about the expected working directory.pkg/template/ast.go (1)
20-23: Consider removing perf tracking from this trivial accessor.
FieldRef.String()just callsstrings.Joinon a small slice. The tracking overhead may exceed the operation time itself. Based on learnings, trivial accessors are typically exempt from perf tracking.That said, if repository linting enforces
perf.Trackon all public functions for consistency, this is fine to keep.toolchain/uninstall_test.go (1)
240-256: FakeInstaller appears underutilized.The
FakeInstallerstruct has several fields (CalledParseToolSpec,UninstallCalled,UninstallErr, etc.) that are never set during tests. The test at line 294 checkstc.installer.UninstallCalledbut the actualRunUninstallcall doesn't inject this fake installer.Consider either completing the dependency injection to use this fake, or removing the unused fields to avoid confusion.
toolchain/path_helpers.go (1)
28-29: Stale comment references unexported method name.The comment on line 28 still says
parseToolSpecbut the code now calls the exportedParseToolSpec.📝 Suggested fix
- // Resolve tool name to owner/repo using parseToolSpec for consistency. + // Resolve tool name to owner/repo using ParseToolSpec for consistency. owner, repo, err := installer.ParseToolSpec(toolName)toolchain/registry/atmos/atmos.go (1)
184-208: Silent skip of malformed overrides could hide config issues.When
overrideRawisn't amap[string]any, the code silently skips it (line 190). This might mask configuration errors. Consider logging a warning for visibility.Also, an override without
goosorgoarchset is essentially a no-op platform selector. Worth validating?🔧 Optional: Add warning for skipped/empty overrides
func parseOverrides(overridesRaw []any) []registry.Override { var overrides []registry.Override for _, overrideRaw := range overridesRaw { overrideMap, ok := overrideRaw.(map[string]any) if !ok { + // Consider: log.Debug("skipping malformed override entry", "type", fmt.Sprintf("%T", overrideRaw)) continue } override := registry.Override{} if goos, ok := overrideMap["goos"].(string); ok { override.GOOS = goos } if goarch, ok := overrideMap["goarch"].(string); ok { override.GOARCH = goarch } + // Skip overrides with no platform selector + if override.GOOS == "" && override.GOARCH == "" { + continue + } if asset, ok := overrideMap["asset"].(string); ok { override.Asset = asset } if format, ok := overrideMap["format"].(string); ok { override.Format = format } overrides = append(overrides, override) } return overrides }toolchain/registry/atmos/atmos_test.go (1)
479-564: Consider adding a negative test for malformed overrides.The happy paths are well covered. You might add a subtest for invalid override format (e.g., override entry is not a map) to ensure proper error handling.
💡 Optional: Example negative test case
t.Run("invalid override format returns error", func(t *testing.T) { toolsConfig := map[string]any{ "owner/tool": map[string]any{ "type": "github_release", "asset": "tool-{{.OS}}-{{.Arch}}.tar.gz", "overrides": []any{"not-a-map"}, }, } _, err := NewAtmosRegistry(toolsConfig) assert.Error(t, err) })toolchain/types_test.go (1)
17-37: Consider asserting the configured values.Tests confirm
installeris non-nil, but don't verify the options actually took effect. Adding assertions oninstaller.GetBinDir()or similar accessors would strengthen coverage.Example assertion
t.Run("creates installer with custom binDir", func(t *testing.T) { tmpDir := t.TempDir() installer := NewInstaller(WithBinDir(tmpDir)) assert.NotNil(t, installer) + assert.Equal(t, tmpDir, installer.GetBinDir()) })toolchain/installer/mock_resolver_test.go (1)
22-25: Potential confusion with no-op SetAtmosConfig.This test helper has the same name as
toolchain.SetAtmosConfigbut is a no-op. If test code imports both packages, or if production code accidentally imports this test file's package, the no-op could silently break configuration.Consider either:
- Renaming to something like
SetAtmosConfigNoopto make intent explicit, or- Documenting why the installer package doesn't need this configuration.
toolchain/installer/download_test.go (1)
257-279: Consider testing the actual implementation rather than duplicating logic.This test duplicates the version prefix logic inline rather than calling the actual function that implements this behavior. If the implementation changes, these tests won't catch regressions.
♻️ Suggested approach
Consider testing via a function that actually implements this logic (if one exists), or at minimum add a comment explaining this tests the expected algorithm for documentation purposes.
toolchain/installer/asset_test.go (1)
347-390: Type assertions on template functions could be fragile.These assertions (e.g.,
funcs["trimV"].(func(string) string)) will panic if the function signature changes. Consider using require with type checks or helper functions.♻️ Safer approach
t.Run("trimV removes v prefix", func(t *testing.T) { - fn := funcs["trimV"].(func(string) string) + fn, ok := funcs["trimV"].(func(string) string) + require.True(t, ok, "trimV should be func(string) string") assert.Equal(t, "1.2.3", fn("v1.2.3")) assert.Equal(t, "1.2.3", fn("1.2.3")) })toolchain/info_test.go (2)
188-189: Empty test function.
TestInfoCommand_TableOutputFormathas no assertions. Either implement the test or remove it to avoid giving false confidence in test coverage.
413-437: Commented-out test code.These commented-out test cases for "tool with files" and "tool with overrides" are dead code. Either implement them or remove them.
toolchain/installer/extract.go (1)
175-226: Multi-file extraction implementation.Solid implementation. A few observations:
- Line 197-203: First file in
tool.Filesis treated as the primary binary. This is implicit - consider adding a comment documenting this convention.- Line 220: Using
defaultMkdirPermissions(0755) for all extracted files is appropriate for executables.📝 Suggested documentation
// extractFilesFromDir extracts files from the extracted archive using the Files config. // The binaryPath parameter specifies the destination for the primary binary. // For multiple files, additional binaries are placed in the same directory. +// Note: The first entry in tool.Files is treated as the primary binary. func (i *Installer) extractFilesFromDir(tempDir, binaryPath string, tool *registry.Tool) error {toolchain/installer/extract_test.go (1)
149-191: Test creates misleading temp file but likely works.The test writes plain text to
tmpFilethen detects its MIME, butisTarGzFileappears to check filename extension (tt.filename), not the temp file's actual content. The temp file MIME detection seems unused in the assertion. Consider simplifying or clarifying intent.toolchain/types.go (1)
98-131: Option wrappers with perf.Track may be noisy.Every option wrapper calls
perf.Track. These are typically called during initialization and the overhead is minimal, but consider if this granularity is needed for options that just delegate toinstaller.*functions.toolchain/installer/installer_test.go (1)
187-197: TestGetBinaryPath needs consistent assertions.Consider using
assert.Equalfrom testify for consistency with other tests in this file.Suggestion
func TestGetBinaryPath(t *testing.T) { binDir := t.TempDir() installer := New(WithBinDir(binDir)) path := installer.GetBinaryPath("suzuki-shunsuke", "github-comment", "v6.3.4", "") expected := filepath.Join(binDir, "suzuki-shunsuke", "github-comment", "v6.3.4", "github-comment") - if path != expected { - t.Errorf("GetBinaryPath() = %v, want %v", path, expected) - } + assert.Equal(t, expected, path, "GetBinaryPath() mismatch") }toolchain/installer/installer.go (2)
210-219: Deprecation notice is helpful.Consider adding a
// Deprecated:comment that tools likestaticcheckcan detect.Suggestion for better tooling support
-// NewInstallerWithResolver allows injecting a custom ToolResolver (for tests). -// Deprecated: Use New() with WithResolver() option instead. +// NewInstallerWithResolver allows injecting a custom ToolResolver (for tests). +// +// Deprecated: Use New() with WithResolver() option instead. func NewInstallerWithResolver(resolver ToolResolver, binDir string) *Installer {
488-529: Uninstall has potential race condition on directory cleanup.The loop removing parent directories (lines 514-525) could race with concurrent installs. In practice, this is unlikely to cause issues since the dirs would just not be empty, but worth noting.
This fixes `atmos bootstrap` failures for multiple tools after PR #1948 by aligning version prefix handling with Aqua's actual behavior. Root causes fixed: 1. buildTemplateData was unconditionally adding "v" prefix when version_prefix was empty, breaking tools like AWS CLI (expects AWSCLIV2-2.32.31 not v2.32.31) 2. buildDownloadError wasn't including ErrHTTP404 for 404 responses, breaking the version fallback mechanism 3. Spinner was suppressing debug log output when running Changes: - Remove unconditional "v" prefix default in buildTemplateData (asset.go) - Same fix in resolveVersionStrings (aqua.go) - Include ErrHTTP404 in 404 errors for fallback detection (download.go) - Disable spinner when debug logging is enabled (install_helpers.go) - Update tests to encode correct Aqua behavior - Add regression tests for AWS CLI, jq, gum, and HTTP type tools Fixes failures for: aws/aws-cli@2.32.31, jqlang/jq@1.7.1, charmbracelet/gum@0.17.0, replicatedhq/replicated@0.124.1 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
These changes were released in v1.204.0-rc.4. |
…ws (#1958) * fix: Fix toolchain bootstrap by removing unconditional version prefix This fixes `atmos bootstrap` failures for multiple tools after PR #1948 by aligning version prefix handling with Aqua's actual behavior. Root causes fixed: 1. buildTemplateData was unconditionally adding "v" prefix when version_prefix was empty, breaking tools like AWS CLI (expects AWSCLIV2-2.32.31 not v2.32.31) 2. buildDownloadError wasn't including ErrHTTP404 for 404 responses, breaking the version fallback mechanism 3. Spinner was suppressing debug log output when running Changes: - Remove unconditional "v" prefix default in buildTemplateData (asset.go) - Same fix in resolveVersionStrings (aqua.go) - Include ErrHTTP404 in 404 errors for fallback detection (download.go) - Disable spinner when debug logging is enabled (install_helpers.go) - Update tests to encode correct Aqua behavior - Add regression tests for AWS CLI, jq, gum, and HTTP type tools Fixes failures for: aws/aws-cli@2.32.31, jqlang/jq@1.7.1, charmbracelet/gum@0.17.0, replicatedhq/replicated@0.124.1 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * fix: Preserve all fields in resolveVersionOverrides for version-specific configs The resolveVersionOverrides function was creating a new Tool struct but only copying a subset of fields from the registry package definition. This caused critical fields like VersionPrefix, Replacements, Overrides, and Files to be lost when version overrides were resolved. Additionally, the versionOverride struct was missing Replacements and Overrides fields, so version-specific replacements (like jq's darwin->macos mapping for versions < 1.8.0) were not being parsed or applied. Fixes: - registryPackage struct now includes all tool fields (Asset, Format, BinaryName, VersionPrefix, Replacements, Overrides, Files) - versionOverride struct now includes Replacements and Overrides fields - resolveVersionOverrides copies all fields from registryPackage to Tool - applyVersionOverride applies replacements and overrides from version overrides Adds regression tests that verify: - Base fields are preserved when no version override matches - Version override replacements are correctly applied - Version override platform overrides are correctly applied - Real-world patterns (jq, gum, opentofu) work correctly Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Fix template expansion in files.src and pkgutil extraction This commit fixes two tool installation issues discovered during bootstrap testing: 1. helm: The `files.src` field from Aqua registry contains templates like `{{.OS}}-{{.Arch}}/helm` that weren't being expanded, causing "file not found in archive" errors. Added `expandFileSrcTemplate` to process these templates using the same data as asset URLs. 2. aws-cli: macOS `pkgutil --expand-full` requires the target directory to NOT exist (it creates it). Changed to create a parent temp dir, then use a non-existent subdirectory as the target. Also: - Set tool.Version before extraction so template functions have access to version data - Added regression tests for template expansion - Added testdata fixture for integration testing with tools not in Aqua registry (like replicated) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add files/replacements/version_prefix parsing to atmos inline registry The inline atmos registry now supports all fields needed for complete tool definitions: - `files`: Array of file extraction configurations with name and src - `replacements`: Map for OS/arch name substitutions (e.g., darwin->macos) - `version_prefix`: Prefix for version tags (e.g., "v", "jq-") This enables defining tools like replicated (not in Aqua registry) with full control over extraction and platform-specific patterns. Example: ```yaml toolchain: registries: - name: custom type: atmos priority: 100 tools: replicatedhq/replicated: type: github_release asset: 'replicated_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz' format: tar.gz files: - name: replicated src: replicated ``` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add automatic toolchain integration for custom commands and workflows Custom commands and workflows now automatically have access to tools defined in .tool-versions. Previously, tools were only available when explicitly declared in the dependencies section. Changes: - Add LoadToolVersionsDependencies() to resolve .tool-versions as dependencies - Update executeCustomCommand() to merge .tool-versions with command deps - Add ensureToolchainDependencies() to workflow executor - Document toolchain integration for both custom commands and workflows Tools from .tool-versions serve as project-wide defaults. Per-command or per-workflow dependencies override these defaults when specified. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add toolchain integration examples for custom commands and workflows Add working examples demonstrating how toolchain-managed tools from .tool-versions are automatically available in custom commands and workflows. Changes: - Add .tool-versions with jq and yq for demonstration - Add custom commands (toolchain-demo) using which/version commands - Add workflow file (toolchain-demo.yaml) with shell steps - Update README with comprehensive documentation - Update .gitignore to allow example .tool-versions file Examples show: - Using `which` to verify toolchain binaries are in PATH - Tool version checking - JSON/YAML processing with jq/yq - Both implicit (.tool-versions) and explicit (dependencies) usage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: Improve toolchain examples to show distinct features Replace redundant examples with four distinct patterns: 1. which - Implicit dependencies from .tool-versions 2. pinned - Exact version pinning (overrides .tool-versions) 3. constrained - SemVer constraints (^1.7.0, ~> 4.40.0) 4. convert - Multi-tool pipeline (yq | jq) Each example now demonstrates a different toolchain capability instead of repeating the same which/version checks. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: Increase test coverage for toolchain integration Add DependencyProvider interface to workflow executor for testability: - New DependencyProvider interface abstracts toolchain dependency operations - DefaultDependencyProvider implements interface using real dependencies package - Executor.WithDependencyProvider() allows injecting mock for testing - Refactored ensureToolchainDependencies() to use interface New tests for pkg/workflow/executor.go (ensureToolchainDependencies): - No dependencies case (early return) - Tool-versions only case - Workflow deps only case - Merged dependencies (workflow overrides tool-versions) - Error paths: load, resolve, merge, install, PATH update New tests for toolchain/installer/extract.go: - extractGzipOrTarGz: tar.gz and single gzip binary paths - extractByMimeType: tar MIME type handling - extractEntry: directory type, path traversal, unknown type warning - extractFile: invalid mode handling - extractPkg: non-Darwin unsupported format New tests for pkg/dependencies/resolver.go: - Directory at .tool-versions path returns error (not NotExist) Coverage improvements: - ensureToolchainDependencies: ~19% → 100% - extractGzipOrTarGz: 66.7% → 100% - extractEntry: 50% → 100% - LoadToolVersionsDependencies: 91.7% → 100% Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Pass AtmosConfig to resolver for toolchain alias resolution The toolchain alias resolution wasn't working for custom commands because the DefaultToolResolver was created without AtmosConfig. This fix: - Add WithAtmosConfig option to pass AtmosConfig to the DefaultToolResolver - NewInstaller() now passes AtmosConfig when available for alias resolution - Update toolchain examples to use jqlang/jq (project moved from stedolan) - Add aliases section to example atmos.yaml mapping short names to full specs - Fix jq registry definition with version_prefix and darwin→macos override Tested: `atmos demo which` now correctly resolves jq→jqlang/jq via aliases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add toolchain integration to workflow execution The workflow command now automatically: - Loads tools from .tool-versions file - Resolves workflow-specific dependencies from workflow definitions - Merges dependencies (workflow deps override .tool-versions) - Installs missing tools before step execution - Prepends toolchain PATH to step environment This ensures shell and atmos steps have access to the correct tool versions without requiring manual PATH configuration. Tested: `atmos workflow which` and `atmos workflow convert` now correctly use tools from .tool-versions when running in the examples/toolchain directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: Simplify toolchain example structure - Remove custom-registry folder (use inline registry only) - Move workflows from stacks/workflows/ to workflows/ - Add base_path: "." to make example self-contained - Add minimal stacks/_placeholder.yaml to satisfy requirements - Update README with simplified registry examples - Update command examples to use "atmos demo" prefix The toolchain example now works standalone without requiring stacks configuration. Tools are defined inline in atmos.yaml. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Make workflow stack processing conditional on --stack flag Workflows no longer require stacks configuration when --stack flag is not provided. Previously, running `atmos workflow <name>` would fail with "stack base path must be provided" even for simple shell workflows that don't use stacks. Changes: - Check --stack flag before calling InitCliConfig in workflow.go - Pass processStacks=true only when --stack is explicitly provided - Add tests for workflow conditional stack processing - Enhance toolchain example with component-level tool dependencies - Add mock component demonstrating opentofu ^1.10.0 constraint - Remove placeholder stack file (no longer needed) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Improve toolchain error messages with proper hints and terminology - Change "tool name" to "tool alias" in error messages (correct terminology) - Add actionable hints to toolchain installation errors: - Check registry availability - Verify network connectivity - Link to toolchain docs (https://atmos.tools/cli/commands/toolchain/) - Use error builder pattern for proper hint formatting in cmd_utils.go - Distinguish explanation (what failed) from hints (what to do about it) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add hint for missing tool alias when tool not found When a tool without "/" is not found in aliases or registries, the error now suggests configuring a tool alias in atmos.yaml and links to the toolchain aliases documentation. Example error output: Tool `aws-cli` is not a valid tool specification 💡 Add an alias in atmos.yaml: toolchain.aliases.aws-cli: owner/repo 💡 Or use full format: owner/repo (e.g., hashicorp/terraform) 💡 See https://atmos.tools/cli/commands/toolchain/aliases for configuring aliases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Use Files[0].Name for binary name resolution in toolchain installer When tools specify a `files` configuration with a custom binary name (e.g., aws-cli uses `files: [{name: aws, src: aws/dist/aws}]`), the installer now correctly uses Files[0].Name as the binary name instead of falling back to the repo name. Priority order: BinaryName > Files[0].Name > Name > RepoName This matches Aqua's behavior where the first file's name represents the primary binary. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Suppress PATH hint for dependency installs When tools are installed as dependencies for workflows or custom commands via EnsureTools(), the PATH export hint is now suppressed. The hint is only shown when running `atmos toolchain install` directly. Added `showHint` parameter to RunInstall() and related functions to control whether the PATH hint is displayed. Refactored InstallSingleTool to use an InstallOptions struct to avoid exceeding the argument limit. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add alias configuration hint when tool not found in registry When a tool without "/" is not found in the Aqua registry, the error now suggests adding an alias in atmos.yaml with the exact syntax: toolchain.aliases.<tool>: owner/repo This helps developers understand that they can either: 1. Add an alias in atmos.yaml 2. Use the full owner/repo format 3. Search the registry for available tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Preserve error hints through error chain propagation The ErrorBuilder.WithCause() was using fmt.Errorf("%w: %w", ...) which breaks hint propagation in cockroachdb/errors.GetAllHints(). Changed to use errors.Wrap() which properly preserves hints from cause errors. Also removed generic hints from outer error wrappers (cmd_utils.go, workflow/executor.go, dependencies/installer.go) that were duplicating or overriding specific hints from inner errors. Now the specific actionable hints like "Add an alias in atmos.yaml" bubble up properly. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add showProgressBar param to RunInstall for custom command installs The progress bar wasn't showing when automatic toolchain dependency installs ran during custom commands. Fixed by making showProgressBar an explicit parameter rather than hardcoding to true. Also fixed test assertions to use cockroachdb/errors.Is() instead of standard errors.Is(), since our error builder uses Mark() which only works with the cockroachdb implementation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Progress bar display in toolchain install The progress bar was stacking up vertically with each status message instead of staying at the bottom and updating in place. Fixed by: 1. Calling resetLine() before printing status messages to clear the progress bar line (same pattern as uninstall which works correctly) 2. Using printProgressBar() helper instead of raw ui.Writef() Also addresses CodeRabbit review comments: - Add version_prefix: "v" to yq registry entry (mikefarah/yq uses v-prefixed tags) - Add language identifier to README code block - Fix comment about caret constraint (allows >=1.10.0, <2.0.0 not just 1.10.x) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Prevent .tool-versions duplication and enable spinner during batch install - Add SkipToolVersionsUpdate option to InstallOptions to prevent duplicate entries when both InstallSingleTool and updateToolVersionsFile are called - Enable ShowProgressBar for batch installs so spinner animates during downloads - Add BatchInstallFunc to dependencies.Installer for batch tool installation - Extract install result status strings to named constants - Clean up duplicate entries in examples/toolchain/.tool-versions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Reduce batch install message noise by separating spinner from details Add ShowInstallDetails option to InstallOptions to control verbose messages independently from spinner animation. In batch mode, only the simple "Installed X" message from showProgress is shown, while single-tool mode retains verbose output (path, size, registered). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Guard against nil error in ErrorBuilder.WithCause Add nil check for b.err before calling b.err.Error() to prevent panic. If b.err is nil, use the cause directly as the stored error. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Restore std errors.Is() compatibility in ErrorBuilder.WithCause The previous change from fmt.Errorf("%w: %w") to errors.Wrap() broke 403 test assertions because cockroachdb/errors.Mark() only works with cockroachdb's errors.Is(), not the standard library's errors.Is() which is used by testify's assert.ErrorIs(). This fix: - Reverts to fmt.Errorf("%w: %w") for std errors.Is() compatibility - Extracts hints from cause via GetAllHints() before wrapping - Preserves hints by adding them to b.hints for later application This maintains both standard errors.Is() compatibility (tests pass) and hint propagation from cause errors (original goal). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: Regenerate snapshots with improved error hints The ErrorBuilder.WithCause() fix now properly propagates hints from inner errors, resulting in more specific and actionable error messages. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add Windows support for binary name test On Windows, executables need .exe extension to be recognized. Updated TestIsToolInstalled_DifferentBinaryName to create the binary with proper extension on Windows. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add Windows executable detection in GetBinaryPath On Windows, executable permission bits don't apply - executables are identified by .exe extension instead. Updated GetBinaryPath to check for .exe suffix on Windows when auto-detecting binaries. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * add tests, address comments * add tests, address comments * add tests, address comments * add tests, address comments --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com> Co-authored-by: aknysh <andriy.knysh@gmail.com>
what
why
The installer subpackage refactoring broke registry lookups because defaultRegistryFactory.NewAquaRegistry() was returning nil. Additionally, NewInstaller() wasn't loading configured registries from atmos.yaml, preventing custom registry support. This fix properly injects a working registry factory and loads configuration during initialization.
references
Fixes toolchain registry factory issues from the installer subpackage refactoring work.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests
Style
✏️ Tip: You can customize this high-level summary in your review settings.