Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions image/actions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,44 @@ function plan() {
# shellcheck disable=SC2086
(cd "$INPUT_PATH" && $TOOL_COMMAND_NAME plan -input=false -no-color -detailed-exitcode -lock-timeout=300s $PARALLEL_ARG $PLAN_OUT_ARG $PLAN_ARGS) \
2>"$STEP_TMP_DIR/terraform_plan.stderr" \
| python3 -c "
import sys
# tfmask uses bufio.Scanner which has a 64KB line limit. Resources that embed
# large base64 blobs (e.g. google_api_gateway_api_config openapi_documents)
# produce lines that exceed this limit, causing tfmask to crash mid-pipe and
# terraform to exit via SIGPIPE with a non-standard exit code. That prevents
# PIPESTATUS[0] from returning 2 (changes), so the apply step is skipped.
# Split long lines into chunks with a sentinel prefix so tfmask can process
# each chunk; the unchunker below reassembles them preserving the full content.
CHUNK = 60000
for line in sys.stdin:
s = line.rstrip('\n')
if len(s) <= CHUNK:
sys.stdout.write(line)
else:
parts = [s[i:i+CHUNK] for i in range(0, len(s), CHUNK)]
for i, p in enumerate(parts):
sys.stdout.write(f'##TF_CHUNK:{i}/{len(parts)}/{p}\n')
" \
| $TFMASK \
| python3 -c "
import sys
# Reassemble lines that were split by the chunker above.
buf = []
for line in sys.stdin:
s = line.rstrip('\n')
if s.startswith('##TF_CHUNK:'):
rest = s[11:]
slash1 = rest.index('/')
slash2 = rest.index('/', slash1 + 1)
i, total = int(rest[:slash1]), int(rest[slash1+1:slash2])
buf.append((i, rest[slash2+1:]))
if len(buf) == total:
sys.stdout.write(''.join(p[1] for p in sorted(buf)) + '\n')
buf = []
else:
sys.stdout.write(line)
" \
| tee /dev/fd/3 "$STEP_TMP_DIR/terraform_plan.stdout" \
| compact_plan \
>"$STEP_TMP_DIR/plan.txt"
Expand Down
13 changes: 10 additions & 3 deletions image/entrypoints/plan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ set-plan-args
exec 3>&1

### Generate a plan
PLAN_OUT="$STEP_TMP_DIR/plan.out"
if [[ "$INPUT_SPECULATIVE" == "true" ]]; then
# Force speculative plan - no -out flag
PLAN_OUT=""
else
# Normal behavior - try to save plan file
PLAN_OUT="$STEP_TMP_DIR/plan.out"
fi
PLAN_ARGS="$PLAN_ARGS -lock=false"
plan

if [[ $PLAN_EXIT -eq 1 ]]; then
# If plan failed because remote backend doesn't support -out flag, retry without it
# Skip this retry if we're already running speculative (PLAN_OUT is already empty)
if [[ $PLAN_EXIT -eq 1 && -n "$PLAN_OUT" ]]; then
if grep -q "Saving a generated plan is currently not supported" "$STEP_TMP_DIR/terraform_plan.stderr"; then
# This terraform module is using the remote backend, which is deficient.
PLAN_OUT=""
PLAN_ARGS="$PLAN_ARGS -lock=false"
plan
fi
fi
Expand Down
3 changes: 3 additions & 0 deletions image/src/github_pr_comment/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ def main() -> int:
status=status
)

if comment.comment_url:
output('comment_url', comment.comment_url)

elif sys.argv[1] == 'status':
if comment.comment_url is None:
debug("Can't set status of comment that doesn't exist")
Expand Down
20 changes: 20 additions & 0 deletions terraform-plan/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,24 @@ The [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/
- Optional
- Default: The Terraform default (10).

* `speculative`

Set to `true` to force a speculative plan that cannot be applied.

This creates a "Planned and finished" run in Terraform Cloud instead of "Planned and saved".
Speculative plans don't lock state and can run in parallel with other operations.

This is useful for PR workflows where you want to preview changes without blocking other runs.

```yaml
with:
speculative: true
```

- Type: boolean
- Optional
- Default: `false`

## Outputs

* `changes`
Expand All @@ -185,6 +203,8 @@ The [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/

The plan can be used as the `plan_file` input to the [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/tree/main/terraform-apply) action.

This won't be set if `speculative` is `true` or if the backend type is `remote`/`cloud` in remote execution mode.

Terraform plans often contain sensitive information, so this output should be treated with care.

- Type: string
Expand Down
16 changes: 16 additions & 0 deletions terraform-plan/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ inputs:
description: Limit the number of concurrent operations
required: false
default: "0"
speculative:
description: |
Set to `true` to force a speculative plan that cannot be applied.

This creates a "Planned and finished" run in Terraform Cloud instead of "Planned and saved".
Speculative plans don't lock state and can run in parallel with other operations.

This is useful for PR workflows where you want to preview changes without blocking other runs.
required: false
default: "false"

outputs:
changes:
Expand All @@ -89,6 +99,8 @@ outputs:

The plan can be used as the `plan_file` input to the [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/tree/main/terraform-apply) action.

This won't be set if `speculative` is `true` or if the backend type is `remote`/`cloud` in remote execution mode.

Terraform plans often contain sensitive information, so this output should be treated with care.
json_plan_path:
description: |
Expand All @@ -112,6 +124,10 @@ outputs:
description: The number of resources that would be affected by this operation.
run_id:
description: If the root module uses the `remote` or `cloud` backend in remote execution mode, this output will be set to the remote run id.
comment_url:
description: |
The URL of the GitHub PR comment that was created or updated with the plan.
This will only be set if a comment was created (i.e., when running on a pull request with add_github_comment enabled).

runs:
using: docker
Expand Down
4 changes: 4 additions & 0 deletions tofu-plan/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ outputs:
description: The number of resources that would be affected by this operation.
run_id:
description: If the root module uses the `remote` or `cloud` backend in remote execution mode, this output will be set to the remote run id.
comment_url:
description: |
The URL of the GitHub PR comment that was created or updated with the plan.
This will only be set if a comment was created (i.e., when running on a pull request with add_github_comment enabled).

runs:
env:
Expand Down