PR作成時にterraform planの結果を自動コメントするGitHub Actionsのワークフロー

最近、アプリケーションのインフラ改修でTerraformを活用しています。

https://qiita.com/suzuki0430/items/2dbd88dfb5ed53016914

PRレビューでレビュワーに`terraform plan`を実行してもらう手間がなかなか面倒だったので、GitHub Actionsのワークフローで`terraform plan`の結果をコメントとして自動投稿する仕組みをつくりました。

# ワークフローの概要
このワークフロー(`.github/workflows/infrastructure-checks.yml`)は、master向けのPRが作成もしくは更新されるたびに実行されます。

以下がワークフローの中身です。

```yml:.github/workflows/infrastructure-checks.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
            })
```

# ワークフローの詳細
1. Checkout: リポジトリをチェックアウトする(コードをGitHubの実行環境にダウンロードする)。
2. Setup Terraform: ワークフローがTerraformコマンドを使用できるようにする。
3. Setup AWS Credentials: AWSの認証情報をセットアップする。TerraformがAWSのリソースを管理できる。
4. Terraform Format: Terraformのフォーマットをチェックする。フォーマットが一貫していることで、コードの可読性と保守性が向上する。
5. Check if directory is not empty: ディレクトリ`environments/dev`が空でないことを確認する。
6. Terraform Init: Terraformを初期化する。Terraformが後続のステップでリソースを管理できるようになる。
7. Terraform Plan: `terraform plan`を実行する。変更内容がPRにコメントとして投稿される。
8. Comment PR: Terraformの各ステップの結果をPRにコメントとして投稿する。

## 補足
PR作成後のプッシュで変更が生じた場合にもワークフローが実行されるようにするために、typesに`synchronize`を追加しています。

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

また、環境ごとの構成(dev, stg, prodなど)についてそれぞれTerraformチェックを行いたい場合は、`strategy.matrix`を使用して各ディレクトリを列挙します。

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

ステップ3で設定しているAWSの認証情報(`AWS_ACCESS_KEY_ID`と`AWS_SECRET_ACCESS_KEY`)は、IAMユーザーの作成後にGitHub Secretsに登録します。

1. GitHubで対象のリポジトリに移動する。
2. リポジトリのメインページの右上にある「Settings」（設定）タブをクリックする。
3. 左側のメニューから「Secrets」を選択する。
4. 「New repository secret」ボタンをクリックする。
5. 「Name」フィールドにシークレットの名前を入力する。
6. 「Value」フィールドにシークレットの値を入力する。
7. 「Add secret」ボタンをクリックしてシークレットを保存する。

また、IAMユーザーにアタッチするIAMポリシーは、Terraformで管理するリソースにあわせて設定します。
`terraform plan`は読み取り専用の操作となるので、もしEC2のリソースを管理するのであれば、`AmazonEC2ReadOnlyAccess`のようなマネージドポリシーをアタッチします。

# コメントの中身
PRを作成、または更新すると、以下のようなコメントが一緒に投稿されるようになります。
![スクリーンショット 2023-07-15 14.30.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/2468512b-1268-68bf-a066-d4adec504ded.png)