Describe the Bug
Description
When running atmos terraform plan --all --stack <stack>, the CI summary hooks (after.terraform.plan) fire only once after all components have been processed, rather than once per component. This results in the GitHub step summary ($GITHUB_STEP_SUMMARY) containing output for only the last component in the dependency order, instead of per-component summaries with IaC change status badges.
Root Cause
The CI hooks are registered in the Cobra command layer (cmd/terraform/plan.go) via PostRunE, which fires a single time after RunE completes:
// cmd/terraform/plan.go
PostRunE: func(cmd *cobra.Command, args []string) error {
return runHooksWithOutput(h.AfterTerraformPlan, cmd, args, capturedPlanOutput)
},
In --all mode, RunE calls ExecuteTerraformAll() → executeInDependencyOrder() → executeTerraformForNode() → ExecuteTerraform() for each component. The info struct is mutated by updateInfoFromNode() for each component, so by the time PostRunE fires:
info.Component / info.Stack reflect only the last processed component
capturedPlanOutput contains the combined stdout of all components (via the shared stdoutBuf), but the CI plugin's onAfterPlan handler parses it as if it belongs to a single component
Relevant code path:
cmd/terraform/plan.go:103 — single PostRunE call
internal/exec/terraform_executor.go:103 — updateInfoFromNode mutates shared info
internal/exec/terraform_executor.go:123 — executeNodeCommand calls ExecuteTerraform without any CI hook invocation
pkg/hooks/hooks.go:151 — RunCIHooks receives stale single-component context
Expected Behavior
When running atmos terraform plan --all --stack <stack> with CI enabled, each component should produce its own entry in $GITHUB_STEP_SUMMARY using the CI templates (e.g., plan.md). For example, with 5 components in the stack, the summary should contain 5 sections with per-component badges (PLAN-CREATE, PLAN-CHANGE, NO_CHANGE, etc.) and resource change details.
Actual Behavior
Only the last component in the dependency order gets a summary entry (or the combined output is misattributed to it). The other components' plan results are lost from the summary.
Steps to Reproduce
- Configure a stack with multiple terraform components that have
depends_on relationships
- Enable CI in
atmos.yaml:
ci:
enabled: true
summary:
enabled: true
templates:
base_path: "ci/templates"
terraform:
plan: "plan.md"
- Run in a GitHub Actions workflow:
atmos terraform plan --all --stack my-stack --ci
- Check the GitHub job summary — only the last component has a summary entry
Suggested Fix
Fire CI hooks per-component inside executeTerraformForNode (or executeNodeCommand) rather than relying on the single PostRunE call. This requires:
- Detecting CI mode in
executeNodeCommand
- Passing
WithStdoutCapture / WithStderrCapture options to ExecuteTerraform per-component
- Calling
RunCIHooks after each component completes with that component's captured output and correct info.Component / info.Stack
- Suppressing the
PostRunE CI hook call when --all mode was used (to avoid double-firing for the last component)
Alternatively, ExecuteTerraformAll could accept a callback/hook interface to fire per-node completion events.
Screenshots
No response
Environment
- Atmos version: v1.217.0
- CI platform: GitHub Actions
- Mode:
atmos terraform plan --all --stack <stack> --ci
Additional Context
Related
Describe the Bug
Description
When running
atmos terraform plan --all --stack <stack>, the CI summary hooks (after.terraform.plan) fire only once after all components have been processed, rather than once per component. This results in the GitHub step summary ($GITHUB_STEP_SUMMARY) containing output for only the last component in the dependency order, instead of per-component summaries with IaC change status badges.Root Cause
The CI hooks are registered in the Cobra command layer (
cmd/terraform/plan.go) viaPostRunE, which fires a single time afterRunEcompletes:In
--allmode,RunEcallsExecuteTerraformAll()→executeInDependencyOrder()→executeTerraformForNode()→ExecuteTerraform()for each component. Theinfostruct is mutated byupdateInfoFromNode()for each component, so by the timePostRunEfires:info.Component/info.Stackreflect only the last processed componentcapturedPlanOutputcontains the combined stdout of all components (via the sharedstdoutBuf), but the CI plugin'sonAfterPlanhandler parses it as if it belongs to a single componentRelevant code path:
cmd/terraform/plan.go:103— singlePostRunEcallinternal/exec/terraform_executor.go:103—updateInfoFromNodemutates sharedinfointernal/exec/terraform_executor.go:123—executeNodeCommandcallsExecuteTerraformwithout any CI hook invocationpkg/hooks/hooks.go:151—RunCIHooksreceives stale single-component contextExpected Behavior
When running
atmos terraform plan --all --stack <stack>with CI enabled, each component should produce its own entry in$GITHUB_STEP_SUMMARYusing the CI templates (e.g.,plan.md). For example, with 5 components in the stack, the summary should contain 5 sections with per-component badges (PLAN-CREATE, PLAN-CHANGE, NO_CHANGE, etc.) and resource change details.Actual Behavior
Only the last component in the dependency order gets a summary entry (or the combined output is misattributed to it). The other components' plan results are lost from the summary.
Steps to Reproduce
depends_onrelationshipsatmos.yaml:Suggested Fix
Fire CI hooks per-component inside
executeTerraformForNode(orexecuteNodeCommand) rather than relying on the singlePostRunEcall. This requires:executeNodeCommandWithStdoutCapture/WithStderrCaptureoptions toExecuteTerraformper-componentRunCIHooksafter each component completes with that component's captured output and correctinfo.Component/info.StackPostRunECI hook call when--allmode was used (to avoid double-firing for the last component)Alternatively,
ExecuteTerraformAllcould accept a callback/hook interface to fire per-node completion events.Screenshots
No response
Environment
atmos terraform plan --all --stack <stack> --ciAdditional Context
Related
--affectedflag likely has the same issue since it uses a similar execution pattern