⛷️

Renovate からのプルリクを条件付きで自動マージする

2023/04/25に公開

概要

Renovate はプロジェクトの依存パッケージを更新するプルリクを自動的に生成してくれるサービスです。
npm において各パッケージの更新は頻繁に行われているため、プルリクを手動で処理していては対応が追いつきません。
そこで main ブランチと Renovate が作成するプルリクのブランチでフロントエンドの build を行い、その差分がない場合だけプルリクをマージする仕組みを構築しました。

この記事ではその仕組みについて紹介します。

この仕組みは次のリポジトリに導入されています。

https://github.com/odanado/blog

main ブランチとトピックブランチで build 結果に diff がないか確認する

Actions の定義は https://github.com/odanado/blog/blob/main/.github/workflows/check-build-diff.yml にあります。

各 job の全体像は次の画像の通りです。

それぞれのブランチで build する

main ブランチとトピックブランチで build する部分の job です。それぞれ build-on-mainbuild-on-current という名前がついています。

それぞれの job は

という処理を実行しています。

  build-on-main:
    needs:
      - if-label
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          ref: main
      - uses: actions/setup-node@v3
        with:
          cache: npm
          node-version-file: .node-version

      - run: npm ci
      - run: npm run build
        env:
          ORIGIN: https://blog.odan.dev

      - uses: actions/upload-artifact@v3
        with:
          name: ${{ github.sha }}-main
          path: dist

  build-on-current:
    needs:
      - if-label
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          cache: npm
          node-version-file: .node-version

      - run: npm ci
      - run: npm run build
        env:
          ORIGIN: https://blog.odan.dev

      - uses: actions/upload-artifact@v3
        with:
          name: ${{ github.sha }}-current
          path: dist

build 結果の diff を取得する

この job では

という処理を実行しています。

diff コマンドの結果は複数行の文字列が出力されます。複数行の文字列を output で扱う場合、エスケープが必要になります。この問題に対応するために GitHub Actions で複数行の文字列を output にセットする方法 | gotohayato.com で紹介されいている gh640/command-result-action 経由で diff コマンドを実行しています。

  check-build-diff:
    needs:
      - build-on-main
      - build-on-current
    outputs:
      diff-name-only: ${{ steps.diff-name-only.outputs.stdout }}
      diff-exit-code: ${{ steps.diff-name-only.outputs.exitCode }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: ${{ github.sha }}-main
          path: dist-main
      - uses: actions/download-artifact@v3
        with:
          name: ${{ github.sha }}-current
          path: dist-current

      - id: diff-name-only
        uses: gh640/command-result-action@v1
        with:
          command: diff -qr dist-main dist-current

diff をプルリクのコメントで通知する

この job では

という処理を実行しています。

mshick/add-pr-comment はすでにコメントが存在するときは内容を update してくれるなど、 gh cli を使用するより便利な機能が用意されています。

  add-pr-comment:
    needs:
      - check-build-diff
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      - uses: mshick/add-pr-comment@v2
        with:
          message: |
            # Check build diff report
            ```
            ${{ needs.check-build-diff.outputs.diff-name-only }}
            ```

diff がないことを表すラベルを付与する

この job では

という処理を実行しています。

  add-label:
    needs:
      - check-build-diff
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions-ecosystem/action-add-labels@v1
        if: ${{ needs.check-build-diff.outputs.diff-exit-code == 0 }}
        with:
          labels: no build diff

自動マージする

build 結果に差分がないことを確認する仕組みを導入できたので、次は自動マージする方法を導入します。
build 結果に差分がない場合 no build diff ラベルが付与されることになっているので、このラベルが存在する場合に自動マージすれば良いです。
しかし、このラベルは GitHub Actions 経由で GITHUB_TOKEN トークンを使用して付与されています。そのためラベルが付与されたときに発生するイベントを起点に GitHub Actions を実行することはできません。

なので自動マージには Mergify という SaaS を利用することにしました。

Mergify は自動マージする条件を yaml で定義しておくと、その条件を満たしたときに自動マージしてくれます。

設定ファイルは https://github.com/odanado/blog/blob/main/.mergify.yml にあります。

今回は次の4つの条件が満たされているときに自動マージされるようにしました。

  • プルリクの作成者が Renovate の GitHub App
  • build の status が成功している
  • dependencies ラベルが付与されている
  • no build diff ラベルが付与されている
pull_request_rules:
  - name: Automatic merge on approval
    conditions:
      - author=renovate[bot]
      - check-success=build
      - label=dependencies
      - label=no build diff
    actions:
      merge:
        method: merge

まとめ

Renovate を使用して依存パッケージの自動更新の運用負荷を軽減するために、build 結果に diff がない場合にプルリクを自動マージする仕組みを紹介しました。

先行研究

Discussion