Run a Preview in GitHub Actions
The following workflows are blueprints and need some adjustments to work for you.
Search for CHANGEME
to adjust needed credentials details for AWS and Google Cloud examples.
Terramate Cloud support
When synchronizing previews to Terramate Cloud previews will be synchronized with a detailed status and can be reviewed on a stack level.
The following actions also post back previews as GitHub comments. This will soon be taken care of by Terramate Cloud to fix some short-comings:
- GitHub limits the size of a comment, so when creating large plans of many stacks, previews are truncated.
- Rate limits in GitHub sometimes prevent comments from being created.
- Terraform plans are hard to read and include a lot of unneeded information for the reviewer
- Destructive operations are hard to spot.
Terramate Cloud will provide:
- Readable plan previews
- Policies to set up blocking pull requests until admins review destructive operations
- Detection and blocking on required re-plan of a stale plan, when the stack was changed on the default branch and in a pull request and the code is not up to date.
Deployment Blueprints
Create the following GitHub Actions configuration at .github/workflows/preview.yml
yml
name: Terraform Preview
on:
pull_request:
branches:
- main
jobs:
preview:
name: Plan Terraform changes in changed Terramate stacks
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
checks: read
steps:
# Create Pull Request comment
- name: Prepare pull request preview comment
if: github.event.pull_request
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
message: |
## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}
:warning: preview is being created... please stand by!
# Check out the code
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
# Install tooling
- name: Install Terramate
uses: terramate-io/terramate-action@v1
- name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.4
terraform_wrapper: false
# Linting
- name: Check Terramate formatting
run: terramate fmt --check
- name: Check Terraform formatting
run: terraform fmt -recursive -check -diff
# Check for changed stacks
- name: List changed stacks
id: list
run: terramate list --changed
# Configure cloud credentials
- name: Configure AWS credentials via OIDC
if: steps.list.outputs.stdout
uses: aws-actions/configure-aws-credentials@v2
with:
aws-region: 'CHANGEME: AWS REGION'
role-to-assume: 'CHANGEME: IAM ROLE ARN'
# Run the Terraform preview via Terramate in each changed stack
- name: Initialize Terraform in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 1 --changed -- terraform init -lock-timeout=5m
- name: Validate Terraform configuration in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 5 --changed -- terraform validate
- name: Plan Terraform changes in changed stacks
if: steps.list.outputs.stdout
run: |
terramate run --parallel 5 --changed --sync-preview --terraform-plan-file=out.tfplan --debug-preview-url preview_url.txt --continue-on-error -- terraform plan -out out.tfplan -detailed-exitcode -lock=false
env:
GITHUB_TOKEN: ${{ github.token }}
# Update Pull Request comment
- name: Generate preview details
if: steps.list.outputs.stdout
id: comment
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "[:mag: View Details on Terramate Cloud]($(cat preview_url.txt))"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt
echo >>pr-comment.txt "#### Terraform Plan"
echo >>pr-comment.txt
echo >>pr-comment.txt '```terraform'
terramate run --changed -- terraform show -no-color out.tfplan |& dd bs=1024 count=248 >>pr-comment.txt
[ "${PIPESTATUS[0]}" == "141" ] && sed -i 's/#### Terraform Plan/#### :warning: Terraform Plan truncated: please check console output :warning:/' pr-comment.txt
echo >>pr-comment.txt '```'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when no stacks changed
if: success() && !steps.list.outputs.stdout
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt 'No changed stacks, no detailed preview will be generated.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when things failed
if: failure()
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "[:mag: View Details on Terramate Cloud]($(cat preview_url.txt))"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt ':boom: Generating preview failed. Please see details in Actions output.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Publish generated preview as GitHub commnent
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
path: pr-comment.txt
yml
name: Terraform Preview
on:
pull_request:
branches:
- main
jobs:
preview:
name: Plan Terraform changes in changed Terramate stacks
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
checks: read
steps:
# Create Pull Request comment
- name: Prepare pull request preview comment
if: github.event.pull_request
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
message: |
## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}
:warning: preview is being created... please stand by!
# Check out the code
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
# Install tooling
- name: Install Terramate
uses: terramate-io/terramate-action@v1
- name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.4
terraform_wrapper: false
# Linting
- name: Check Terramate formatting
run: terramate fmt --check
- name: Check Terraform formatting
run: terraform fmt -recursive -check -diff
# Check for changed stacks
- name: List changed stacks
id: list
run: terramate list --changed
# Configure cloud credentials
- name: Authenticate to Google Cloud via OIDC
if: steps.list.outputs.stdout
id: auth
uses: google-github-actions/auth@v1
with:
workload_identity_provider: 'CHANGEME: WORKLOAD IDENTITY PROVIDER ID'
service_account: 'CHANGEME: SERVICE ACCOUNT EMAIL'
# Run the Terraform preview via Terramate in each changed stack
- name: Initialize Terraform in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 1 --changed -- terraform init -lock-timeout=5m
- name: Validate Terraform configuration in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 5 --changed -- terraform validate
- name: Plan Terraform changes in changed stacks
if: steps.list.outputs.stdout
run: |
terramate run --parallel 5 --changed --sync-preview --terraform-plan-file=out.tfplan --debug-preview-url preview_url.txt --continue-on-error -- terraform plan -out out.tfplan -detailed-exitcode -lock=false
env:
GITHUB_TOKEN: ${{ github.token }}
# Update Pull Request comment
- name: Generate preview details
if: steps.list.outputs.stdout
id: comment
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "[:mag: View Details on Terramate Cloud]($(cat stacks/preview_url.txt))"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt
echo >>pr-comment.txt "#### Terraform Plan"
echo >>pr-comment.txt
echo >>pr-comment.txt '```terraform'
terramate run --changed -- terraform show -no-color out.tfplan |& dd bs=1024 count=248 >>pr-comment.txt
[ "${PIPESTATUS[0]}" == "141" ] && sed -i 's/#### Terraform Plan/#### :warning: Terraform Plan truncated: please check console output :warning:/' pr-comment.txt
echo >>pr-comment.txt '```'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when no stacks changed
if: success() && !steps.list.outputs.stdout
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt 'No changed stacks, no detailed preview will be generated.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when things failed
if: failure()
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "[:mag: View Details on Terramate Cloud]($(cat stacks/preview_url.txt))"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt ':boom: Generating preview failed. Please see details in Actions output.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Publish generated preview as GitHub commnent
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
path: pr-comment.txt
yml
name: Terraform Preview
on:
pull_request:
branches:
- main
jobs:
preview:
name: Plan Terraform changes in changed Terramate stacks
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
checks: read
steps:
# Create Pull Request comment
- name: Prepare pull request preview comment
if: github.event.pull_request
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
message: |
## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}
:warning: preview is being created... please stand by!
# Check out the code
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
# Install tooling
- name: Install Terramate
uses: terramate-io/terramate-action@v1
- name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.4
terraform_wrapper: false
# Linting
- name: Check Terramate formatting
run: terramate fmt --check
- name: Check Terraform formatting
run: terraform fmt -recursive -check -diff
# Check for changed stacks
- name: List changed stacks
id: list
run: terramate list --changed
# Configure cloud credentials
- name: Configure AWS credentials via OIDC
if: steps.list.outputs.stdout
uses: aws-actions/configure-aws-credentials@v2
with:
aws-region: 'CHANGEME: AWS REGION'
role-to-assume: 'CHANGEME: IAM ROLE ARN'
# Run the Terraform preview via Terramate in each changed stack
- name: Initialize Terraform in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 1 --changed -- terraform init -lock-timeout=5m
- name: Validate Terraform configuration in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 5 --changed -- terraform validate
- name: Plan Terraform changes in changed stacks
if: steps.list.outputs.stdout
run: |
terramate run --parallel 5 --changed --continue-on-error -- terraform plan -out out.tfplan -detailed-exitcode -lock=false
env:
GITHUB_TOKEN: ${{ github.token }}
# Update Pull Request comment
- name: Generate preview details
if: steps.list.outputs.stdout
id: comment
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt
echo >>pr-comment.txt "#### Terraform Plan"
echo >>pr-comment.txt
echo >>pr-comment.txt '```terraform'
terramate run --changed -- terraform show -no-color out.tfplan |& dd bs=1024 count=248 >>pr-comment.txt
[ "${PIPESTATUS[0]}" == "141" ] && sed -i 's/#### Terraform Plan/#### :warning: Terraform Plan truncated: please check console output :warning:/' pr-comment.txt
echo >>pr-comment.txt '```'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when no stacks changed
if: success() && !steps.list.outputs.stdout
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt 'No changed stacks, no detailed preview will be generated.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when things failed
if: failure()
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt ':boom: Generating preview failed. Please see details in Actions output.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Publish generated preview as GitHub commnent
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
path: pr-comment.txt
yml
name: Terraform Preview
on:
pull_request:
branches:
- main
jobs:
preview:
name: Plan Terraform changes in changed Terramate stacks
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
pull-requests: write
checks: read
steps:
# Create Pull Request comment
- name: Prepare pull request preview comment
if: github.event.pull_request
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
message: |
## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}
:warning: preview is being created... please stand by!
# Check out the code
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
# Install tooling
- name: Install Terramate
uses: terramate-io/terramate-action@v1
- name: Install Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.4
terraform_wrapper: false
# Linting
- name: Check Terramate formatting
run: terramate fmt --check
- name: Check Terraform formatting
run: terraform fmt -recursive -check -diff
# Check for changed stacks
- name: List changed stacks
id: list
run: terramate list --changed
# Configure cloud credentials
- name: Authenticate to Google Cloud via OIDC
if: steps.list.outputs.stdout
id: auth
uses: google-github-actions/auth@v1
with:
workload_identity_provider: 'CHANGEME: WORKLOAD IDENTITY PROVIDER ID'
service_account: 'CHANGEME: SERVICE ACCOUNT EMAIL'
# Run the Terraform preview via Terramate in each changed stack
- name: Initialize Terraform in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 1 --changed -- terraform init -lock-timeout=5m
- name: Validate Terraform configuration in changed stacks
if: steps.list.outputs.stdout
run: terramate run --parallel 5 --changed -- terraform validate
- name: Plan Terraform changes in changed stacks
if: steps.list.outputs.stdout
run: |
terramate run --parallel 5 --changed --continue-on-error -- terraform plan -out out.tfplan -detailed-exitcode -lock=false
env:
GITHUB_TOKEN: ${{ github.token }}
# Update Pull Request comment
- name: Generate preview details
if: steps.list.outputs.stdout
id: comment
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt
echo >>pr-comment.txt "#### Terraform Plan"
echo >>pr-comment.txt
echo >>pr-comment.txt '```terraform'
terramate run --changed -- terraform show -no-color out.tfplan |& dd bs=1024 count=248 >>pr-comment.txt
[ "${PIPESTATUS[0]}" == "141" ] && sed -i 's/#### Terraform Plan/#### :warning: Terraform Plan truncated: please check console output :warning:/' pr-comment.txt
echo >>pr-comment.txt '```'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when no stacks changed
if: success() && !steps.list.outputs.stdout
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt 'No changed stacks, no detailed preview will be generated.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Generate preview when things failed
if: failure()
run: |
echo >>pr-comment.txt "## Preview of Terraform changes in ${{ github.event.pull_request.head.sha }}"
echo >>pr-comment.txt
echo >>pr-comment.txt "### Changed Stacks"
echo >>pr-comment.txt
echo >>pr-comment.txt '```bash'
echo >>pr-comment.txt "${{ steps.list.outputs.stdout }}"
echo >>pr-comment.txt '```'
echo >>pr-comment.txt ':boom: Generating preview failed. Please see details in Actions output.'
cat pr-comment.txt >>$GITHUB_STEP_SUMMARY
- name: Publish generated preview as GitHub commnent
uses: marocchino/sticky-pull-request-comment@v2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
header: preview
path: pr-comment.txt