Skip to main content

Apply Stage

terraform-apply

The final stage is the apply stage. The steps within the apply stage aim to initialise the Terraform directory, download the artifact saved in the plan stage, apply the changes in the artifact, and then push the Terraform apply results to the open PR.

Input variables

name: 'Terraform setup and apply'
description: 'Sets up Terraform and applies the changes'
inputs:
terraform_directory:
description: 'Directory that holds Terraform code'
required: true
terraform_version:
description: 'Terraform version'
required: true
default: 1.9.2
github_token:
description: 'GitHub token for auth'
required: true
pr_id:
description: 'Pull request ID'
required: true
aws_role_to_assume:
description: 'AWS Role to assume'
required: true
default: <aws-role-arn>
aws_role_session_name:
description: 'AWS Role session name'
required: true
default: <aws-role-session-name>
aws_region:
description: 'AWS Region'
required: true
default: '<aws-region>'

These are the input variables we use for the apply stage. Fill in the previously created AWS Role ARN, AWS Role Session Name and AWS Region.

Composite

runs:
using: "composite"
steps:
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ inputs.terraform_version }}
terraform_wrapper: false

The next code block defines a composite. The use of a composite is to reuse these defined steps in different pipelines. The composite is also using the terraform_version input variable defined earlier.

Configure AWS Credentials

    - name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ inputs.aws_role_to_assume }}
role-session-name: ${{ inputs.aws_role_session_name }}
aws-region: ${{ inputs.aws_region }}

With this code block, we are authenticating the GitHub Actions runner with our AWS account using the previously created AWS Role which are defined in the input variables.

Initialise Terraform

    - name: Terraform Init
id: init
working-directory: ${{ inputs.terraform_directory }}
shell: bash
run: |
terraform init

The next step is running an intialisation on the Terraform directory to install the providers.

Download Artifact

    - name: Download Artifact
id: download-artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.pr_id }}-tf-plan
path: ${{ inputs.terraform_directory }}

With the tfplan created in the plan stage, we run a step in which the tfplan artifact is downloaded to be used in the next step to be applied.

Applying Terraform

    - name: Terraform Apply
id: apply
working-directory: ${{ inputs.terraform_directory }}
shell: bash
run: |
echo 'apply<<EOF' >> $GITHUB_OUTPUT
terraform apply -input=false -no-color tfplan >> $GITHUB_OUTPUT
echo 'EOF' >> $GITHUB_OUTPUT

Our main step in this pipeline is applying the code changes. This step uses the previously downloaded artifact tfplan and applies the changes to our current infrastructure.

Comment Apply Results to PR

    - name: Comment Apply
id: comment-apply
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ inputs.github_token }}
issue-number: ${{ inputs.pr_id }}
body: |
Terraform Apply:
${{ steps.apply.outputs.apply }}

NOTE: The body of the message can be found in the Github repo. Please check it there to get this step properly configured.

Finally, we comment out the apply result to the current PR for the reviewer to check (along with the previous test and plan results comment) for a holistic view on the code changes. An example would look like this:

terraform-apply-results