やりたいこと
GitHubでPull Requestを作成すると、CIで自動的にテストが走る構成にしていることが多いかと思います。その際、そのブランチ上でのテストは通っても、mainブランチ(デフォルトブランチがmasterのケースもあるかと思いますが、以降はmainとして記述します)にマージしたらテストが失敗することが、稀によくありませんか?
並行していた別のブランチでの対応が先にマージされ、そこに自PRでの対応と矛盾する(しかしgitとしてはコンフリクトしない)ロジックが含まれていたようなケースです。
うちのチームでの直近の発生は、2022年9月、2024年11月にあったようでした。そこまで開発がアクティブではないプロダクトだからか頻繁とはいえないですが、防げるものなら防ぎたいです。
アプローチ
- ベースブランチが古くなっていても、マージしたコードでテストする
- CIツール(Jenkins, CircleCI)をどのように設定すれば、マージしたコードでテストできるか
- マージ前にブランチを最新に更新する
- ベースブランチが古くなっている場合は更新するよう促すまたは強制する
上記のようなアプローチで、現在できることをまとめました。
Jenkinsでの対応
GitHubでは、PRを作成すると pull/{PR番号}/merge
というPRブランチをベースブランチにマージした結果の状態を持つブランチがremoteに作られます。そのブランチを、 GitHub Pull Request Builder を使ってビルドする際の「ビルドするブランチ」に指定する形で実現します。
Jenkinsジョブの設定の要点は、以下のとおりです。
-
ソースコード管理
にて、以下の指定をする- 高度な設定>Refspec に
+refs/pull/*:refs/remotes/origin/pr/*
を設定 - ビルドするブランチ>ブランチ指定子 に
${sha1}
という文字列を指定
- 高度な設定>Refspec に
-
GitHub Pull Request Builder
プラグインを有効にする- そうすると、PR作成時にCIが走るようになる
CircleCIでの対応
.circleci/config.yml
ファイルで build-tools/merge-with-parent を以下のように指定します。
steps:
- checkout
+ - build-tools/merge-with-parent:
+ parent: main
なお公式のExampleでは parent: main
は書かれていませんが、これがないとmainブランチにpushされたときのビルドでも自身へのマージ処理が走ってエラーになっちゃうようでした。
GitHub Actionsでの対応
まだActions使ってないので、未調査です。
GitHubの設定
ブランチを更新する提案
GitHubリポジトリの settings
> General
ページの Pull Requests
セクションに Always suggest updating pull request branches Loading
という設定項目があります(ヘルプ)。これを有効にしていると、ベースブランチがPRブランチがよりも進んでいる場合に、以下のような「提案」をPR上に表示してくれます。
PR作業者がこの「提案」をトリガーにrebaseなりmergeなりをしてブランチを更新すれば、CIが再度走るでしょう。
なお、この提案を無視してマージも可能ではあります。
ブランチが最新状態であることを必須とする
GitHubリポジトリの settings
> Rules
> Ruleset
にて、 Require status checks to pass before merging
を有効にすると、サブオプションとして Require branches to be up to date before merging
が選べます(ヘルプ)。これを有効にしていると、CIチェックがOKでも、ベースブランチに対して最新でない場合はマージボタンが使えません。
マージできないので前述の「提案」よりも安全ですが、mainブランチが頻繁に進むような活発なリポジトリで、CIチェックに時間がかかるような場合、何度更新してもなかなかマージできない事態に陥る懸念はあります。
また純粋に、明らかに自PRと無関係な修正がmainブランチに入ったケースにおいても更新を強いられるのは、正直だるいです。
考慮事項
上記のように、CIツール上の設定で、mainブランチとマージしたコードでテストすることできます。これで、PRを作った段階では、マージ後のエラーを事前に知ることはできます。
ただ、PRがオープンなうちにmainブランチの方が進んでしまった場合、その最新コードでテストし直さないとマージ後のエラーのリスクはあります。かといって、mainブランチが進むたびにPRブランチをビルドし直すようなことは現実的でないです。
よって、前述の「ブランチを更新する提案」を有効にしてmainブランチ側が進んでいるかを確認しつつ、必要に応じてブランチ更新して再テストをするのが、バランス良さそうだと個人的には思いました。