Upgrading
Use this page when moving between Terraform Branch Deploy releases. Upgrade one release line at a time, review the changed public interface, and test the exact action ref before using it in production workflows.
Choosing an Action Ref
Replace <terraform-branch-deploy-ref> in the examples with the ref your repository policy allows:
| Ref style | Use when |
|---|---|
v0.3.0 |
You want the reviewed v0.3.0 release and will update deliberately. For future releases, use the current release tag you reviewed. |
| Full release commit SHA | You need an immutable ref for stricter supply-chain controls. |
v0 |
You intentionally accept the moving latest v0 release line. |
For production workflows, prefer an exact release tag or the full commit SHA for the release you reviewed.
v0.2.0 to v0.3.0
v0.3.0 changes how saved plans persist between the .plan and .apply runs. GitHub made the Actions cache read-only for issue_comment-triggered workflows on 2026-06-26 (changelog), which silently broke cache-based plan saves: .plan appeared to succeed, but .apply could no longer find the plan. v0.3.0 saves plans as GitHub Actions workflow artifacts instead, which are unaffected by that change, immutable once uploaded, and provenance-checked on restore.
Breaking: Add actions: read to Workflow Permissions
The apply run lists and downloads the plan artifact saved by the plan run, which requires actions: read on the workflow token:
permissions:
contents: write
pull-requests: write
issues: write
deployments: write
checks: read
statuses: read
actions: read
Without it, .apply fails with a PR comment reading "Could not list workflow artifacts".
Re-run .plan After Upgrading
Plans saved by v0.2.x live in the Actions cache and are not restored by v0.3.0. After upgrading, run .plan to <env> again before .apply to <env> for any in-flight deployment.
New Input: plan-retention-days
Saved plan artifacts expire after plan-retention-days (default 7, matching the previous cache eviction window; valid range 1-90, capped by the repository's artifact retention setting). An expired plan means re-running .plan. Plan files can embed sensitive resolved values, so prefer short retention.
Plan Persistence Failures Are Now Loud
If a plan cannot be uploaded as an artifact, the plan run fails and posts a PR comment instead of reporting success for a plan that a later apply could never find.
Apply Is Bound to the Latest Plan Command
Every plan run records an intent artifact before Terraform runs, and .apply resolves the plan only through the newest intent record. If your most recent .plan for an environment and commit failed — for example, a targeted plan that errored — .apply refuses with an actionable comment instead of silently applying an older plan created with different arguments. This closes the failure class where a superseded plan (for example, one with different -target arguments) could be applied after a newer plan failed to persist. Re-run .plan and wait for it to succeed before applying.
Branch Deploy v11.1.5
The embedded github/branch-deploy is updated from v11.1.4 to v11.1.5 (dependency updates and upstream documentation hardening). No command behavior changes.
v0.1.0 to v0.2.0
This section applies to v0.1.0, v0.1.0-ghes, and workflows pinned to commits with the v0.1.0 public interface.
v0.2.0 changes Terraform Branch Deploy from a single-step action into a two-mode action:
mode: triggerruns Branch Deploy, checks the PR comment, and exportsTF_BD_*state.- Your workflow checks out
TF_BD_REFand configures cloud credentials only whenTF_BD_CONTINUE == 'true'. mode: executereads the exported state, runs Terraform, posts the result, and completes the Branch Deploy lifecycle.
Workflow Shape
Replace the old single action call with trigger mode, gated checkout and credentials, and execute mode:
- uses: scarowar/terraform-branch-deploy@<terraform-branch-deploy-ref>
with:
mode: trigger
github-token: ${{ secrets.GITHUB_TOKEN }}
disable-naked-commands: true
checks: all
outdated-mode: strict
- uses: actions/checkout@v6
if: env.TF_BD_CONTINUE == 'true'
with:
ref: ${{ env.TF_BD_REF }}
# Configure cloud credentials here.
- uses: scarowar/terraform-branch-deploy@<terraform-branch-deploy-ref>
if: env.TF_BD_CONTINUE == 'true'
with:
mode: execute
github-token: ${{ secrets.GITHUB_TOKEN }}
Keep both Terraform Branch Deploy calls in the same job. TF_BD_* values are written to GITHUB_ENV, which does not cross job boundaries.
Configuration
Move Terraform path settings into .tf-branch-deploy.yml. The working-directory action input from v0.1.0 is no longer used.
default-environment: dev
production-environments: [prod]
stable-branch: main
environments:
dev:
working-directory: terraform/dev
prod:
working-directory: terraform/prod
If your stable branch is not main, set it in both places:
- uses: scarowar/terraform-branch-deploy@<terraform-branch-deploy-ref>
with:
mode: trigger
github-token: ${{ secrets.GITHUB_TOKEN }}
stable-branch: release
Inputs
Update renamed inputs:
| v0.1.0 input | v0.2.0 input |
|---|---|
stable_branch |
stable-branch |
admins_pat |
admins-pat |
disable_naked_commands |
disable-naked-commands |
Remove inputs that are no longer part of the public action interface:
| Removed input | What to do |
|---|---|
skip |
Use mode: trigger to get Branch Deploy state before credentials and Terraform execution. |
working-directory |
Move per-environment paths to .tf-branch-deploy.yml. |
uv-version |
Remove it. Internal bootstrap tool versions are not public action inputs. |
allow-forks |
Remove it. Forked pull request execution is not enabled by Terraform Branch Deploy. |
successful-deploy-labels |
Remove it. Result labels are not part of the public v0.2.0 interface. |
failed-deploy-labels |
Remove it. Result labels are not part of the public v0.2.0 interface. |
successful-noop-labels |
Remove it. Result labels are not part of the public v0.2.0 interface. |
failed-noop-labels |
Remove it. Result labels are not part of the public v0.2.0 interface. |
skip-successful-noop-labels-if-approved |
Remove it. Result labels are not part of the public v0.2.0 interface. |
skip-successful-deploy-labels-if-approved |
Remove it. Result labels are not part of the public v0.2.0 interface. |
merge-deploy-mode |
Remove it. Terraform Branch Deploy uses the comment-driven deploy-before-merge workflow. |
unlock-on-merge-mode |
Remove it. Use .unlock <env> for manual lock release when needed. |
environment-url-in-comment |
Remove it. Use environment-urls for GitHub deployment environment URLs. |
deploy-message-path |
Remove it. Terraform result comments are generated by Terraform Branch Deploy. |
GitHub Actions warns about unknown inputs and then ignores them. Search workflow files before upgrading:
rg "stable_branch|admins_pat|disable_naked_commands|skip:|working-directory|uv-version|allow-forks|successful-deploy-labels|failed-deploy-labels|successful-noop-labels|failed-noop-labels|skip-successful-noop-labels-if-approved|skip-successful-deploy-labels-if-approved|merge-deploy-mode|unlock-on-merge-mode|environment-url-in-comment|deploy-message-path" .github/workflows
Defaults to Review
Review these values instead of relying on old behavior:
| Setting | v0.2.0 guidance |
|---|---|
disable-naked-commands |
Set it explicitly. Use true when every command must name an environment. |
allow-non-default-target-branch |
Defaults to false. Set it to true only if you intentionally deploy PRs targeting non-default branches. |
outdated-mode |
Use strict when stale PR branches must not deploy. |
checks |
Use all for the broadest status-check gate, or required when branch protection defines the gate. |
Outputs
Prefer TF_BD_* environment variables after trigger mode. If your workflow used action outputs from v0.1.0, update them:
| v0.1.0 output | v0.2.0 replacement |
|---|---|
env |
environment or TF_BD_ENVIRONMENT |
rollback |
is-rollback or TF_BD_IS_ROLLBACK |
plan |
TF_BD_OPERATION == 'plan' |
apply |
TF_BD_OPERATION == 'apply' |
parsed_params |
Not exposed. Use params or TF_BD_PARAMS when needed. |
Terraform Behavior
Normal apply uses the latest successful saved plan for the same environment and commit SHA:
The apply command restores and applies the saved targeted plan. It does not run a fresh untargeted apply. The restored plan artifact name and saved metadata must agree on the plan argument hash. If you run another successful plan for the same environment and commit, that newer plan supersedes the older one.
Rollback remains a direct stable-branch apply:
Rollback does not use a pull request saved plan and does not accept Terraform arguments such as -target.