Creating a GitHub Actions Workflow to Automatically Comment with the Results of Terraform Plan During Pull Request Creation
Tags: githubactions, terraform, git, beginners
Published: 2023-07-15 06:28:35

Recently, I have been using Terraform for application infrastructure modifications.

https://dev.to/suzuki0430/terraform-beginners-aws-security-group-management-3pl3

It was quite a hassle to have reviewers run `terraform plan` during PR reviews, so I created a workflow in GitHub Actions to automatically post the results of `terraform plan` as comments.

## Overview of the workflow
This workflow (`.github/workflows/infrastructure-checks.yml`) is executed every time a PR for master is created or updated.

The following is a description of the workflow.

```yml
name: 'Infrastructure Checks'
on:
  pull_request:
    branches:
      - master
    types: [opened, synchronize]

jobs:
  terraform:
    name: 'Terraform Checks'
    runs-on: ubuntu-latest
    strategy:
      matrix:
        # stg, prodは未使用のため一旦コメントアウト
        # directory: ['environments/dev', 'environments/stg', 'environments/prod']
        directory: ['environments/dev']
    defaults:
      run:
        working-directory: ${{ matrix.directory }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v1

      - name: Setup AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Terraform Format
        id: fmt
        run: terraform fmt -check

      - name: Check if directory is not empty
        id: check
        run: |
          if [ "$(ls -A .)" ]; then
            echo "Directory is not empty"
          else
            echo "Directory is empty"
            exit 1
          fi

      - name: Terraform Init
        id: init
        run: terraform init

      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color
        continue-on-error: true

      - name: Comment PR
        uses: actions/github-script@v3
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outputs.stdout }}\`
            #### Terraform Initialization ⚙️\`${{ steps.init.outputs.stdout }}\`
            #### Terraform Plan 📖\`${{ steps.plan.outputs.stdout }}\``;
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Terraform checks in directory '${{ matrix.directory }}'\n` + output
            })
```

## Workflow Details
1. Checkout: Check out the repository (download the code to the GitHub execution environment).
2. Setup Terraform: Enables the workflow to use Terraform commands.
3. Setup AWS Credentials: Setup AWS credentials so Terraform can manage AWS resources.
4. Terraform Format: Check Terraform formatting. Consistent formatting improves code readability and maintainability.
5. Check if directory is not empty: Check if the directory `environments/dev` is not empty.
6. Terraform Init: Initialize Terraform so that Terraform can manage resources in subsequent steps.
7. Terraform Plan: Execute the `terraform plan`. The changes are posted to the PR as comments.
8. Comment PR: Post the results of each step of Terraform as a comment in the PR.

### Tip.
To ensure that the workflow is executed even when changes occur in the push after the PR is created, we have added `synchronize` to types.

```yml
on:
  pull_request:
    branches:
      - master
    types: [opened, synchronize]
```

Also, if you want to perform Terraform checks for each configuration per environment (dev, stg, prod, etc.), use `strategy.matrix` to enumerate each directory.

```yml
  terraform:
    name: 'Terraform Checks'
    runs-on: ubuntu-latest
    strategy:
      matrix:
        directory: ['environments/dev', 'environments/stg', 'environments/prod']
      run:
        working-directory: ${{ matrix.directory }}
```

The AWS credentials (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`) that you set up in step 3 will be registered in GitHub Secrets after creating the IAM user.

1. Navigate to the target repository on GitHub.
2. Click on the "Settings" tab in the upper right corner of the repository's main page.
3. Select "Secrets" from the menu on the left.
4. Click on the "New repository secret" button.
5. Enter a name for the secret in the "Name" field.
6. Enter the value of the secret in the "Value" field.
7. Click the "Add secret" button to save the secret.

Also, set the IAM policy to be attached to the IAM user according to the resource to be managed by Terraform.
Since `terraform plan` is a read-only operation, if you are managing EC2 resources, attach a managed policy such as `AmazonEC2ReadOnlyAccess`.

## What's in the Comments
When you create or update a PR, the following comments will be posted with it.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3h0l8ryels5jrl970m7l.png)