GitHub Actions: PR時にterraform planをコメントで返す

1. 概要

  • PRにterraform planの結果をコメントで自動投稿する仕組み
  • tfcmtを使ったリッチなコメント表示
  • github-scriptを使ったシンプルな実装
  • 古いコメントを更新(重複を防ぐ)する方法

PRレビュー時にterraform planの結果を自動的にコメント投稿することで、レビュアーがインフラ変更の影響を把握しやすくなります。


2. 最もシンプルな実装(github-script)

# .github/workflows/terraform-plan.yml
name: Terraform Plan

on:
  pull_request:
    branches: [main]

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: ap-northeast-1

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan
        id: plan
        run: terraform plan -no-color 2>&1 | tee /tmp/plan.txt
        continue-on-error: true

      - name: Post Plan Comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            let plan = fs.readFileSync('/tmp/plan.txt', 'utf8');
            if (plan.length > 65000) plan = plan.substring(0, 65000) + '\n...(省略)';

            const header = '## Terraform Plan 結果';
            const body = [
              header,
              '```',
              plan,
              '```',
            ].join('\n');

            // 既存コメントを検索して更新(重複防止)
            const comments = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });
            const existing = comments.data.find(c =>
              c.body.startsWith(header) && c.user.type === 'Bot'
            );

            if (existing) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: existing.id,
                body,
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body,
              });
            }

3. tfcmtを使ったリッチなコメント(推奨)

tfcmtはterraform planの出力を見やすく整形してGitHubにコメントするCLIツールです。

# .github/workflows/terraform-plan-tfcmt.yml
name: Terraform Plan (tfcmt)

on:
  pull_request:
    branches: [main]

permissions:
  id-token: write
  contents: read
  pull-requests: write

env:
  TFCMT_VERSION: "v4.13.0"

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: ap-northeast-1

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"

      - name: Install tfcmt
        run: |
          curl -sSL https://github.com/suzuki-shunsuke/tfcmt/releases/download/${{ env.TFCMT_VERSION }}/tfcmt_linux_amd64.tar.gz | tar xz
          sudo mv tfcmt /usr/local/bin/

      - name: Terraform Init
        run: terraform init

      - name: Terraform Plan with tfcmt
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          tfcmt plan -patch -- terraform plan -no-color
        # -patch: 既存コメントを更新(重複防止)

tfcmtを使うと変更リソースの増減がアイコン付きで分かりやすく表示されます。


4. 複数ディレクトリ(monorepo)での対応

# .github/workflows/terraform-multi-dir.yml
name: Terraform Plan (Multi Dir)

on:
  pull_request:
    branches: [main]

permissions:
  id-token: write
  contents: read
  pull-requests: write

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      dirs: ${{ steps.changed.outputs.dirs }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2
      - name: Detect changed Terraform directories
        id: changed
        run: |
          DIRS=$(git diff --name-only HEAD~1 HEAD | grep '\.tf$' | xargs -I{} dirname {} | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))')
          echo "dirs=$DIRS" >> $GITHUB_OUTPUT

  plan:
    needs: detect-changes
    if: needs.detect-changes.outputs.dirs != '[]'
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dir: ${{ fromJson(needs.detect-changes.outputs.dirs) }}
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: ap-northeast-1
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~> 1.9"
      - name: Terraform Init
        run: terraform init
        working-directory: ${{ matrix.dir }}
      - name: Terraform Plan
        run: terraform plan -no-color
        working-directory: ${{ matrix.dir }}

5. plan結果コメントのベストプラクティス

プラクティス理由
既存コメントを更新(-patch)PRに大量のコメントが積み重なるのを防ぐ
長い出力を切り詰める(65KB制限)GitHub APIのコメントサイズ制限に対応
continue-on-error: trueplanが失敗してもコメント投稿ステップを実行する
ディレクトリパスをコメントに含めるmonorepoでどの環境のplanかを明示

6. 関連記事


7. まとめ

  • terraform planの結果をPRコメントに投稿することでレビュアーの負担を減らせる
  • シンプルな実装はgithub-script、見た目を重視するならtfcmt
  • 既存コメントを更新する(-patch)ことでPRのコメント欄が溢れるのを防ぐ
  • monorepoでは変更があったディレクトリのみをplanするようにすると効率的

対象バージョン: Terraform >= 1.9 / GitHub Actions (2024) / tfcmt v4 公式ドキュメント: https://github.com/suzuki-shunsuke/tfcmt