Gitlab CIのrulesの挙動を確認する
はじめに
GitLab CIのruleを使うと、いろいろな条件でパイプラインの実行を制御できます。その際にrulesキーワードを使用するのですが、理解が怪しかったので、実際に触りながら検証しいきます。
検証環境はgitlab-runnerのDockerイメージを使用して、ローカル環境でGitLab CIを実行する、で構築した環境を使っています。
ドキュメントを読む
rules
rulesを確認してみます。
- rulesはパイプラインの作成時に評価され、最初に一致するまで順番に評価される。
- 一致するものが見つかると、設定に応じて、そのジョブがパイプラインに含まれたり、除外される。
ジョブがパイプラインに追加される条件
if
、changes
、exists
のruleがマッチし、かつwhen: on_success
(デフォルト)、when: delayed
、またはwhen: always
のいずれかを持つ場合when: on_success
、when: delayed
、when: always
のいずれかのみを持つruleに到達した場合
ジョブがパイプラインに追加されない条件
- マッチするrulesがない場合
- マッチしたruleが
when: never
になっている場合
when
whenを確認してみます。
whenのデフォルトはon_success
whenの値 | 説明 |
---|---|
on_success | それ以前のステージのジョブがすべて成功するか、allow_failure: trueとなったときのみ、ジョブを実行する。 |
manual | 手動でのみ実行できる Create a job that must be run manually |
always | 前に実行されたjobのstatusに関係なくジョブを実行する |
on_failure | 以前のステージのジョブが少なくとも1つ失敗した場合にのみ、そのジョブを実行する。allow_failure: trueを指定したジョブは、常に成功したとみなされる |
delayed | 指定した期間、ジョブの実行を遅らせる。 |
never | ジョブを実行しない。rulesセクションまたはworkflow: rules でのみ使用可能 |
検証
リポジトリのルートにマークダウンファイルをコミットしたときのみジョブを実行したくない
というケースを想定して検証してみます。
検証1: mainブランチにファイルをコミットする
設定 1-1
.gitlab-ci.yml
を以下の設定にします。
結果 1-1
ジョブの実行を o、実行しなかったものを x とします。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | x |
リポジトリのルートにtest.jsをコミットする | o | x |
この設定では、理想と結果に違いがあります。先ほど記述した “マッチするrulesがない場合、ジョブがパイプラインに追加されない” が関係していそうです。マークダウンファイル以外はジョブを実行してほしいので、追加でwhen: always
をつけてみます。
設定 1-2
結果 1-2
想定した結果になりました。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | o |
リポジトリのルートにtest.jsをコミットする | o | o |
検証2: ブランチを作成し、検証1と同じ.gitlab-ci.ymlを使用する
検証1ではmainブランチに直接コミットしました。しかし、普段の開発ではそんなことをしないはずです。
次はmainから作成したブランチにコミットします。
設定 2-1
設定は設定1-2と同じです。
結果 2-1
ファイルへのコミットは検証1と相違はありませんでした。
しかし、test.md, example/test.md, test.jsの変更を含んだマージリクエストをmainブランチにマージするとジョブは実行されませんでした。これはマージリクエストのtest.mdがchangesの条件に引っ掛かり、パイプラインにジョブが追加されなかったからです。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | o |
リポジトリのルートにtest.jsをコミットする | o | o |
mainブランチにマージする | o | x |
検証3: 検証2のchangesをneverからon_successにする
検証2ではブランチを作成して、changesの条件 (“*.md”) がtrueの場合、when: never
でジョブの実行を止めていました。
次は条件を逆にして、実行したい条件をchangesに書きました。
設定 3-1
changesの条件を設定2-1から変更します。
結果 3-1
意図した通りになりました。意図した挙動なので設定はこれで合っていそうです。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | o |
リポジトリのルートにtest.jsをコミットする | o | o |
mainブランチにマージする | o | o |
設定 3-2
今度はwhen: never
を追加して、動作確認してみます。
結果 3-2
こちらも意図した通りになりました。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | o |
リポジトリのルートにtest.jsをコミットする | o | o |
mainブランチにマージする | o | o |
設定 3-3
今度はchangesの条件の順番を入れ替えます。
結果 3-3
設定2-1と同じように、mainブランチへのマージしたときにジョブが実行されませんでした。
rulesは最初に一致するまで順番に評価される
ので、test.md, example/test.md, test.js をmaibブランチにマージした場合、最初の条件であるwhen: never
が評価されたことになります。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.mdをコミットする | x | x |
exapmle/test.mdをコミットする | o | o |
リポジトリのルートにtest.jsをコミットする | o | o |
mainブランチにマージする | o | x |
検証4: おまけ rulesにマッチしないファイルをコミットする
設定 4-1
設定 3-2の.gitlab-ci.yml
を使います。
changesの条件に評価されないファイルをコミットした場合を確認してみます。
結果 4-1
test.tsをコミットして確認してみます。
rulesの条件に一致しない場合は、ジョブが実行されないことがわかりました。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.ts | - | x |
mainブランチにマージする | - | x |
設定 4-2
設定 3-3の.gitlab-ci.yml
を使います。
changesの条件に評価されないファイルをコミットした場合を確認してみます。
結果 4-2
test.tsをコミットして確認してみます。
rulesの条件に一致しない場合は、ジョブが実行されないことがわかりました。
手を動かしていて思ったのは、やっていることは設定1-1のときと同じでしたね。
内容 | 理想 | 結果 |
---|---|---|
リポジトリのルートにtest.ts | - | x |
mainブランチにマージする | - | x |
エイリアスとアンカーを使用する
ジョブを実行したいファイルパターンをリストで書くと、行数が多くなると思います。そこからさらに、複数ジョブにもchangesを書いていくと重複し、メンテナンスが難しくなるはずです。
しかし、yamlのエイリアスとアンカーを利用すると記述を再利用できます。設定3-1で使用した.gitlab-ci.yml
は以下のように書くことができます。
さらにgitlabではrulesの条件を再利用したい場合、!reference
tagを利用することで再利用できます。
Reuse rules in different jobs - GitLab Docs
まとめ
以下のことがわかりました。
- GitLab CIのrulesは順番に評価するので、記述の順番が大切
- コミットがすべてのrulesに引っかからない場合、ジョブは実行されない
さいごに
.gitlab-ci.yml
ではいろいろな設定、書き方ができるので、引き続き検証を進めていきたいと思います。
gitlab 本体のCIの設定は書き方の参考になったので、備忘録として残しておきます。