目录
1. 用途
2. 机制
2.1. Rules attributes
2.2. Rules clauses
2.3. rules:if
2.3.1. Common if clauses for rules
2.4. rules:changes
2.5. rules:exists
3. 综合示例
3.1. 示例1:根据 commit meesage 触发
3.2. 示例2:根据 Tag 触发
1. 用途?
.gitlab-ci.yml 的 rules 配置,能让我们根据自定义的筛选条件,控制 job 是否执行:
-
这段脚本我只想在 dev 分支执行,另一段只想在 master 分支执行;
-
这段脚本我只想在 master 分支上打 tag 的时候触发,其他情况不触发;
-
这段脚本我只想在 这些文件产生变更时触发,其他情况不触发;
-
这段脚本我只想在 commit message 中包含某些特定关键字时才触发;
-
....
一个例子:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
allow_failure: true
- if: '$CI_PIPELINE_SOURCE == "schedule"'
2. 机制
The rules keyword can be used to include or exclude jobs in pipelines.
Rules are evaluated in order until the first match. When matched, the job is either included or excluded from the pipeline, depending on the configuration. If included, the job also has certain attributes added to it.
2.1. Rules attributes
The job attributes you can use with rules are:
-
when: If not defined, defaults to when: on_success.
-
If used as when: delayed, start_in is also required.
-
-
allow_failure: If not defined, defaults to allow_failure: false.
-
variables: If not defined, uses the variables defined elsewhere.
If a rule evaluates to true, and when has any value except never, the job is included in the pipeline.
For example:
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: delayed
start_in: '3 hours'
allow_failure: true
2.2. Rules clauses
Available rule clauses are:
-
if:Add or exclude jobs from a pipeline by evaluating an if statement.
-
changes:Add or exclude jobs from a pipeline based on what files are changed.
-
exists:Add or exclude jobs from a pipeline based on the presence of specific files.
Rules are evaluated in order until a match is found. If a match is found, the attributes are checked to see if the job should be added to the pipeline. If no attributes are defined, the defaults are:
-
when: on_success
-
allow_failure: false
The job is added to the pipeline:
-
If a rule matches and has when: on_success, when: delayed or when: always.
-
If no rules match, but the last clause is when: on_success, when: delayed or when: always (with no rule).
The job is not added to the pipeline:
-
If no rules match, and there is no standalone when: on_success, when: delayed or when: always.
-
If a rule matches, and has when: never as the attribute.
For example, using if clauses to strictly limit when jobs run:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: manual
allow_failure: true
- if: '$CI_PIPELINE_SOURCE == "schedule"'
In this example:
-
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:
-
when: manual (manual job)
-
allow_failure: true (the pipeline continues running even if the manual job is not run)
-
-
If the pipeline is not for a merge request, the first rule doesn’t match, and the second rule is evaluated.
-
If the pipeline is a scheduled pipeline, the second rule matches, and the job is added to the scheduled pipeline. No attributes were defined, so it is added with:
-
when: on_success (default)
-
allow_failure: false (default)
-
-
In all other cases, no rules match, so the job is not added to any other pipeline.
Alternatively, you can define a set of rules to exclude jobs in a few cases, but run them in all other cases:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: never
- when: on_success
-
If the pipeline is for a merge request, the job is not be added to the pipeline.
-
If the pipeline is a scheduled pipeline, the job is not be added to the pipeline.
-
In all other cases, the job is added to the pipeline, with when: on_success.
2.3. rules:if
rules:if clauses determine whether or not jobs are added to a pipeline by evaluating an if statement. If the if statement is true, the job is either included or excluded from a pipeline. In plain English, if rules can be interpreted as one of:
-
“If this rule evaluates to true, add the job” (default).
-
“If this rule evaluates to true, do not add the job” (by adding when: never).
Any set of expressions to be evaluated can be conjoined into a single expression by using && or ||, and the variable matching operators (==, !=, =~ and !~).
Unlike variables in script sections, variables in rules expressions are always formatted as $VARIABLE.
For example:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ ^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: always
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ ^feature/'
when: manual
allow_failure: true
- if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' # Checking for the presence of a variable is possible
Some details regarding the logic that determines the when for the job:
-
If none of the provided rules match, the job is set to when: never and is not included in the pipeline.
-
A rule without any conditional clause, such as a when or allow_failure rule without if or changes, always matches, and is always used if reached.
-
If a rule matches and has no when defined, the rule uses the when defined for the job, which defaults to on_success if not defined.
-
You can define when once per rule, or once at the job-level, which applies to all rules. You can’t mix when at the job-level with when in rules.
2.3.1. Common if clauses for rules
You can check the value of the $CI_PIPELINE_SOURCE variable:
For example:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: manual
allow_failure: true
- if: '$CI_PIPELINE_SOURCE == "push"'
-
This example runs the job as a manual job in scheduled pipelines or in push pipelines (to branches or tags), with when: on_success (default). It does not add the job to any other pipeline type.
Another example:
job:
script: echo "Hello, Rules!"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
-
This example runs the job as a when: on_success job in merge request pipelines and scheduled pipelines. It does not run in any other pipeline type.
Other commonly used variables for if clauses:
-
if: $CI_COMMIT_TAG: If changes are pushed for a tag.
-
if: $CI_COMMIT_BRANCH: If changes are pushed to any branch.
-
if: '$CI_COMMIT_BRANCH == "master"': If changes are pushed to master.
-
if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH': If changes are pushed to the default branch (usually master). Use when you want to have the same configuration in multiple projects with different default branches.
-
if: '$CI_COMMIT_BRANCH =~ regex-expression/': If the commit branch matches a regular expression.
-
if: '$CUSTOM_VARIABLE !~ regex-expression/': If the custom variable CUSTOM_VARIABLE does not match a regular expression.
-
if: '$CUSTOM_VARIABLE == "value1"': If the custom variable CUSTOM_VARIABLE is exactly value1.
2.4. rules:changes
rules:changes determines whether or not to add jobs to a pipeline by checking for changes to specific files.
It’s recommended to only use rules: changes with branch pipelines or merge request pipelines. For example, it’s common to use rules: changes with merge request pipelines:
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- Dockerfile
when: manual
allow_failure: true
In this example:
-
If the pipeline is a merge request pipeline, check Dockerfile for changes.
-
If Dockerfile has changed, add the job to the pipeline as a manual job, and the pipeline continues running even if the job is not triggered (allow_failure: true).
-
If Dockerfile has not changed, do not add job to any pipeline (same as when: never).
To use rules: changes with branch pipelines instead of merge request pipelines, change the if: clause in the example above to:
rules:
- if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
To implement a rule similar to except:changes, use when: never.
-
You can use rules: changes with other pipeline types, but it is not recommended because rules: changes always evaluates to true when there is no Git push event. Tag pipelines, scheduled pipelines, and so on do not have a Git push event associated with them. A rules: changes job is always added to those pipeline if there is no if: statement that limits the job to branch or merge request pipelines.
2.5. rules:exists
exists accepts an array of paths and matches if any of these paths exist as files in the repository:
job:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- exists:
- Dockerfile
You can also use glob patterns to match multiple files in any directory in the repository:
job:
script: bundle exec rspec
rules:
- exists:
- spec/**.rb
For performance reasons, using exists with patterns is limited to 10,000 checks. After the 10,000th check, rules with patterned globs always match.
3. 综合示例
3.1. 示例1:根据 commit meesage 触发
publish-modern-docs:
stage: build
trigger:
include: sef/sef_docs_modern/.gitlab-ci.yml
rules:
- if: '$CI_COMMIT_MESSAGE =~ /^docs/'
changes:
- sef/sef_docs_modern/**/*
3.2. 示例2:根据 Tag 触发
build_sef:
stage: build
trigger:
include: sef/.gitlab-ci_sef.yml
rules:
- if: $CI_COMMIT_TAG