Skip to content

fix: CI job summary shows NO_CHANGE badge for output-only Terraform changes - #2306

Merged
Andriy Knysh (aknysh) merged 6 commits into
mainfrom
osterman/ci-output-changes-badge
Apr 11, 2026
Merged

Andriy Knysh (aknysh) merged 6 commits into
mainfrom
osterman/ci-output-changes-badge

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Apr 9, 2026 •

Copy link
Copy Markdown
Member

what

  • When Terraform plan detects only output changes (exit code 2), the CI job summary now correctly distinguishes this from "no changes" and "resource changes"
  • Added a new blue OUTPUT_CHANGE badge for output-only plans/applies, distinct from the gray NO_CHANGE badge and the resource-level CREATE/CHANGE/REPLACE/DESTROY badges
  • Template headings now differentiate: "Resource Changes Found" vs "Output Changes Found" vs "No Changes"
  • Plan detail summary shows "Output values will change. No infrastructure changes." for output-only changes

why

  • Terraform exits with code 2 when there are changes, including output-only changes (no infrastructure modifications). The existing HasChanges() method only checked resource counts, so output-only changes were incorrectly reported as "NO_CHANGE" in CI job summaries. This was misleading because Terraform considers these real changes that need to be applied.
  • Making the distinction between resource changes and output-only changes explicit helps CI users understand at a glance whether infrastructure will be modified or just state outputs will be updated.

references

  • Terraform plan exit codes: 0 = no changes, 1 = error, 2 = changes detected (includes output-only changes)

Summary by CodeRabbit

  • New Features

    • Detect and report Terraform output-only changes with distinct "Output Changes Found" / "Output Changes Applied" messaging.
  • Improvements

    • Separate resource vs output-only summaries, badges, and details for clearer plan/apply results.
    • Revised workspace handling to prefer selection before creation and improved handling of missing state files on Windows.
    • Added utilities to clear Terraform caches to reduce stale-state issues.
  • Tests

    • Added/expanded tests for output-only detection, summaries, workspace behaviors, and cache isolation.
  • Documentation

    • Updated templates and fixtures to reflect new messaging.

…hanges

When Terraform exits with code 2 (changes detected) but only outputs
changed (no resource changes), the CI job summary incorrectly displayed
a gray NO_CHANGE badge. This happened because HasChanges() only checked
resource counts, ignoring output changes entirely.

- Add HasOutputChanges field and HasResourceChanges() method to context
- Update ParsePlanJSON and ParsePlanOutput to detect output-only changes
- Add distinct OUTPUT_CHANGE badge (blue) to plan and apply templates
- Differentiate headings: "Resource Changes Found" vs "Output Changes Found"
- Add "Changes to Outputs:" as plan output marker for preamble stripping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@atmos-pro

atmos-pro Bot commented Apr 9, 2026 •

Copy link
Copy Markdown
Contributor

Tip

Atmos Pro  

No affected stacks workflow was detected for this pull request.
If this is expected, no action is needed.
Learn More.

@github-actions github-actions Bot added the size/m Medium size PR label Apr 9, 2026
@github-actions

github-actions Bot commented Apr 9, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA d3d96f5.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@osterman Erik Osterman (Cloud Posse) (osterman) added the patch A minor, backward compatible change label Apr 9, 2026
@coderabbitai

coderabbitai Bot commented Apr 9, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 51fc81d1-1d85-4000-8875-871cdcce2476

📥 Commits

Reviewing files that changed from the base of the PR and between 02511fb and d3d96f5.

📒 Files selected for processing (3)
  • pkg/terraform/output/executor_test.go
  • pkg/terraform/output/workspace.go
  • pkg/terraform/output/workspace_test.go

📝 Walkthrough

Walkthrough

Detects Terraform plan output-only changes separately from resource changes, adds HasOutputChanges and HasResourceChanges(), updates plan parsing and templates to distinguish output vs resource changes, adds tests/fixtures, introduces cache-reset helpers, and retries Windows state-file checks.

Changes

Cohort / File(s) Summary
Context Model
pkg/ci/plugins/terraform/context.go
Added HasOutputChanges bool, new HasResourceChanges() method, and updated HasChanges() to combine resource/output checks.
Parser Logic & Tests
pkg/ci/plugins/terraform/parser.go, pkg/ci/plugins/terraform/parser_test.go
Detect output-only changes (new regexp), set HasChanges for outputs, added buildOutputChangeSummary(), and tests for output-only JSON and stdout plan parsing.
Plugin Output Cleaning
pkg/ci/plugins/terraform/plugin.go
Extended planOutputMarkers with "Changes to Outputs:" so cleaning can start after the outputs section header.
Templates
pkg/ci/plugins/terraform/templates/plan.md, pkg/ci/plugins/terraform/templates/apply.md
Replaced .HasChanges branching with .HasResourceChanges/.HasOutputChanges to render resource vs output-only vs no-change messages and badges.
Template Tests & Golden Fixtures
pkg/ci/plugins/terraform/template_test.go, pkg/ci/plugins/terraform/testdata/golden/*, tests/fixtures/*, tests/test-cases/*
Updated headings from “Changes Found” to “Resource Changes Found”; added template test for output-only rendering and adjusted expectations.
Plan JSON Testdata
pkg/ci/plugins/terraform/testdata/plan_json/success_output_only.json
Added fixture representing a plan with no resource changes but two output changes.
Terraform Output Package
pkg/terraform/output/executor.go, pkg/terraform/output/workspace.go, pkg/terraform/output/workspace_test.go, pkg/terraform/output/executor_test.go
Added ResetOutputsCache(), changed EnsureWorkspace to select-before-create with isWorkspaceMissingError, and updated tests/mocks to match select-first behavior.
Internal Exec & Tests
internal/exec/terraform_state_utils.go, internal/exec/yaml_func_*.go
Added ResetStateCache(), added test calls to reset caches before/after tests, and updated tests to import output package for cache reset.
Windows File Handling
internal/terraform_backend/terraform_backend_local.go
Added short retry/delay on Windows when state file is missing to reduce transient failures.
Misc. Fixtures
tests/fixtures/scenarios/native-ci/github-output.txt, .../github-step-summary.txt, tests/fixtures/terraform-ci-summaries/changes.md
Updated headings/fixtures to use “Resource Changes Found” wording.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • osterman
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: distinguishing output-only Terraform changes from no-change scenarios in CI summaries.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osterman/ci-output-changes-badge

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
pkg/ci/plugins/terraform/parser_test.go (1)

968-972: Consider adding a zero-count edge case.

The buildOutputChangeSummary(0) path would return "0 outputs to change" which may or may not be intentional. While unlikely to be called with 0 in practice, documenting the behavior with a test case could prevent surprises.

Optional test addition
 func TestBuildOutputChangeSummary(t *testing.T) {
+	assert.Equal(t, "0 outputs to change", buildOutputChangeSummary(0))
 	assert.Equal(t, "1 output to change", buildOutputChangeSummary(1))
 	assert.Equal(t, "2 outputs to change", buildOutputChangeSummary(2))
 	assert.Equal(t, "5 outputs to change", buildOutputChangeSummary(5))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/ci/plugins/terraform/parser_test.go` around lines 968 - 972, Add a
zero-count test case to TestBuildOutputChangeSummary to document and lock in the
behavior for the edge case where buildOutputChangeSummary(0) is called; update
the test in pkg/ci/plugins/terraform/parser_test.go (function
TestBuildOutputChangeSummary) to include an assertion like assert.Equal(t, "0
outputs to change", buildOutputChangeSummary(0)) so the expected output for 0 is
explicit.
pkg/ci/plugins/terraform/context.go (1)

46-48: Clarify field semantics in the comment.

The field HasOutputChanges is set to true whenever outputs exist (line 72), regardless of whether resource changes also exist. The current comment says "without resource changes" which could be misleading. Templates would need to check HasOutputChanges && !HasResourceChanges() for output-only scenarios.

Consider updating the comment to reflect actual semantics:

Suggested comment clarification
-	// HasOutputChanges indicates if there are terraform output value changes (without resource changes).
+	// HasOutputChanges indicates if there are terraform output value changes.
+	// For output-only changes (no resource changes), check HasOutputChanges && !HasResourceChanges().
 	HasOutputChanges bool
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/ci/plugins/terraform/context.go` around lines 46 - 48, The comment for
the struct field HasOutputChanges is misleading — update it to state that
HasOutputChanges is true whenever Terraform outputs exist (regardless of
resource changes), rather than implying outputs-only; mention that callers must
combine HasOutputChanges with HasResourceChanges() (e.g., check HasOutputChanges
&& !HasResourceChanges()) to detect output-only changes; modify the comment
above the HasOutputChanges field and keep references to HasOutputChanges and
HasResourceChanges() so readers know how to interpret the flag.
pkg/ci/plugins/terraform/template_test.go (1)

543-554: Test name could be clearer.

The test case "output changes only does not count" doesn't actually set HasOutputChanges: true on the context. Since HasResourceChanges() only checks resource counts (not HasOutputChanges), the test passes correctly — but the name implies output changes are being tested when they aren't.

Consider renaming to "empty resources" or adding a dedicated test case that explicitly sets HasOutputChanges: true to confirm the method ignores it.

♻️ Optional: Add explicit output-only test case
 		tests := []struct {
 			name      string
 			resources plugin.ResourceCounts
+			hasOutputChanges bool
 			want      bool
 		}{
 			{"no changes", plugin.ResourceCounts{}, false},
 			{"create only", plugin.ResourceCounts{Create: 1}, true},
-			{"output changes only does not count", plugin.ResourceCounts{}, false},
+			{"empty resources", plugin.ResourceCounts{}, false},
+			{"output changes only does not count as resource changes", plugin.ResourceCounts{}, false}, // HasOutputChanges would be true but irrelevant
 		}

 		for _, tt := range tests {
 			t.Run(tt.name, func(t *testing.T) {
-				ctx := &TerraformTemplateContext{Resources: tt.resources}
+				ctx := &TerraformTemplateContext{
+					Resources:        tt.resources,
+					HasOutputChanges: tt.name == "output changes only does not count as resource changes",
+				}
 				assert.Equal(t, tt.want, ctx.HasResourceChanges())
 			})
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/ci/plugins/terraform/template_test.go` around lines 543 - 554, The test
name "output changes only does not count" is misleading because the table entry
doesn't set TerraformTemplateContext.HasOutputChanges; either rename that case
to "empty resources" or add a new table case that sets
TerraformTemplateContext{Resources: plugin.ResourceCounts{}, HasOutputChanges:
true} to assert HasResourceChanges() still returns false; update the test table
and t.Run entries accordingly so TerraformTemplateContext and its
HasResourceChanges() behavior are explicitly and accurately covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/ci/plugins/terraform/context.go`:
- Around line 46-48: The comment for the struct field HasOutputChanges is
misleading — update it to state that HasOutputChanges is true whenever Terraform
outputs exist (regardless of resource changes), rather than implying
outputs-only; mention that callers must combine HasOutputChanges with
HasResourceChanges() (e.g., check HasOutputChanges && !HasResourceChanges()) to
detect output-only changes; modify the comment above the HasOutputChanges field
and keep references to HasOutputChanges and HasResourceChanges() so readers know
how to interpret the flag.

In `@pkg/ci/plugins/terraform/parser_test.go`:
- Around line 968-972: Add a zero-count test case to
TestBuildOutputChangeSummary to document and lock in the behavior for the edge
case where buildOutputChangeSummary(0) is called; update the test in
pkg/ci/plugins/terraform/parser_test.go (function TestBuildOutputChangeSummary)
to include an assertion like assert.Equal(t, "0 outputs to change",
buildOutputChangeSummary(0)) so the expected output for 0 is explicit.

In `@pkg/ci/plugins/terraform/template_test.go`:
- Around line 543-554: The test name "output changes only does not count" is
misleading because the table entry doesn't set
TerraformTemplateContext.HasOutputChanges; either rename that case to "empty
resources" or add a new table case that sets TerraformTemplateContext{Resources:
plugin.ResourceCounts{}, HasOutputChanges: true} to assert HasResourceChanges()
still returns false; update the test table and t.Run entries accordingly so
TerraformTemplateContext and its HasResourceChanges() behavior are explicitly
and accurately covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ef862e8c-9416-4783-9ac2-ed652f8b5d2d

📥 Commits

Reviewing files that changed from the base of the PR and between 5c8cd16 and 5ea7cde.

📒 Files selected for processing (11)
  • pkg/ci/plugins/terraform/context.go
  • pkg/ci/plugins/terraform/parser.go
  • pkg/ci/plugins/terraform/parser_test.go
  • pkg/ci/plugins/terraform/plugin.go
  • pkg/ci/plugins/terraform/template_test.go
  • pkg/ci/plugins/terraform/templates/apply.md
  • pkg/ci/plugins/terraform/templates/plan.md
  • pkg/ci/plugins/terraform/testdata/golden/plan_creates_only.md
  • pkg/ci/plugins/terraform/testdata/golden/plan_destroys_warning.md
  • pkg/ci/plugins/terraform/testdata/golden/plan_with_warnings.md
  • pkg/ci/plugins/terraform/testdata/plan_json/success_output_only.json

coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 9, 2026
The plan template was changed to use "Resource Changes Found" instead of
"Changes Found" for resource-level changes, but test assertions and
golden files were not updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 9, 2026
@codecov

codecov Bot commented Apr 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.87755% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.22%. Comparing base (5ee9d81) to head (d3d96f5).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ernal/terraform_backend/terraform_backend_local.go 40.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2306      +/-   ##
==========================================
+ Coverage   77.19%   77.22%   +0.03%     
==========================================
  Files        1070     1070              
  Lines      101511   101547      +36     
==========================================
+ Hits        78359    78418      +59     
+ Misses      18835    18812      -23     
  Partials     4317     4317              
Flag Coverage Δ
unittests 77.22% <93.87%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/exec/terraform_state_utils.go 77.02% <100.00%> (+2.02%) ⬆️
pkg/ci/plugins/terraform/context.go 100.00% <100.00%> (ø)
pkg/ci/plugins/terraform/parser.go 96.41% <100.00%> (+0.09%) ⬆️
pkg/ci/plugins/terraform/plugin.go 93.61% <ø> (ø)
pkg/terraform/output/executor.go 91.54% <100.00%> (+0.19%) ⬆️
pkg/terraform/output/workspace.go 96.15% <100.00%> (+0.59%) ⬆️
...ernal/terraform_backend/terraform_backend_local.go 77.27% <40.00%> (-11.62%) ⬇️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Reverse EnsureWorkspace to try WorkspaceSelect before WorkspaceNew,
fixing a Windows race condition where WorkspaceNew creates a new empty
workspace instead of failing with "already exists" after init -reconfigure.

Add cache reset functions (ResetOutputsCache, ResetStateCache) and clear
caches at test start to prevent cross-test contamination via shared
package-level sync.Map caches.

Add Windows-specific retry in ReadTerraformBackendLocal for state file
visibility after apply.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
internal/exec/yaml_func_terraform_output_test.go (1)

19-20: Pair the pre-test reset with a cleanup reset.

This clears shared cache state on entry, but the test repopulates the cache before exiting. Register the same helper in t.Cleanup so later tests don't inherit this run's outputs.

Suggested fix
 	tfoutput.ResetOutputsCache()
+	t.Cleanup(func() {
+		tfoutput.ResetOutputsCache()
+	})

Based on learnings: "cloudposse/atmos: pkg/utils now exposes ResetPathMatchCache() and ResetGlobMatchesCache() (export_test.go). In tests, prefer these helpers with t.Cleanup over direct global var assignment to avoid races and inter-test coupling."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/exec/yaml_func_terraform_output_test.go` around lines 19 - 20, Add a
matching cleanup call so the pre-test cache reset doesn't leak state: after
calling tfoutput.ResetOutputsCache() in the test setup, register a t.Cleanup
that calls tfoutput.ResetOutputsCache() again (use the test's t and t.Cleanup to
ensure the cache is reset after the test finishes); if other cache helpers are
available in this package (e.g., ResetPathMatchCache or ResetGlobMatchesCache),
prefer using those helper functions both at setup and inside t.Cleanup to avoid
races and inter-test coupling.
internal/exec/yaml_func_utils_test.go (1)

237-239: Reset these caches again in t.Cleanup.

This gives you a clean start, but the test repopulates both caches and leaves shared state behind for whatever runs next. Add the same resets in t.Cleanup so isolation is bidirectional.

Suggested fix
 	ResetStateCache()
 	tfoutput.ResetOutputsCache()
+	t.Cleanup(func() {
+		ResetStateCache()
+		tfoutput.ResetOutputsCache()
+	})

Based on learnings: "cloudposse/atmos: pkg/utils now exposes ResetPathMatchCache() and ResetGlobMatchesCache() (export_test.go). In tests, prefer these helpers with t.Cleanup over direct global var assignment to avoid races and inter-test coupling."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/exec/yaml_func_utils_test.go` around lines 237 - 239, Add cache
resets into t.Cleanup so the test cleans up shared state after it runs: call
ResetStateCache() and tfoutput.ResetOutputsCache() inside t.Cleanup to mirror
the initial clears, or if available prefer the exported helpers
ResetPathMatchCache() and ResetGlobMatchesCache() (and
tfoutput.ResetOutputsCache()) in the t.Cleanup closure; update the test to
register those cleanup calls using t.Cleanup to avoid leaking state between
tests.
internal/exec/yaml_func_terraform_state_test.go (1)

19-21: Add post-test cache cleanup for stronger isolation.

Lines 19-21 clear shared caches only at test start. Add t.Cleanup to clear them again after the test so this test doesn’t leak state into later tests.

Suggested patch
 func TestYamlFuncTerraformState(t *testing.T) {
 	// Clear caches to ensure isolation from other tests that may have run first.
 	ResetStateCache()
 	tfoutput.ResetOutputsCache()
+	t.Cleanup(func() {
+		ResetStateCache()
+		tfoutput.ResetOutputsCache()
+	})
 
 	if _, lookErr := exec.LookPath("tofu"); lookErr != nil {

Based on learnings: cloudposse/atmos tests should use cache reset helpers with t.Cleanup to avoid races and inter-test coupling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/exec/yaml_func_terraform_state_test.go` around lines 19 - 21, The
test currently calls ResetStateCache() and tfoutput.ResetOutputsCache() only at
the start causing possible leakage; add post-test cleanup by registering
t.Cleanup callbacks that call ResetStateCache() and tfoutput.ResetOutputsCache()
so both caches are reset after the test finishes (use t.Cleanup(func() {
ResetStateCache() }) and t.Cleanup(func() { tfoutput.ResetOutputsCache() })
adjacent to the existing setup calls).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/exec/terraform_state_utils.go`:
- Around line 21-24: ResetStateCache currently rebinds terraformStateCache to a
new sync.Map which races with concurrent GetTerraformState Load/Store calls;
instead, iterate over the existing terraformStateCache (use
terraformStateCache.Range) and call terraformStateCache.Delete(key) for each
entry so the same sync.Map instance is cleared in place; update ResetStateCache
to perform an in-place clear and keep references used by GetTerraformState and
other callers.

In `@pkg/terraform/output/executor.go`:
- Around line 47-50: The ResetOutputsCache function currently rebinds the shared
terraformOutputsCache to a new sync.Map which races with concurrent readers;
instead, clear the existing sync.Map in place by iterating over
terraformOutputsCache and deleting each key (use terraformOutputsCache.Range and
terraformOutputsCache.Delete) so goroutines holding references to the map see it
emptied rather than swapped; keep the existing perf.Track defer and replace the
assignment terraformOutputsCache = sync.Map{} with in-place clearing logic
inside ResetOutputsCache.

In `@pkg/terraform/output/workspace.go`:
- Around line 63-85: The WorkspaceSelect error handling currently treats any
error as "missing" and calls WorkspaceNew; add a helper
isWorkspaceMissingError(err error) that mirrors the existing
isWorkspaceExistsError pattern to detect explicit "workspace not found" messages
from terraform-exec, then change the select-fallback logic in the function that
calls runner.WorkspaceSelect(ctx, workspace) to only call runner.WorkspaceNew
when isWorkspaceMissingError(err) is true and otherwise return/wrap the original
error (using the same wrapErrorWithStderr/errUtils.Build flow). Also add a unit
test that simulates a non-missing select error (e.g., errors.New("permission
denied")) and asserts WorkspaceNew is not invoked and the original error is
returned to cover the negative-path behavior.

---

Nitpick comments:
In `@internal/exec/yaml_func_terraform_output_test.go`:
- Around line 19-20: Add a matching cleanup call so the pre-test cache reset
doesn't leak state: after calling tfoutput.ResetOutputsCache() in the test
setup, register a t.Cleanup that calls tfoutput.ResetOutputsCache() again (use
the test's t and t.Cleanup to ensure the cache is reset after the test
finishes); if other cache helpers are available in this package (e.g.,
ResetPathMatchCache or ResetGlobMatchesCache), prefer using those helper
functions both at setup and inside t.Cleanup to avoid races and inter-test
coupling.

In `@internal/exec/yaml_func_terraform_state_test.go`:
- Around line 19-21: The test currently calls ResetStateCache() and
tfoutput.ResetOutputsCache() only at the start causing possible leakage; add
post-test cleanup by registering t.Cleanup callbacks that call ResetStateCache()
and tfoutput.ResetOutputsCache() so both caches are reset after the test
finishes (use t.Cleanup(func() { ResetStateCache() }) and t.Cleanup(func() {
tfoutput.ResetOutputsCache() }) adjacent to the existing setup calls).

In `@internal/exec/yaml_func_utils_test.go`:
- Around line 237-239: Add cache resets into t.Cleanup so the test cleans up
shared state after it runs: call ResetStateCache() and
tfoutput.ResetOutputsCache() inside t.Cleanup to mirror the initial clears, or
if available prefer the exported helpers ResetPathMatchCache() and
ResetGlobMatchesCache() (and tfoutput.ResetOutputsCache()) in the t.Cleanup
closure; update the test to register those cleanup calls using t.Cleanup to
avoid leaking state between tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d7dbd71-ad4c-49df-99da-27d05894b96d

📥 Commits

Reviewing files that changed from the base of the PR and between dadb988 and ee92300.

📒 Files selected for processing (9)
  • internal/exec/terraform_state_utils.go
  • internal/exec/yaml_func_terraform_output_test.go
  • internal/exec/yaml_func_terraform_state_test.go
  • internal/exec/yaml_func_utils_test.go
  • internal/terraform_backend/terraform_backend_local.go
  • pkg/terraform/output/executor.go
  • pkg/terraform/output/executor_test.go
  • pkg/terraform/output/workspace.go
  • pkg/terraform/output/workspace_test.go

Comment thread internal/exec/terraform_state_utils.go Outdated
Comment thread pkg/terraform/output/executor.go Outdated
Comment thread pkg/terraform/output/workspace.go
Andriy Knysh (aknysh) and others added 2 commits April 10, 2026 18:18
…test isolation

- Fix cache reset race: ResetStateCache and ResetOutputsCache now use
  Range+Delete to clear entries in place instead of reassigning
  sync.Map{}, which races with concurrent Load/Store calls.

- Add t.Cleanup cache resets to yaml_func_terraform_output_test.go,
  yaml_func_terraform_state_test.go, and yaml_func_utils_test.go for
  bidirectional test isolation (clear before AND after each test).

- Guard WorkspaceSelect→WorkspaceNew fallback: only fall back to
  WorkspaceNew when isWorkspaceMissingError confirms the workspace
  doesn't exist. Other errors (auth, backend, permission) now fail
  fast instead of silently creating empty workspaces that produce
  wrong outputs. New isWorkspaceMissingError helper checks for
  Terraform "doesn't exist" and OpenTofu "does not exist" patterns.

- Fix existing tests to use realistic Terraform error messages instead
  of generic strings. Add negative-path test confirming non-missing
  select errors (e.g. "permission denied") fail fast without triggering
  WorkspaceNew.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/terraform/output/workspace.go`:
- Around line 126-132: The isWorkspaceMissingError helper is too broad (it
treats any error containing "does not exist"/"doesn't exist" as a missing
workspace), so restrict the matcher to workspace-specific messages (e.g.,
require patterns like "workspace .* does not exist", "workspace .* doesn't
exist", or the exact select/terraform output format such as `No workspace named
"<name>"`/`workspace "<name>" not found`) inside isWorkspaceMissingError to
avoid matching bucket/config errors; update the function to check for those
workspace-specific substrings or regexes and add a regression test that passes a
non-workspace error (e.g., "bucket does not exist") to ensure
isWorkspaceMissingError returns false and that WorkspaceNew does not run in that
case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8fc75db7-6121-4d80-9eea-d1f44eb8f29b

📥 Commits

Reviewing files that changed from the base of the PR and between ee92300 and 02511fb.

📒 Files selected for processing (7)
  • internal/exec/terraform_state_utils.go
  • internal/exec/yaml_func_terraform_output_test.go
  • internal/exec/yaml_func_terraform_state_test.go
  • internal/exec/yaml_func_utils_test.go
  • pkg/terraform/output/executor.go
  • pkg/terraform/output/workspace.go
  • pkg/terraform/output/workspace_test.go
✅ Files skipped from review due to trivial changes (1)
  • internal/exec/yaml_func_utils_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/terraform/output/workspace_test.go

Comment thread pkg/terraform/output/workspace.go Outdated
- Require "workspace" in the error message alongside "doesn't exist" /
  "does not exist" so non-workspace errors like "bucket does not exist"
  don't trigger WorkspaceNew fallback.

- Fix executor_test.go: replace generic "workspace not found" with
  realistic Terraform error message matching the tightened guard.

- Add regression tests for "bucket does not exist" and "resource does
  not exist" confirming they are NOT treated as missing-workspace errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aknysh
Andriy Knysh (aknysh) merged commit c6ba03f into main Apr 11, 2026
58 checks passed
@atmos-pro

atmos-pro Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Note

Atmos Pro  

Waiting for your GitHub Actions workflow to upload affected stacks.
Learn More.

@aknysh
Andriy Knysh (aknysh) deleted the osterman/ci-output-changes-badge branch April 11, 2026 03:57
@github-actions

Copy link
Copy Markdown

These changes were released in v1.215.0-rc.7.

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

Labels

patch A minor, backward compatible change size/m Medium size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants