Workflow
To bring it all together, we create a workflow that uses the composites of the test, plan, and apply stage in the final workflow.
Pipeline Trigger and Environment Variables
name: Terraform setup, test, plan, and apply
on:
pull_request:
env:
TERRAFORM_VERSION: "1.9.2"
TERRAFORM_DIRECTORY: "<terraform-directory>"
TF_IN_AUTOMATION: "True"
AWS_REGION: "<aws-region>"
AWS_ROLE_TO_ASSUME: "<aws-role-arn>"
AWS_ROLE_SESSION_NAME: "<aws-role-session-name>"
We start with the first code block in the workflow. In this code block, we specify the name of the workflow, how we want it to be triggered, and the environment variables to be used by the entire workflow.
The name is an arbitrary value that you can decide on. As for the way we want it to be triggered, we have specified it to be triggered whenever a pull request is opened. This allows for the feature of posting comments to the PR to shine and give reviewers a chance to look over the test, plan, and apply results.
Finally, the environment variables specified are applied to the whole workflow. Specify the Terraform directory based on your folder structure, and the AWS Role ARN, AWS Role Session Name and AWS Region which we have specified before.
Permissions
permissions:
id-token: write
contents: read
pull-requests: write
actions: read
The next code block specifies the permissions this pipeline has. The id-token
makes use of the GITHUB_TOKEN
used for authentication that then contents
uses to read the repository contents such as commits.
Also, the pull-requests
permission allows the pipeline to write to the open pull request, and finally, actions
permissions is used to read the status of the action pipeline.
Test Stage
jobs:
terraform_init_test:
runs-on: ubuntu-latest
if: github.event.review.state != 'approved'
steps:
- uses: actions/checkout@v4
- name: Get PR ID
id: pr-id
shell: bash
env:
GITHUB_REF: ${{ inputs.github_ref }}
run: |
PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
- name: Terraform Init and Test
uses: ./.github/test
with:
terraform_directory: ${{ env.TERRAFORM_DIRECTORY }}
root_directory: "."
terraform_version: ${{ env.TERRAFORM_VERSION }}
github_token: ${{ secrets.GITHUB_TOKEN }}
pr_id: ${{ steps.pr-id.outputs.PR_NUMBER }}
aws_role_to_assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws_role_session_name: ${{ env.AWS_ROLE_SESSION_NAME }}
aws_region: ${{ env.AWS_REGION }}
Next up is the test stage. In this code block, we specify where this job runs on and if it runs. These are the first two conditions we have for the stage. Afterwards, we start defining the steps for this stage. First of all, the runner fetches the code through the checkout step, then gets the pull request ID, and finally uses the test stage composite leveraging the environment variables.
Plan Stage
terraform_plan:
runs-on: ubuntu-latest
if: github.event.review.state != 'approved'
needs: terraform_init_test
steps:
- uses: actions/checkout@v4
- name: Get PR ID
id: pr-id
shell: bash
env:
GITHUB_REF: ${{ inputs.github_ref }}
run: |
PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
- name: Terraform Init and Plan
uses: ./.github/plan
with:
terraform_directory: ${{ env.TERRAFORM_DIRECTORY }}
terraform_version: ${{ env.TERRAFORM_VERSION }}
github_token: ${{ secrets.GITHUB_TOKEN }}
pr_id: ${{ steps.pr-id.outputs.PR_NUMBER }}
aws_role_to_assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws_role_session_name: ${{ env.AWS_ROLE_SESSION_NAME }}
aws_region: ${{ env.AWS_REGION }}
In this code block, we have the plan stage where we specify where this job runs on and if it runs. These are the first two conditions we have for the stage. Afterwards, we start defining the steps for this stage. First of all, the runner fetches the code through the checkout step, then gets the pull request ID, and finally uses the plan stage composite leveraging the environment variables.
Apply Stage
terraform_apply:
runs-on: ubuntu-latest
if: github.event.review.state != 'approved'
needs: terraform_plan
steps:
- uses: actions/checkout@v4
- name: Get PR ID
id: pr-id
shell: bash
env:
GITHUB_REF: ${{ inputs.github_ref }}
run: |
PR_NUMBER=$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
- name: Terraform Init and Apply
uses: ./.github/apply
with:
terraform_directory: ${{ env.TERRAFORM_DIRECTORY }}
terraform_version: ${{ env.TERRAFORM_VERSION }}
github_token: ${{ secrets.GITHUB_TOKEN }}
pr_id: ${{ steps.pr-id.outputs.PR_NUMBER }}
aws_role_to_assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws_role_session_name: ${{ env.AWS_ROLE_SESSION_NAME }}
aws_region: ${{ env.AWS_REGION }}
Finally, we have the apply stage. We again specify where this job runs on and if it runs. These are the first two conditions we have for the stage. Afterwards, we start defining the steps for this stage. First of all, the runner fetches the code through the checkout step, then gets the pull request ID, and finally uses the apply stage composite leveraging the environment variables.