🦔

【Github Actions】checksで失敗があればmergeできないようにしてdevelopの汚染を防ぐ

2024/05/06に公開

概要

github上でchecksに失敗がある場合にmergeボタンを押せないようにします。
設定するのは

  • github actions
  • repository settings
    の2点のみです。

背景

github上でmonorepoで運用していると複数のchecksが走ると思います。
その全ての状態を確認した後にmergeする作業でミスしてしまい、不正な状態のまま運用ブランチにmergeしてしまうと復旧が必要になったりして思わぬ事故に繋がってしまうので、そのミスを発生させないように実施した内容が今回のものになります。

目的

上記の背景で述べた問題の防止策をgithub上で構築します。
その防止策としては自動的に全てのchecksの状態を確認して問題がある場合はmergeボタンを押せないようする設定を行いました。

設定・作成内容

github actionsの作成

まずは全てのchecksの状態を確認するgithub actions(ci-checks.yaml)[1]を.github/workflows内に作成します。

ci-ckecks
name: check-ci-failed
on:
  push:
    branches:
      - '**'
      - '!main'
      - '!develop'
defaults:
  run:
    shell: bash
jobs:
  check-ci-failed:
    name: check-ci
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    runs-on: ubuntu-latest
    steps:
      - name: check ci
        run: |
          # 後の状態チェックでこのsuiteは除くのでidを取得する
          CHECK_SUITE_ID=$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" | jq -r '.check_suite_id')
          SECONDS=0
          echo "CHECK_SUITE_ID:${CHECK_SUITE_ID}"
          # 今回のsuiteに何が入っているのか確認のlogを出す
          SUITES=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/check-suites" \
            | jq -r ".check_suites[]")
          echo "${SUITES}"
          # 全てのciが完了するまで待機
          while [ ${SECONDS} -lt 900 ] # 15分
          do
            STATUS=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/check-suites" \
              | jq -r ".check_suites[] \
                | select(any(.app;.slug != \"dependabot\")) \
                | select(.id != ${CHECK_SUITE_ID}) \
                | .status" \
              | sort \
              | uniq)
            echo "Current STATUS: ${STATUS}"
            [ "${STATUS}" = "completed" ] && break
            sleep 30
          done
          # checksの結果を取得
          RESULT=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/check-suites" \
            | jq -r ".check_suites[] \
              | select(any(.app;.slug != \"dependabot\")) \
              | select(.id != ${CHECK_SUITE_ID}) \
              | .conclusion" \
            | sort \
            | uniq)
          echo "RESULT:${RESULT}"
          # 結果が全てsuccess、neutral、skippedなら成功
          echo "$RESULT" | grep -v -E "(success|neutral|skipped)" && exit 1 || exit 0

ファイルを作成してpushできたらgithub上で動作確認をします。

他のcheckが正常に終了している時にこのcheckがOKになっていることを確認できれば完了です。

github上での設定

該当するリポジトリのSettings > Branches > Branch protection ruleを選択してmerge時に保護したいbranchに対してルールを追加します。
mergeブロックするためにはRequire status checks to pass before mergingにチェックを入れて、上記で作成したcheck-ciを選択して完了します。
branch-protection

以上で設定は完了です。
エラーになるとmergeボタンが非活性になって押せないことが確認できます。
merge-block-image

注意点

このactionがpush eventに紐づいているのでPRを作成しているのかに関係なくpushすれば動作してしまいます。
そのためPRに紐づけて処理するような別のactionがあると実行が終わらずに無駄なエラーが出てしまう可能性があるので、その部分で改善が必要です。(GCPと連携させている場合にqueuedのまま処理が終わらずにエラーになるケースに私は遭遇しています)
pull requestで動作させられればいいのですが、使用しているgithub APIがpush eventでしか動作しない[2]ので今回はこの形で使用しています。

参考

脚注
  1. yamlの参考にさせていただいた記事 ↩︎

  2. github APIドキュメント ↩︎

Discussion