Gitlab CI でマージリクエストのマージ結果でパイプラインを実行する

Gitlab は マージリクエストに対してそれがマージされた結果を元にパイプラインを実行できます。

便利そうですけど、これは gitlab.com なら Silver 以上、セルフホスティングなら Premium 以上じゃないと使えないようなので、Gitlab CE でも似たようなことをやる方法。

要するにパイプラインの実行時にマージしてしまえばいいので次のような感じに。

image: gitコマンドが使えるイメージ

stages:
  - build

.merge_result: &merge_result >
  [ "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-}" != "" ]
  && git checkout "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
  && git merge --squash -v -
  && git diff --stat --staged

build:
  stage: build
  rules:
    - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"
  script:
    - *merge_result
    - いろいろ

[ "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-}" != "" ] のような条件を付けているのは同じジョブがマージリクエスト以外から実行されたとき用です(この例だと rules$CI_MERGE_REQUEST_TARGET_BRANCH_NAME を見ているのでマージリクエスト以外から実行されることはありませんが)。

その後の git checkoutgit merge で実際にマージリクエストのターゲットブランチをチェックアウトして、ソースブランチをマージしています。--squash なのでマージはされるもののマージコミットは作成されず、ワークツリーとインデックスに書き込まれるのみです。

マージコミットを作成するようにしても良いと思いますが、その場合は git config user.name とか git config user.email とかも必要です。

最後に git diff --stat --staged で、このマージでどんなことが行われたかをざっくり表示しています。

さいごに

Gitlab でマージリクエストでパイプラインを実行できると知ってから結構使ってましたが、てっきりマージ結果で実行されるのがデフォだと思ってました。

例えばマージリクエストのパイプラインでデプロイを実行していると、素のままだとマージ前のコードがデプロイされてしまうので要注意です。

この方法でとりあえず対応はできますが、Gitlab の WebUI からはそれがわからないし、ジョブを手動で再実行したときにターゲットブランチが進んでしまっていると同じワーキングツリーが再現できなかったり、いろいろ問題もありそうなのであきらめるかどうしても必要なら素直に Premium にするか考えたほうが良いかも。