株式会社ネットワールドのエンジニアがお届けする技術情報ブログです。
各製品のエキスパートたちが旬なトピックをご紹介します。

GitとCI/CDに関する知識ゼロのSEによる、GitLabのCI/CDパイプラインのキーワード解説 ~rules 編~

皆様こんにちは。SEの小池と申します。

以前、GitLabのCI/CDパイプラインのキーワード解説で stages を取り上げました。(こちら)
ほぼ筆者の自習メモと化しているキーワード解説記事の第4弾をお送りいたします。

今回はキーワード rules の概要と具体例を用いた説明をします。

本記事の対象の方

  • GitLabのCI/CDパイプラインのジョブに、"if" のような実行条件を設定したい方。
  • GitLabのCI/CDパイプラインのキーワードrulesについて情報収集中の方。

今回のブログのゴール

このブログのゴールはこちらです。


今回のゴール
  • GitLabのCI/CDパイプラインのキーワード rules の概要を把握する。

このブログをお読みいただくにあたっての事前ご連絡事項

  • 本記事はSaaS版 (GitLab.com) の Enterprise Edition 15.10.0-pre における仕様をベースに記載しております。それ以外のエディションやバージョンではこの記事に記載の通りではない可能性がございます。
  • 本記事はGitやCI/CDに関する知識ゼロのSEによるなんちゃって記事です。GitLabのディープな使用法についてはGitLabの公式オンラインドキュメント (こちら) をご参照ください。

キーワード rules の概要

rulesは、CI/CDパイプラインにそのジョブを含めるか除外するかを設定する、ジョブレベルのキーワードです。
参考 : '.gitlab-ci.yml' keyword reference | GitLab

例えば、コミット先のブランチが "main" の時のみ実行したい ジョブB があるとします。

こんなときに使用できるのがrulesです。
ジョブBにrulesを使って、「コミット先のブランチが "main" だった場合」という条件を設定します。
具体的な.gitlab-ci.ymlファイルの書き方は後述致します。

これによりこのCI/CDパイプラインは、コミット先ブランチが "main" のときは ジョブA, B, C を実行し、コミット先ブランチが "main" 以外の場合は ジョブA, C を実行します。
(rulesはパイプライン作成時に評価され、該当しない場合はそもそもそのジョブ自体が作成されません。)

この様に、CI/CDパイプラインにそのジョブを含めるか除外するかを設定できるのがrulesです。

あくまでジョブを作成するか否かを判定するキーワードなので、1つのジョブの中で実行する処理に条件分岐を付けることはできません
例えば以下の図のように、ジョブBで 「コミット先が "main" だった場合は処理●●、コミット先が "develop" だったら処理□□をする。」というような条件は設定できません。

仮に「コミット先が "main" だった場合は処理●●、コミット先が "develop" だったら処理□□をする。」を実現したい場合は、ジョブを2個に分けることで実装できます。

rulesは単体ではなく、以下のキーワードの内の1つ もしくは 複数と併せて使用します。

表1. rulesと併せて使うキーワード概要
キーワード 概要
if 変数の値について真偽を判定し、ジョブを作成する (真) or しない (偽) を制御します。
changes 特定のファイルに変更があったかを判定し、ジョブを作成する (真) or しない (偽) を制御します。
exists リポジトリにあるファイルの存在を判定し、ジョブを作成する (真) or しない (偽) を制御します。
allow_failure 前のステージで失敗するジョブがあっても、このジョブを実行させます
true(実行させる) または false(実行しない)で指定します。
本キーワードを設定していない場合は、デフォルト値 falseが適用されます。
本キーワードの設定はCI/CDパイプライン作成時点で真偽を判定できないため、実行される/実行されないを問わず、ジョブ自体は作成されます。
variables 変数を定義します。
単独でも利用可能ですが、ifなどと併用して、「条件Aを満たす場合は、変数 $ABC の値を true にする。」といった風に使うことが想定されます。
when ジョブがいつ実行されるかの条件を設定します。
on_success, manual, always, on_failure, delayed または neverを指定します。
(それぞれの詳細は後述致します。)
本キーワードを設定していない場合は、デフォルト値 on_successが適用されます。
本キーワードはneverを設定している場合を除き、CI/CDパイプライン作成時点で真偽を判定できないため、実行される/実行されないを問わずジョブ自体は作成されます。

上記のサブキーワードを複数設定することで、より複雑な条件を設定することもできます。
複数指定の例は本記事でも紹介いたしますが、GitLab Docs (こちら) にたくさんのサンプルが載っているので、参考になるかと存じます。
参考:Choose when to run jobs - Complex rules | GitLab

以上がキーワードrulesの概要でした。

【補足】rules:when の設定値に関して

前章の表1で記載致しました、rules:whenの設定値について少しだけ補足いたします。
というか補足として書いておかないと筆者はすぐ忘れるので、書きます。

そもそもGitLabのCI/CDパイプライン (デフォルト設定) は、前のステージのジョブが全て成功で終了してから、次のステージのジョブが開始される、という仕様になっています。
この仕様を無視することができるキーワードはいくつか存在しますが、そのうちの1つがrules:whenです。

rules:whenで指定できる値は、on_success (デフォルト値) , manual, always, on_failure, delayed または neverです。多い…。
それぞれの概要は以下の通りです。
参考:'.gitlab-ci.yml' keyword reference - when | GitLab

表2. rules:when の設定値の概要
設定値 概要
on_success この値を指定したジョブは、以下のどちらか1つ以上を満たすと実行されます。
  • 前のステージのジョブが全て成功で終了した場合。
  • このジョブにrules:allow_failuretrueで設定されている場合。
この値はGitLabのCI/CDパイプラインのデフォルト値です。
明示的にrules:whenを設定していない場合、この値が暗黙的に適用されます。
manual この値を設定したジョブは、自動では実行されず、手動でトリガーされたときのみ実行されます。
always この値を設定したジョブは、前のステージのジョブの終了ステータス (成功/失敗) に関係なく実行されます。
on_failure この値を指定したジョブは、以下のどちらか1つ以上を満たすと実行されます。
  • 前のステージで少なくとも1つ以上のジョブが失敗した。
  • このジョブにrules:allow_failuretrueで設定されている場合。
delayed この値を指定したジョブは、指定した時間 (1秒~1週間) だけ遅延して実行されます。
never この値を指定したジョブは、CI/CDパイプライン開始時に作成されません。

rules の超簡単な使い方の例

ここからは実際にキーワードrulesの使い方を、サブキーワード毎に紹介してまいります。
いつものごとく、ここで紹介する例は入門者 (筆者) レベルです!

特定の変数の値によって、ジョブを作成する or しない (rules:if)

rules:ifを使って特定の変数の値をチェックし、真であればジョブを作成・実行し、偽であればジョブを作成しないCI/CDパイプラインの例を紹介いたします。

例として、既定の変数CI_COMMIT_REF_NAMEを用いて、「コミット先ブランチが "main" だった場合のみジョブAを実行する」ようなCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。

stages:
  - stage_1
  - stage_2

job_A:
  stage: stage_1
  rules: 
    - if: $CI_COMMIT_REF_NAME == "main"
  script: echo "ジョブAです。コミット先が main だった時のみ実行されます。"

job_B:
  stage: stage_2
  script: echo "ジョブBです。"

上記のCI/CDパイプラインを実行させます。
まず、コミット先のブランチが "main" だった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAが作成・実行されていることがわかります。

コミット先のブランチが "main" 以外だった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAは作成されていないことがわかります。

rules:ifを使って特定の変数の値をチェックし、ジョブを作成する or しない例は以上です。

特定のファイルに対する変更の有無によって、ジョブを作成する or しない (rules:changes)

rules:changesを使って特定のファイルに対する変更の有無をチェックし、変更があれば (真であれば) ジョブを作成・実行し、変更が無ければ (偽であれば) ジョブを作成しないCI/CDパイプラインの例を紹介いたします。

例として、「リポジトリのルートにあるREADME.mdに変更があった場合のみジョブAを実行する」ようなCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。

stages:
  - stage_1
  - stage_2

job_A:
  stage: stage_1
  rules: 
    - changes: 
       - README.md
  script: echo "ジョブAです。README.mdが変更されたときのみ実行されます。"

job_B:
  stage: stage_2
  script: echo "ジョブBです。"

上記のCI/CDパイプラインを実行させます。
まず、README.mdに変更があった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAが作成・実行されていることがわかります。

README.mdに変更がなかった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAは作成されていないことがわかります。

rules:changesを使って特定のファイルに対する変更の有無をチェックし、ジョブを作成する or しない例は以上です。

特定のファイルの存在有無によって、ジョブを作成する or しない (rules:exists)

rules:existsを使って特定のファイルの存在有無をチェックし、有れば (真であれば) ジョブを作成・実行し、無ければ (偽であれば) ジョブを作成しないCI/CDパイプラインの例を紹介いたします。

例として、「リポジトリのルートにREADME.mdが存在する場合のみジョブAを実行する」ようなCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。

stages:
  - stage_1
  - stage_2

job_A:
  stage: stage_1
  rules: 
    - exists: 
       - README.md
  script: echo "ジョブAです。README.mdが存在するときのみ実行されます。"

job_B:
  stage: stage_2
  script: echo "ジョブBです。"

上記のCI/CDパイプラインを実行させます。
まず、リポジトリのルートのREADME.mdに変更があった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAが作成・実行されていることがわかります。

リポジトリのルートのREADME.mdに変更がなかった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブAは作成されていないことがわかります。

rules:existsを使って特定のファイルの存在有無をチェックし、ジョブを作成する or しない例は以上です。

前のステージのジョブが失敗しても、ジョブを実行させる (rules:allow_failure)

rules:allow_failureを使って、前のステージのジョブが失敗しても、ジョブを実行させる例を紹介いたします。

例として、「ステージ1で失敗したジョブがあっても、ステージ2のジョブBは実行させる」というCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。
なお、今回はrules:allow_failureのテストをしたいので、意図的にジョブAを失敗させます。
11行目にあるコマンドo-na-ka-su-i-taは存在しないコマンドなので、ここが原因でジョブAは失敗します。

stages:
  - stage_1
  - stage_2

job_A:
  stage: stage_1
  rules: 
    - allow_failure: true
  script: 
    - echo "ジョブAです。このジョブが失敗しても、ジョブBは実行されます。"
    - o-na-ka-su-i-ta

job_B:
  stage: stage_2
  script: echo "ジョブBです。"

上記をそのまま (11行目をコメントアウトせず) CI/CDパイプラインを実行させます。
すると、ステージ1のジョブAは失敗しているにもかかわらず、ステージ2のジョブBが実行されていることがわかります。
通常、GitLabのCI/CDパイプラインは、前のステージのジョブが全て成功して終了しないと、次のステージのジョブは実行されません。

なお、前のステージのジョブが全て成功で終了した場合、alllow_failure:trueが設定されたジョブは通常通り作成・実行されます。
したがって、先述の.gitlab-ci.ymlの11行目をコメントアウトして実行した場合、下図の通りジョブBは通常通り作成・実行されます。

rules:allow_failureを使って、前のステージのジョブが失敗しても、ジョブを実行させる例は以上です。

特定の条件を満たす場合に、変数を設定する (rules:variables)

rules:ifrules:variablesを使って、rules:ifの判定が真であれば、特定の変数の値を変更し 且つ ジョブを作成・実行する例を紹介いたします。

例として、既定の変数CI_COMMIT_REF_NAMEを用いてコミット先ブランチを判定し、「コミット先のブランチが "main" だった場合、変数SAMPLE_ENVの値をo-ya-tsuに変更し 且つ ジョブAを実行する」というCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。
ジョブAに設定したrules:valiablesの効果を確認するために、6行目でグローバル変数SAMPLE_ENVの値をgo-ha-nに設定しています。

stages:
  - stage_1
  - stage_2

variables:
  SAMPLE_ENV: "go-ha-n"

job_A:
  stage: stage_1
  rules:
    - if: $CI_COMMIT_REF_NAME == "main"
      variables:
        SAMPLE_ENV: "o-ya-tsu"
  script:
    - echo "ジョブAです。"
    - echo $SAMPLE_ENV

job_B:
  stage: stage_2
  script:
    - echo "ジョブBです。"
    - echo $SAMPLE_ENV

上記のCI/CDパイプラインを実行させます。
まず、コミット先ブランチが "main" だった場合、上記のCI/CDパイプラインは以下の通りとなります。

ジョブAのログをみると、変数SAMPLE_ENVechoの出力がo-ya-tsuになっていることがわかります。
この.gitlab-ci.ymlの場合、6行目で変数SAMPLE_ENVの値をgo-ha-nにしていますが、ジョブA内ではrules:valiablesの効果で値が変更されたことが確認できます。

rules:ifの判定が真であれば、特定の変数の値を変更し 且つ ジョブを作成・実行する例は以上です。

特定の条件を満たす場合に、手動実行でジョブを作成する (rules:when)

rules:ifrules:whenを使って、rules:ifの判定が真であれば、手動実行でジョブを作成する例を紹介いたします。
なおこの例ではrules:ifの判定が偽であれば、rules:whenを設定したジョブは作成されません。

既定の変数CI_COMMIT_REF_NAMEを用いてコミット先ブランチを判定し、「コミット先ブランチが "main" だった場合は、ジョブBをトリガーを手動実行にして作成する」ようなCI/CDパイプライン (下図) を作成します。

上の図のCI/CDパイプラインの.gitlab-ci.ymlはこうなります。

stages:
  - stage_1
  - stage_2

job_A:
  stage: stage_1
  script:
    - echo "ジョブAです。"

job_B:
  stage: stage_2
  rules:
    - if: $CI_COMMIT_REF_NAME == "main"
      when: manual
  script:
    - echo "ジョブBです。コミット先ブランチがmainなら、手動実行で作成されます。コミット先ブランチがmain以外なら、作成されません。"

上記のCI/CDパイプラインを実行させます。
まず、コミット先のブランチが "main" だった場合、上記のCI/CDパイプラインは以下の通りとなります。
ステージ2のジョブBが自動実行されず、手動による実行待ちになっていることがわかります。

コミット先のブランチが "main" 以外だった場合、上記のCI/CDパイプラインは以下の通りとなります。
ジョブBが作成されていないことがわかります。

rules:ifrules:whenを使って、rules:ifの判定が真であれば、手動実行でジョブを作成する例は以上です。

最後に

この度はGitもCI/CDもよくわかっていないど素人SEによるGitLab検証ブログをお読みいただき、誠にありがとうございます。
このブログの目標は以下のとおりでしたが、皆さまはいかがでしたでしょうか。


今回のゴール
  • GitLabのCI/CDパイプラインのキーワード rules の概要を把握する。

CI/CDパイプラインで条件分岐のようなことをしたい場合、rules は避けて通れないキーワードです。
とはいえ、rulesでどんな条件分岐も作成できる!・・・というわけではないので、最初はサブキーワードをご確認いただき、実装可能な方向性を模索いただければと存じます。

この記事がGitLabを触り始めた方の一助となれば幸いにございます。


GitLabに関するお問い合わせは、以下のフォームからお願い致します。
GitLab製品 お問い合わせ

今までのGitLabの検証ブログはこちらです。
GitLab カテゴリーの記事一覧 - ネットワールド らぼ

GitLab操作デモ動画 (基本編) を作ってみました。(音声の録音は自宅でiPhoneのボイスメモ使うという超低クオリティですが…。)
つたない内容ではありますが、ご興味がおありでしたら是非ご視聴いただければと存じます。

www.youtube.com