Skip to content

Gitlab CIのrulesの挙動を確認する

はじめに

GitLab CIのruleを使うと、いろいろな条件でパイプラインの実行を制御できます。その際にrulesキーワードを使用するのですが、理解が怪しかったので、実際に触りながら検証しいきます。

検証環境はgitlab-runnerのDockerイメージを使用して、ローカル環境でGitLab CIを実行する、で構築した環境を使っています。

ドキュメントを読む

rules

rulesを確認してみます。

  • rulesはパイプラインの作成時に評価され、最初に一致するまで順番に評価される。
  • 一致するものが見つかると、設定に応じて、そのジョブがパイプラインに含まれたり、除外される。

ジョブがパイプラインに追加される条件

  • ifchangesexistsのruleがマッチし、かつwhen: on_success(デフォルト)、when: delayed、またはwhen: alwaysのいずれかを持つ場合
  • when: on_successwhen: delayedwhen: 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を以下の設定にします。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "*.md"
when: never

結果 1-1

ジョブの実行を o、実行しなかったものを x とします。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするox
リポジトリのルートにtest.jsをコミットするox

この設定では、理想と結果に違いがあります。先ほど記述した “マッチするrulesがない場合、ジョブがパイプラインに追加されない” が関係していそうです。マークダウンファイル以外はジョブを実行してほしいので、追加でwhen: alwaysをつけてみます。

設定 1-2

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "*.md"
when: never
- when: always

結果 1-2

想定した結果になりました。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするoo
リポジトリのルートにtest.jsをコミットするoo

検証2: ブランチを作成し、検証1と同じ.gitlab-ci.ymlを使用する

検証1ではmainブランチに直接コミットしました。しかし、普段の開発ではそんなことをしないはずです。
次はmainから作成したブランチにコミットします。

設定 2-1

設定は設定1-2と同じです。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "*.md"
when: never
- when: always

結果 2-1

ファイルへのコミットは検証1と相違はありませんでした。

しかし、test.md, example/test.md, test.jsの変更を含んだマージリクエストをmainブランチにマージするとジョブは実行されませんでした。これはマージリクエストのtest.mdがchangesの条件に引っ掛かり、パイプラインにジョブが追加されなかったからです。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするoo
リポジトリのルートにtest.jsをコミットするoo
mainブランチにマージするox

検証3: 検証2のchangesをneverからon_successにする

検証2ではブランチを作成して、changesの条件 (“*.md”) がtrueの場合、when: neverでジョブの実行を止めていました。

次は条件を逆にして、実行したい条件をchangesに書きました。

設定 3-1

changesの条件を設定2-1から変更します。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "example/**/*.md"
- "*.js"

結果 3-1

意図した通りになりました。意図した挙動なので設定はこれで合っていそうです。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするoo
リポジトリのルートにtest.jsをコミットするoo
mainブランチにマージするoo

設定 3-2

今度はwhen: neverを追加して、動作確認してみます。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "example/**/*.md"
- "*.js"
- changes:
- "*.md"
when: never

結果 3-2

こちらも意図した通りになりました。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするoo
リポジトリのルートにtest.jsをコミットするoo
mainブランチにマージするoo

設定 3-3

今度はchangesの条件の順番を入れ替えます。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "*.md"
when: never
- changes:
- "example/**/*.md"
- "*.js"

結果 3-3

設定2-1と同じように、mainブランチへのマージしたときにジョブが実行されませんでした。

rules最初に一致するまで順番に評価されるので、test.md, example/test.md, test.js をmaibブランチにマージした場合、最初の条件であるwhen: neverが評価されたことになります。

内容理想結果
リポジトリのルートにtest.mdをコミットするxx
exapmle/test.mdをコミットするoo
リポジトリのルートにtest.jsをコミットするoo
mainブランチにマージするox

検証4: おまけ rulesにマッチしないファイルをコミットする

設定 4-1

設定 3-2の.gitlab-ci.ymlを使います。

changesの条件に評価されないファイルをコミットした場合を確認してみます。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "example/**/*.md"
- "*.js"
- changes:
- "*.md"
when: never

結果 4-1

test.tsをコミットして確認してみます。

rulesの条件に一致しない場合は、ジョブが実行されないことがわかりました。

内容理想結果
リポジトリのルートにtest.ts-x
mainブランチにマージする-x

設定 4-2

設定 3-3の.gitlab-ci.ymlを使います。

changesの条件に評価されないファイルをコミットした場合を確認してみます。

stages:
- test
test:
stage: test
script:
- ls
rules:
- changes:
- "*.md"
when: never
- changes:
- "example/**/*.md"
- "*.js"

結果 4-2

test.tsをコミットして確認してみます。

rulesの条件に一致しない場合は、ジョブが実行されないことがわかりました。
手を動かしていて思ったのは、やっていることは設定1-1のときと同じでしたね。

内容理想結果
リポジトリのルートにtest.ts-x
mainブランチにマージする-x

エイリアスとアンカーを使用する

ジョブを実行したいファイルパターンをリストで書くと、行数が多くなると思います。そこからさらに、複数ジョブにもchangesを書いていくと重複し、メンテナンスが難しくなるはずです。

しかし、yamlのエイリアスとアンカーを利用すると記述を再利用できます。設定3-1で使用した.gitlab-ci.ymlは以下のように書くことができます。

.test-pattern: &test-pattern
- "example/**/*.md"
- "*.js"
stages:
- test
test:
stage: test
script:
- ls
rules:
- changes: *test-pattern

さらにgitlabではrulesの条件を再利用したい場合、!reference tagを利用することで再利用できます。

Reuse rules in different jobs - GitLab Docs

まとめ

以下のことがわかりました。

  • GitLab CIのrulesは順番に評価するので、記述の順番が大切
  • コミットがすべてのrulesに引っかからない場合、ジョブは実行されない

さいごに

.gitlab-ci.ymlではいろいろな設定、書き方ができるので、引き続き検証を進めていきたいと思います。

gitlab 本体のCIの設定は書き方の参考になったので、備忘録として残しておきます。

参考