【GitHub Actions】terraform fmt結果をpushしてPRを自動更新する

terraform fmt結果を自動プッシュして自動でプルリクエストを更新する用にしたら便利では?と思ったのでGitHub Actionsで書いてみました。

PR駆動でGitHub Actionsを動かし、その中で行ったterraform fmtを自動でpushさせてPRを自動更新するようにしました。
これで常に*.tfファイルが綺麗な状態で保たれます。

terraform fmt結果をpushする方法

こんな感じのワークフローファイルを書きました。

name: terraform fmt

on:
  pull_request:
    paths:
      - '**.tf'

jobs:
  terraform_fmt:
    permissions:
      contents: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref }}

      - uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: "1.6.2"

      - name: terraform fmt -check
        id: fmt_check
        continue-on-error: true
        run: terraform fmt -check -recursive

      - name: fmt, commit, and push
        if: steps.fmt_check.outcome == 'failure'
        run: |
          terraform fmt -recursive
          git config user.name __YOUR_NAME__
          git config user.email __YOUR_EMAIL__
          git add *.tf
          git commit -m "[auto] terraform fmt -recursive"
          git push origin ${{ github.head_ref }}          

いくつか説明を書きます。

説明1: contents: writeを設定している

fmt結果をコミットしてプッシュするので、contents: writeの権限が必要です。

説明2: actions/checkout時にブランチを指定している

actions/checkout@v4の箇所でwithを使ってブランチを指定しています。指定しているブランチはプルリクエストを出しているブランチです。
github.head_refについてはGitHub Actions内で参照できるコンテキストです。詳細は githubコンテキスト で確認できます。

ブランチをわざわざ指定しているのは detached head を避けるためです。以下に補足があるので、ご存じの方は飛ばしてくださいませ。

補足:actions/checkoutの挙動

actions/checkout@v4のREADMEを見ると$GITHUB_SHAが指すものをフェッチしてくると書かれています。
この$GITHUB_SHA既定の環境変数というドキュメントを見てみると以下のように書かれています。

ワークフローをトリガーしたコミットSHA。このコミットSHAの値は、ワークフローをトリガーしたイベントによって異なります。

ではon.pull_requestでワークフローをトリガーしたときにはどんなコミットが値に入っているかというと、pull_requestのイベントのドキュメントを覗いてみるとこのように書かれています。

このイベントの GITHUB_SHA が pull request マージ ブランチの最後のマージ コミットであることに注意してください。

「最後のマージコミット」というのがイマイチ伝わりませんが、これは仮想的にプルリクエストのブランチをターゲットにマージしたときの、マージコミットを意味します。ようは未来のマージコミットです。検索力が足りずこれの原典ドキュメントに当たれなかったのですが、以下のstackoverflowも参考になると思います。

https://stackoverflow.com/questions/68061051/get-commit-sha-in-github-actions

actions/checkout@v4のログを見ても、確かに /usr/bin/git checkout --progress --force refs/remotes/pull/5/mergeというコマンドが吐かれており、謎のrefs/remotes/pull/5/mergeというブランチをチェックアウトしていることが分かりますが、このブランチこそが仮想的にマージを試し、マージコミットが生成されたブランチです。

さて、謎ブランチの未来のマージコミットがチェックアウトされていることが分かりましたが、これだとこの後terraform fmtした後に、プルリクエストを出したブランチにpushできずに困ってしまいますよね。

そこで、withオプションでプルリクエストのヘッドブランチを指定することでこの問題を解決しています。

説明3: fmt -check時にcontinue-on-errorを指定している

terraform fmt -check -recursive時にcontinue-on-error: trueを設定しています。仮にfmtのチェックに引っ掛かっても次のstepに進みます。

説明4: fmt -checkがエラーの場合だけコミット&プッシュしている

if: steps.fmt_check.outcome == 'failure'を設定してfmt -checkがエラーの時だけ処理を行います。これにより、何もfmtされなかった場合はコミットもプッシュも行いません。

ここではgitコマンドをたくさん実行していますが、このような便利アクションも存在するようです。
https://github.com/stefanzweifel/git-auto-commit-action

終わりに

terraform fmt -checkだけでフォーマットに問題があったらCIを失敗させるのでもいいですが、1人開発なのでfmtを自動化しました。これでfmtを気にせずに開発をすることができそうです。

のんびり生きていきたい。
Image by Freepik
Built with Hugo
Theme Stack designed by Jimmy