以下の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/05/18/221620より取得しました。


GitLab CI/CDでジョブを実行する条件を設定する

これは、なにをしたくて書いたもの?

前に、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.

CI/CD Jobs | GitLab Docs

ジョブは.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.

CI/CD pipelines | GitLab Docs

パイプラインは、以下の要素から構成されます。

小さなパイプラインだと、少ないステージとその中に含まれるジョブだけで構成されそうですね。

平たく言うと、.gitlab-ci.ymlで定義された内容そのものですね。

パイプラインには、いくつか種類があります。また自動で実行することもできれば、手動で実行することもできます。

  • 基本的なパイプライン
    • 基本的なパイプライン
    • needsを使用して、ジョブ間の依存関係を定義したパイプライン
    • 親子パイプライン
    • Pipeline architecture | 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の設定をしている時の宿命みたいなものの気がしますが。

ひとまず、条件分岐の基礎みたいなところは押さえられた気はするので今後使っていってみましょう。




以上の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/05/18/221620より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14