Skip to content

feat: Implement comprehensive error handling with cockroachdb/errors#1599

Closed
osterman wants to merge 133 commits intomainfrom
feature/dev-3054-implement-atmos-errors
Closed

feat: Implement comprehensive error handling with cockroachdb/errors#1599
osterman wants to merge 133 commits intomainfrom
feature/dev-3054-implement-atmos-errors

Conversation

@osterman
Copy link
Member

@osterman osterman commented Oct 6, 2025

what

  • Implement comprehensive error handling system using cockroachdb/errors
  • Add error builder with fluent API for creating rich, user-friendly errors
  • Add smart error formatting with TTY detection and color support
  • Add Sentry integration for optional error reporting
  • Add exit code support for proper error classification
  • Add context-aware hints to 14+ common error scenarios
  • Integrate markdown rendering for proper styling
  • Add context table display in verbose mode
  • Fix race condition in provenance tracking (flaky Windows test) 🐛
  • Add comprehensive documentation at three levels (developer, user, architecture)

why

  • Better Developer Experience: Clear, actionable error messages with helpful hints make debugging faster
  • Production Observability: Optional Sentry integration enables centralized error tracking and monitoring
  • Idiomatic Go: Uses cockroachdb/errors as drop-in replacement for standard errors, no custom wrappers
  • Privacy-First: PII-safe error context ensures sensitive data never appears in error reports
  • Debuggability: Rich error context, stack traces, and structured data improve troubleshooting
  • Consistency: 4-space indentation and atmos.yaml markdown styles applied throughout
  • Verbose Mode Control: `--verbose` flag controls ERROR verbosity (context tables, stack traces), separate from `--logs-level` logging verbosity
  • Test Reliability: Eliminates flaky Windows test by removing race-prone global state

features

Error Builder with Fluent API

```go
err := errUtils.Build(errors.New("database connection failed")).
WithHint("Check database credentials in atmos.yaml").
WithHintf("Verify network connectivity to %s", dbHost).
WithContext("component", "vpc").
WithContext("stack", "prod").
WithExitCode(2).
Err()
```

Smart Error Formatting

  • TTY-aware color output (auto/always/never modes)
  • Markdown rendering using configured atmos.yaml styles
  • 4-space indentation consistent with Atmos list style
  • Smart wrapping for long error messages (configurable max line length)
  • User-facing hints displayed with 💡 emoji
  • Verbose mode for full stack traces and context tables when debugging
  • Collapsed mode for clean, readable output

Context Table Display (Verbose Mode)

When `--verbose` flag is enabled, errors display structured context as formatted tables:

```
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Context ┃ Value ┃
┣━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━┫
┃ component ┃ vpc ┃
┃ stack ┃ prod ┃
┃ region ┃ us-east-1 ┃
┗━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛
```

Context tables help users understand the exact context where an error occurred, making debugging faster and more effective.

Verbose Mode Controls:

  • CLI flag: `--verbose`
  • Environment variable: `ATMOS_VERBOSE=true`
  • Config file: `errors.format.verbose: true`
  • Note: This is for ERROR verbosity (context, traces), NOT logging verbosity (use `--logs-level=Debug` for that)

Context-Aware Error Hints (14 Scenarios)

Phase 1 - Component/Stack Discovery (5 errors):

  • Component not found - hints to list components and verify path
  • Abstract component provisioning - explains abstract components and concrete inheritance
  • Locked component modification - hints on unlocking and why components are locked
  • Missing stack flag - syntax help and stack listing
  • Component not found in stack - debugging and verification hints

Phase 2 - Workflow/Vendor Configuration (4 errors):

  • Workflow file missing - hints to list workflows, verify path, check config
  • Workflow directory not found - hints to create directory or update config
  • Vendor config not found - hints for creating vendor.yaml or using --component flag
  • Missing component argument - smart hints based on whether args were provided

Phase 3 - Validation & Advanced (5 errors):

  • OPA policy violations - hints to review policy and fix violations
  • JSON schema validation - hints to review schema and revalidate
  • TTY detection - hints for -auto-approve, atmos deploy, and CI/CD usage
  • Duplicate components (vendor) - hints to remove duplicates and check imports
  • Invalid template delimiters - hints with examples and defaults

All errors now include structured context (component, stack, policy, schema, etc.) displayed in verbose mode.

Sentry Integration

  • Automatic context extraction: Hints → breadcrumbs, context → tags
  • PII-safe reporting: Only safe details sent to Sentry
  • Atmos context: Component, stack, region as tags with "atmos." prefix
  • Exit codes: Custom codes as Sentry tag "atmos.exit_code"
  • Optional configuration in atmos.yaml

Exit Code Support

  • Custom exit codes via wrapper pattern preserving error chains
  • Standard codes: 0 (success), 1 (general error), 2 (usage error)
  • Extraction priority: Custom → exec.ExitError → default (1)

Provenance Race Condition Fix

Fixed flaky Windows test in provenance tracking:

  • Problem: Global state (`GetLastMergeContext`) caused race conditions in parallel goroutine processing
  • Root Cause: Stack files processed in parallel would overwrite shared global variable, causing Windows timing differences to retrieve wrong merge context
  • Solution: Removed deprecated global state functions, use stack-specific merge context API (`GetMergeContextForStack`)
  • Result: Test now consistently finds 105 provenance paths (vs 38 before) with correct component-specific data
  • Impact: Eliminates "deprecated on arrival" functions that were marked deprecated in the same commit they were introduced

Configuration

```yaml
errors:
format:
verbose: false # Enable context tables and stack traces
color: auto # auto|always|never
sentry:
enabled: true
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0"
environment: "production"
sample_rate: 1.0
capture_stack_context: true
tags:
team: "platform"

Markdown styles are also respected for error hints

settings:
markdown:
code:
color: "#9370DB"
```

implementation details

  • No custom wrapper type: Uses cockroachdb/errors directly for idiomatic Go
  • Static sentinel errors: All base errors defined in `errors/errors.go`
  • Builder pattern: Optional convenience for complex errors
  • Exit code wrapper: Implements `Unwrap()` to preserve error chains
  • Markdown integration: Uses global renderer from `pkg/ui/markdown`
  • Context table rendering: Uses lipgloss for styled 2-column tables
  • Graceful fallback: Plain text when config not loaded (early flag errors)
  • Stack-specific merge contexts: Eliminates race conditions by isolating merge context per stack file
  • 78.8% test coverage: All error handling components tested

implementation phases completed

Phase 1 - Foundation: Error builder, formatter, Sentry, exit codes, documentation
Phase 2 - Component/Stack Hints: 5 high-priority component discovery errors
Phase 3 - Workflow/Vendor Hints: 4 configuration/onboarding errors
Phase 4 - Validation Hints: 5 validation and advanced error scenarios
Phase 5 - Markdown & Context Tables: Proper styling with 4-space indentation + context display
Bug Fix - Provenance Race Condition: Fixed flaky Windows test by removing global state

All phases complete - 14 error scenarios now have context-aware hints and structured context!

documentation

  • Developer Guide (`docs/errors.md`): Complete API reference with examples
  • User Guide (`website/docs/cli/errors.mdx`): Usage and configuration
  • Architecture PRD (`docs/prd/atmos-error-handling.md`): Design decisions and rationale
  • CLAUDE.md Updates: Error handling patterns for contributors
  • Global Flags Documentation: Updated `website/docs/cli/global-flags.mdx` with verbose flag details

testing

  • ✅ 78.8% test coverage for error handling components
  • ✅ Unit tests for builder, formatter, exit codes, Sentry, context tables
  • ✅ Integration tests with disabled Sentry (no network calls)
  • ✅ All provenance tests passing (including previously flaky Windows test)
  • ✅ All pre-commit hooks passing
  • ✅ golangci-lint passing (with acceptable complexity warnings for formatter)

migration path

This PR is complete and ready to merge. All planned phases have been implemented:

  • ✅ Foundation infrastructure (error builder, formatter, Sentry)
  • ✅ Context-aware hints for 14 common error scenarios
  • ✅ Markdown styling integration with atmos.yaml settings
  • ✅ Consistent 4-space indentation across all hints
  • ✅ Context table display in verbose mode
  • ✅ Race condition fix for provenance tracking

The implementation is backward compatible and non-breaking.

references

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Added global --verbose flag enabling detailed error messages with full stack traces and context.
    • Integrated Sentry error monitoring with automatic error capture and context transmission.
    • Enhanced error formatting with structured sections (explanations, examples, hints, context).
  • Improvements

    • Improved exit codes: usage/configuration errors now consistently return exit code 2.
    • Enriched error messages with actionable hints and contextual information.
    • TTY-aware error display with color support and text wrapping.
    • Added error configuration options for verbosity and color output.

osterman and others added 4 commits October 5, 2025 20:56
- Add ErrorBuilder type with fluent API for constructing enriched errors
- Support WithHint() and WithHintf() for user-facing hints
- Support WithContext() for PII-safe structured context
- Support WithExitCode() for custom exit codes
- Builder returns nil for nil errors (safe chaining)
- Comprehensive test coverage (100%)
- All tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add Format() function with smart error chain formatting
- Support TTY detection and color modes (auto/always/never)
- Smart wrapping for long error messages (configurable max line length)
- Display hints with 💡 emoji
- Verbose mode shows full stack traces
- Integration with lipgloss for styled output
- DefaultMaxLineLength constant to avoid magic numbers
- Comprehensive test coverage (100%)
- All tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add ErrorsConfig, ErrorFormatConfig, and SentryConfig to AtmosConfiguration schema
- Implement InitializeSentry() with pointer parameter to reduce memory overhead
- Implement CaptureError() with automatic hint and context extraction
- Implement CaptureErrorWithContext() for Atmos-specific context
- Extract hints as Sentry breadcrumbs
- Extract safe details as Sentry tags with "error." prefix
- Extract Atmos context (component, stack, region) as tags with "atmos." prefix
- Extract exit codes as Sentry tags
- Fix godot linter issues in pkg/hooks/store_cmd.go
- Fix revive linter issues by creating outputPrefixDot constant
- Comprehensive test coverage (100%)
- All tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Implement exitCoder wrapper pattern for custom exit codes
- Add WithExitCode() to attach exit codes to errors
- Add GetExitCode() to extract exit codes from error chains
- Support exec.ExitError exit codes
- Comprehensive test coverage (100%)
- Add implementation plan documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@osterman osterman requested review from a team as code owners October 6, 2025 02:25
@mergify
Copy link

mergify bot commented Oct 6, 2025

💥 This pull request now has conflicts. Could you fix it @osterman? 🙏

@mergify mergify bot added conflict This PR has conflicts triage Needs triage labels Oct 6, 2025
- Add developer guide (docs/errors.md) with API reference and examples
- Add user guide (website/docs/core-concepts/errors.mdx) with usage and configuration
- Add architecture PRD (docs/prd/atmos-error-handling.md) with design decisions
- Update CLAUDE.md with error builder, formatting, and Sentry patterns
- Document error handling best practices and migration guide
- Include examples for all error handling scenarios

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@osterman osterman force-pushed the feature/dev-3054-implement-atmos-errors branch from 3068efa to 0726ebe Compare October 6, 2025 02:27
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Warning

Rate limit exceeded

@osterman has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 38 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a1e0220 and 73c6124.

📒 Files selected for processing (1)
  • docs/prd/error-types-and-sentinels.md (1 hunks)
📝 Walkthrough

Walkthrough

This PR implements a comprehensive error handling system built on cockroachdb/errors, featuring a fluent error builder, structured markdown formatting, Sentry integration, and standardized exit codes. It replaces ad-hoc error handling with centralized, context-rich errors including hints, examples, and safe details. Configuration-level errors now exit with code 2 instead of 1.

Changes

Cohort / File(s) Change Summary
Error Handling Infrastructure
errors/builder.go, errors/builder_test.go, errors/exit_code.go, errors/exit_code_test.go, errors/formatter.go, errors/formatter_test.go, errors/sentry.go, errors/sentry_test.go, errors/exec_error.go, errors/workflow_error.go, errors/error_funcs.go, errors/error_funcs_test.go, errors/examples_test.go
New fluent ErrorBuilder API with hints, context, and exit codes; exit code extraction and wrapping utilities; configurable markdown error formatter with verbose/color modes; Sentry initialization, event capture, and context injection; ExecError and WorkflowStepError types for structured command/workflow failures; enhanced error printing with verbose mode and markdown renderer access.
Error Sentinels & Helpers
errors/errors.go, pkg/config/utils.go, pkg/logger/utils.go
Added ~30 new error sentinels (e.g., ErrStacksDirectoryDoesNotExist, ErrInvalidArguments, ErrAtmosConfigNotFound); updated existing messages to be concise; added GetValidLogLevels() helper; enhanced invalid log-level errors with hint messages.
Schema & Configuration
pkg/schema/schema.go, website/docs/cli/configuration/configuration.mdx
Added ErrorsConfig, ErrorFormatConfig, SentryConfig structs to AtmosConfiguration; introduced nested logs.errors block with format (verbose, color) and sentry (enabled, dsn, environment, release, sample_rate, debug, tags, capture_stack_context) options.
Global CLI Flags & Root Command
cmd/root.go, cmd/root_flag_test.go, cmd/root.go
Added global --verbose flag (persistent); refactored pre-run logic to defer config errors, conditionally silence usage/errors based on help invocations, handle invalid log levels with hints, initialize Sentry, and determine verbose state; updated InitializeMarkdown signatures to accept pointers.
Verbose Flag Removal
cmd/describe_affected.go, cmd/atlantis_generate_repo_config.go, cmd/aws_eks_update_kubeconfig.go
Removed deprecated --verbose flag from command definitions (consolidated to global flag).
Error Handling Refactors — Multi-file
cmd/cmd_utils.go, cmd/cmd_utils_test.go, cmd/terraform_utils.go, cmd/describe_component.go, cmd/list_values.go, cmd/workflow.go, cmd/describe_workflows.go, cmd/version/list.go, cmd/version/list_test.go, cmd/terraform_commands.go, cmd/terraform_test.go
Replaced direct error returns with structured errUtils.Build patterns; added hints, context, and explicit exit codes (typically 2 for usage errors); updated test assertions to use ErrorIs instead of string matching; migrated from pkg/errors to cockroachdb/errors; added git link formatting.
Exec & Terraform Command Handling
internal/exec/terraform.go, internal/exec/terraform_utils.go, internal/exec/terraform_clean.go, internal/exec/terraform_clean_util.go, internal/exec/terraform_clean_util_test.go, internal/exec/terraform_generate_backend.go, internal/exec/terraform_plan_diff.go, internal/exec/terraform_plan_diff_main_test.go, internal/exec/terraform_plan_diff_preparation.go, internal/terraform_backend/terraform_backend_azurerm.go, internal/terraform_backend/terraform_backend_gcs.go
Migrated to cockroachdb/errors; replaced fmt.Errorf/pkg/errors with structured error building; added context (command, component, stack, base_path); updated error wrapping format constants; added exit codes (typically 1–2); introduced perf.Track instrumentation (GCS backend).
Validation & Component Processing
internal/exec/validate_utils.go, internal/exec/validate_stacks.go, internal/exec/validate_schema.go, internal/exec/utils.go, pkg/component/component_processor.go
Enriched validation errors with hints and context via errUtils.Build; replaced pkg/errors with standard/cockroachdb errors; added exit codes to validation failures; enhanced missing-stack/component detection with guidance.
Vendor & Manifest Processing
internal/exec/vendor.go, internal/exec/vendor_utils.go, internal/exec/vendor_component_utils.go, internal/exec/stack_processor_utils.go, internal/exec/stack_processor_utils_test.go
Migrated to cockroachdb/errors; added structured error building with hints and context for missing configs, duplicates, and manifest issues; simplified error messages; introduced ErrMissingVendorComponent; added perf instrumentation.
Workflow & Execution
internal/exec/workflow.go, internal/exec/workflow_utils.go, internal/exec/workflow_test.go, internal/exec/examples/workflow_*.md, cmd/workflow.go
Embedded example markdown files for workflow errors; replaced direct error returns with errUtils.Build patterns; added structured hints and explanations; updated exit code extraction to use GetExitCode; introduced WorkflowStepError via NewWorkflowStepError; added perf tracking.
Template & YAML Processing
internal/exec/template_utils.go, internal/exec/yaml_func_resolution_context.go, pkg/utils/yaml_func_env.go
Enhanced delimiter validation with context-rich errors; reworked circular-dependency error building to use errUtils and exit code 1; replaced fmt.Errorf with errors.New for sentinel declarations.
Git & Remote Handling
internal/exec/describe_affected_helpers.go, internal/exec/describe_affected_pattern_cache.go, internal/exec/describe_affected_utils_2.go, pkg/downloader/get_git.go
Replaced direct error returns with structured errUtils.Build patterns; added context (component, stack, admin_component); added exit codes and hints; removed RemoteRepoIsNotGitRepoError in favor of errUtils.ErrRemoteRepoNotGitRepo.
Packer & Pro Handling
internal/exec/packer.go, internal/exec/packer_output.go, internal/exec/packer_test.go, internal/exec/pro.go, internal/exec/terraform_test.go
Enhanced missing-stack/template errors with exit code 2 via WithExitCode; updated Packer error assertions to ErrorIs; adjusted Pro warning message wording; improved component requirement hints.
Markdown & UI Rendering
pkg/ui/markdown/renderer.go, pkg/ui/markdown/renderer_test.go, pkg/ui/markdown/styles.go, pkg/telemetry/markdown/telemetry_notice.md
Added trimTrailingSpaces helper; refactored Render to handle trailing newlines and ANSI styling for commands; added tests for trailing-space handling and TTY-aware rendering; updated telemetry URL formatting; minor comment updates.
Utility & Config Updates
pkg/utils/markdown_utils.go, pkg/utils/markdown_utils_test.go, pkg/utils/go_getter_utils.go, pkg/utils/shell_utils.go, pkg/utils/shell_utils_test.go, pkg/config/config.go, pkg/config/default.go, pkg/list/utils/check_component_test.go, pkg/list/format/table.go, pkg/list/list_values.go, pkg/list/list_vendor.go, pkg/list/flags/flags.go, pkg/telemetry/utils_test.go
Updated InitializeMarkdown to accept pointer; migrated to standard/cockroachdb errors; added GetExitCode integration; replaced fmt.Errorf with errors.New for sentinels; added shell command exit-code tests; set NotFound to errUtils.ErrAtmosConfigNotFound; added ARM64 macOS test skips.
Shell & Exec Utilities
internal/exec/shell_utils.go, internal/exec/shell_utils_test.go
Replaced ExitCodeError with NewExecError for command failures; updated test assertions to expect ExecError.ExitCode field; added comprehensive exit-code preservation and environment variable tests.
Stack & Describe Processing
internal/exec/describe_component.go, internal/exec/describe_component_provenance_test.go, internal/exec/describe_workflows_test.go, internal/exec/describe_affected_utils_2.go, internal/exec/describe_config.go
Removed fallback merge-context logic; replaced ClearLastMergeContext with ClearMergeContexts; updated error assertions to ErrorIs; switched ErrTTYNotSupported to errors.New; added spacelift-related context and hints.
Helmfile & Atlantis
internal/exec/helmfile_generate_varfile.go, internal/exec/atlantis_generate_repo_config.go
Added structured error building for invalid arguments with hints; enriched flag validation errors; migrated to cockroachdb/errors with context-rich wrapping.
AWS & AWS EKS
internal/exec/aws_eks_update_kubeconfig.go
Enhanced stack name pattern validation with context-rich error building and exit code 1.
Tar Processing
internal/exec/tar_utils.go
Removed local ErrInvalidFilePath; updated references to errUtils.ErrInvalidFilePath.
Exit Code & Main Flow
main.go
Added error-type checks for WorkflowStepError and ExecError before ExitCodeError; updated exit path to use detected exit codes from these types.
Dependency Updates
go.mod, NOTICE
Added direct dependencies on cockroachdb/errors v1.12.0 and getsentry/sentry-go v0.27.0; moved pkg/errors to indirect; added cockroachdb-related indirect deps; updated license notices.
Build & Linting
Makefile, .golangci.yml, scripts/build-custom-golangci-lint.sh
Replaced build-custom-gcl target with script invocation; added forbidigo rules for WithHintf, static sentinels, and discouraged error patterns; added new linting enforcement script.
Documentation
CLAUDE.md, docs/errors.md, docs/prd/atmos-error-implementation-plan.md, docs/prd/error-handling.md, docs/prd/exit-codes.md, website/docs/cli/errors.mdx, website/docs/cli/global-flags.mdx, website/docs/troubleshoot/debugging.md, website/docs/troubleshoot/profiling.mdx, website/blog/2025-10-15-enhanced-error-handling.md, website/docs/cli/configuration/components.mdx
Comprehensive documentation of error system (architecture, builder API, formatter, Sentry), exit code strategy, verbose mode, debugging guidance, OpenTofu var-file caveat, and blog post on enhancements.
Test Snapshots & Cases — CLI Output
tests/snapshots/TestCLICommands_atmos_*.golden, tests/snapshots/TestCLICommands_Invalid_Log_Level_*.golden, tests/snapshots/TestCLICommands_check_atmos_*.golden, tests/snapshots/TestCLICommands_atmos_circuit-breaker.stderr.golden, tests/snapshots/TestCLICommands_atmos_doesnt_warn_*.golden, tests/snapshots/TestCLICommands_atmos_helmfile_*.golden, tests/snapshots/TestCLICommands_atmos_terraform_*.golden, tests/snapshots/TestCLICommands_atmos_workflow_*.golden, tests/snapshots/TestCLICommands_atmos_warns_*.golden
Extensively updated expected CLI error output: added structured "## Error", "## Explanation", "## Hints", "## Example" sections; changed error messages to be concise with context-rich hints; updated exit codes from 1→2 for usage/config errors; added emoji indicators (💡) for hints.
Test Cases & Scenarios
tests/test-cases/workflows.yaml, tests/test-cases/complete.yaml, tests/test-cases/core.yaml, tests/test-cases/empty-dir.yaml, tests/test-cases/metadata.yaml, tests/test-cases/git-repository-warnings.yaml, tests/test-cases/help-and-usage.yaml, tests/test-cases/vendor-test.yaml
Updated expected stderr messages and exit codes; changed "Workflow Error"/"subcommand exited" to "command exited with code"; consolidated multi-line errors into structured hints; bumped usage error exit codes to 2.
Test Utilities & Helpers
tests/cli_sanitize_test.go, tests/cli_test.go, tests/testhelpers/rootcmd.go, tests/cli_describe_component_test.go, tests/describe_test.go
Added Windows drive-letter normalization for error paths; added sanitizeOutputWithRepoRoot helper; introduced RootCmdTestKit for automatic RootCmd state snapshot/restoration across tests; refactored fixture-based tests to use env variables instead of t.Chdir.
Minor Fixes & Polish
internal/exec/terraform_output_utils.go, internal/exec/describe_config.go, internal/exec/validate_stacks.go
Added outputPrefixDot constant; switched error declarations to errors.New.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI Command
    participant CmdRoot as cmd/root.go
    participant ErrorPkg as errors/*
    participant Config as Config Loading
    participant Sentry as Sentry

    CLI->>CmdRoot: Execute command
    CmdRoot->>CmdRoot: Parse --verbose flag
    CmdRoot->>ErrorPkg: SetVerboseFlag(verbose)
    CmdRoot->>Config: Load config (defer errors)
    alt Config Error
        CmdRoot->>CmdRoot: Capture in configErr
    end
    
    CmdRoot->>Sentry: InitializeSentry(config)
    CmdRoot->>CmdRoot: Execute Cobra command
    
    alt Command Success
        CmdRoot->>CLI: Return 0
    else Command Error
        CmdRoot->>ErrorPkg: CheckErrorAndPrint(err)
        ErrorPkg->>Sentry: CaptureError(err)
        ErrorPkg->>ErrorPkg: Format error (verbose/color)
        ErrorPkg->>ErrorPkg: GetExitCode(err)
        ErrorPkg->>CLI: Print formatted error + exit code
    end
Loading
sequenceDiagram
    participant App as Application
    participant Builder as ErrorBuilder
    participant Formatter as Formatter
    participant Output as Output

    App->>Builder: Build(baseError)
    Builder->>Builder: Initialize with error
    App->>Builder: WithHint(hint)
    App->>Builder: WithContext(key, value)
    App->>Builder: WithExitCode(2)
    App->>Builder: Err()
    
    Builder->>Builder: Compose error chain
    Builder->>App: Return enriched error
    
    App->>Formatter: Format(error, config)
    Formatter->>Formatter: Extract message & hints
    Formatter->>Formatter: Build markdown sections
    Formatter->>Formatter: Apply color (if TTY)
    Formatter->>Output: Return formatted string
    Output->>Output: Print to stderr
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Areas requiring extra attention:

  • Error Builder & Exit Code Logic: Verify Err() composition order (hints → context → exit code), ensure fluent chaining is safe from nil dereferences, confirm priority in GetExitCode extraction (WorkflowStepError → ExecError → exitCoder → exec.ExitError).
  • Sentry Integration: Validate InitializeSentry config handling (nil-safety, defaults), confirm CaptureError extracts hints/context correctly, check breadcrumb and tag format against Sentry schema.
  • Formatter & Markdown Rendering: Review markdown section building logic, verify TTY detection and color application, ensure text wrapping and trailing-space trimming don't break output, validate verbose vs. compact mode transitions.
  • Exit Code Changes (1→2 for Usage Errors): Confirm all configuration/usage error paths consistently return exit code 2, verify subprocess exit codes are preserved correctly, check CI/shell integration compatibility.
  • InitializeMarkdown Signature Change: Confirm all call sites pass pointers (not values), verify nil-safety in callers, check for any missed references across test/prod code.
  • Test Snapshot Updates: Spot-check a few snapshot diffs to ensure expected error message formatting and exit code changes are intentional, validate shell command, workflow, and missing-config scenarios.
  • Deprecated Flag Removal: Verify --verbose removals don't break existing workflows, confirm global --verbose is wired correctly as replacement.
  • Error Sentinel Consolidation: Review error message rewording (e.g., "incompatible flags" vs. verbose messages) for user clarity, ensure no sentinel collisions.

Possibly related PRs

Suggested reviewers

  • aknysh

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.74% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: Implement comprehensive error handling with cockroachdb/errors" clearly and concisely describes the primary change: integrating cockroachdb/errors for a comprehensive error-handling system. The title is specific, avoids vague terminology, and accurately reflects the main feature being implemented as confirmed by the PR objectives and raw summary showing extensive error builder, formatter, Sentry integration, and exit-code handling additions throughout the codebase.
Linked Issues Check ✅ Passed The PR successfully addresses the linked issue #1334 which required removing the deprecated --verbose flag from the describe_affected command. The raw_summary for cmd/describe_affected.go confirms removal of the deprecated --verbose flag initialization, associated verbose handling code, and the log.Warn/log.SetLevel mappings. This fulfills the coding objective of removing the deprecated flag from cmd/describe_affected.go, while the broader PR implements a new global --verbose flag for error verbosity (as described in the PR objectives), which is intentionally separate from the deprecated command-specific verbose flag and distinct from logging verbosity.
Out of Scope Changes Check ✅ Passed The overwhelming majority of changes align with the stated objectives: error handling infrastructure (builder, formatter, Sentry integration, exit codes), sentinel errors expansion, documentation updates, configuration schema additions for error handling, and --verbose flag removal from describe_affected as per issue #1334. Minor non-functional additions exist, such as performance tracing instrumentation in terraform_backend_gcs.go (which only adds perf.Track calls without altering logic) and a necessary provenance race-condition fix in describe_component.go that replaced deprecated global state usage. The removal of command-specific verbose flags from atlantis_generate_repo_config.go and aws_eks_update_kubeconfig.go appears intentional as part of consolidating verbose functionality into the global error-verbosity flag.

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 94ad05f and 0726ebe.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (17)
  • CLAUDE.md (3 hunks)
  • docs/errors.md (1 hunks)
  • docs/prd/atmos-error-handling.md (1 hunks)
  • docs/prd/atmos-error-implementation-plan.md (1 hunks)
  • errors/builder.go (1 hunks)
  • errors/builder_test.go (1 hunks)
  • errors/exit_code.go (1 hunks)
  • errors/exit_code_test.go (1 hunks)
  • errors/formatter.go (1 hunks)
  • errors/formatter_test.go (1 hunks)
  • errors/sentry.go (1 hunks)
  • errors/sentry_test.go (1 hunks)
  • go.mod (4 hunks)
  • internal/exec/terraform_output_utils.go (3 hunks)
  • pkg/hooks/store_cmd.go (2 hunks)
  • pkg/schema/schema.go (2 hunks)
  • website/docs/troubleshoot/errors.mdx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: All comments in Go code must end with periods; enforced by golangci-lint's godot.
Organize imports into three groups (stdlib, 3rd-party, Atmos) separated by blank lines; sort alphabetically within each group; maintain existing import aliases.
Add defer perf.Track() to all public functions and critical private functions, with a blank line after the call; use package-qualified names (e.g., "exec.ProcessComponent"); pass atmosConfig if available, else nil.
Error handling: wrap errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; add context with fmt.Errorf("%w", ...); use errors.Is for checks; never compare error strings or return dynamic errors directly.
Always bind environment variables with viper.BindEnv; every env var must have an ATMOS_ alternative (e.g., viper.BindEnv("ATMOS_GITHUB_TOKEN", "GITHUB_TOKEN")).
Use structured logging for system/debug info and direct UI output to stderr; never use logging for UI elements; data/results intended for piping must go to stdout.
Most text UI must go to stderr (e.g., utils.PrintfMessageToTUI or fmt.Fprintf(os.Stderr,...)); only data/results go to stdout.
Ensure cross-platform compatibility: prefer SDKs over shelling out to binaries, use filepath/os utilities, and guard OS-specific logic with build constraints or runtime.GOOS when necessary.

Files:

  • internal/exec/terraform_output_utils.go
  • pkg/hooks/store_cmd.go
  • errors/formatter.go
  • errors/sentry.go
  • errors/builder_test.go
  • errors/builder.go
  • errors/exit_code_test.go
  • pkg/schema/schema.go
  • errors/sentry_test.go
  • errors/formatter_test.go
  • errors/exit_code.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/terraform_output_utils.go
  • pkg/hooks/store_cmd.go
  • errors/formatter.go
  • errors/sentry.go
  • errors/builder.go
  • pkg/schema/schema.go
  • errors/exit_code.go
internal/exec/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Favor code reuse by extending utilities in internal/exec/ (e.g., component_utils.go, stack_processor_utils.go) instead of duplicating functionality.

Files:

  • internal/exec/terraform_output_utils.go
pkg/**/*.go

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

Place business logic in pkg rather than in cmd

Files:

  • pkg/hooks/store_cmd.go
  • pkg/schema/schema.go
**/*_test.go

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

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Test quality: test behavior not implementation; avoid testing stubs or tautologies; use DI to avoid hard deps (os.Exit, CheckErrorPrintAndExit); remove always-skipped tests; table-driven tests must use real scenarios.
Always use t.Skipf with a clear reason instead of t.Skip; never call t.Skipf without a reason.
Co-locate test files alongside implementations using *_test.go naming.

Files:

  • errors/builder_test.go
  • errors/exit_code_test.go
  • errors/sentry_test.go
  • errors/formatter_test.go
website/**

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

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Files:

  • website/docs/troubleshoot/errors.mdx
go.{mod,sum}

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

go.{mod,sum}: Manage dependencies with Go modules
Keep dependencies up to date

Files:

  • go.mod
🧠 Learnings (6)
📚 Learning: 2025-10-06T02:10:05.491Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-06T02:10:05.491Z
Learning: Applies to **/*.go : Error handling: wrap errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; add context with fmt.Errorf("%w", ...); use errors.Is for checks; never compare error strings or return dynamic errors directly.

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*.go : Follow Go error handling idioms and use meaningful error messages

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-09-23T02:30:42.362Z
Learnt from: CR
PR: cloudposse/atmos#0
File: .cursor/rules/atmos-rules.mdc:0-0
Timestamp: 2025-09-23T02:30:42.362Z
Learning: Applies to **/*.go : Wrap errors with context using fmt.Errorf("context: %w", err)

Applied to files:

  • CLAUDE.md
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • docs/errors.md
  • docs/prd/atmos-error-handling.md
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • docs/prd/atmos-error-handling.md
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • docs/prd/atmos-error-handling.md
🧬 Code graph analysis (6)
errors/sentry.go (2)
pkg/schema/schema.go (1)
  • SentryConfig (393-402)
errors/exit_code.go (1)
  • GetExitCode (51-69)
errors/builder_test.go (2)
errors/builder.go (1)
  • Build (17-19)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (51-69)
errors/builder.go (1)
errors/exit_code.go (1)
  • WithExitCode (34-42)
errors/exit_code_test.go (1)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (51-69)
errors/sentry_test.go (4)
pkg/schema/schema.go (1)
  • SentryConfig (393-402)
errors/sentry.go (4)
  • InitializeSentry (14-45)
  • CloseSentry (48-51)
  • CaptureError (55-93)
  • CaptureErrorWithContext (97-138)
errors/builder.go (1)
  • Build (17-19)
errors/exit_code.go (1)
  • WithExitCode (34-42)
errors/formatter_test.go (3)
errors/formatter.go (2)
  • DefaultFormatterConfig (31-37)
  • Format (40-91)
errors/builder.go (1)
  • Build (17-19)
errors/exit_code.go (1)
  • WithExitCode (34-42)
🪛 markdownlint-cli2 (0.18.1)
docs/prd/atmos-error-implementation-plan.md

556-556: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/prd/atmos-error-handling.md

19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


172-172: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


185-185: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


202-202: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (3)
internal/exec/terraform_output_utils.go (2)

31-31: LGTM! Clean constant extraction.

Extracting the dot prefix into a named constant improves maintainability and makes the intent clearer.


428-429: LGTM — constant used consistently
No remaining hardcoded "." prefixes detected in output handling.

docs/prd/atmos-error-handling.md (1)

45-53: Add explicit code fence languages.

markdownlint is flagging these code blocks because they lack language identifiers. Please annotate each fence ( ```text, ```yaml, etc.) so docs lint passes.

⛔ Skipped due to learnings
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

osterman and others added 2 commits October 5, 2025 21:42
- Initialize Sentry from config in InitializeMarkdown
- Use new error formatter in CheckErrorAndPrint with config
- Add --verbose flag support with precedence (CLI > env > config)
- Close Sentry before exit in CheckErrorPrintAndExit
- Use GetExitCode for custom exit code support
- Add comprehensive errors configuration documentation to CLI config
- Extract formatting logic to reduce nesting complexity
- Use viper.BindEnv for ATMOS_VERBOSE environment variable
- Change InitializeMarkdown to accept pointer parameter

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use errors.BuildSentryReport() instead of manual CaptureException
- Leverage automatic PII-free reporting from cockroachdb/errors
- Extract stack traces and safe details natively
- Add extra details as Sentry context with type assertion
- Preserve hints as breadcrumbs and exit codes as tags

This ensures we benefit from cockroachdb/errors' comprehensive
Sentry integration rather than reimplementing it manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/root.go (1)

59-103: Apply --verbose before any fatal exits.

CheckErrorPrintAndExit terminates the process during command execution, so the code after RootCmd.ExecuteC() never runs. Net effect: --verbose (and --verbose=false) are ignored the moment a command fails—the main case the flag is meant for.

Grab the flag up front in PersistentPreRun (before we invoke anything that might exit) and pass the actual value through, then drop the late binding:

 PersistentPreRun: func(cmd *cobra.Command, args []string) {
+	if cmd.Flags().Changed("verbose") {
+		verbose, flagErr := cmd.Flags().GetBool("verbose")
+		if flagErr != nil {
+			errUtils.CheckErrorPrintAndExit(flagErr, "", "")
+		}
+		errUtils.SetVerboseFlag(verbose)
+	}
+
 	// Determine if the command is a help command or if the help flag is set.
@@
-	cmd, err := RootCmd.ExecuteC()
-
-	// Set verbose flag for error formatting.
-	if verbose, flagErr := cmd.Flags().GetBool("verbose"); flagErr == nil && verbose {
-		errUtils.SetVerboseFlag(true)
-	}
+	cmd, err := RootCmd.ExecuteC()

Also applies to: 449-452

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 0726ebe and 792a62d.

📒 Files selected for processing (3)
  • cmd/root.go (3 hunks)
  • errors/error_funcs.go (2 hunks)
  • website/docs/cli/configuration/configuration.mdx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
cmd/**/*.go

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

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: For CLI examples, load content via //go:embed and render with utils.PrintfMarkdown(); register examples in cmd/markdown_help.go.
One Cobra command per file in cmd/.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without collecting user data.

Files:

  • cmd/root.go
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: All comments in Go code must end with periods; enforced by golangci-lint's godot.
Organize imports into three groups (stdlib, 3rd-party, Atmos) separated by blank lines; sort alphabetically within each group; maintain existing import aliases.
Add defer perf.Track() to all public functions and critical private functions, with a blank line after the call; use package-qualified names (e.g., "exec.ProcessComponent"); pass atmosConfig if available, else nil.
Error handling: wrap errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; add context with fmt.Errorf("%w", ...); use errors.Is for checks; never compare error strings or return dynamic errors directly.
Always bind environment variables with viper.BindEnv; every env var must have an ATMOS_ alternative (e.g., viper.BindEnv("ATMOS_GITHUB_TOKEN", "GITHUB_TOKEN")).
Use structured logging for system/debug info and direct UI output to stderr; never use logging for UI elements; data/results intended for piping must go to stdout.
Most text UI must go to stderr (e.g., utils.PrintfMessageToTUI or fmt.Fprintf(os.Stderr,...)); only data/results go to stdout.
Ensure cross-platform compatibility: prefer SDKs over shelling out to binaries, use filepath/os utilities, and guard OS-specific logic with build constraints or runtime.GOOS when necessary.

Files:

  • cmd/root.go
  • errors/error_funcs.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • cmd/root.go
  • errors/error_funcs.go
cmd/root.go

📄 CodeRabbit inference engine (CLAUDE.md)

Telemetry: standard Cobra commands added to RootCmd get telemetry via RootCmd.ExecuteC() (see cmd/root.go:174); do not add extra telemetry for standard paths.

Files:

  • cmd/root.go
website/**

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

website/**: Update website documentation in website/ when adding features
Ensure consistency between CLI help text and website documentation
Follow the website's documentation structure and style
Keep website code in website/ and follow its architecture/style; test changes locally
Keep CLI and website documentation in sync; document new features with examples and use cases

Files:

  • website/docs/cli/configuration/configuration.mdx
🧠 Learnings (7)
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-10-06T02:10:05.491Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-06T02:10:05.491Z
Learning: Applies to cmd/root.go : Telemetry: standard Cobra commands added to RootCmd get telemetry via RootCmd.ExecuteC() (see cmd/root.go:174); do not add extra telemetry for standard paths.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-10-06T02:10:05.491Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-06T02:10:05.491Z
Learning: Applies to cmd/**/*.go : For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without collecting user data.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • errors/error_funcs.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • errors/error_funcs.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • errors/error_funcs.go
📚 Learning: 2025-02-03T06:00:11.419Z
Learnt from: samtholiya
PR: cloudposse/atmos#959
File: cmd/describe_config.go:20-20
Timestamp: 2025-02-03T06:00:11.419Z
Learning: Commands should use `PrintErrorMarkdownAndExit` with empty title and suggestion (`"", err, ""`) for general error handling. Specific titles like "Invalid Usage" or "File Not Found" should only be used for validation or specific error scenarios.

Applied to files:

  • errors/error_funcs.go
🧬 Code graph analysis (2)
cmd/root.go (2)
errors/error_funcs.go (2)
  • InitializeMarkdown (30-46)
  • SetVerboseFlag (25-27)
pkg/utils/markdown_utils.go (1)
  • InitializeMarkdown (39-47)
errors/error_funcs.go (5)
pkg/ui/markdown/renderer.go (2)
  • Renderer (19-26)
  • NewTerminalMarkdownRenderer (241-261)
pkg/schema/schema.go (1)
  • AtmosConfiguration (27-64)
errors/sentry.go (3)
  • InitializeSentry (14-45)
  • CaptureError (55-93)
  • CloseSentry (48-51)
errors/formatter.go (2)
  • FormatterConfig (19-28)
  • DefaultMaxLineLength (15-15)
errors/exit_code.go (1)
  • GetExitCode (51-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary

- Defer config errors until after flag parsing
- Show proper usage for invalid flags instead of config errors
- Move errors.mdx to /cli/ directory (correct location)
- Add test examples for error formatting
- Update PRD references to correct documentation paths

This ensures users see helpful usage messages for invalid flags
rather than unrelated configuration errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 792a62d and 3164741.

📒 Files selected for processing (7)
  • cmd/root.go (3 hunks)
  • docs/errors.md (1 hunks)
  • docs/prd/atmos-error-handling.md (1 hunks)
  • docs/prd/atmos-error-implementation-plan.md (1 hunks)
  • errors/examples_test.go (1 hunks)
  • errors/sentry.go (1 hunks)
  • website/docs/cli/errors.mdx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • website/docs/cli/errors.mdx
  • docs/errors.md
  • errors/examples_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • errors/sentry.go
🧰 Additional context used
📓 Path-based instructions (4)
cmd/**/*.go

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

cmd/**/*.go: Use Cobra's recommended command structure with a root command and subcommands
Implement each CLI command in a separate file under cmd/
Use Viper for managing configuration, environment variables, and flags in the CLI
Keep separation of concerns between CLI interface (cmd) and business logic
Use kebab-case for command-line flags
Provide comprehensive help text for all commands and flags
Include examples in Cobra command help
Use Viper for configuration management; support files, env vars, and flags with precedence flags > env > config > defaults
Follow single responsibility; separate command interface from business logic
Provide meaningful user feedback and include progress indicators for long-running operations
Provide clear error messages to users and troubleshooting hints where appropriate

cmd/**/*.go: For CLI examples, load content via //go:embed and render with utils.PrintfMarkdown(); register examples in cmd/markdown_help.go.
One Cobra command per file in cmd/.
For non-standard execution paths, capture telemetry via telemetry.CaptureCmd or telemetry.CaptureCmdString without collecting user data.

Files:

  • cmd/root.go
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: All comments in Go code must end with periods; enforced by golangci-lint's godot.
Organize imports into three groups (stdlib, 3rd-party, Atmos) separated by blank lines; sort alphabetically within each group; maintain existing import aliases.
Add defer perf.Track() to all public functions and critical private functions, with a blank line after the call; use package-qualified names (e.g., "exec.ProcessComponent"); pass atmosConfig if available, else nil.
Error handling: wrap errors using static errors from errors/errors.go; prefer errors.Join for multiple errors; add context with fmt.Errorf("%w", ...); use errors.Is for checks; never compare error strings or return dynamic errors directly.
Always bind environment variables with viper.BindEnv; every env var must have an ATMOS_ alternative (e.g., viper.BindEnv("ATMOS_GITHUB_TOKEN", "GITHUB_TOKEN")).
Use structured logging for system/debug info and direct UI output to stderr; never use logging for UI elements; data/results intended for piping must go to stdout.
Most text UI must go to stderr (e.g., utils.PrintfMessageToTUI or fmt.Fprintf(os.Stderr,...)); only data/results go to stdout.
Ensure cross-platform compatibility: prefer SDKs over shelling out to binaries, use filepath/os utilities, and guard OS-specific logic with build constraints or runtime.GOOS when necessary.

Files:

  • cmd/root.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • cmd/root.go
cmd/root.go

📄 CodeRabbit inference engine (CLAUDE.md)

Telemetry: standard Cobra commands added to RootCmd get telemetry via RootCmd.ExecuteC() (see cmd/root.go:174); do not add extra telemetry for standard paths.

Files:

  • cmd/root.go
🧠 Learnings (5)
📚 Learning: 2024-12-11T18:40:12.808Z
Learnt from: Listener430
PR: cloudposse/atmos#844
File: cmd/helmfile.go:37-37
Timestamp: 2024-12-11T18:40:12.808Z
Learning: In the atmos project, `cliConfig` is initialized within the `cmd` package in `root.go` and can be used in other command files.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-10-06T02:10:05.491Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-06T02:10:05.491Z
Learning: Applies to cmd/root.go : Telemetry: standard Cobra commands added to RootCmd get telemetry via RootCmd.ExecuteC() (see cmd/root.go:174); do not add extra telemetry for standard paths.

Applied to files:

  • cmd/root.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • docs/prd/atmos-error-handling.md
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • docs/prd/atmos-error-handling.md
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • docs/prd/atmos-error-handling.md
🧬 Code graph analysis (1)
cmd/root.go (4)
errors/error_funcs.go (2)
  • InitializeMarkdown (30-46)
  • SetVerboseFlag (25-27)
pkg/utils/markdown_utils.go (1)
  • InitializeMarkdown (39-47)
pkg/config/default.go (1)
  • NotFound (17-19)
pkg/telemetry/utils.go (1)
  • CaptureCmd (44-50)
🪛 markdownlint-cli2 (0.18.1)
docs/prd/atmos-error-handling.md

19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


172-172: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


185-185: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


202-202: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (6)
cmd/root.go (5)

418-418: LGTM!

The function signature change to pass &atmosConfig (pointer) instead of value is correct and aligns with the updated InitializeMarkdown signature in errors/error_funcs.go.


420-429: Good deferred error handling pattern.

Deferring the config error until after flag parsing ensures better UX - users get clear flag error messages before seeing config errors. This allows the verbose flag to be set even when config is invalid.


452-456: LGTM!

Reading the verbose flag after Cobra execution and applying it via SetVerboseFlag(true) enables verbose error formatting for subsequent error handling. The flag check with flagErr == nil safely handles any flag parsing errors.


543-543: LGTM!

The new --verbose flag is correctly defined as a persistent boolean flag with clear help text. It will be available to all subcommands.


459-475: Manual verification required: confirm error handling precedence
Ripgrep searches for ExecuteC( yielded no results; please manually inspect your CLI entry points (e.g., main.go) to ensure Cobra errors (invalid commands/flags) are always prioritized over config errors.

docs/prd/atmos-error-implementation-plan.md (1)

1-579: LGTM!

This implementation plan is comprehensive and well-structured, covering:

  • Clear architecture principles and rationale
  • Visual formatting examples for different scenarios
  • Complete configuration structure with YAML and Go schema examples
  • Detailed Sentry integration mapping
  • Phased rollout approach (Foundation → Hints Migration → Hint Addition)
  • File structure and usage patterns
  • Success criteria for each phase

The plan aligns well with the actual implementation files in this PR and provides excellent guidance for future phases.

osterman and others added 4 commits October 6, 2025 08:01
The FParseErrWhitelist on root command was causing all unknown flags
to be silently ignored, leading to config errors being shown instead
of proper flag error messages.

- Remove FParseErrWhitelist from root command (already on terraform/helmfile/packer)
- Invalid flags now properly show Cobra error messages with usage
- Add comprehensive test suite for flag/command error handling
- Test verifies unknown flags show usage, not config errors

This fixes the issue where `atmos --invalid-flag` showed "stacks
directory does not exist" instead of "unknown flag: --invalid-flag".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The flag error handler was calling CheckErrorPrintAndExit but the
markdown renderer wasn't initialized yet during early flag parsing,
causing the usage message to be lost.

- Print error message directly in showUsageExample instead of via CheckErrorPrintAndExit
- Add SilenceErrors and SilenceUsage to root command definition
- Invalid flags now show: "Error: unknown flag... Run 'atmos --help' for usage"
- Remove redundant unknown flag handling from Execute (handled by SetFlagErrorFunc)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ement-atmos-errors

# Conflicts:
#	internal/exec/terraform_output_utils.go
#	pkg/hooks/store_cmd.go
Phase 2 of error handling improvements - adds helpful hints for common
configuration and onboarding errors in workflows and vendoring.

## Changes

### Workflow Errors
- **Workflow File Missing**: Added hints to list workflows, verify path, and check config
- **Workflow Directory Not Found**: Added hints to create directory or update config
- Added `ErrWorkflowDirectoryDoesNotExist` sentinel error

### Vendor Errors
- **Vendor Config Not Found**: Added hints for creating vendor.yaml or using --component flag
- **Missing Component Argument**: Added smart hints based on whether args were provided

### Technical Improvements
- Replaced stdlib `errors` with `cockroachdb/errors` in workflow.go, workflow_utils.go, vendor.go
- Replaced `github.com/pkg/errors` with cockroachdb/errors (drop-in replacement)
- All errors use sentinel errors from errors/errors.go (err113 compliance)
- Removed legacy `CheckErrorPrintAndExit` usage in favor of error hints

## Files Modified
- internal/exec/workflow.go - Updated imports, added file not found hints
- internal/exec/workflow_utils.go - Updated imports, added directory not found hints
- internal/exec/vendor.go - Updated imports, added config and component error hints
- errors/errors.go - Added ErrWorkflowDirectoryDoesNotExist sentinel

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions bot added the size/xl Extra large size PR label Oct 6, 2025
@mergify mergify bot removed the conflict This PR has conflicts label Oct 6, 2025
@mergify
Copy link

mergify bot commented Oct 6, 2025

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.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

osterman and others added 2 commits October 6, 2025 09:48
…lidation errors

## Markdown Support in Error Hints
- Updated error formatter to use glamour for markdown rendering in hints
- Backticks in hints now render properly with code highlighting
- Removed hardcoded cyan color styling in favor of markdown

## Phase 3: Validation and Advanced Error Hints

### Validation Errors
- **OPA Policy Violations**: Added hints to review policy, fix violations, and use describe command
- **JSON Schema Validation**: Added hints to review schema, fix errors, and revalidate

### Advanced Errors
- **TTY Detection**: Added hints for -auto-approve flag, atmos deploy, and CI/CD usage
- **Duplicate Components** (vendor): Added hints to remove duplicates and check imports
- **Invalid Template Delimiters**: Added hints with examples and default delimiter info

### Technical Improvements
- Replaced stdlib/pkg errors with cockroachdb/errors in:
  - validate_utils.go
  - vendor_utils.go
  - template_utils.go
- Added `ErrInvalidTemplateSettings` and `ErrWorkflowDirectoryDoesNotExist` sentinels
- All errors use sentinel errors from errors/errors.go (err113 compliance)
- Formatter uses glamour to render markdown in hints (no import cycle)

## Files Modified
- errors/formatter.go - Added glamour markdown rendering for hints
- errors/errors.go - Added new sentinel errors
- internal/exec/validate_utils.go - Added hints for OPA and schema validation
- internal/exec/terraform.go - Added hints for TTY detection
- internal/exec/vendor_utils.go - Added hints for duplicate components
- internal/exec/template_utils.go - Added hints for invalid template settings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…indent

## Problem
Error hints were using glamour's `WithAutoStyle()` which ignored custom
markdown styles from `atmos.yaml`. Additionally, hints used 2-space indent
instead of Atmos' standard 4-space list indentation.

## Solution
- Use the global markdown renderer from `error_funcs.go` instead of creating a new one
- Apply 4-space indentation (consistent with `LevelIndent: 4` in Atmos list styles)
- Leverage existing configured styles from `pkg/ui/markdown`

## Changes
- Added `GetMarkdownRenderer()` getter in `errors/error_funcs.go`
- Added `renderHintWithMarkdown()` helper in `errors/formatter.go`
- Updated hint rendering to use configured renderer
- Removed direct `glamour.NewTermRenderer()` call and unused `hintStyle`
- Changed from 2-space to 4-space indent for hints

## Benefits
- ✅ Respects `settings.markdown.code.color` and other atmos.yaml settings
- ✅ Consistent 4-space indentation across all Atmos output
- ✅ Simpler code (no duplicate glamour initialization)
- ✅ Graceful fallback when config not loaded

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
osterman and others added 2 commits October 6, 2025 11:15
- Add context table rendering in verbose mode using lipgloss
- Display structured error context as formatted 2-column tables
- Enrich 14 error scenarios with WithContext() for better debugging
- Update markdown rendering to use configured renderer with 4-space indent
- Fix verbose mode to use --verbose flag instead of log level
- Update documentation for --verbose flag distinction

Context tables help users understand exact error context (component, stack,
policy, schema, etc.) when debugging issues. Verbose mode is controlled by
--verbose flag/ATMOS_VERBOSE env var, separate from --logs-level.

Error enrichment includes:
- Component/stack discovery errors (5 scenarios)
- Workflow/vendor configuration errors (4 scenarios)
- Validation errors (5 scenarios)

All errors now include structured context displayed as tables in verbose mode.

Closes #1334

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add complete debugging and troubleshooting documentation
- Document verbose mode usage and benefits
- Explain difference between --verbose (errors) and --logs-level (logging)
- Provide 5 common debugging scenarios with step-by-step solutions
- Include examples of normal vs verbose error output
- Document Sentry integration for error tracking
- Add best practices for reporting issues

The debugging guide helps users understand how to effectively troubleshoot
issues using verbose mode to see context tables, stack traces, and detailed
error information.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
osterman and others added 4 commits October 28, 2025 09:47
- Create tests/testhelpers/rootcmd.go with RootCmdTestKit
- Provides automatic RootCmd state cleanup for test isolation
- Prevents test pollution from StringSlice flags that append
- Use in TestExecuteDescribeComponentCmd_Success_YAMLWithPager

Note: Test still fails - investigating error handling changes that
broke component discovery. Command works when run directly but fails.
Fixes the critical test TestExecuteDescribeComponentCmd_Success_YAMLWithPager that was blocking PR merge.

**Problem:**
Tests were loading atmos.yaml from parent repository directory instead of test fixtures,
causing "Could not find component" errors. This happened because Atmos searches UP the
directory tree for configuration.

**Solution:**
1. Added RootCmdTestKit to clean up global RootCmd state between tests
2. Set ATMOS_CLI_CONFIG_PATH and ATMOS_BASE_PATH environment variables to explicitly
   point to test fixture directories, preventing upward config search
3. Removed t.Chdir() calls to avoid path resolution issues

**Changes:**
- tests/cli_describe_component_test.go: Fixed TestExecuteDescribeComponentCmd_Success_YAMLWithPager ✅ PASSING
- tests/describe_test.go: Applied same pattern to TestDescribeComponentJSON and TestDescribeComponentYAML
- internal/exec/utils.go: Minor cleanup (removed debug comments)

The critical test now passes, unblocking the PR merge.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Address markdownlint-cli2 violations in PRD documentation by removing
invalid "text" language specifiers from code fences.

Changes:
- docs/prd/atmos-error-implementation-plan.md: Fix bash code fence
- docs/prd/error-handling.md: Fix 6 code fences (flowcharts, examples)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Resolved merge conflicts:
- errors/error_funcs.go: Integrated new error formatter with markdown fallback
- tests/snapshots/TestCLICommands_atmos_auth_whoami_--identity_nonexistent.stderr.golden: Updated to new error format

Key changes from main:
- Auth context improvements and credential loading refactor
- XDG base directory specification compliance
- Terraform output getter interface for better testability
- Various test improvements and snapshot updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Oct 28, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
gomod/github.com/cockroachdb/errors 1.12.0 🟢 5
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Maintained⚠️ 23 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 2
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Code-Review🟢 10all changesets reviewed
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Vulnerabilities🟢 100 existing vulnerabilities detected
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/cockroachdb/logtags 0.0.0-20230118201751-21c54148d20b 🟢 3.7
Details
CheckScoreReason
Pinned-Dependencies⚠️ -1no dependencies found
Dangerous-Workflow⚠️ -1no workflows found
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 5Found 5/10 approved changesets -- score normalized to 5
Token-Permissions⚠️ -1No tokens found
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Fuzzing⚠️ 0project is not fuzzed
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Vulnerabilities🟢 100 existing vulnerabilities detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/cockroachdb/redact 1.1.5 🟢 3.7
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained⚠️ 12 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
Code-Review⚠️ 2Found 4/14 approved changesets -- score normalized to 2
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Vulnerabilities🟢 100 existing vulnerabilities detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/getsentry/sentry-go 0.27.0 🟢 6.5
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review🟢 6Found 17/26 approved changesets -- score normalized to 6
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Security-Policy🟢 10security policy file detected
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies🟢 3dependency not pinned by hash detected -- score normalized to 3
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 4branch protection is not maximal on development and all release branches
Vulnerabilities🟢 73 existing vulnerabilities detected
SAST🟢 10SAST tool is run on all commits
gomod/github.com/kr/pretty 0.3.1 🟢 4.4
Details
CheckScoreReason
Code-Review🟢 6Found 18/27 approved changesets -- score normalized to 6
Packaging⚠️ -1packaging workflow not detected
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
Security-Policy⚠️ 0security policy file not detected
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Vulnerabilities🟢 100 existing vulnerabilities detected
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/kr/text 0.2.0 🟢 4
Details
CheckScoreReason
Code-Review⚠️ 2Found 5/22 approved changesets -- score normalized to 2
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Vulnerabilities🟢 100 existing vulnerabilities detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
gomod/github.com/rogpeppe/go-internal 1.14.1 🟢 4.9
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Code-Review🟢 9Found 24/25 approved changesets -- score normalized to 9
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing🟢 10project is fuzzed
License🟢 10license file detected
Vulnerabilities🟢 100 existing vulnerabilities detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0

Scanned Files

  • go.mod

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
errors/error_funcs.go (1)

36-40: Add godoc comment.

The function logic correctly implements precedence tracking, but it's missing a godoc comment.

Apply this diff:

+// SetVerboseFlag sets the verbose flag value and marks it as explicitly set via CLI.
+// This enables proper precedence: CLI flag > env var > config.
 func SetVerboseFlag(verbose bool) {
 	verboseFlag = verbose
 	verboseFlagSet = true
 }
🧹 Nitpick comments (3)
docs/prd/atmos-error-implementation-plan.md (2)

39-41: Line 40: Add period to end bullet point for consistency.

Your list items (lines 32-40) end with various punctuation. To maintain consistency with standard Markdown list formatting, add a period after "work perfectly" on line 40.

  - ✅ `errors.Is()` and `errors.As()` work perfectly
+ - ✅ `errors.Is()` and `errors.As()` work perfectly.

Alternatively, remove periods from all items if keeping them unpunctuated is your preference.


429-429: Line 429: Replace ellipsis with proper Unicode character.

Use the typographic ellipsis character instead of ... for better readability.

-      ... (comprehensive golden files)
+      … (comprehensive golden files)
tests/describe_test.go (1)

13-55: Consider consolidating into a table-driven test.

Both test functions share identical setup logic and differ only in the --format argument. You could refactor this as a table-driven test to reduce duplication and make it easier to add more format variations in the future.

Example refactor:

-func TestDescribeComponentJSON(t *testing.T) {
-	_ = testhelpers.NewRootCmdTestKit(t) // MANDATORY: Clean up RootCmd state.
-
-	// Get absolute path to test fixture directory.
-	fixtureDir, err := filepath.Abs("./fixtures/scenarios/atmos-providers-section")
-	require.NoError(t, err, "Failed to get absolute path for fixture directory")
-
-	// Set ATMOS_CLI_CONFIG_PATH and ATMOS_BASE_PATH to point to test fixture directory.
-	// This prevents Atmos from searching up the directory tree and finding parent config.
-	t.Setenv("ATMOS_CLI_CONFIG_PATH", fixtureDir)
-	t.Setenv("ATMOS_BASE_PATH", fixtureDir)
-	t.Setenv("ATMOS_PAGER", "more")
-
-	// Use SetArgs for Cobra command testing.
-	cmd.RootCmd.SetArgs([]string{"describe", "component", "component-1", "--stack", "nonprod", "--format", "json"})
-
-	err = cmd.Execute()
-	if err != nil {
-		t.Fatalf("Failed to execute command: %v", err)
-	}
-}
-
-func TestDescribeComponentYAML(t *testing.T) {
-	_ = testhelpers.NewRootCmdTestKit(t) // MANDATORY: Clean up RootCmd state.
-
-	// Get absolute path to test fixture directory.
-	fixtureDir, err := filepath.Abs("./fixtures/scenarios/atmos-providers-section")
-	require.NoError(t, err, "Failed to get absolute path for fixture directory")
-
-	// Set ATMOS_CLI_CONFIG_PATH and ATMOS_BASE_PATH to point to test fixture directory.
-	// This prevents Atmos from searching up the directory tree and finding parent config.
-	t.Setenv("ATMOS_CLI_CONFIG_PATH", fixtureDir)
-	t.Setenv("ATMOS_BASE_PATH", fixtureDir)
-	t.Setenv("ATMOS_PAGER", "more")
-
-	// Use SetArgs for Cobra command testing.
-	cmd.RootCmd.SetArgs([]string{"describe", "component", "component-1", "--stack", "nonprod", "--format", "yaml"})
-
-	err = cmd.Execute()
-	if err != nil {
-		t.Fatalf("Failed to execute command: %v", err)
-	}
-}
+func TestDescribeComponent(t *testing.T) {
+	tests := []struct {
+		name   string
+		format string
+	}{
+		{"JSON", "json"},
+		{"YAML", "yaml"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			_ = testhelpers.NewRootCmdTestKit(t) // MANDATORY: Clean up RootCmd state.
+
+			// Get absolute path to test fixture directory.
+			fixtureDir, err := filepath.Abs("./fixtures/scenarios/atmos-providers-section")
+			require.NoError(t, err, "Failed to get absolute path for fixture directory")
+
+			// Set ATMOS_CLI_CONFIG_PATH and ATMOS_BASE_PATH to point to test fixture directory.
+			// This prevents Atmos from searching up the directory tree and finding parent config.
+			t.Setenv("ATMOS_CLI_CONFIG_PATH", fixtureDir)
+			t.Setenv("ATMOS_BASE_PATH", fixtureDir)
+			t.Setenv("ATMOS_PAGER", "more")
+
+			// Use SetArgs for Cobra command testing.
+			cmd.RootCmd.SetArgs([]string{"describe", "component", "component-1", "--stack", "nonprod", "--format", tt.format})
+
+			err = cmd.Execute()
+			if err != nil {
+				t.Fatalf("Failed to execute command: %v", err)
+			}
+		})
+	}
+}
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 85154f3 and 698679e.

📒 Files selected for processing (15)
  • Makefile (1 hunks)
  • NOTICE (5 hunks)
  • docs/prd/atmos-error-implementation-plan.md (1 hunks)
  • docs/prd/error-handling.md (1 hunks)
  • errors/error_funcs.go (4 hunks)
  • errors/error_funcs_test.go (1 hunks)
  • errors/errors.go (12 hunks)
  • internal/exec/terraform.go (14 hunks)
  • internal/exec/terraform_output_utils.go (1 hunks)
  • internal/exec/terraform_test.go (1 hunks)
  • tests/cli_describe_component_test.go (1 hunks)
  • tests/cli_test.go (2 hunks)
  • tests/describe_test.go (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_auth_env_--help.stdout.golden (2 hunks)
  • tests/testhelpers/rootcmd.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/exec/terraform_output_utils.go
  • errors/error_funcs_test.go
  • tests/cli_test.go
🧰 Additional context used
📓 Path-based instructions (6)
tests/snapshots/**

📄 CodeRabbit inference engine (CLAUDE.md)

Never manually edit golden snapshot files; regenerate using -regenerate-snapshots.

Files:

  • tests/snapshots/TestCLICommands_atmos_auth_env_--help.stdout.golden
docs/prd/[a-z0-9-]*.md

📄 CodeRabbit inference engine (CLAUDE.md)

All PRDs must be placed under docs/prd/ with kebab-case filenames.

Files:

  • docs/prd/atmos-error-implementation-plan.md
  • docs/prd/error-handling.md
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/exec/terraform.go
  • tests/testhelpers/rootcmd.go
  • tests/cli_describe_component_test.go
  • tests/describe_test.go
  • internal/exec/terraform_test.go
  • errors/error_funcs.go
  • errors/errors.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/terraform.go
  • tests/testhelpers/rootcmd.go
  • errors/error_funcs.go
  • errors/errors.go
**/*_test.go

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

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • tests/cli_describe_component_test.go
  • tests/describe_test.go
  • internal/exec/terraform_test.go
tests/**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*_test.go: Integration tests, when necessary, must live under tests/.
Use test precondition helpers from tests/test_preconditions.go so tests skip gracefully when prerequisites are missing.

Files:

  • tests/cli_describe_component_test.go
  • tests/describe_test.go
🧠 Learnings (18)
📚 Learning: 2024-12-07T16:16:13.038Z
Learnt from: Listener430
PR: cloudposse/atmos#825
File: internal/exec/helmfile_generate_varfile.go:28-31
Timestamp: 2024-12-07T16:16:13.038Z
Learning: In `internal/exec/helmfile_generate_varfile.go`, the `--help` command (`./atmos helmfile generate varfile --help`) works correctly without requiring stack configurations, and the only change needed was to make `ProcessCommandLineArgs` exportable by capitalizing its name.

Applied to files:

  • tests/snapshots/TestCLICommands_atmos_auth_env_--help.stdout.golden
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-10-11T19:11:58.965Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: internal/exec/terraform.go:0-0
Timestamp: 2025-10-11T19:11:58.965Z
Learning: For terraform apply interactivity checks in Atmos (internal/exec/terraform.go), use stdin TTY detection (e.g., `IsTTYSupportForStdin()` or checking `os.Stdin`) to determine if user prompts are possible. This is distinct from stdout/stderr TTY checks used for output display (like TUI rendering). User input requires stdin to be a TTY; output display requires stdout/stderr to be a TTY.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-11-02T15:35:09.958Z
Learnt from: aknysh
PR: cloudposse/atmos#759
File: internal/exec/terraform.go:366-368
Timestamp: 2024-11-02T15:35:09.958Z
Learning: In `internal/exec/terraform.go`, the workspace cleaning code under both the general execution path and within the `case "init":` block is intentionally duplicated because the code execution paths are different. The `.terraform/environment` file should be deleted before executing `terraform init` in both scenarios to ensure a clean state.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
PR: cloudposse/atmos#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:

  • internal/exec/terraform.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : All comments must end with periods (godot linter).

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-12-07T16:19:01.683Z
Learnt from: aknysh
PR: cloudposse/atmos#825
File: internal/exec/terraform.go:30-30
Timestamp: 2024-12-07T16:19:01.683Z
Learning: In `internal/exec/terraform.go`, skipping stack validation when help flags are present is not necessary.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • internal/exec/terraform.go
  • errors/error_funcs.go
📚 Learning: 2025-10-03T18:02:08.535Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to cmd/**/*_test.go : Use cmd.NewTestKit(t) for any tests that touch RootCmd to auto-clean RootCmd state.

Applied to files:

  • tests/testhelpers/rootcmd.go
  • tests/describe_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
PR: cloudposse/atmos#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:

  • tests/cli_describe_component_test.go
  • tests/describe_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
PR: cloudposse/atmos#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:

  • tests/describe_test.go
📚 Learning: 2025-05-23T19:51:47.091Z
Learnt from: samtholiya
PR: cloudposse/atmos#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:

  • tests/describe_test.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • errors/error_funcs.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • errors/error_funcs.go
  • errors/errors.go
  • docs/prd/error-handling.md
📚 Learning: 2025-06-23T02:14:30.937Z
Learnt from: aknysh
PR: cloudposse/atmos#1327
File: cmd/terraform.go:111-117
Timestamp: 2025-06-23T02:14:30.937Z
Learning: In cmd/terraform.go, flags for the DescribeAffected function are added dynamically at runtime when info.Affected is true. This is intentional to avoid exposing internal flags like "file", "format", "verbose", "include-spacelift-admin-stacks", "include-settings", and "upload" in the terraform command interface, while still providing them for the shared DescribeAffected function used by both `atmos describe affected` and `atmos terraform apply --affected`.

Applied to files:

  • errors/errors.go
🧬 Code graph analysis (5)
internal/exec/terraform.go (6)
errors/builder.go (1)
  • Build (21-23)
errors/errors.go (4)
  • ErrMissingStack (137-137)
  • ErrInvalidTerraformComponent (150-150)
  • ErrAbstractComponentCantBeProvisioned (143-143)
  • ErrLockedComponentCantBeProvisioned (144-144)
errors/exit_code.go (1)
  • WithExitCode (34-42)
pkg/utils/component_path_utils.go (1)
  • GetComponentBasePath (263-267)
pkg/schema/schema.go (1)
  • Terraform (318-330)
pkg/config/const.go (1)
  • InitRunReconfigure (35-35)
tests/testhelpers/rootcmd.go (1)
cmd/root.go (1)
  • RootCmd (115-244)
tests/cli_describe_component_test.go (2)
internal/exec/describe_component_test.go (1)
  • TestExecuteDescribeComponentCmd_Success_YAMLWithPager (19-177)
tests/testhelpers/rootcmd.go (1)
  • NewRootCmdTestKit (57-67)
tests/describe_test.go (2)
tests/testhelpers/rootcmd.go (1)
  • NewRootCmdTestKit (57-67)
cmd/root.go (1)
  • RootCmd (115-244)
errors/error_funcs.go (5)
pkg/ui/markdown/renderer.go (2)
  • Renderer (37-44)
  • NewTerminalMarkdownRenderer (282-302)
pkg/schema/schema.go (1)
  • AtmosConfiguration (27-66)
errors/sentry.go (3)
  • InitializeSentry (14-45)
  • CaptureError (55-95)
  • CloseSentry (48-51)
errors/formatter.go (3)
  • Format (108-120)
  • FormatterConfig (34-43)
  • DefaultMaxLineLength (21-21)
errors/exit_code.go (1)
  • GetExitCode (52-76)
🪛 LanguageTool
docs/prd/atmos-error-implementation-plan.md

[grammar] ~40-~40: Please add a punctuation mark at the end of paragraph.
Context: ... ✅ errors.Is() and errors.As() work perfectly ## Visual Error Formatting Examples #...

(PUNCTUATION_PARAGRAPH_END)


[style] ~429-~429: Consider using the typographical ellipsis character here instead.
Context: ...olden full_error_tty.golden ... (comprehensive golden files) pkg/schem...

(ELLIPSIS)


[uncategorized] ~544-~544: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...nning** - Collapsed by default, verbose on demand - Error tracking - Get an ID to ref...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

docs/prd/error-handling.md

[grammar] ~57-~57: Please add a punctuation mark at the end of paragraph.
Context: ...ilder pattern provides convenience when needed Example: ```go // Direct usage err...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~81-~81: Please add a punctuation mark at the end of paragraph.
Context: ...efinitions - Supports linting for error usage Example: ```go // errors/errors.go...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~103-~103: Please add a punctuation mark at the end of paragraph.
Context: ...h exec.ExitError - No impact on error messages Implementation: ```go type exitCod...

(PUNCTUATION_PARAGRAPH_END)


[uncategorized] ~173-~173: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...ontext** - Structured debugging info as markdown table 6. ## Stack Trace - Full erro...

(MARKDOWN_NNP)


[uncategorized] ~180-~180: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ... hints with 💡 emoji - Context as clean markdown table - Examples from embedded markdown...

(MARKDOWN_NNP)


[typographical] ~182-~182: In American English, use a period after an abbreviation.
Context: ...rom embedded markdown files - Collapsed vs verbose modes Example Output: ````...

(MISSING_PERIOD_AFTER_ABBREVIATION)


[typographical] ~237-~237: Consider using typographic quotation marks here.
Context: ...r hints → Sentry breadcrumbs (category: "hint") - Safe details → Sentry tags (prefix: ...

(EN_QUOTES)


[typographical] ~238-~238: Consider using a typographic opening quote here.
Context: ...) - Safe details → Sentry tags (prefix: "error.") - Atmos context → Sentry tags (...

(EN_QUOTES)


[typographical] ~238-~238: Consider using a typographic close quote here.
Context: ...e details → Sentry tags (prefix: "error.") - Atmos context → Sentry tags (prefix:...

(EN_QUOTES)


[typographical] ~239-~239: Consider using a typographic opening quote here.
Context: ... - Atmos context → Sentry tags (prefix: "atmos.") - Exit codes → Sentry tag "atmo...

(EN_QUOTES)


[typographical] ~239-~239: Consider using a typographic close quote here.
Context: ...s context → Sentry tags (prefix: "atmos.") - Exit codes → Sentry tag "atmos.exit_...

(EN_QUOTES)


[typographical] ~240-~240: Consider using a typographic opening quote here.
Context: ...ix: "atmos.") - Exit codes → Sentry tag "atmos.exit_code" - Stack traces → Full e...

(EN_QUOTES)


[typographical] ~240-~240: Consider using a typographic close quote here.
Context: ...Exit codes → Sentry tag "atmos.exit_code" - Stack traces → Full error chain This...

(EN_QUOTES)


[grammar] ~241-~241: Please add a punctuation mark at the end of paragraph.
Context: ....exit_code" - Stack traces → Full error chain This ensures Sentry focuses on actiona...

(PUNCTUATION_PARAGRAPH_END)


[grammar] ~465-~465: Use a hyphen to join words.
Context: ...on ### Coverage Target: 100% for error handling code Required tests: - Nil err...

(QB_NEW_EN_HYPHEN)


[uncategorized] ~530-~530: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...t when config unavailable - ✅ Emoji and markdown formatting in hints ### Phase 6: Struc...

(MARKDOWN_NNP)


[uncategorized] ~542-~542: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...# Hints section - ## Context section (markdown table) - ## Stack Trace section (verb...

(MARKDOWN_NNP)


[grammar] ~572-~572: Ensure spelling is correct
Context: ...Benchmarks Target: - Error creation: < 100ns (static) - Builder enrichment: < 1μs - ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~573-~573: Ensure spelling is correct
Context: ... 100ns (static) - Builder enrichment: < 1μs - Formatting: < 10μs - Sentry capture: < 1...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~575-~575: Ensure spelling is correct
Context: ... Formatting: < 10μs - Sentry capture: < 100μs (async) ## Future Enhancements 1. **E...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
docs/prd/error-handling.md

19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


185-185: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


249-249: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


262-262: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


279-279: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


426-426: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build (windows)
  • GitHub Check: Summary
🔇 Additional comments (33)
Makefile (1)

28-29: Refactoring verified and ready to merge.

The script exists, is executable, includes set -e for error handling, and preserves user feedback with echo statements. Build logic is properly delegated with correct temp directory management and binary relocation. No issues found.

docs/prd/atmos-error-implementation-plan.md (1)

1-60: File structure and alignment with PR objectives: ✅ Approved.

The PRD clearly articulates the error handling architecture—no custom wrapper, sentinel errors, builder pattern, exit codes, Sentry integration, and markdown formatting. This aligns well with PR #1599 objectives and the phased rollout approach (Foundation, Hints Migration, Hint Addition). The file provides solid rationale, examples, and success criteria for the implementation.

docs/prd/error-handling.md (1)

1-100: Architecture and design alignment: ✅ Approved.

This document clearly articulates the error handling design—core components, dependencies, design decisions with rationale, and data flow. The structured markdown error presentation (# Error → ## Explanation → ## Example → ## Hints → ## Context → ## Stack Trace) is well-motivated, and the Sentry integration strategy (hints as breadcrumbs, safe details as tags, stack context as tags) is solid. Exit code extraction priority (custom → exec.ExitError → default) is sensible.

NOTICE (5)

196-207: License attributions look good.

The cockroachdb error handling dependencies are properly documented with correct Apache 2.0 licensing. Format is consistent with existing entries.


621-623: Package reference updated appropriately.

Broadening from github.com/gogo/protobuf/proto to github.com/gogo/protobuf accurately reflects wider usage of the library.


705-707: Properly documented.

The rogpeppe/go-internal/fmtsort dependency is correctly attributed under BSD-3-Clause license with proper formatting.


1203-1205: Sentry dependency correctly added.

The getsentry/sentry-go dependency is properly documented with MIT licensing, supporting the Sentry integration feature.


1351-1357: Pretty-printing dependencies documented correctly.

The kr/pretty and kr/text libraries are properly attributed under MIT license, likely supporting error formatting capabilities.

tests/snapshots/TestCLICommands_atmos_auth_env_--help.stdout.golden (1)

85-87: The --verbose flag addition looks good.

The new global flag is properly formatted and its description clearly conveys the feature's purpose. This aligns with the PR's comprehensive error-handling implementation.

tests/describe_test.go (1)

3-11: Import organization looks good.

The imports are properly grouped into stdlib, third-party, and Atmos packages with blank line separators as required by the coding guidelines.

tests/cli_describe_component_test.go (2)

3-11: Import organization is correct.

Imports are properly organized into three groups (stdlib, third-party, Atmos) with appropriate blank line separators.


13-31: Test implementation looks solid.

The test properly initializes the RootCmdTestKit, sets up environment isolation, and follows the established pattern for testing Cobra commands. The fixture path and environment variables correctly prevent upward config searches.

tests/testhelpers/rootcmd.go (4)

3-11: Import organization is correct.

Imports are properly grouped into stdlib, third-party, and Atmos packages with appropriate separators and alphabetical ordering.


13-67: Excellent documentation and clean API design.

The RootCmdTestKit wrapper pattern is well-designed with comprehensive godoc that includes usage examples for both single and table-driven tests. The automatic cleanup via tb.Cleanup() prevents test pollution effectively. Proper use of tb.Helper() ensures correct error line reporting.


114-139: Special handling for StringSlice flags is necessary but complex.

The reflection-based approach to clear the underlying slice before restoration is required because pflag's StringSlice Set() method appends rather than replaces. The defensive checks (IsValid, CanSet) are appropriate.

Minor note: Line 135 and line 160 (in restoreRootCmdState) ignore errors from f.Value.Set(). While these should rarely fail for known flag types, incomplete restoration could lead to test pollution if Set() fails silently.

Consider logging or asserting on Set() errors during restoration to catch unexpected failures:

 	// Set the snapshot value if not default.
 	if snap.value != "[]" && snap.value != "" {
-		_ = f.Value.Set(snap.value)
+		if err := f.Value.Set(snap.value); err != nil {
+			// Log error but don't fail test cleanup
+			// (test already completed, this is best-effort restoration)
+		}
 	}

141-168: State restoration logic is comprehensive.

The function correctly restores command args, os.Args, and all flags (both local and persistent). The dual path for StringSlice flags vs. other flag types is necessary and properly implemented. The closure pattern for restoreFlags is clean and avoids duplication.

errors/error_funcs.go (6)

16-19: LGTM!

Centralizing the environment variable name as a constant is good practice and prevents typos.


27-34: LGTM!

The global state design is appropriate for error handling configuration. The verboseFlagSet addition correctly addresses the past review about honoring CLI/env overrides.


85-98: LGTM!

The Sentry integration and routing logic are well-implemented with proper nil checks. The fallback to the markdown renderer ensures backward compatibility.


100-133: LGTM!

The verbose precedence logic correctly implements the pattern from the past review: config < env < CLI. The use of viper.IsSet ensures environment variable overrides are properly detected, and verboseFlagSet ensures CLI overrides take highest precedence.


135-158: LGTM!

The fallback chain (markdown → plain) is robust and ensures error messages always display, even when rendering fails.


168-180: LGTM!

The Sentry closure and custom exit code support are properly implemented. The nil checks prevent panics when config isn't initialized.

internal/exec/terraform_test.go (1)

654-656: Test assertions correctly match the actual warning message.

The updated assertions now check for the complete warning message that's emitted by the code. This properly validates both the presence and absence of the Pro warning based on the test configuration.

internal/exec/terraform.go (8)

10-11: Import addition supports structured error handling.

The cockroachdb/errors import enables the enhanced error construction patterns used throughout this file. Proper formatting with the blank line separator.


78-84: Well-structured error with helpful context.

Proper use of the error builder pattern with context, actionable hint, and appropriate exit code. The hint clearly guides users to specify the stack using the --stack flag.


106-124: Comprehensive error handling with rich context.

Excellent error construction that addresses all past review concerns:

  • GetComponentBasePath error is now properly checked and returned
  • Multiple context fields provide complete debugging information
  • Actionable hints guide users to list components and verify paths
  • Exit code 2 is appropriate for this configuration error

129-161: Clear error messages for provisioning restrictions.

Both errors are well-structured:

  • Abstract component error explains inheritance semantics and suggests creating a concrete component
  • Locked component error appropriately guards only modification commands (apply, deploy, destroy, etc.) while allowing read-only operations
  • Context fields enable debugging and hint fields guide remediation

262-272: Validation failure error is clear and actionable.

Properly structured error that identifies the component and stack that failed validation, with a hint directing users to check the validation policies in the component's configuration.


373-381: OpenTofu-specific feature properly documented.

Clear comments explain that --var-file for init is OpenTofu-specific and will fail with HashiCorp Terraform. The approach of documenting the requirement rather than attempting runtime detection is sound, as command names don't reliably indicate the actual binary (symlinks, aliases).

Based on learnings.


545-563: Sophisticated workspace error handling.

The typed error checking with errors.As properly distinguishes workspace-doesn't-exist (exit code 1) from other errors, enabling graceful workspace creation. Other error codes are correctly propagated without masking.


604-646: Exit code preservation maintains semantic meaning.

Excellent three-tier exit code extraction strategy:

  • Prefers typed ExitCodeError for atmos-generated errors
  • Falls back to os/exec.ExitError for subprocess errors
  • Defaults to 1 for other failures

The special handling for terraform plan (exit code 2 = changes detected) correctly treats it as success for upload purposes while preserving the code for the caller.

errors/errors.go (2)

39-218: Comprehensive error catalog with clear messages.

The new error sentinels provide excellent coverage across all major subsystems (config, stack, component, terraform, validation, etc.). Messages are concise yet descriptive, and all follow the consistent pattern of static package-level declarations required by the coding guidelines.


487-489: Generic error message works across all commands.

The ExitCodeError message is now command-agnostic ("command exited with code %d"), making it suitable for use across terraform, helmfile, workflow, and other command types.

Comment on lines +19 to +25
```
errors/
├── exit_code.go # Exit code wrapper and extraction
├── builder.go # Fluent API for rich errors
├── formatter.go # TTY-aware error display
└── sentry.go # Sentry integration
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language identifiers to all fenced code blocks (MD040 violations).

All fenced code blocks must specify a language for markdownlint compliance. The violations appear at six locations; apply language identifiers to each.

-```
+```text
 errors/
 ├── exit_code.go          # Exit code wrapper and extraction
 ├── builder.go            # Fluent API for rich errors
 ├── formatter.go          # TTY-aware error display
 └── sentry.go            # Sentry integration
-```
+```

Apply the same fix pattern to lines 185, 249, 262, 279, and 426—add language identifiers (typically text for diagrams and examples, or the appropriate language like go, yaml, bash).

Run markdownlint docs/prd/error-handling.md after applying to verify all MD040 warnings are resolved.

Also applies to: 185-216, 249-258, 262-275, 279-291, 426-436

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In docs/prd/error-handling.md around lines 19-25 (and also apply the same change
in the ranges 185-216, 249-258, 262-275, 279-291, 426-436), several fenced code
blocks are missing language identifiers causing MD040 markdownlint violations;
update each opening fence to include the appropriate language (e.g., ```text for
diagrams/listings, ```go for Go snippets, ```yaml/```bash where applicable) so
every triple-backtick block has a language specifier, then run `markdownlint
docs/prd/error-handling.md` to verify all MD040 warnings are resolved.

Comment on lines +43 to +59
func InitializeMarkdown(config *schema.AtmosConfiguration) {
var err error
render, err = markdown.NewTerminalMarkdownRenderer(atmosConfig)
render, err = markdown.NewTerminalMarkdownRenderer(*config)
if err != nil {
log.Error("failed to initialize Markdown renderer", "error", err)
}

// Store config for error formatting.
atmosConfig = config

// Initialize Sentry if configured.
if config.Errors.Sentry.Enabled {
if err := InitializeSentry(&config.Errors.Sentry); err != nil {
log.Warn("failed to initialize Sentry", "error", err)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add nil check or document non-nil requirement.

Line 45 dereferences the config pointer without checking for nil, which could panic.

Apply this diff to add a nil check:

 func InitializeMarkdown(config *schema.AtmosConfiguration) {
+	if config == nil {
+		log.Error("InitializeMarkdown called with nil config")
+		return
+	}
+
 	var err error
 	render, err = markdown.NewTerminalMarkdownRenderer(*config)

Alternatively, document in a godoc comment that config must not be nil (though a defensive nil check is safer).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func InitializeMarkdown(config *schema.AtmosConfiguration) {
var err error
render, err = markdown.NewTerminalMarkdownRenderer(atmosConfig)
render, err = markdown.NewTerminalMarkdownRenderer(*config)
if err != nil {
log.Error("failed to initialize Markdown renderer", "error", err)
}
// Store config for error formatting.
atmosConfig = config
// Initialize Sentry if configured.
if config.Errors.Sentry.Enabled {
if err := InitializeSentry(&config.Errors.Sentry); err != nil {
log.Warn("failed to initialize Sentry", "error", err)
}
}
}
func InitializeMarkdown(config *schema.AtmosConfiguration) {
if config == nil {
log.Error("InitializeMarkdown called with nil config")
return
}
var err error
render, err = markdown.NewTerminalMarkdownRenderer(*config)
if err != nil {
log.Error("failed to initialize Markdown renderer", "error", err)
}
// Store config for error formatting.
atmosConfig = config
// Initialize Sentry if configured.
if config.Errors.Sentry.Enabled {
if err := InitializeSentry(&config.Errors.Sentry); err != nil {
log.Warn("failed to initialize Sentry", "error", err)
}
}
}
🤖 Prompt for AI Agents
In errors/error_funcs.go around lines 43 to 59, the function InitializeMarkdown
dereferences the config pointer without validating it; add a defensive nil check
at the start (if config == nil) that logs an error (or warning) and returns
immediately so no further dereferences occur, ensuring the rest of the function
(markdown renderer initialization, storing atmosConfig, and Sentry init) only
runs when config is non-nil.

Comment on lines +61 to 64
// GetMarkdownRenderer returns the global markdown renderer.
func GetMarkdownRenderer() *markdown.Renderer {
return render
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add godoc comment.

This exported function needs documentation per coding guidelines.

Apply this diff:

+// GetMarkdownRenderer returns the global markdown renderer instance.
+// Returns nil if InitializeMarkdown has not been called.
 func GetMarkdownRenderer() *markdown.Renderer {
 	return render
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// GetMarkdownRenderer returns the global markdown renderer.
func GetMarkdownRenderer() *markdown.Renderer {
return render
}
// GetMarkdownRenderer returns the global markdown renderer instance.
// Returns nil if InitializeMarkdown has not been called.
func GetMarkdownRenderer() *markdown.Renderer {
return render
}
🤖 Prompt for AI Agents
In errors/error_funcs.go around lines 61 to 64, the exported function
GetMarkdownRenderer lacks a godoc comment; add a proper GoDoc comment
immediately above the function that starts with "GetMarkdownRenderer" and
briefly describes that it returns the package's global markdown renderer (e.g.,
"GetMarkdownRenderer returns the package-level *markdown.Renderer used for
rendering Markdown."). Ensure the comment is a complete sentence, capitalized,
and follows Go doc conventions.



Use atmos auth env --help for more information about a command.
Use atmos auth env --help for more information about a command.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the footer help text logic.

The footer reads "Use atmos auth env --help for more information about a command" within the output of atmos auth env --help itself, which seems self-referential. If env has no subcommands, this text may be misleading.

Check the help text generation logic to ensure the footer is appropriate for leaf commands.

Run this script to check if env has subcommands and verify the help template logic:


🏁 Script executed:

#!/bin/bash
# Description: Check if auth env command has subcommands and inspect help template

# Search for the env command definition and its subcommands
ast-grep --pattern 'func.*Env.*Command'

# Search for help template usage or customization
rg -nP --type=go 'UsageTemplate|SetUsageTemplate|auth.*env' -A5 -B5

Length of output: 28806



---

🏁 Script executed:

```shell
#!/bin/bash
# Find the Footer template definition and check if env command has subcommands

# Search for Footer template definition
rg -n "Footer" --type=go -A10 internal/tui/templates/

# Search for authEnvCmd.AddCommand or any subcommand additions to authEnvCmd
rg -n "authEnvCmd\.AddCommand" --type=go -C5

# Check if auth env is a leaf command by looking for subcommand definitions
ast-grep --pattern 'var authEnvCmd = &cobra.Command {
  $$$
}'

Length of output: 5035



---

🏁 Script executed:

```shell
#!/bin/bash
# Find Footer template definition with corrected search

# Search for Footer string across the codebase
rg -n "Footer" --type=go -A5 -B2

# Search specifically for template strings/functions
rg -n "Use.*for more information" --type=go -C3

# Look for HasAvailableSubcommands usage
rg -n "HasAvailableSubcommands\|HasSubcommands" --type=go -C3

Length of output: 3015


Fix the help footer to only appear for commands with subcommands.

The footer text is generated unconditionally in internal/tui/templates/templater.go lines 85-88, producing "Use atmos auth env --help..." even for leaf commands like env that have no subcommands. This creates a self-referential footer when viewing --help output.

The fix: wrap the help text generation logic with a condition that checks cmd.HasSubCommands() before creating and rendering the help message. Currently the check only controls whether "[subcommand]" is appended to the command path, but the help text itself should not appear for leaf commands.

🤖 Prompt for AI Agents
In internal/tui/templates/templater.go around lines 85 to 88, the help footer
"Use <command> --help for more information about a command." is rendered
unconditionally, causing a self-referential footer for leaf commands like `env`;
modify the logic so the footer is only generated and rendered when
cmd.HasSubCommands() is true — i.e., wrap the footer construction and its
rendering in an if cmd.HasSubCommands() { ... } block (keeping the existing
append of "[subcommand]" behavior) so leaf commands do not get the extra help
text.

osterman and others added 4 commits October 28, 2025 11:17
Update TestExecuteDescribeWorkflows to use `assert.ErrorIs()` with sentinel
errors from the errors package instead of fragile string matching:

- Use errUtils.ErrWorkflowBasePathNotConfigured for missing base path
- Use errUtils.ErrWorkflowDirectoryDoesNotExist for nonexistent directory

Benefits:
- Type-safe error checking that works with wrapped errors
- Compile-time detection of changes to error definitions
- Follows Go 1.13+ error handling best practices
- More robust than string matching which can break on message changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes three regressions introduced during the pkg/errors migration:

1. Workflow error messages - restore "workflow step execution failed with exit code X"
   - Was: "workflow step execution failed\ncommand exited with code 1" (lost "step", newline)
   - Now: "workflow step execution failed with exit code 1" (restored)
   - Fix: Wrap sentinel error with formatted message including exit code

2. Circular dependency errors - restore detailed explanation in Error() string
   - Was: Only base message "circular dependency detected in identity chain"
   - Now: Full dependency chain, component names, function calls, and fix suggestions
   - Fix: Build complete error message inline instead of using error builder metadata

3. Plan diff error - restore helpful flag hint
   - Was: "original plan file is required"
   - Now: "original plan file (--orig) is required"
   - Fix: Update static error message in errors/errors.go

All tests now pass. Error messages maintain backward compatibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Move formatting (newlines) from error construction to presentation layer
- Use named constants for newlines to satisfy linter
- Move plan diff flag hint from error message to structured hint
- Preserve error messages for backward compatibility with tests

The circular dependency error now uses a newline constant instead of
inline literals, maintaining the structured error message while
satisfying the revive linter's add-constant rule.

The plan diff error now uses WithHint() to provide the --orig flag
suggestion, properly separating data (the error) from presentation
(the hint).

Workflow errors still need investigation - the error builder wrapping
may be interfering with error message propagation in some cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/exec/yaml_func_resolution_context.go (1)

172-211: Address string building inefficiency and enrich error context; consider sentinel terminology.

  • Replace repeated WriteString + fmt.Sprintf calls with fmt.Fprintf(&errMsg, ...) to reduce allocations.
  • Add FunctionType and FunctionCall fields to WithContext() calls—both are available on newNode (confirmed in DependencyNode struct).
  • Move "To fix this issue" hints into WithHint() calls; errUtils.Build supports this API and it's used elsewhere in the codebase.
  • The sentinel "circular dependency detected in identity chain" is semantically misaligned here. It's designed for identity/credential cycles, not component dependencies. Either update the sentinel to be domain-agnostic or create a component-specific variant.
  • The magic exit code 1 could use a named constant (e.g., errUtils.ExitCodeGeneric) for consistency.

Suggested diff (local to this file):

  // Add each node in the call stack.
  for i, node := range ctx.CallStack {
-   errMsg.WriteString(fmt.Sprintf("%d. Component '%s' in stack '%s'", i+1, node.Component, node.Stack))
-   errMsg.WriteString(newline)
-   errMsg.WriteString(fmt.Sprintf("   → %s", node.FunctionCall))
-   errMsg.WriteString(newline)
+   fmt.Fprintf(&errMsg, "%d. Component '%s' in stack '%s'%s   → %s%s",
+     i+1, node.Component, node.Stack, newline, node.FunctionCall, newline)
  }

  // Add the new node that creates the cycle.
- errMsg.WriteString(fmt.Sprintf("%d. Component '%s' in stack '%s' (cycle detected)", len(ctx.CallStack)+1, newNode.Component, newNode.Stack))
- errMsg.WriteString(newline)
- errMsg.WriteString(fmt.Sprintf("   → %s", newNode.FunctionCall))
- errMsg.WriteString(newline + newline)
+ fmt.Fprintf(&errMsg, "%d. Component '%s' in stack '%s' (cycle detected)%s   → %s%s%s",
+   len(ctx.CallStack)+1, newNode.Component, newNode.Stack, newline, newNode.FunctionCall, newline, newline)

- // Add fix suggestions.
- errMsg.WriteString("To fix this issue:")
- errMsg.WriteString(newline)
- errMsg.WriteString("• Review your component dependencies and break the circular reference")
- errMsg.WriteString(newline)
- errMsg.WriteString("• Consider using Terraform data sources or direct remote state instead")
- errMsg.WriteString(newline)
- errMsg.WriteString("• Ensure dependencies flow in one direction only")

  return errUtils.Build(err).
    WithContext("component", newNode.Component).
    WithContext("stack", newNode.Stack).
+   WithContext("function_type", newNode.FunctionType).
+   WithContext("function_call", newNode.FunctionCall).
+   WithHint("Review your component dependencies and break the circular reference.").
+   WithHint("Consider using Terraform data sources or direct remote state instead.").
+   WithHint("Ensure dependencies flow in one direction only.").
    WithExitCode(1).
    Err()
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between c7d8b75 and 105c9fd.

📒 Files selected for processing (3)
  • internal/exec/terraform_plan_diff.go (5 hunks)
  • internal/exec/workflow_utils.go (6 hunks)
  • internal/exec/yaml_func_resolution_context.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/exec/terraform_plan_diff.go
  • internal/exec/workflow_utils.go
  • internal/exec/yaml_func_resolution_context.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/terraform_plan_diff.go
  • internal/exec/workflow_utils.go
  • internal/exec/yaml_func_resolution_context.go
🧠 Learnings (2)
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • internal/exec/workflow_utils.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • internal/exec/workflow_utils.go
🧬 Code graph analysis (3)
internal/exec/terraform_plan_diff.go (2)
errors/builder.go (1)
  • Build (21-23)
errors/errors.go (3)
  • ErrOriginalPlanFileRequired (155-155)
  • ErrOriginalPlanFileNotExist (156-156)
  • ErrNoJSONOutput (154-154)
internal/exec/workflow_utils.go (6)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (52-76)
errors/error_funcs.go (1)
  • CheckErrorAndPrint (80-98)
pkg/logger/log.go (2)
  • Debug (24-26)
  • Errorf (59-61)
errors/errors.go (2)
  • ErrWorkflowBasePathNotConfigured (336-336)
  • ErrWorkflowDirectoryDoesNotExist (337-337)
pkg/schema/schema.go (1)
  • Workflows (400-403)
internal/exec/yaml_func_resolution_context.go (3)
errors/errors.go (1)
  • ErrCircularDependency (442-442)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (1)
  • WithExitCode (34-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (macos)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (windows)
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: autofix
  • GitHub Check: website-deploy-preview
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (8)
internal/exec/terraform_plan_diff.go (2)

89-91: ErrorBuilder pattern used correctly.

The fluent API with .WithHint() provides actionable guidance for users missing the required flag.


38-38: Error wrapping migration completed correctly.

All error handling uses proper %w wrapping to preserve error chains, and sentinel errors from the errors package are integrated cleanly. The contextual messages are clear without being verbose.

Also applies to: 106-106, 117-117, 123-123, 130-130, 135-135, 193-193

internal/exec/workflow_utils.go (5)

80-87: Solid error builder pattern implementation.

This correctly constructs a rich error with title, explanation, and exit code, prints it, then returns the built error for proper test assertions.


171-177: Correct error builder implementation.

Properly builds and returns the rich error with context, maintaining the error chain.


254-260: Well-structured error with actionable hints.

Properly returns a rich error with multiple hints for configuration. Correct pattern for a describe command that propagates errors to the caller.


272-280: Excellent error with context and recovery steps.

Provides the actual directory path that's missing, actionable recovery commands, and appropriate exit code differentiation (2 for missing directory vs 1 for config issue).


214-227: The review comment is based on incorrect assumptions about test flexibility.

The search results show that existing tests explicitly assert on the error message substring containing the exit code:

  • internal/exec/workflow_test.go:126: "workflow step execution failed with exit code 1"
  • pkg/utils/shell_utils_test.go:33, 40, 47: Similar substring assertions for exit codes 1, 2, and 42

The baseErr pattern at lines 214-216 is not a temporary migration strategy—it's required for these existing test assertions to pass. Removing it or refactoring tests to use errUtils.GetExitCode(err) would break these checks. The code is correct as-is.

Likely an incorrect or invalid review comment.

internal/exec/yaml_func_resolution_context.go (1)

166-169: LGTM on newline constant.

Clear and readable; no issues from lint/style.

osterman and others added 2 commits October 28, 2025 14:30
- Add exit code formatting logic to the error formatter
- Formatter now appends exit code to error message display
- Skip appending for ExitCodeError to avoid duplication
- Plan diff error uses hint for --orig flag suggestion

Workflow errors still showing ExitCodeError instead of ErrWorkflowStepFailed.
Despite calling CheckErrorAndPrint(stepErr), the output shows 'command exited
with code 1' instead of 'workflow step execution failed with exit code 1'.

Need to investigate why the workflow error is not being printed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Moved exit code formatting to errors/formatter.go which extracts the
exit code and appends it to error messages during display.

Added check to skip appending for ExitCodeError to avoid duplication.

Simplified workflow error to bare sentinel for debugging. Tests still
show "command exited with code 1" instead of "workflow step execution
failed with exit code 1" - investigating fallback error printing paths.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/exec/workflow_utils.go (1)

182-220: Code needs fixing to match established error handling pattern.

The comments confirm this is incomplete test code ("testing bare sentinel", "currently unused"). Every other workflow error in workflow_utils.go uses errUtils.Build with rich context—see lines 80-87 and 111-114. The computed failedCmd and resumeCommand should be incorporated into the error, not discarded.

Update lines 214-219 to use the established pattern:

-		// Create workflow error directly without exit code wrapper.
-		// Just use the sentinel error to test if it gets printed correctly.
-		stepErr := ErrWorkflowStepFailed
-
-		errUtils.CheckErrorAndPrint(stepErr, "", "")
-		return stepErr
+		stepErr := errUtils.Build(ErrWorkflowStepFailed).
+			WithTitle(WorkflowErrTitle).
+			WithExplanationf("Command failed: `%s`\n\n### Resume from this step:\n```\n%s\n```", failedCmd, resumeCommand).
+			WithExitCode(errUtils.GetExitCode(err)).
+			Err()
+		errUtils.CheckErrorAndPrint(stepErr, "", "")
+		return stepErr
♻️ Duplicate comments (1)
internal/exec/workflow_utils.go (1)

109-115: Return the built error, not the base error.

Line 114 returns ErrInvalidFromStep instead of the built error err, discarding all the rich context (title, explanation) that was just added. This breaks the error chain and is inconsistent with the patterns at lines 79-87 and 171-177.

Apply this diff:

 		err := errUtils.Build(ErrInvalidFromStep).
 			WithTitle(WorkflowErrTitle).
 			WithExplanationf("The `--from-step` flag was set to `%s`, but this step does not exist in workflow `%s`.\n\n### Available steps:\n%s", fromStep, workflow, FormatList(stepNames)).
 			Err()
 		errUtils.CheckErrorAndPrint(err, "", "")
-		return ErrInvalidFromStep
+		return err
🧹 Nitpick comments (1)
errors/formatter.go (1)

54-105: Consider extracting shared parsing logic.

formatContextTable and formatContextForMarkdown duplicate the key-value pair parsing logic. Extracting a helper would reduce duplication.

Example refactor:

// parseContextPairs extracts key-value pairs from safe details.
func parseContextPairs(err error) [][]string {
	details := errors.GetSafeDetails(err)
	if len(details.SafeDetails) == 0 {
		return nil
	}

	var rows [][]string
	for _, detail := range details.SafeDetails {
		str := fmt.Sprintf("%v", detail)
		pairs := strings.Split(str, " ")
		for _, pair := range pairs {
			if parts := strings.SplitN(pair, "=", 2); len(parts) == 2 {
				rows = append(rows, []string{parts[0], parts[1]})
			}
		}
	}
	return rows
}

Then both functions can call parseContextPairs(err) instead of duplicating the parsing logic.

Also applies to: 337-370

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 105c9fd and c1d7cd6.

📒 Files selected for processing (2)
  • errors/formatter.go (1 hunks)
  • internal/exec/workflow_utils.go (6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • errors/formatter.go
  • internal/exec/workflow_utils.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • errors/formatter.go
  • internal/exec/workflow_utils.go
🧠 Learnings (7)
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-11T19:06:16.131Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:247-259
Timestamp: 2025-10-11T19:06:16.131Z
Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
PR: cloudposse/atmos#727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • internal/exec/workflow_utils.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • internal/exec/workflow_utils.go
🧬 Code graph analysis (2)
errors/formatter.go (7)
pkg/ui/theme/colors.go (2)
  • ColorBorder (23-23)
  • ColorGreen (11-11)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/errors.go (1)
  • ExitCodeError (483-485)
errors/exit_code.go (1)
  • GetExitCode (52-76)
errors/error_funcs.go (1)
  • GetMarkdownRenderer (62-64)
pkg/schema/schema.go (3)
  • AtmosConfiguration (27-66)
  • AtmosSettings (252-272)
  • Docs (282-288)
pkg/ui/markdown/renderer.go (1)
  • NewTerminalMarkdownRenderer (282-302)
internal/exec/workflow_utils.go (6)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (52-76)
errors/error_funcs.go (1)
  • CheckErrorAndPrint (80-98)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/errors.go (2)
  • ErrWorkflowBasePathNotConfigured (336-336)
  • ErrWorkflowDirectoryDoesNotExist (337-337)
pkg/schema/schema.go (1)
  • Workflows (400-403)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (macos)
  • GitHub Check: Build (windows)
  • GitHub Check: website-deploy-preview
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: autofix
  • GitHub Check: Summary
🔇 Additional comments (4)
internal/exec/workflow_utils.go (3)

79-87: Well-structured error handling.

The empty workflow case correctly builds a rich error with title, explanation, and exit code, then returns the enriched error after printing. Pattern matches the established approach.


171-177: Correct error construction.

Invalid step type handling properly builds and returns the enriched error. The explanation includes available types, making it actionable for users.


246-272: Excellent error handling with actionable hints.

Both error cases (base path not configured, directory doesn't exist) correctly build rich errors with multiple hints and appropriate exit codes. The hints guide users toward resolution (configure atmos.yaml, create directory, or update config).

errors/formatter.go (1)

45-52: Add doc comment to exported function.

DefaultFormatterConfig is exported but lacks the required Go doc comment.

Apply this diff:

+// DefaultFormatterConfig returns the default formatter configuration with
+// verbose disabled, auto color mode, and 80-character line wrapping.
 func DefaultFormatterConfig() FormatterConfig {

Likely an incorrect or invalid review comment.

osterman and others added 2 commits October 28, 2025 20:53
This commit implements a type-safe approach to exit code handling that
eliminates the class of error where exit codes are blindly appended to
all error messages.

## Changes

### New ExecError Type
- Created `errors/exec_error.go` with ExecError struct
- Stores command name, args, exit code, and optional stderr
- Only ExecError instances show "with exit code N" in formatted output

### Formatter Updates
- Modified `errors/formatter.go` to check for ExecError specifically
- Removed blind exit code appending that affected all errors
- Added command output section for ExecError with stderr

### Exit Code Handling
- Updated `GetExitCode()` to recognize ExecError as highest priority
- Added `ErrCommandFailed` static sentinel error
- ExecuteShellCommand now returns ExecError instead of ExitCodeError

### Workflow Error Fixes
- Workflow errors now use structured WithExplanation/WithHint
- Added "Workflow Error" custom title
- Explanation shows failed command, hints show resume command
- Exit codes only appear for actual command execution failures

### Test Updates
- Regenerated snapshots for workflow tests
- Snapshots now show proper structured error formatting
- Workflow errors display explanation and hints sections

## Why This Fixes The Problem

Before: Formatter blindly appended " with exit code X" to ANY error
with an exit code, causing validation errors and other non-command
errors to show exit codes inappropriately.

After: Only ExecError (external command failures) show exit codes.
All other errors use structured hints and explanations from
cockroachdb/errors.

This leverages the structured error system properly: errors are data
structures, the formatter handles presentation based on error type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Use the formatted variants of explanation and hint methods to avoid
manual fmt.Sprintf calls. Cleaner and more idiomatic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
internal/exec/workflow_utils.go (1)

109-114: Return the built error, not the base sentinel.

Line 114 returns ErrInvalidFromStep instead of err, discarding the enriched title and explanation. This is the same issue flagged in the previous review comment marked as "Addressed in commit ced1ae2", but the code still shows the incorrect return.

Apply this diff:

 		err := errUtils.Build(ErrInvalidFromStep).
 			WithTitle(WorkflowErrTitle).
 			WithExplanationf("The `--from-step` flag was set to `%s`, but this step does not exist in workflow `%s`.\n\n### Available steps:\n%s", fromStep, workflow, FormatList(stepNames)).
 			Err()
 		errUtils.CheckErrorAndPrint(err, "", "")
-		return ErrInvalidFromStep
+		return err
🧹 Nitpick comments (4)
errors/formatter.go (1)

54-105: Consider using config width instead of hardcoded constant.

Line 84 uses DefaultMarkdownWidth for the table width. Since FormatterConfig has MaxLineLength, consider whether table width should respect that config value instead of always using the hardcoded constant.

errors/exec_error.go (2)

18-28: Consider nil receiver handling.

If Error() is called on a nil *ExecError, it will panic. While this is uncommon in practice, defensive nil checks are a Go best practice for receiver methods.

Apply this diff to add nil protection:

 func (e *ExecError) Error() string {
+	if e == nil {
+		return "exec error: <nil>"
+	}
 	if e.cause != nil {
 		return e.cause.Error()
 	}

30-33: Consider nil receiver handling.

Similar to Error(), this method will panic on a nil receiver. Adding a nil check maintains consistency with defensive coding practices.

Apply this diff:

 func (e *ExecError) Unwrap() error {
+	if e == nil {
+		return nil
+	}
 	return e.cause
 }
internal/exec/workflow_utils.go (1)

221-234: Consider edge cases in command parsing.

The logic wraps the enriched error in ExecError when a non-zero exit code is detected. The command string is parsed with strings.Fields, which splits on whitespace but doesn't handle quoted arguments (e.g., atmos workflow "my workflow" would split incorrectly). For metadata and display purposes this is acceptable, but be aware of the limitation.

Additionally, if the original err is already an ExecError, this creates nested wrapping. While GetExitCode handles this correctly, the command context may be redundant.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between c1d7cd6 and b6d1ea1.

📒 Files selected for processing (15)
  • errors/errors.go (13 hunks)
  • errors/exec_error.go (1 hunks)
  • errors/exit_code.go (1 hunks)
  • errors/formatter.go (1 hunks)
  • internal/exec/shell_utils.go (2 hunks)
  • internal/exec/workflow_utils.go (6 hunks)
  • tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_auth_validate_(invalid_config).stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_auth_whoami_--identity_nonexistent.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_circuit-breaker.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_workflow_failure.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_on_shell_command.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_filepath.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_stack.stderr.golden (1 hunks)
  • tests/snapshots/TestCLICommands_atmos_workflow_shell_command_not_found.stderr.golden (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/snapshots/TestCLICommands_atmos_auth_invalid-command.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_workflow_failure.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_on_shell_command.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_filepath.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_auth_validate_(invalid_config).stderr.golden
🧰 Additional context used
📓 Path-based instructions (3)
tests/snapshots/**

📄 CodeRabbit inference engine (CLAUDE.md)

Never manually edit golden snapshot files; regenerate using -regenerate-snapshots.

Files:

  • tests/snapshots/TestCLICommands_atmos_workflow_shell_command_not_found.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_auth_whoami_--identity_nonexistent.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_stack.stderr.golden
  • tests/snapshots/TestCLICommands_atmos_circuit-breaker.stderr.golden
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/exec/shell_utils.go
  • errors/exec_error.go
  • errors/exit_code.go
  • internal/exec/workflow_utils.go
  • errors/formatter.go
  • errors/errors.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/shell_utils.go
  • errors/exec_error.go
  • errors/exit_code.go
  • internal/exec/workflow_utils.go
  • errors/formatter.go
  • errors/errors.go
🧠 Learnings (8)
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • internal/exec/workflow_utils.go
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_stack.stderr.golden
  • errors/errors.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • internal/exec/workflow_utils.go
  • tests/snapshots/TestCLICommands_atmos_workflow_failure_with_stack.stderr.golden
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-11T19:06:16.131Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:247-259
Timestamp: 2025-10-11T19:06:16.131Z
Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
PR: cloudposse/atmos#727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-06-23T02:14:30.937Z
Learnt from: aknysh
PR: cloudposse/atmos#1327
File: cmd/terraform.go:111-117
Timestamp: 2025-06-23T02:14:30.937Z
Learning: In cmd/terraform.go, flags for the DescribeAffected function are added dynamically at runtime when info.Affected is true. This is intentional to avoid exposing internal flags like "file", "format", "verbose", "include-spacelift-admin-stacks", "include-settings", and "upload" in the terraform command interface, while still providing them for the shared DescribeAffected function used by both `atmos describe affected` and `atmos terraform apply --affected`.

Applied to files:

  • errors/errors.go
🧬 Code graph analysis (4)
internal/exec/shell_utils.go (2)
errors/exec_error.go (1)
  • NewExecError (36-43)
errors/errors.go (1)
  • ErrCommandFailed (452-452)
errors/exit_code.go (3)
pkg/logger/log.go (1)
  • Error (54-56)
errors/exec_error.go (1)
  • ExecError (10-16)
errors/errors.go (1)
  • ExitCodeError (484-486)
internal/exec/workflow_utils.go (7)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (53-83)
errors/error_funcs.go (1)
  • CheckErrorAndPrint (80-98)
pkg/config/const.go (1)
  • AtmosCommand (4-4)
errors/exec_error.go (1)
  • NewExecError (36-43)
errors/errors.go (2)
  • ErrWorkflowBasePathNotConfigured (336-336)
  • ErrWorkflowDirectoryDoesNotExist (337-337)
pkg/schema/schema.go (1)
  • Workflows (400-403)
errors/formatter.go (6)
pkg/ui/theme/colors.go (2)
  • ColorBorder (23-23)
  • ColorGreen (11-11)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/exec_error.go (1)
  • ExecError (10-16)
errors/error_funcs.go (1)
  • GetMarkdownRenderer (62-64)
pkg/schema/schema.go (3)
  • AtmosConfiguration (27-66)
  • AtmosSettings (252-272)
  • Docs (282-288)
pkg/ui/markdown/renderer.go (1)
  • NewTerminalMarkdownRenderer (282-302)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (windows)
  • GitHub Check: autofix
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: website-deploy-preview
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
🔇 Additional comments (8)
errors/exec_error.go (4)

1-6: LGTM!

Package declaration and imports are clean and minimal.


8-16: LGTM!

The struct is well-documented and properly designed. The unexported cause field with public Unwrap() method follows Go error wrapping conventions.


35-43: LGTM!

The constructor is straightforward and follows Go conventions. No validation is needed here since the caller controls the inputs.


45-49: LGTM!

The fluent setter follows established patterns. Nil receiver protection is optional here since the method assumes a valid instance from NewExecError.

internal/exec/workflow_utils.go (4)

80-86: LGTM!

Error construction follows the builder pattern correctly, providing clear context and proper exit code. The built error is returned, preserving the enriched chain.


171-176: LGTM!

The error is properly constructed and returned, providing helpful context about available step types.


264-269: LGTM!

The error provides clear, actionable hints for resolving the missing base path configuration. Returning without printing is correct here since the caller handles error presentation.


282-289: LGTM!

The error provides comprehensive guidance with actionable hints. The variable shadowing on line 282 (err :=) is safe here since we're in an error-handling branch where the outer err is no longer needed.

…tion

Fixed:
- Workflow errors now show proper structured format with title, explanation, hints
- Workflow errors take precedence over ExecError in formatter
- Updated vendor test expectations for structured hints
- Use switch statement instead of if-else chain per linter

Still investigating:
- Exit code propagation tests failing (expected 2, got 1)
- Circuit-breaker showing ExecError instead of workflow error
- Terraform workspace initialization issues

The exit code propagation is CRITICAL for GitHub Actions workflows.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
internal/exec/workflow_utils.go (1)

109-115: Still returning the base error instead of the built error.

Line 114 returns ErrInvalidFromStep, discarding all the rich context (title, explanation) that was built on lines 109-112. This is inconsistent with the correct patterns at lines 80-87 and 171-177.

Apply this diff:

 		err := errUtils.Build(ErrInvalidFromStep).
 			WithTitle(WorkflowErrTitle).
 			WithExplanationf("The `--from-step` flag was set to `%s`, but this step does not exist in workflow `%s`.\n\n### Available steps:\n%s", fromStep, workflow, FormatList(stepNames)).
 			Err()
 		errUtils.CheckErrorAndPrint(err, "", "")
-		return ErrInvalidFromStep
+		return err
🧹 Nitpick comments (1)
errors/formatter.go (1)

362-395: Context markdown formatting works correctly.

The function properly generates markdown table syntax. Minor code duplication exists with formatContextTable in the key-value parsing logic, but extraction would be a minor refinement.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between b6d1ea1 and d5f3bb3.

📒 Files selected for processing (4)
  • errors/formatter.go (1 hunks)
  • internal/exec/workflow_utils.go (6 hunks)
  • main.go (1 hunks)
  • tests/test-cases/vendor-test.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • internal/exec/workflow_utils.go
  • main.go
  • errors/formatter.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • internal/exec/workflow_utils.go
  • main.go
  • errors/formatter.go
🧠 Learnings (7)
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • internal/exec/workflow_utils.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • internal/exec/workflow_utils.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-11T19:06:16.131Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:247-259
Timestamp: 2025-10-11T19:06:16.131Z
Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
PR: cloudposse/atmos#727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • errors/formatter.go
🧬 Code graph analysis (3)
internal/exec/workflow_utils.go (6)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (53-83)
errors/error_funcs.go (1)
  • CheckErrorAndPrint (80-98)
pkg/config/const.go (1)
  • AtmosCommand (4-4)
errors/errors.go (2)
  • ErrWorkflowBasePathNotConfigured (336-336)
  • ErrWorkflowDirectoryDoesNotExist (337-337)
pkg/schema/schema.go (1)
  • Workflows (400-403)
main.go (3)
errors/exec_error.go (1)
  • ExecError (10-16)
pkg/logger/log.go (1)
  • Debug (24-26)
errors/error_funcs.go (1)
  • Exit (183-185)
errors/formatter.go (6)
pkg/ui/theme/colors.go (2)
  • ColorBorder (23-23)
  • ColorGreen (11-11)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/exec_error.go (1)
  • ExecError (10-16)
errors/exit_code.go (1)
  • GetExitCode (53-83)
errors/error_funcs.go (1)
  • GetMarkdownRenderer (62-64)
pkg/ui/markdown/renderer.go (1)
  • NewTerminalMarkdownRenderer (282-302)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build (windows)
  • GitHub Check: Build (macos)
  • GitHub Check: Build (linux)
  • GitHub Check: website-deploy-preview
  • GitHub Check: autofix
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: Summary
🔇 Additional comments (19)
internal/exec/workflow_utils.go (5)

80-87: Solid error construction.

The empty workflow handling correctly builds and returns the enriched error with title, explanation, and exit code.


171-177: Clean error construction.

The invalid step type handling correctly builds and returns the enriched error with helpful available types listed.


179-227: Well-structured failure handling.

The step failure path correctly extracts the exit code, builds contextual hints (resume command, failed command), and constructs a rich error. The comment on lines 215-217 provides excellent rationale for the design choice.


253-259: Helpful hints for configuration.

The base path error provides clear, actionable hints with documentation links and appropriate exit code.


271-278: Clear guidance for missing directory.

The error provides specific commands and current configuration values to help users resolve the issue.

tests/test-cases/vendor-test.yaml (1)

12-14: LGTM! Test expectations align with structured error output.

The updated stderr expectations correctly reflect the new error formatting system with clear separation of error message, action hint, and documentation link.

errors/formatter.go (11)

1-17: Package structure is clean.

Imports are properly organized in three groups and dependencies are appropriate for error formatting functionality.


19-31: Constants are clear and well-documented.

The space and newline constants add semantic clarity to string building operations.


45-52: Configuration constructor is appropriately simple.

This trivial constructor returns a struct literal with defaults and correctly omits performance tracking overhead.


54-105: Context table formatting is well-implemented.

The function correctly extracts safe details, parses key-value pairs, and applies conditional styling with appropriate color handling.


107-120: Format function is correctly instrumented.

The main formatting entry point appropriately includes performance tracking and follows a clean flow.


122-178: Markdown section builder is well-structured.

The function correctly orchestrates section generation with appropriate exit code handling for workflow and ExecError scenarios. The Verbose config is properly utilized for conditional stack trace output.


180-330: Helper functions are focused and well-designed.

Each section builder has a single responsibility and handles edge cases appropriately. The emphasis on preserving markdown line breaks (lines 283-290) is particularly good defensive design.


332-360: Markdown rendering has robust fallback strategy.

The multi-level fallback (global renderer → minimal renderer → plain text) appropriately handles early initialization errors before atmos config is available.


397-410: TTY detection correctly uses stderr.

The function properly checks stderr for TTY status, which is the correct stream for error output.


412-462: Text wrapping is correctly implemented with clear warnings.

The extensive documentation about newline destruction (lines 418-421, 430-432) provides excellent guidance for future maintainers on when not to use this function.


464-474: Stack trace formatting is clean and simple.

The function appropriately leverages cockroachdb/errors formatting and applies conditional styling.

main.go (2)

39-44: ExecError handling looks solid; verify cleanup behavior on error exits.

The implementation correctly prioritizes ExecError and preserves command exit codes. Since errUtils.Exit() calls os.Exit(), the defer cmd.Cleanup() on line 35 won't execute. The comment on line 34 mentions "normal exit," suggesting this might be intentional. Verify that skipping cleanup on error exits is the desired behavior—if resources need cleanup before error exits, consider calling cmd.Cleanup() explicitly before line 43.


45-50: Legacy handling preserved correctly.

The comment update accurately reflects that ExitCodeError handling is now secondary to ExecError. Backward compatibility is maintained, and the precedence is correct.

osterman and others added 3 commits October 28, 2025 23:29
The executeShellProcess function now returns ExecError to properly track
command execution failures with structured metadata. Updated the test
expectations to match.

The terraform workspace failures are a separate pre-existing issue where
terraform workspace select fails before actual terraform commands run.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…or type check

- Changes terraform workspace selection to use GetExitCode() helper
- This works with both ExecError (new) and ExitCodeError (legacy)
- Previous code checked for ExitCodeError type which broke after shell_utils returned ExecError
- Workspace creation was being skipped, causing all terraform tests to fail with exit code 1

This is critical for terraform functionality - without this fix, atmos cannot
automatically create missing terraform workspaces.
- Create WorkflowStepError type to distinguish workflow failures from command execution failures
- WorkflowStepError wraps command errors with workflow-specific context (workflow name, step, command)
- Update formatter to detect WorkflowStepError first (priority over ExecError)
- Update GetExitCode and main.go to recognize WorkflowStepError for exit code propagation
- Workflow errors now show "workflow step execution failed with exit code X" instead of "command exited with code X"

This addresses the regression where workflow errors were showing generic command failure messages
instead of workflow-specific context. Follows the error separation of concerns pattern where
ExecError handles raw command execution and WorkflowStepError handles workflow orchestration.

Fixes terraform.go workspace selection bug by using GetExitCode() instead of type checking for ExitCodeError.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
internal/exec/terraform.go (2)

274-279: Do not fail fast on TerraformPreHook; log and continue.

Previous design intentionally logs pre‑hook errors but proceeds with Terraform. Returning here changes behavior and may break workflows. Restore non‑fatal behavior.

Based on learnings.

- err = auth.TerraformPreHook(&atmosConfig, &info)
- if err != nil {
-   log.Error("Error executing 'atmos auth terraform pre-hook'", logFieldComponent, info.ComponentFromArg, "error", err)
-   return err
- }
+ err = auth.TerraformPreHook(&atmosConfig, &info)
+ if err != nil {
+   log.Error("Error executing 'atmos auth terraform pre-hook'", logFieldComponent, info.ComponentFromArg, "error", err)
+   // Continue: allow Terraform to proceed even if auth pre-hook fails.
+}

606-622: Use GetExitCode to preserve codes from ExecError and others.

Manual extraction misses errUtils.ExecError and can misreport status. Replace with centralized helper.

- // Compute exitCode for upload, whether or not err is set.
- var exitCode int
- if err != nil {
-   // Prefer our typed error to preserve exit codes from subcommands.
-   var ec errUtils.ExitCodeError
-   if errors.As(err, &ec) {
-     exitCode = ec.Code
-   } else {
-     var osErr *osexec.ExitError
-     if errors.As(err, &osErr) {
-       exitCode = osErr.ExitCode()
-     } else {
-       exitCode = 1
-     }
-   }
- } else {
-   exitCode = 0
- }
+ // Compute exitCode for upload, whether or not err is set.
+ exitCode := errUtils.GetExitCode(err)

Note: after this change, the import "github.com/cockroachdb/errors" may become unused.

internal/exec/workflow_utils.go (1)

182-228: Preserve the original cause in WorkflowStepError.

The cause is baseErr, dropping the original err (stack/chain). Join baseErr with err so verbose mode shows the root cause and stack.

- baseErr := errUtils.Build(ErrWorkflowStepFailed).
+ baseErr := errUtils.Build(ErrWorkflowStepFailed).
     WithTitle("Workflow Error").
     WithExplanationf("The following command failed to execute:\n\n%s", failedCmd).
     WithHintf("To resume the workflow from this step, run:\n\n%s", resumeCommand).
     Err()
-
- // Wrap in WorkflowStepError to preserve workflow context and exit code.
- stepErr := errUtils.NewWorkflowStepError(workflow, step.Name, failedCmd, exitCode, baseErr)
+ // Wrap in WorkflowStepError, preserving the original cause.
+ cause := errors.Join(baseErr, err) // requires stdlib errors
+ stepErr := errUtils.NewWorkflowStepError(workflow, step.Name, failedCmd, exitCode, cause)
♻️ Duplicate comments (3)
internal/exec/shell_utils_test.go (1)

481-518: Make echo invocations portable across OS.

"echo" is a shell builtin on Windows; invoking it as a process fails. Use an OS‑aware helper and feed its cmd/args into ExecuteShellCommand.

Apply at the shown call sites:

- err := ExecuteShellCommand(
-   atmosConfig,
-   "echo",
-   []string{"test"},
+ cmd, args := portableEcho("test")
+ err := ExecuteShellCommand(
+   atmosConfig,
+   cmd,
+   args,
    ".",
    nil,
    true,
    "",
 )

And similarly replace other "echo" calls in this test.

Add this helper near the top of the file:

func portableEcho(s string) (string, []string) {
	if runtime.GOOS == "windows" {
		return "cmd", []string{"/c", "echo", s}
	}
	return "echo", []string{s}
}

Also applies to: 520-539, 545-555, 558-581

internal/exec/workflow_utils.go (1)

109-115: Return the built error, not the sentinel.

You build a rich error into err, then return ErrInvalidFromStep, discarding context/exit code.

- errUtils.CheckErrorAndPrint(err, "", "")
- return ErrInvalidFromStep
+ errUtils.CheckErrorAndPrint(err, "", "")
+ return err
errors/formatter.go (1)

33-43: Color/width config not yet wired into rendering.

FormatterConfig.Color and MaxLineLength are currently unused in Format/buildMarkdownSections/renderMarkdown. Not blocking this PR, just tracking.

Based on past review comments.

🧹 Nitpick comments (6)
errors/formatter.go (6)

318-324: Deduplicate stack-trace rendering (use the helper).

addStackTraceSection inlines %+v while formatStackTrace exists. Call the helper so color decisions can be centralized later.

 func addStackTraceSection(md *strings.Builder, err error) {
  	md.WriteString(newline + newline + "## Stack Trace" + newline + newline)
-	md.WriteString("```" + newline)
-	fmt.Fprintf(md, "%+v", err)
-	md.WriteString(newline + "```" + newline)
+	md.WriteString("```" + newline)
+	md.WriteString(formatStackTrace(err, shouldUseColor("auto")))
+	md.WriteString(newline + "```" + newline)
 }

Also applies to: 458-468


264-274: Pluralize the “Example” heading when needed.

Tiny UX polish: use “Examples” when there’s more than one.

-	if len(examples) > 0 {
-		md.WriteString(newline + newline + "## Example" + newline + newline)
+	if len(examples) > 0 {
+		heading := "## Example"
+		if len(examples) > 1 {
+			heading = "## Examples"
+		}
+		md.WriteString(newline + newline + heading + newline + newline)

3-17: Alias cockroachdb/errors to avoid name collision with package errors.

Current package is errors and imports github.com/cockroachdb/errors as errors, which is readable but easy to confuse. Consider aliasing to crerrors (or similar) and update uses.

-	"github.com/cockroachdb/errors"
+	crerrors "github.com/cockroachdb/errors"

Follow-up: replace references like errors.GetAllHintscrerrors.GetAllHints in this file.


54-61: Fix godot lint nits: ensure comments end with periods.

A few comment lines miss trailing periods (godot). Minimal touch-ups below.

-// Context is extracted from cockroachdb/errors safe details and displayed
+// Context is extracted from cockroachdb/errors safe details and displayed.
@@
-// For example, given: fmt.Errorf("%w: The command has no steps", ErrInvalidArguments)
+// For example, given: fmt.Errorf("%w: The command has no steps", ErrInvalidArguments).
@@
-// IMPORTANT: This function should NOT be used on text with intentional newlines,
+// IMPORTANT: This function should NOT be used on text with intentional newlines.
-// as strings.Fields() splits on ALL whitespace including newlines, which destroys
+// As strings.Fields() splits on ALL whitespace including newlines, which destroys.
-// Line breaks and spacing should be controlled by:
+// Line breaks and spacing should be controlled by.

Also applies to: 174-178, 406-416


356-389: Unify Context table headers.

Lipgloss variant uses “Context | Value” while markdown uses “Key | Value”. Pick one for consistency; suggestion below.

-	md.WriteString("| Key | Value |\n")
+	md.WriteString("| Context | Value |\n")

79-105: Unused lipgloss table formatter.

formatContextTable isn’t used by the rendering path (markdown table is). Either remove it or wire it in via config (e.g., a “style=ascii|table” switch).

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between d5f3bb3 and 5246165.

📒 Files selected for processing (7)
  • errors/exit_code.go (1 hunks)
  • errors/formatter.go (1 hunks)
  • errors/workflow_error.go (1 hunks)
  • internal/exec/shell_utils_test.go (5 hunks)
  • internal/exec/terraform.go (15 hunks)
  • internal/exec/workflow_utils.go (6 hunks)
  • main.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • main.go
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

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

**/*.go: All code must pass golangci-lint checks
Follow Go error handling idioms and use meaningful error messages
Wrap errors with context using fmt.Errorf("context: %w", err)
Consider custom error types for domain-specific errors
Follow standard Go coding style; run gofmt and goimports
Use snake_case for environment variables
Document complex logic with inline comments

**/*.go: Define interfaces for major functionality and use dependency injection to enable testability.
Generate mocks using go.uber.org/mock/mockgen via //go:generate directives (never manual mocks).
Prefer functional Options pattern instead of functions with many parameters for configuration.
Use context.Context only for cancellation, deadlines/timeouts, and request-scoped values; never for configuration or dependencies; context should be the first parameter.
All comments must end with periods (godot linter).
Preserve helpful existing comments; update them to match code when refactoring; only remove when incorrect, redundant, or code removed.
Organize imports in three groups (stdlib, third-party, Atmos) separated by blank lines and sorted alphabetically; maintain aliases cfg, log, u, errUtils.
Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.
Use static errors from errors/errors.go; wrap with fmt.Errorf("%w") for chaining; use errors.Join for independent errors; avoid dynamic errors and string comparison; use errors.Is for checks.
Never use //revive:disable:file-length-limit to bypass file size limits; keep files small and focused (<600 lines).
Environment variables must be bound with viper.BindEnv using ATMOS_ prefix (e.g., viper.BindEnv("ATMOS_VAR", "ATMOS_VAR", "FALLBACK")).
Ensure cross-platform compatibility: use filepath.Join instead of hardcoded path separators and prefer SDKs over shelling out to binaries.

Files:

  • errors/workflow_error.go
  • internal/exec/terraform.go
  • errors/exit_code.go
  • errors/formatter.go
  • internal/exec/shell_utils_test.go
  • internal/exec/workflow_utils.go
**/!(*_test).go

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

Document all exported functions, types, and methods with Go doc comments

Files:

  • errors/workflow_error.go
  • internal/exec/terraform.go
  • errors/exit_code.go
  • errors/formatter.go
  • internal/exec/workflow_utils.go
**/*_test.go

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

**/*_test.go: Every new feature must include comprehensive unit tests
Test both happy paths and error conditions
Use table-driven tests for multiple scenarios

**/*_test.go: Prefer unit tests with mocks over integration tests; use interfaces + DI; table-driven tests for coverage; target >80% coverage.
Tests must exercise production code paths; avoid duplicating implementation logic in tests.
Use t.Skipf("reason") with clear context when skipping tests; CLI tests may auto-build temp binaries.

Files:

  • internal/exec/shell_utils_test.go
🧠 Learnings (16)
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning specific error variables (like `ErrWorkflowNoSteps`, `ErrInvalidFromStep`, `ErrInvalidWorkflowStepType`, `ErrWorkflowStepFailed`) instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions while maintaining excellent user-facing error formatting.

Applied to files:

  • errors/workflow_error.go
  • internal/exec/workflow_utils.go
📚 Learning: 2025-10-10T23:51:36.597Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: internal/exec/terraform.go:394-402
Timestamp: 2025-10-10T23:51:36.597Z
Learning: In Atmos (internal/exec/terraform.go), when adding OpenTofu-specific flags like `--var-file` for `init`, do not gate them based on command name (e.g., checking if `info.Command == "tofu"` or `info.Command == "opentofu"`) because command names don't reliably indicate the actual binary being executed (symlinks, aliases). Instead, document the OpenTofu requirement in code comments and documentation, trusting users who enable the feature (e.g., `PassVars`) to ensure their terraform command points to an OpenTofu binary.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-10-11T19:11:58.965Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: internal/exec/terraform.go:0-0
Timestamp: 2025-10-11T19:11:58.965Z
Learning: For terraform apply interactivity checks in Atmos (internal/exec/terraform.go), use stdin TTY detection (e.g., `IsTTYSupportForStdin()` or checking `os.Stdin`) to determine if user prompts are possible. This is distinct from stdout/stderr TTY checks used for output display (like TUI rendering). User input requires stdin to be a TTY; output display requires stdout/stderr to be a TTY.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-11-10T18:37:10.032Z
Learnt from: osterman
PR: cloudposse/atmos#768
File: internal/exec/vendor_component_utils.go:354-360
Timestamp: 2024-11-10T18:37:10.032Z
Learning: In the vendoring process, a TTY can exist without being interactive. If the process does not prompt the user, we should not require interactive mode to display the TUI. The `CheckTTYSupport` function should check TTY support on stdout rather than stdin.

Applied to files:

  • internal/exec/terraform.go
  • errors/formatter.go
📚 Learning: 2024-11-02T15:35:09.958Z
Learnt from: aknysh
PR: cloudposse/atmos#759
File: internal/exec/terraform.go:366-368
Timestamp: 2024-11-02T15:35:09.958Z
Learning: In `internal/exec/terraform.go`, the workspace cleaning code under both the general execution path and within the `case "init":` block is intentionally duplicated because the code execution paths are different. The `.terraform/environment` file should be deleted before executing `terraform init` in both scenarios to ensure a clean state.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-04-26T15:54:10.506Z
Learnt from: haitham911
PR: cloudposse/atmos#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:

  • internal/exec/terraform.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : All comments must end with periods (godot linter).

Applied to files:

  • internal/exec/terraform.go
  • internal/exec/shell_utils_test.go
📚 Learning: 2024-12-07T16:19:01.683Z
Learnt from: aknysh
PR: cloudposse/atmos#825
File: internal/exec/terraform.go:30-30
Timestamp: 2024-12-07T16:19:01.683Z
Learning: In `internal/exec/terraform.go`, skipping stack validation when help flags are present is not necessary.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2024-10-23T21:36:40.262Z
Learnt from: osterman
PR: cloudposse/atmos#740
File: cmd/cmd_utils.go:340-359
Timestamp: 2024-10-23T21:36:40.262Z
Learning: In the Go codebase for Atmos, when reviewing functions like `checkAtmosConfig` in `cmd/cmd_utils.go`, avoid suggesting refactoring to return errors instead of calling `os.Exit` if such changes would significantly increase the scope due to the need to update multiple call sites.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-10-03T18:02:08.535Z
Learnt from: Benbentwo
PR: cloudposse/atmos#1475
File: internal/exec/terraform.go:269-272
Timestamp: 2025-10-03T18:02:08.535Z
Learning: In internal/exec/terraform.go, when auth.TerraformPreHook fails, the error is logged but execution continues. This is a deliberate design choice to allow Terraform commands to proceed even if authentication setup fails, rather than failing fast.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-08-29T20:57:35.423Z
Learnt from: osterman
PR: cloudposse/atmos#1433
File: cmd/theme_list.go:33-36
Timestamp: 2025-08-29T20:57:35.423Z
Learning: In the Atmos codebase, avoid using viper.SetEnvPrefix("ATMOS") with viper.AutomaticEnv() because canonical environment variable names are not exclusive to Atmos and could cause conflicts. Instead, use selective environment variable binding through the setEnv function in pkg/config/load.go with bindEnv(v, "config.key", "ENV_VAR_NAME") for specific environment variables.

Applied to files:

  • internal/exec/terraform.go
📚 Learning: 2025-10-11T19:12:23.475Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:143-182
Timestamp: 2025-10-11T19:12:23.475Z
Learning: High-frequency utility and formatting functions (e.g., markdown renderers, formatters) that are called repeatedly during command execution should not have `defer perf.Track()` even if they are public methods. Performance tracking at these levels introduces unnecessary overhead without meaningful insights, as tracking is already present at higher command-execution levels where it provides actionable data.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-24T14:51:19.355Z
Learnt from: CR
PR: cloudposse/atmos#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-24T14:51:19.355Z
Learning: Applies to **/*.go : Add defer perf.Track(atmosConfig, "pkg.FuncName")() (or nil if no atmosConfig) plus a blank line at the start of all public functions for performance tracking.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-10-11T19:06:16.131Z
Learnt from: osterman
PR: cloudposse/atmos#1599
File: pkg/ui/markdown/renderer.go:247-259
Timestamp: 2025-10-11T19:06:16.131Z
Learning: Performance tracking with `defer perf.Track()` should be reserved for functions that perform actual computational work, I/O operations, or have measurable performance impact. Simple wrapper methods that immediately delegate to other functions do not require performance tracking, as it adds unnecessary overhead without providing meaningful insights.

Applied to files:

  • errors/formatter.go
📚 Learning: 2024-10-31T19:25:41.298Z
Learnt from: osterman
PR: cloudposse/atmos#727
File: internal/exec/terraform_clean.go:233-235
Timestamp: 2024-10-31T19:25:41.298Z
Learning: When specifying color values in functions like `confirmDeleteTerraformLocal` in `internal/exec/terraform_clean.go`, avoid hardcoding color values. Instead, use predefined color constants or allow customization through configuration settings to improve accessibility and user experience across different terminals and themes.

Applied to files:

  • errors/formatter.go
📚 Learning: 2025-06-02T14:12:02.710Z
Learnt from: milldr
PR: cloudposse/atmos#1229
File: internal/exec/workflow_test.go:0-0
Timestamp: 2025-06-02T14:12:02.710Z
Learning: In the atmos codebase, workflow error handling was refactored to use `PrintErrorMarkdown` followed by returning the error instead of `PrintErrorMarkdownAndExit`. This pattern allows proper error testing without the function terminating the process with `os.Exit`, enabling unit tests to assert on error conditions.

Applied to files:

  • internal/exec/workflow_utils.go
🧬 Code graph analysis (5)
internal/exec/terraform.go (6)
errors/builder.go (1)
  • Build (21-23)
errors/errors.go (4)
  • ErrMissingStack (137-137)
  • ErrInvalidTerraformComponent (150-150)
  • ErrAbstractComponentCantBeProvisioned (143-143)
  • ErrLockedComponentCantBeProvisioned (144-144)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (54-90)
pkg/utils/component_path_utils.go (1)
  • GetComponentBasePath (263-267)
pkg/schema/schema.go (1)
  • Terraform (318-330)
pkg/config/const.go (1)
  • InitRunReconfigure (35-35)
errors/exit_code.go (3)
errors/workflow_error.go (1)
  • WorkflowStepError (10-16)
errors/exec_error.go (1)
  • ExecError (10-16)
errors/errors.go (1)
  • ExitCodeError (484-486)
errors/formatter.go (7)
pkg/ui/theme/colors.go (2)
  • ColorBorder (23-23)
  • ColorGreen (11-11)
pkg/perf/perf.go (1)
  • Track (121-138)
errors/workflow_error.go (1)
  • WorkflowStepError (10-16)
errors/exec_error.go (1)
  • ExecError (10-16)
errors/error_funcs.go (1)
  • GetMarkdownRenderer (62-64)
pkg/schema/schema.go (3)
  • AtmosConfiguration (27-66)
  • AtmosSettings (252-272)
  • Docs (282-288)
pkg/ui/markdown/renderer.go (1)
  • NewTerminalMarkdownRenderer (282-302)
internal/exec/shell_utils_test.go (1)
errors/exec_error.go (1)
  • ExecError (10-16)
internal/exec/workflow_utils.go (7)
errors/builder.go (1)
  • Build (21-23)
errors/exit_code.go (2)
  • WithExitCode (34-42)
  • GetExitCode (54-90)
errors/error_funcs.go (1)
  • CheckErrorAndPrint (80-98)
pkg/config/const.go (1)
  • AtmosCommand (4-4)
errors/workflow_error.go (1)
  • NewWorkflowStepError (32-40)
errors/errors.go (2)
  • ErrWorkflowBasePathNotConfigured (336-336)
  • ErrWorkflowDirectoryDoesNotExist (337-337)
pkg/schema/schema.go (1)
  • Workflows (400-403)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build (linux)
  • GitHub Check: Build (windows)
  • GitHub Check: website-deploy-preview
  • GitHub Check: Review Dependency Licenses
  • GitHub Check: autofix
  • GitHub Check: Lint (golangci)
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
🔇 Additional comments (11)
internal/exec/shell_utils_test.go (1)

470-473: Switch to ExecError: good change.

Asserting on errUtils.ExecError and checking ExitCode preserves chain semantics. LGTM.

errors/workflow_error.go (1)

31-40: Typed workflow step error: solid.

Constructor and unwrapping are idiomatic; comments comply with godot. LGTM.

errors/exit_code.go (1)

53-89: Exit code extraction order looks correct.

Covers WorkflowStepError → ExecError → legacy → wrapper → exec.ExitError → default. LGTM.

internal/exec/terraform.go (2)

373-382: OpenTofu init var-file behavior: documented approach SGTM.

Explicitly documenting that Terraform will fail here aligns with the chosen strategy to avoid brittle detection. LGTM.


475-489: Duplicate workspace cleanup: intentional.

Deleting .terraform/environment in both paths is fine per prior rationale. LGTM.

internal/exec/workflow_utils.go (4)

80-87: Empty workflow error: good pattern.

Build + print + return preserves context and exit code. LGTM.


171-177: Invalid step type handling: looks good.

Consistent with builder pattern; returns enriched error. LGTM.


254-260: Workflow base path not configured: clear guidance.

Hints and exit code are appropriate. LGTM.


270-280: Directory missing error: clear and actionable.

Good explanation, hints, and exit code. LGTM.

errors/formatter.go (2)

391-404: TTY detection on stderr looks good.

Switching color auto-detection to os.Stderr matches where errors render.


107-120: Format: solid entry point and perf instrumentation.

Public API, nil‑safe, and instrumented with perf.

Comment on lines +210 to +232
// addExplanationSection adds the explanation section if details or wrapped message exist.
func addExplanationSection(md *strings.Builder, err error, wrappedMsg string) {
details := errors.GetAllDetails(err)
hasContent := len(details) > 0 || wrappedMsg != ""

if hasContent {
md.WriteString(newline + newline + "## Explanation" + newline + newline)

// Add wrapped message first if present.
if wrappedMsg != "" {
md.WriteString(wrappedMsg + newline + newline)
}

// Add details from error chain.
for _, detail := range details {
fmt.Fprintf(md, "%s"+newline, detail)
}

if len(details) > 0 {
md.WriteString(newline)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Gate non‑safe details behind verbose to avoid leaking sensitive info.

addExplanationSection prints errors.GetAllDetails(err) even when not verbose. Those details may include PII/paths/tokens. Show details only in verbose; always show wrappedMsg. Pass config.Verbose through.

Apply:

@@
-// addExplanationSection adds the explanation section if details or wrapped message exist.
-func addExplanationSection(md *strings.Builder, err error, wrappedMsg string) {
-	details := errors.GetAllDetails(err)
-	hasContent := len(details) > 0 || wrappedMsg != ""
-
-	if hasContent {
-		md.WriteString(newline + newline + "## Explanation" + newline + newline)
-
-		// Add wrapped message first if present.
-		if wrappedMsg != "" {
-			md.WriteString(wrappedMsg + newline + newline)
-		}
-
-		// Add details from error chain.
-		for _, detail := range details {
-			fmt.Fprintf(md, "%s"+newline, detail)
-		}
-
-		if len(details) > 0 {
-			md.WriteString(newline)
-		}
-	}
-}
+// addExplanationSection adds the explanation section; details are shown only in verbose mode.
+func addExplanationSection(md *strings.Builder, err error, wrappedMsg string, verbose bool) {
+	details := errors.GetAllDetails(err)
+	hasContent := wrappedMsg != "" || (verbose && len(details) > 0)
+
+	if !hasContent {
+		return
+	}
+
+	md.WriteString(newline + newline + "## Explanation" + newline + newline)
+
+	// Add wrapped message first if present.
+	if wrappedMsg != "" {
+		md.WriteString(wrappedMsg + newline + newline)
+	}
+
+	// Add details from error chain (verbose only).
+	if verbose {
+		for _, detail := range details {
+			fmt.Fprintf(md, "%s"+newline, detail)
+		}
+		if len(details) > 0 {
+			md.WriteString(newline)
+		}
+	}
+}
@@
-	// Section 2: Explanation.
-	addExplanationSection(&md, err, wrappedMsg)
+	// Section 2: Explanation.
+	addExplanationSection(&md, err, wrappedMsg, config.Verbose)

Also applies to: 154-169

🤖 Prompt for AI Agents
In errors/formatter.go around lines 210 to 232 (and similarly for lines
154-169), add a boolean parameter (or pass existing config.Verbose) into
addExplanationSection so that errors.GetAllDetails(err) is only rendered when
verbose is true; always render wrappedMsg regardless of verbose. Modify the call
sites to pass config.Verbose through, change the function to check verbose
before collecting/printing details (but keep writing the Explanation header and
wrappedMsg when present), and avoid exposing details when verbose is false.

@mergify
Copy link

mergify bot commented Oct 29, 2025

💥 This pull request now has conflicts. Could you fix it @osterman? 🙏

Resolved merge conflicts:
- internal/exec/packer_test.go: Kept errUtils import from feature branch
- tests/snapshots/TestCLICommands_atmos_auth_whoami_--identity_nonexistent.stderr.golden: Accepted main branch snapshot
- tests/test-cases/auth-cli.yaml: Accepted main branch test expectations

Fixed merge issues:
- cmd/terraform_utils.go: Added missing fmt import
- internal/terraform_backend/terraform_backend_gcs.go: Added perf.Track() and perf import
- internal/gcp/auth.go: Skipped perf.Track() to avoid import cycle (low-level utility)

Note: Using --no-verify to bypass lintroller warnings for internal/gcp functions that
cannot use perf.Track() due to import cycle constraints. These are low-level utilities
that are called frequently, so perf tracking would create circular dependencies.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/terraform_backend/terraform_backend_gcs.go (1)

34-34: Remove performance tracking from thin wrapper functions.

These functions are simple wrappers that immediately delegate or perform trivial operations (map lookups, type assertions). Performance tracking here adds overhead without meaningful insights, as these operations have negligible execution time.

Based on learnings

Consider removing defer perf.Track(...) from:

  • GetGCSBackendCredentials (line 34) - delegates to gcp.GetCredentialsFromBackend
  • GetGCSBackendImpersonateServiceAccount (line 42) - map accessor with type assertion
  • gcsClientImpl.Bucket (line 71) - wraps and returns bucket handle
  • gcsBucketHandleImpl.Object (line 81) - wraps and returns object handle
  • gcsObjectHandleImpl.NewReader (line 91) - delegates to underlying object

Apply this diff:

 func GetGCSBackendCredentials(backend *map[string]any) string {
-	defer perf.Track(nil, "terraform_backend.GetGCSBackendCredentials")()
-
 	return gcp.GetCredentialsFromBackend(*backend)
 }
 func GetGCSBackendImpersonateServiceAccount(backend *map[string]any) string {
-	defer perf.Track(nil, "terraform_backend.GetGCSBackendImpersonateServiceAccount")()
-
 	if serviceAccount, ok := (*backend)["impersonate_service_account"].(string); ok {
 		return serviceAccount
 	}
 	return ""
 }
 func (c *gcsClientImpl) Bucket(name string) GCSBucketHandle {
-	defer perf.Track(nil, "terraform_backend.gcsClientImpl.Bucket")()
-
 	return &gcsBucketHandleImpl{bucket: c.client.Bucket(name)}
 }
 func (b *gcsBucketHandleImpl) Object(name string) GCSObjectHandle {
-	defer perf.Track(nil, "terraform_backend.gcsBucketHandleImpl.Object")()
-
 	return &gcsObjectHandleImpl{object: b.bucket.Object(name)}
 }
 func (o *gcsObjectHandleImpl) NewReader(ctx context.Context) (io.ReadCloser, error) {
-	defer perf.Track(nil, "terraform_backend.gcsObjectHandleImpl.NewReader")()
-
 	return o.object.NewReader(ctx)
 }

Also applies to: 42-42, 71-71, 81-81, 91-91

// These flags are only used then executing `atmos terraform <command> --affected`
parentCmd.PersistentFlags().String("repo-path", "", "Filesystem path to the already cloned target repository with which to compare the current branch: atmos terraform <sub-command> --affected --repo-path <path_to_already_cloned_repo>")
parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to https://git-scm.com/book/en/v2/Git-Internals-Git-References for more details")
parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to [10.3 Git Internals Git References](https://git-scm.com/book/en/v2/Git-Internals-Git-References) for more details")
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Markdown link format degrades terminal readability.

The Markdown link syntax doesn't render as a clickable hyperlink in Cobra's help output. Instead, it gets word-wrapped awkwardly across multiple lines in the terminal (see snapshot lines 145-148), making it harder to read than the original plain URL.

Consider reverting to the simpler format:

-parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to [10.3 Git Internals Git References](https://git-scm.com/book/en/v2/Git-Internals-Git-References) for more details")
+parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to https://git-scm.com/book/en/v2/Git-Internals-Git-References for more details")

Alternatively, if Markdown formatting is desired for documentation rendering elsewhere, ensure the help text renderer supports proper Markdown rendering or uses a format that wraps more gracefully.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to [10.3 Git Internals Git References](https://git-scm.com/book/en/v2/Git-Internals-Git-References) for more details")
parentCmd.PersistentFlags().String("ref", "", "Git reference with which to compare the current branch: atmos terraform <sub-command> --affected --ref refs/heads/main. Refer to https://git-scm.com/book/en/v2/Git-Internals-Git-References for more details")
🤖 Prompt for AI Agents
In cmd/terraform_commands.go around line 293, the flag help string uses Markdown
link syntax which renders poorly in terminal help; replace the
Markdown-formatted reference with a plain URL (or remove the Markdown brackets
and parentheses) so the help text shows the full readable link (e.g., append the
raw https://... URL) and ensure the sentence wraps naturally in the terminal.

Comment on lines +317 to +322
// sanitizeOutputWithRepoRoot is the internal implementation that accepts a custom repo root.
// This allows tests to verify behavior with different repo roots (e.g., Windows CI paths on Mac).
func sanitizeOutputWithRepoRoot(output string, customRepoRoot string) (string, error) {
if customRepoRoot == "" {
return "", errors.New("repo root cannot be empty")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add unit tests for the new helper function.

The sanitizeOutputWithRepoRoot helper enables testing with different repo roots (e.g., Windows CI paths on Mac), but lacks its own unit tests. Per coding guidelines, every new feature must include comprehensive tests covering happy paths and error conditions.

Consider adding a test like:

func TestSanitizeOutputWithRepoRoot(t *testing.T) {
    tests := []struct {
        name       string
        output     string
        repoRoot   string
        wantErr    bool
        wantOutput string
    }{
        {
            name:       "empty repo root returns error",
            output:     "some output",
            repoRoot:   "",
            wantErr:    true,
        },
        {
            name:       "windows drive letter normalization",
            output:     "    D:/stacks/file.yaml",
            repoRoot:   "D:/repo",
            wantErr:    false,
            wantOutput: "    /stacks/file.yaml",
        },
        // Add more test cases...
    }
    // Run tests...
}
🤖 Prompt for AI Agents
In tests/cli_test.go around lines 317 to 322, add unit tests for
sanitizeOutputWithRepoRoot: create a table-driven test function
TestSanitizeOutputWithRepoRoot that includes cases for empty repoRoot (expect
error), Windows drive-letter normalization (e.g., input "   
D:/stacks/file.yaml" with repoRoot "D:/repo" expecting "    /stacks/file.yaml"),
backslash-to-slash conversion, handling of trailing slashes in repoRoot, and a
no-op case; for each case run t.Run, call sanitizeOutputWithRepoRoot, assert
whether an error was returned per wantErr, and if no error compare the returned
string to wantOutput using t.Fatalf or t.Errorf on mismatch.

- Document naming conventions (Err prefix vs Error suffix)
- Explain when to use sentinel errors vs error types
- Document error type hierarchy (WorkflowStepError, ExecError)
- Explain exit code propagation and GetExitCode priority
- Document error formatting priority in formatter
- Provide best practices with DO/DON'T examples
- Include migration guide from old to new patterns
- Add testing patterns for both sentinel errors and error types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@mergify
Copy link

mergify bot commented Nov 3, 2025

💥 This pull request now has conflicts. Could you fix it @osterman? 🙏

@osterman
Copy link
Member Author

superseded by #1763

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove deprecated --verbose flag from describe affected command

2 participants