github actions で少し複雑な workflow を組んでいると auto-merge を使うのが厳しい感じがする

これは 2021/12/12 時点の情報で github actions のアップデートが早いので近いうちに治っているかも。
また、軽く調査しただけなので、間違ったことを発信しているかも。

やりたいこと

github で PR の CI が全部通ったら自動的にマージしてほしい

前提条件

レポジトリの workflow は簡略化した具体例を書いておきます(動きません)

ポイントとしては以下のとおりです。

  • フロントとバックエンドで workflow が別れている
  • path で workflow の起動条件を絞っている
  • バックエンドは jobs を2つに分けており直列実行している
    • テスト分割のため martix を利用しており、job を1つにすることが難しい

サンプル

name: front

on:
  pull_request:
    types:
      - opened
      - synchronize
      - reopened
    path:
      - "front/**"

jobs:
  test:
    runs-on: ubuntu-latest
    steps: 
      - name: test
        run: yarn test
name: backend

on:
  pull_request:
    types:
      - opened
      - synchronize
      - reopened
    path:
      - "backend/**"

jobs:
  build:
    runs-on: ubuntu-latest
    steps: 
      - name: build
        run: docker build && docker push

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        test_id: ["01", "02"]
    needs: build
    steps: 
      - name: docker run test${test_id}

auto-merge

やりたいことを実現するために、まず思いつくのが公式が用意している auto-merge です。

If you enable auto-merge for a pull request, the pull request will merge automatically when all required reviews are met and status checks have passed

プルリクエストを自動的にマージする - GitHub Docs

とまさにやりたいことができるような感じがします。

status checks で CI がすべて通ったときを選択できれば一件落着だったんですが、そう簡単には行きません。

Search for status checks, selecting the checks you want to require.

ブランチ保護ルールを管理する - GitHub Docs

branch protection rule で status checks を選び、それらが全て成功していれば auto-merge されるという仕組みでした。
status checks は github actions の job 名にあたるようです。
ここからは実際に検証した内容です。

検証

branch protection rule に指定されているが、path の対象外で workflow が起動しない場合

以下の指定で foo/xxx のファイルしか変更しなかった場合

name: echo1

on:
  pull_request:
    types:
      - xxx
    path:
      - "bar/**"

結果

required のまま動かなくなります(それはそうって感じ) f:id:k-murakami0609kun:20211212225404p:plain

branch protection rule に指定されており、その job 名が複数 workflow で指定されていた場合

branch protection rule が echo で workflow は以下のような感じです

name: echo1

jobs:
  echo:
    steps: 
name: echo2

jobs:
  echo:
    steps: 

結果

起動中の同名の job が全て終わった後に auto-merge されます。 f:id:k-murakami0609kun:20211212225717p:plain

ただし、同名でも起動していない場合はそれを待たずに auto-merge されます。
以下の例だと echo2.init-echo の sleep が長いため、echo2.echo が起動する前に echo1.echo が完了し、そのタイミングで auto-merge されてしまいます。

name: echo1

jobs:
  init-echo:
    steps: 
      run: sleep 20
  echo:
    steps: 
      run: sleep 10
name: echo2

jobs:
  init-echo:
    steps: 
      run: sleep 900
  echo:
    steps: 
      run: sleep 10

検証からわかったこと

auto-merge がうまくいくケース

paths を使っていない

素朴に branch protection rule に全ての job を入れればうまくいくはずです(未検証)

pathsは使っているが、全ての workflow で job が1個

全て job 名を同じにして branch protection rule にその job 名を入れればうまくいくはずです

pathsは使っており、全ての workflow で job が複数あるが、workflow 内で直列実行してない

ちょっとトリッキーですが、以下の方法がとれます。

I created another workflow with dummy jobs that have the same names with those required jobs that are not always triggered.

https://github.community/t/github-actions-and-required-checks-in-a-monorepo-using-paths-to-limit-execution/16586/2

auto-merge がうまくいかないケース

上に当てはめることができないケースで、私のレポジトリでは適用が難しそうでした。
paths の指定を無しにするもの、テスト分割実行をやめるわけにもいかないので...。

で、どうするかというと、外からポーリングしてPRの状態を見るようにするのが地道だけどうまくいきそうだと思っています。
すでに marketplace に何かあるかもしれません。

actions で良い機能ないか調べてみたんですが workflow_run で待ち合わせするのはしんどそうで、check_suite っていうそれっぽい trigger もあるんですけど使い方が悪いのかなんだか動いてません。

まとめ

私の用途では使えなさそうでした。
またこれに限らず、workflow は個々で動いているのでCIが全部終わったらみたいな制御はしんどいなと思っています(通知とかも難しい)