これは、なにをしたくて書いたもの?
前に、GitLab RunnerをGitLabに登録してジョブを動かせるようにしてみました。
Ubuntu Linux 24.04 LTSにGitLab Runnerをインストールして、TerraformでGitLabに登録する - CLOVER🍀
今回は、ジョブを実行する条件を設定してみようと思います。
GitLab CI/CDでジョブを実行する条件を設定する
ドキュメントとしてはこちらです。
Specify when jobs run with `rules` | GitLab Docs
パイプラインにジョブを含めるか除外するかを制御するには、rulesを使います。
CI/CD YAML syntax reference / rules
ジョブの制御そのものは、ドキュメントの以下の順で見ていくとよいでしょう。
Control how jobs run | GitLab Docs
Specify when jobs run with `rules` | GitLab Docs
Troubleshooting jobs | GitLab Docs
ジョブを実行したいケースとしては、以下のようなパターンが考えられます。
- Merge Requestが作成・更新された時に実行する
- Protectedブランチが更新された時に実行する
- 定期的に実行する
- 特定のファイルが変更された時に、ジョブを実行する
ジョブの実行条件を絞りたくなるのは、たいていの場合はジョブを実行するリソースの節約ですね。
挙げたようなユースケースに近い例は、以下に書かれています。
Specify when jobs run with rules / rules examples
ところで、ドキュメントを見ているとパイプラインとジョブの違いを押さえておいた方がよさそうですね。
GitLab CI/CDのジョブとパイプラインの定義を確認する
ジョブ
ジョブは、GitLab CI/CDパイプラインの基本要素です。
CI/CD jobs are the fundamental elements of a GitLab CI/CD pipeline.
ジョブは.gitlab-ci.ymlファイル内で、ビルドやテスト、デプロイなどを行うコマンドのリストで構成されます。
Jobs are configured in the .gitlab-ci.yml file with a list of commands to execute to accomplish tasks like building, testing, or deploying code.
実際、jobというキーワードで.gitlab-ci.ymlで書かれますからね。
CI/CD YAML syntax reference / Job keywords
パイプライン
(CI/CD)パイプラインはGitLab CI/CDの基本要素です。
CI/CD pipelines are the fundamental component of GitLab CI/CD.
パイプラインは、以下の要素から構成されます。
- グローバルなYAMLキーワード
- ジョブ
- ステージ
- ジョブをグループ化したもの
- CI/CD YAML syntax reference / stage
小さなパイプラインだと、少ないステージとその中に含まれるジョブだけで構成されそうですね。
平たく言うと、.gitlab-ci.ymlで定義された内容そのものですね。
パイプラインには、いくつか種類があります。また自動で実行することもできれば、手動で実行することもできます。
- 基本的なパイプライン
- 基本的なパイプライン
- needsを使用して、ジョブ間の依存関係を定義したパイプライン
- 親子パイプライン
- Pipeline architecture | GitLab Docs
- マージリクエストのパイプラインタブに表示されるパイプライン
- ブランチパイプライン
- タグパイプライン
- マージリクエストパイプライン
- マージ結果パイプライン
- マージトレイン
- Types of pipelines | GitLab Docs
- スケジュールされたパイプライン
GitLab CI/CDでジョブを実行する条件を設定する、とは?
ここまで見ると、今回のお題である「ジョブを実行する条件を設定する」というのは、「あるジョブを実行することをパイプラインの
実行対象に加えるかどうかの条件を設定する」と言えそうです。
こういう目線で見ると、rulesの例で「ジョブがマージリクエストパイプラインに追加される」といった表現の意味がわかるように
なります。
If the pipeline is for a merge request, the first rule matches, and the job is added to the merge request pipeline with attributes of:
Specify when jobs run with rules / rules examples
あとは例や.gitlab-ci.ymlを見て慣れていきましょう。
環境はTerraformで構築することにします。
環境
今回の環境はこちら。GitLabはすでに構築済みで、192.168.0.6で動作しているものとします。
$ sudo gitlab-rake gitlab:env:info System information System: Ubuntu 24.04 Current User: git Using RVM: no Ruby Version: 3.2.5 Gem Version: 3.6.7 Bundler Version:2.6.5 Rake Version: 13.0.6 Redis Version: 7.2.7 Sidekiq Version:7.3.9 Go Version: unknown GitLab information Version: 18.0.0 Revision: c481e1bd1b8 Directory: /opt/gitlab/embedded/service/gitlab-rails DB Adapter: PostgreSQL DB Version: 16.8 URL: http://192.168.0.6 HTTP Clone URL: http://192.168.0.6/some-group/some-project.git SSH Clone URL: git@192.168.0.6:some-group/some-project.git Using LDAP: no Using Omniauth: yes Omniauth Providers: GitLab Shell Version: 14.41.0 Repository storages: - default: unix:/var/opt/gitlab/gitaly/gitaly.socket GitLab Shell path: /opt/gitlab/embedded/service/gitlab-shell Gitaly - default Address: unix:/var/opt/gitlab/gitaly/gitaly.socket - default Version: 18.0.0 - default Git Version: 2.49.0.gl2
GitLab Runnder。
$ gitlab-runner --version Version: 18.0.1 Git revision: 3e653c4e Git branch: 18-0-stable GO version: go1.23.6 X:cacheprog Built: 2025-05-16T17:25:38Z OS/Arch: linux/amd64
Terraform。
$ terraform version Terraform v1.12.0 on linux_amd64
GitLabプロジェクトを作成する
最初に、GitLabプロジェクトを作成します。
Terraformでのリソース定義。
terraform.tf
terraform { required_version = "1.12.0" required_providers { gitlab = { source = "gitlabhq/gitlab" version = "18.0.0" } } }
main.tf
variable "root_access_token" { type = string ephemeral = true } provider "gitlab" { token = var.root_access_token base_url = "http://192.168.0.6/" } resource "gitlab_group" "sample_group" { name = "sample group" path = "sample-group" } resource "gitlab_project" "sample_app" { name = "sample-app" namespace_id = gitlab_group.sample_group.id default_branch = "main" visibility_level = "private" auto_devops_enabled = false only_allow_merge_if_pipeline_succeeds = true only_allow_merge_if_all_discussions_are_resolved = true } resource "gitlab_branch_protection" "main_branch" { project = gitlab_project.sample_app.id branch = "main" allow_force_push = false merge_access_level = "maintainer" push_access_level = "no one" unprotect_access_level = "maintainer" } resource "gitlab_group_membership" "sample_owner" { group_id = gitlab_group.sample_group.id user_id = gitlab_user.sample_user.id access_level = "owner" } resource "gitlab_user" "sample_user" { name = "sample-user" username = "sample-user" password = "P@ssw0rd" email = "sample-user@example.com" } resource "gitlab_user_runner" "group_runner" { runner_type = "group_type" group_id = gitlab_group.sample_group.id description = "sample group runner" untagged = true } output "runner_authentication_token" { value = gitlab_user_runner.group_runner.token sensitive = true }
Protectedブランチはこの時点ではmainのみにしておきます。
$ export TF_VAR_root_access_token=...
リソース作成。
$ terraform init $ terraform apply
GitLab Runnerのauthentication tokenを確認して
$ terraform output runner_authentication_token "glrt-xxxxxxxxxx"
GitLabにGitLab Runnerを登録します。
$ RUNNER_TOKEN=... $ sudo gitlab-runner register \ --non-interactive \ --url "http://192.168.0.6/" \ --token "$RUNNER_TOKEN" \ --executor "docker" \ --docker-image ubuntu:24.04 \ --description "sample group runner"
GitLabプロジェクトに登録するサンプルコードも用意します。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>sample-app</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <maven.compiler.release>21</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.12.2</version> <scope>test</scope> </dependency> </dependencies> </project>
src/main/java/org/littlewings/gitlab/CalcService.java
package org.littlewings.gitlab; public class CalcService { public int plus(int a, int b) { return a + b; } }
src/test/java/org/littlewings/gitlab/CalcServiceTest.java
package org.littlewings.gitlab; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class CalcServiceTest { @Test void plus() { CalcService sut = new CalcService(); Assertions.assertEquals(5, sut.plus(2, 3)); } }
GitLabに登録。
$ git init --initial-branch=main $ git remote add origin http://192.168.0.6/sample-group/sample-app.git $ git config --local user.name "sample-user" $ git config --local user.email "sample-user@example.com" $ git add pom.xml src $ git commit -m "initial commit" $ git push origin HEAD
developブランチも作成します。
$ git switch -c develop $ git push origin HEAD
ここで、デフォルトブランチをdevelopに、developブランチもProtectedブランチにします。
resource "gitlab_project" "sample_app" {
name = "sample-app"
namespace_id = gitlab_group.sample_group.id
#default_branch = "main"
default_branch = "develop"
visibility_level = "private"
auto_devops_enabled = false
only_allow_merge_if_pipeline_succeeds = true
only_allow_merge_if_all_discussions_are_resolved = true
}
...
resource "gitlab_branch_protection" "develop_branch" {
project = gitlab_project.sample_app.id
branch = "develop"
allow_force_push = false
merge_access_level = "maintainer"
push_access_level = "no one"
unprotect_access_level = "maintainer"
}
適用。
$ terraform apply
これで準備完了です。
.gitlab-ci.ymlを追加して、いろいろ設定する
それでは、ここからは.gitlab-ci.ymlを追加して、設定変更していってみましょう。
新しいブランチを作成。
$ git switch -c add-cicd-pipeline
こんな.gitlab-ci.ymlを作成して
.gitlab-ci.yml
stages: - build - test - deploy default: image: maven:3.9.9-eclipse-temurin-21 compile: stage: build script: - mvn compile test: stage: test script: - mvn test packaging: stage: deploy script: - mvn package -DskipTests
リポジトリーに追加して、GitLabにブランチをpushします。
$ git add .gitlab-ci.yml $ git commit -m 'add, ci/cd pipeline' $ git push origin HEAD
すると、パイプラインが動き出します。

ここで、rulesを追加してみます。
.gitlab-ci.yml
stages: - build - test - deploy default: image: maven:3.9.9-eclipse-temurin-21 compile: stage: build script: - mvn compile rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never test: stage: test script: - mvn test rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never packaging: stage: deploy script: - mvn package -DskipTests rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never
最後のwhen: neverは明示的に書いているだけで、なくても意味は変わりません。また今回はデフォルトブランチと
Protectedブランチの扱いを明確に分けていますが、通常はデフォルトブランチもProtectedブランチであることが多いと
思いますので、$CI_COMMIT_REF_PROTECTED == "true"だけでもよいでしょう。
こうすると、マージリクエストにだけ反応するようになります。

そしてdevelopにマージすると、パイプラインが実行されます。

mainブランチにマージしてもパイプラインが実行されます。

このあたりの設定は、事前定義済みの変数を利用しています。
Predefined CI/CD variables reference | GitLab Docs
変数には以下の3種類があります。
- Pre-pipeline … パイプラインの作成前に使える変数で、
include:rulesでのみ利用可能(rulesでも使えそう) - Pipeline … パイプライン作成中に使える変数で、
rulesを使ったジョブ定義で使用し、パイプラインにジョブを追加するかどうかに利用できる - Job-only … GitLab Runnerがジョブを取得して実行した場合にのみ利用できる変数
今回使用したのはすべてPre-pipelineな変数ですね。
ところで、今回はすべてのジョブに同じrulesを書いています。これが面倒だなと思う場合は、ワークフローを使っても
よいでしょう。
GitLab CI/CD `workflow` keyword | GitLab Docs
こんな感じになります。
.gitlab-ci.yml
stages: - build - test - deploy default: image: maven:3.9.9-eclipse-temurin-21 workflow: rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never compile: stage: build script: - mvn compile test: stage: test script: - mvn test packaging: stage: deploy script: - mvn package -DskipTests
ジョブの方にはrulesがなくなりましたが、結果は変わりません。
あるいは、ジョブを継承してもよいかもしれません。ジョブの名前を.で始めると、無効なジョブを定義することができます。
このようなジョブはパイプライン内で実行はされませんが、他のジョブの継承やYAMLアンカーとして利用できます。
CI/CD Jobs / Add a job to a pipeline / Hide a job
Optimize GitLab CI/CD configuration files / Anchors
extendsを使った例。
.gitlab-ci.yml
stages: - build - test - deploy default: image: maven:3.9.9-eclipse-temurin-21 .trigger_job_rule: rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never compile: extends: .trigger_job_rule stage: build script: - mvn compile test: extends: .trigger_job_rule stage: test script: - mvn test packaging: extends: .trigger_job_rule stage: deploy script: - mvn package -DskipTests
これも結果は同じです。
最後に、rules:changesを使ってみましょう。rules:changesを使うことで、条件分岐に変更したファイルを加えることが
できます。
Specify when jobs run with rules / Complex rules
CI/CD YAML syntax reference / rules / rules:changes
変更例。
.gitlab-ci.yml
stages: - build - test - deploy default: image: maven:3.9.9-eclipse-temurin-21 compile: stage: build script: - mvn compile rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" changes: - pom.xml - src/main/**/* # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never test: stage: test script: - mvn test rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" changes: - pom.xml - src/main/**/* - src/test/**/* # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never packaging: stage: deploy script: - mvn package -DskipTests rules: # Merge Requestを対象 - if: $CI_PIPELINE_SOURCE == "merge_request_event" # デフォルトブランチを対象 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Protectedブランチを対象 - if: $CI_COMMIT_REF_PROTECTED == "true" # それ以外は実行しない - when: never
Merge Requestの時にpom.xmlまたはsrc/main配下が変わっていればmvn compileを実行するようにして、
- if: $CI_PIPELINE_SOURCE == "merge_request_event" changes: - pom.xml - src/main/**/*
Merge Requestの時にpom.xmlまたはsrc/main配下、src/test配下が変わっていればmvn testを実行するようにしています。
- if: $CI_PIPELINE_SOURCE == "merge_request_event" changes: - pom.xml - src/main/**/* - src/test/**/*
こんなところでしょうか。
おわりに
GitLab CI/CDでジョブを実行する条件を設定してみました。
ちょっと設定するだけならすぐ済むのですが、それなりにドキュメントに目を通して用語の意味を理解したり、動作確認を
しているとけっこう時間がかかりますね。
CI/CDの設定をしている時の宿命みたいなものの気がしますが。
ひとまず、条件分岐の基礎みたいなところは押さえられた気はするので今後使っていってみましょう。