Skip to main content

Plan Stage

terraform-plan

Our next stage is the plan stage. The steps within the plan stage aim to initialise the Terraform directory, run a plan against the pushed Terraform code, save the plan file as an artifact for later use, and then push the Terraform plan results to the open PR.

Input variables

name: 'Terraform setup and plan'
description: 'Sets up Terraform and creates a plan'
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 plan 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.

Planning Terraform

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

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

To our main steps, we are running an intialisation on the Terraform directory to install the providers, and then run a plan on the pushed code. This results in a tfplan file that is written on a file inside the runner.

Saving the artifact

    - name: Save Artifact
id: save-artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.pr_id }}-tf-plan
path: ${{ inputs.terraform_directory }}/tfplan

With the tfplan created above, we run a step in which the tfplan is saved as an artifact for later use.

Comment Plan Results to PR

    - name: Comment Plan
id: comment-plan
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ inputs.github_token }}
issue-number: ${{ inputs.pr_id }}

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 plan result to the current PR for the reviewer to check (along with the previous test results comment) for a holistic view on the code changes. An example would look like this:

terraform-plan-results