Open1

GitHub Actions で PR がマージされたときにどの event で workflow を実行するか

Shunsuke SuzukiShunsuke Suzuki

GitHub Actions で Pull Request がマージされたときに workflow を実行するには幾つかのやり方があります。
それらのやり方の中でどれが適切なのか自分なりに整理したいと思います。

  • pull_request:closed, pull_request_target, push event の 3 つがある
  • 絶対にこれが正しいという方法は多分ない
  • やりたいこと
    • merged commit を checkout して workflow を実行したい
    • merge された pull request 番号を取得したい
  • 自分は push event を使い、 GitHub API で merged commit に関連付けられた pull request を取得する
    • GitHub API で pull request 番号を取得する必要がある
    • 自分は ci-info というツールを使って pull request 番号を取得することがあるが、他にもツールや action は探せばあると思う
    • 複数の pull request が関連づいている場合、上手く pull request を取得できない、最悪間違った pull request の情報を使って処理を実行してしまう危険性がある
    • ブランチ戦略によっては、 pull request 作成時に空コミットを追加するようにするなどの工夫が必要
  • pull_request:closed
    • トリガーされないことがある
      • 頻度は環境によってまちまちで、問題に遭遇したことがないという人もいるでしょう。自分の場合数回に一度起こってしまうような状況に陥ったことがある
      • 必ずしも実行されなくても問題ないようなユースケースでは使える。例えば PR を close したあとにリソースを削除したい場合、 closed event でリアルタイムに削除しつつ、 schedule で定期的に削除もするというような使い方であれば定期実行の方でカバーされるので良いかもしれない
    • merged commit の commit status ではなく、 pull request の head commit の status が更新される
  • pull_request_target
    • 注意が必要(特に public repository で使う場合): https://pankona.github.io/blog/2021/03/29/github-actions-pull-request-target/
    • https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
      • fork であっても secret にアクセスできる
      • 仕事で private repository で作業する分には問題ないのかな
    • context が default branch になる
      • default branch の workflow ファイルを元に workflow が実行される
      • これは merge されたときに workflow を実行するという今回のユースケースからすると問題にならない
    • checkout 時には pull_request.merge_commit_sha を指定する必要がある (pull_request.base.sha だと 1 つ前のコミットになる)
      • branch protection rule で pr が最新じゃないと merge できないようになっていれば head でもほぼ問題ないと思うが、それでも pull_request.merge_commit_sha のほうが無難では
    • merged commit の commit status ではなく、 pull request の head commit の status が更新される

色々書いた上でがまとめると、

  • closed event は実行されないことがあるので自分は基本使わない
  • pull_request_target では merged commit の commit status が更新されないという問題があるが、それが許容できれば pull_request_target がいいかもしれない
  • push event は pull request number を API で取得しなければならず、かつ複数の PR が関連づいている場合上手く取得できないケースがある
  • pull_request_target, push それぞれメリット・デメリットがあるので、各ユースケースに合わせて選ぶべし

今まで自分が workflow を書く際は push 一択でしたが、 private repository なら pull_request_target もありかもなという気がしてきました。

また気づいたことがあれば更新します。

関連

https://github.com/actions/checkout/issues/518