Terraform PlanをPRコメントに色付きで表示する
はじめに
Terraformを使用したインフラ管理では、コードレビューの際にterraform plan
コマンドでリソースの変更内容を確認することが非常に重要です。GitHub Actionsを用いて自動でterraform plan
を実行し、その結果をPull Requestのコメントとして投稿する機能を構築することで開発チームの効率を向上させることができます。
本記事では、GitHub Actionsを利用してPRにterraform plan
の結果を色付きのdiff形式で表示する方法を解説します。この仕組みにより、変更内容を簡単かつ直感的に確認できるようになり、レビュー時の効率が格段に向上します。
完成イメージ
以下のようなコメントがPRに自動で投稿されます。変更点が色付きのdiff形式で表示されるため、確認が容易になるのがポイントです。
では、この仕組みを構築するための手順を説明していきます。
ワークフローの全体コード
以下は最終的に構築するGitHub Actionsワークフロー全体のコードです。内容を確認しやすいように、後ほど部分ごとに詳しく解説します。また、内容のほとんどはsetup-terraformのREADMEのサンプルをそのまま持ってきております。
name: "Terraform Plan"
on:
pull_request:
paths:
- "**/*.tf" # 対象ファイルをTerraformファイルに制限
jobs:
terraform-plan:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Terraformのセットアップ
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
# Terraform Initの実行
- name: Terraform Init
run: terraform init
# Terraform Validateの実行
- name: Terraform Validate
id: validate
run: terraform validate -no-color
# Terraform Planの実行
- name: Run terraform plan
id: plan
run: terraform plan -no-color
# Planの結果を整形してハイライト可能なdiff形式に変換
- name: Reformat Plan
run: |
echo '${{ steps.plan.outputs.stdout || steps.plan.outputs.stderr }}' \
| sed -E 's/^([[:space:]]+)([-+])/\2\1/g' > plan.txt
# Planの内容を環境変数に入れる
- name: Put Plan in Env Var
run: |
PLAN=$(cat plan.txt)
echo "PLAN<<EOF" >> $GITHUB_ENV
echo "$PLAN" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
# PRコメントにPlanの結果を投稿
- name: Read Plan and Post Comment
uses: actions/github-script@v7
if: github.event_name == 'pull_request'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// 1. Retrieve existing bot comments for the PR
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
})
const botComment = comments.find(comment => {
return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style')
})
// 2. Prepare format of the comment
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
<details><summary>Validation Output</summary>
\`\`\`terraform
${{ steps.validate.outputs.stdout }}
\`\`\`
</details>
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`diff
${{ env.PLAN }}
\`\`\`
</details>
*Pusher: @${{ github.actor }}, Working Directory: \`${{ matrix.directory }}\``;
// 3. If we have a comment, update it, otherwise create a new one
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: output
})
} else {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
}
解説: ワークフローの各ステップ
-
terraform plan
の実行:
Terraformの設定ファイルを基にPlanを生成します。この際、no-color
オプションを使って余計な装飾を排除し、Planデータをシンプルなテキスト形式で得ます。- name: Run terraform plan id: plan run: terraform plan -no-color
-
Planの結果を整形:
sed
コマンドを使って、リソースの変更に該当する最初の+
(追加)および-
(削除)が行頭に出るように整形します。これにより、GitHubのdiffコードブロック内で適切に強調されます。- name: Reformat Plan run: | echo '${{ steps.plan.outputs.stdout || steps.plan.outputs.stderr }}' \ | sed -E 's/^([[:space:]]+)([-+])/\2\1/g' > plan.txt
さらに整形された結果を環境変数に保存し、後続のステップで利用できるようにします。
- name: Put Plan in Env Var run: | PLAN=$(cat plan.txt) echo "PLAN<<EOF" >> $GITHUB_ENV echo "$PLAN" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV
-
PRにコメントを投稿:
Terraform Planの結果をPRにコメントとして投稿します。GitHub Actionのgithub-script
を利用して、既存のBotコメントがある場合は更新し、なければ新規作成するロジックを追加しています。# PRコメントにPlanの結果を投稿 - name: Read Plan and Post Comment uses: actions/github-script@v7 if: github.event_name == 'pull_request' with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | // 1. Retrieve existing bot comments for the PR const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, }) const botComment = comments.find(comment => { return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style') }) // 2. Prepare format of the comment const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\` #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\` #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\` <details><summary>Validation Output</summary> \`\`\`terraform ${{ steps.validate.outputs.stdout }} \`\`\` </details> #### Terraform Plan 📖\`${{ steps.plan.outcome }}\` <details><summary>Show Plan</summary> \`\`\`diff ${{ env.PLAN }} \`\`\` </details> *Pusher: @${{ github.actor }}, Working Directory: \`${{ matrix.directory }}\``; // 3. If we have a comment, update it, otherwise create a new one if (botComment) { await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: botComment.id, body: output }) } else { await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: output }) }
まとめ
インフラ変更はプロダクション環境にも大きな影響を与える可能性があるため、適切な確認とレビューのプロセスが重要です。GitHub Actionsを利用してterraform planの結果をPRに自動で投稿し、色付きのdiff形式で可視化することで、レビューが効率的になり、抜け漏れや確認ミスを防ぐことができます。インフラ管理をより安全で効率的に行うための一助となれば幸いです。
Discussion