{{< details >}}
- Tier: 基础版, 专业版, 旗舰版
- Offering: JihuLab.com, 私有化部署
{{< /details >}}
使用 rules
在流水线中包含或排除作业。
规则按顺序进行评估,直到找到第一个匹配项。找到匹配项时,作业会根据配置被包含或排除在流水线之外。
你不能在规则中使用在作业脚本中创建的 dotenv 变量,因为规则在任何作业运行之前就被评估。
rules
示例
以下示例使用 if
定义作业仅在两个特定情况下运行:
job:
script: echo "Hello, Rules!"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: manual
allow_failure: true
- if: $CI_PIPELINE_SOURCE == "schedule"
- 如果流水线是为了合并请求,则第一个规则匹配,作业被添加到合并请求流水线,具有以下属性:
-
when: manual
(手动作业) -
allow_failure: true
(即使手动作业未运行,流水线也会继续运行)
-
- 如果流水线不是为了合并请求,则第一个规则不匹配,第二个规则被评估。
- 如果流水线是一个计划的流水线,则第二个规则匹配,作业被添加到计划的流水线中。由于未定义任何属性,因此它将以以下方式添加:
-
when: on_success
(默认) -
allow_failure: false
(默认)
-
- 在所有其他情况下,没有规则匹配,因此作业不会添加到任何其他流水线中。
或者,你可以定义一组规则在少数情况下排除作业,而在所有其他情况下运行它们:
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
- 如果流水线是为了合并请求,作业不会被添加到流水线中。
- 如果流水线是一个计划的流水线,作业不会被添加到流水线中。
- 在所有其他情况下,作业会被添加到流水线中,使用
when: on_success
。
{{< alert type=”warning” >}}
如果你使用 when
子句作为最终规则(不包括 when: never
),可能会启动两个同时进行的流水线。推送流水线和合并请求流水线可能会因同一事件触发(推送到一个开放的合并请求的源分支)。请参阅如何防止重复的流水线了解更多详情。
{{< /alert >}}
为计划的流水线运行作业
你可以配置一个作业仅在流水线被计划时执行。例如:
job:on-schedule:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- make world
job:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
script:
- make build
在此示例中,make world
在计划的流水线中运行,而 make build
在分支和标签流水线中运行。
如果分支为空则跳过作业
使用 rules:changes:compare_to
跳过在分支为空时的作业,从而节省 CI/CD 资源。配置将分支与默认分支进行比较,如果分支:
- 没有更改的文件,作业不会运行。
- 有更改的文件,作业会运行。
例如,在一个以 main
为默认分支的项目中:
job:
script:
- echo "This job only runs for branches that are not empty"
rules:
- if: $CI_COMMIT_BRANCH
changes:
compare_to: 'refs/heads/main'
paths:
- '**/*'
此作业的规则将当前分支中的所有文件和路径递归地(**/*
)与 main
分支进行比较。规则匹配且只有当分支中的文件有更改时,作业才会运行。
常见 if
子句与预定义变量
rules:if
子句通常与预定义的 CI/CD 变量一起使用,特别是 CI_PIPELINE_SOURCE
预定义变量。
以下示例将作业作为手动作业在计划的流水线或推送流水线(到分支或标签)中运行,使用 when: on_success
(默认)。它不会将作业添加到任何其他流水线类型中。
job:
script: echo "Hello, Rules!"
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: manual
allow_failure: true
- if: $CI_PIPELINE_SOURCE == "push"
以下示例在合并请求流水线和计划的流水线中将作业作为 when: on_success
作业运行。它不会在任何其他流水线类型中运行。
job:
script: echo "Hello, Rules!"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "schedule"
其他常用的 if
子句:
-
if: $CI_COMMIT_TAG
: 如果更改是为标签推送的。 -
if: $CI_COMMIT_BRANCH
: 如果更改是推送到任何分支的。 -
if: $CI_COMMIT_BRANCH == "main"
: 如果更改是推送到main
的。 -
if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
: 如果更改是推送到默认分支的。当你想在多个项目中具有相同配置但默认分支不同的情况下使用。 -
if: $CI_COMMIT_BRANCH =~ /regex-expression/
: 如果提交分支匹配正则表达式。 -
if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_TITLE =~ /Merge branch.*/
: 如果提交分支是默认分支且提交消息标题匹配正则表达式。例如,合并提交的默认提交消息以Merge branch
开头。 -
if: $CUSTOM_VARIABLE == "value1"
: 如果自定义变量CUSTOM_VARIABLE
恰好是value1
。
仅在特定的流水线类型中运行作业
你可以使用预定义的 CI/CD 变量和 rules
来选择作业应运行的流水线类型。
下表列出了一些可以使用的变量,以及这些变量可以控制的流水线类型:
- 分支流水线:运行在 Git
push
事件到分支时,如新提交或标签。 - 标签流水线:仅在新的 Git 标签推送到分支时运行。
- 合并请求流水线:运行在合并请求的更改时,如新的提交或在合并请求的流水线选项卡中选择运行流水线。
- 计划的流水线。
变量 | 分支 | 标签 | 合并请求 | 计划 |
---|---|---|---|---|
CI_COMMIT_BRANCH |
是 | 是 | ||
CI_COMMIT_TAG |
是 | 是,如果计划的流水线被配置为在标签上运行。 | ||
CI_PIPELINE_SOURCE = push |
是 | 是 | ||
CI_PIPELINE_SOURCE = schedule |
是 | |||
CI_PIPELINE_SOURCE = merge_request_event |
是 | |||
CI_MERGE_REQUEST_IID |
是 |
例如,要配置一个作业以在合并请求流水线和计划的流水线中运行,而不是分支或标签流水线:
job1:
script:
- echo
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "push"
when: never
CI_PIPELINE_SOURCE
预定义变量
使用 CI_PIPELINE_SOURCE
变量控制何时为这些流水线类型添加作业:
值 | 描述 |
---|---|
api |
为通过 流水线 API 触发的流水线。 |
chat |
为使用 极狐GitLab ChatOps 命令创建的流水线。 |
external |
当你使用其他 CI 服务而不是极狐GitLab 时。 |
external_pull_request_event |
当 GitHub 上的外部拉取请求 被创建或更新时。 |
merge_request_event |
为创建或更新合并请求时创建的流水线。需要启用合并请求流水线、合并结果流水线和合并列车。 |
ondemand_dast_scan |
为 DAST 按需扫描 流水线。 |
ondemand_dast_validation |
为 DAST 按需验证 流水线。 |
parent_pipeline |
为由 父/子流水线 触发的流水线。使用此流水线源在子流水线配置中,以便它可以由父流水线触发。 |
pipeline |
为 多项目流水线,由使用 API 和 CI_JOB_TOKEN 或 trigger 关键字创建。 |
push |
为由 Git 推送事件触发的流水线,包括分支和标签。 |
schedule |
为计划的流水线。 |
security_orchestration_policy |
为安全编排策略 流水线。 |
trigger |
为使用触发令牌 创建的流水线。 |
web |
为通过极狐GitLab UI 中的项目 Build > Pipelines 部分选择新建流水线创建的流水线。 |
webide |
为使用 Web IDE 创建的流水线。 |
这些值与使用 流水线 API 端点 时返回的 source
参数值相同。
复杂规则
你可以在同一规则中使用所有 rules
关键字,例如 if
、changes
和 exists
。只有当所有包含的关键字评估为 true 时,规则才会评估为 true。
例如:
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: $VAR == "string value"
changes: # 如果以下任何路径匹配修改过的文件,则包含作业并设置为 when:manual。
- Dockerfile
- docker/scripts/**/*
when: manual
allow_failure: true
如果 Dockerfile
文件或 /docker/scripts
中的任何文件发生更改并且 $VAR
== “string value”,则作业手动运行并允许失败。
你可以使用括号与 &&
和 ||
组合来构建更复杂的变量表达式。
job1:
script:
- echo This rule uses parentheses.
rules:
- if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE
避免重复的流水线
如果一个作业使用 rules
,一个动作(如向分支推送提交)可以触发多个流水线。你不需要显式地为多个类型的流水线配置规则来意外触发它们。
有可能导致重复流水线的一些配置会显示pipeline 警告。
例如:
job:
script: echo "This job creates double pipelines!"
rules:
- if: $CUSTOM_VARIABLE == "false"
when: never
- when: always
此作业在 $CUSTOM_VARIABLE
为 false 时不会运行,但它在所有其他流水线中运行,包括推送(分支)和合并请求流水线。使用此配置,每次推送到一个开放合并请求的源分支都会导致重复的流水线。
为了避免重复的流水线,你可以:
- 使用
workflow
指定可以运行哪些类型的流水线。 -
重写规则以仅在非常特定的情况下运行作业,并避免使用最终的
when
规则:job: script: echo "This job does NOT create double pipelines!" rules: - if: $CUSTOM_VARIABLE == "true" && $CI_PIPELINE_SOURCE == "merge_request_event"
你也可以通过更改作业规则来避免推送(分支)流水线或合并请求流水线来避免重复的流水线。但是,如果你使用 - when: always
规则而没有使用 workflow: rules
,极狐GitLab 仍然会显示pipeline 警告。
例如,以下不会触发重复的流水线,但不推荐在没有 workflow: rules
的情况下使用:
job:
script: echo "This job does NOT create double pipelines!"
rules:
- if: $CI_PIPELINE_SOURCE == "push"
when: never
- when: always
你不应该在同一作业中同时包含推送和合并请求流水线而没有防止重复流水线的 workflow:rules
:
job:
script: echo "This job creates double pipelines!"
rules:
- if: $CI_PIPELINE_SOURCE == "push"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
同时,不要在同一流水线中混合使用 only/except
作业和 rules
作业。它可能不会导致 YAML 错误,但 only/except
和 rules
的不同默认行为可能会导致难以排查的问题:
job-with-no-rules:
script: echo "This job runs in branch pipelines."
job-with-rules:
script: echo "This job runs in merge request pipelines."
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
对于每次推送到分支的更改,都会运行重复的流水线。一个分支流水线运行一个作业(job-with-no-rules
),一个合并请求流水线运行另一个作业(job-with-rules
)。没有规则的作业默认是except: merge_requests
,因此 job-with-no-rules
在所有情况下都会运行,除了合并请求。
在不同作业中重用规则
使用 !reference
标签 在不同作业中重用规则。你可以将 !reference
规则与常规作业定义的规则结合使用。例如:
.default_rules:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
when: never
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
job1:
rules:
- !reference [.default_rules, rules]
script:
- echo "This job runs for the default branch, but not schedules."
job2:
rules:
- !reference [.default_rules, rules]
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- echo "This job runs for the default branch, but not schedules."
- echo "It also runs for merge requests."
CI/CD 变量表达式
使用 rules:if
的变量表达式来控制何时应将作业添加到流水线。
你可以使用相等运算符 ==
和 !=
将变量与字符串进行比较。单引号和双引号都有效。变量必须在比较的左侧。例如:
if: $VARIABLE == "some value"
if: $VARIABLE != "some value"
你可以比较两个变量的值。例如:
if: $VARIABLE_1 == $VARIABLE_2
if: $VARIABLE_1 != $VARIABLE_2
你可以将变量与 null
关键字进行比较以查看其是否已定义。例如:
if: $VARIABLE == null
if: $VARIABLE != null
你可以检查变量是否已定义但为空。例如:
if: $VARIABLE == ""
if: $VARIABLE != ""
你可以仅通过在表达式中使用变量名来检查变量是否已定义且不为空。例如:
if: $VARIABLE
将变量与正则表达式进行比较
你可以使用 =~
和 !~
运算符对变量值进行正则表达式匹配。使用正则表达式进行变量模式匹配采用 RE2 正则表达式语法。
表达式评估为 true
如果:
- 使用
=~
时找到了匹配项。 - 使用
!~
时没有找到匹配项。
例如:
if: $VARIABLE =~ /^content.*/
if: $VARIABLE !~ /^content.*/
另外:
- 单字符正则表达式,如
/./
,不支持并会产生invalid expression syntax
错误。 - 模式匹配默认是区分大小写的。使用
i
标志修饰符使模式不区分大小写。例如:/pattern/i
。 - 只有标签或分支名称可以通过正则表达式匹配。如果给定,存储库路径始终按字面匹配。
- 整个模式必须用
/
包围。例如,你不能使用issue-/.*/
来匹配所有以issue-
开头的标签名或分支名,但可以使用/issue-.*/
。 -
@
符号表示引用的存储库路径的开头。要在正则表达式中匹配包含@
字符的引用名称,必须使用十六进制字符代码匹配\x40
。 - 使用锚点
^
和$
避免正则表达式仅匹配标签名或分支名的子字符串。例如,/^issue-.*$/
等效于/^issue-/
,而仅/issue/
还会匹配名为severe-issues
的分支。
将正则表达式存储在变量中
{{< history >}}
- 在极狐GitLab 15.0 引入,使用名为
ci_fix_rules_if_comparison_with_regexp_variable
的功能标志,默认禁用。 - 在极狐GitLab 15.1 GA,功能标志
ci_fix_rules_if_comparison_with_regexp_variable
被移除。
{{< /history >}}
在 =~
和 !~
表达式的右侧,变量被评估为正则表达式。正则表达式必须用正斜杠(/
)括起来。例如:
variables:
pattern: '/^ab.*/'
regex-job1:
variables:
teststring: 'abcde'
script: echo "This job will run, because 'abcde' matches the /^ab.*/ pattern."
rules:
- if: '$teststring =~ $pattern'
regex-job2:
variables:
teststring: 'fghij'
script: echo "This job will not run, because 'fghi' does not match the /^ab.*/ pattern."
rules:
- if: '$teststring =~ $pattern'
正则表达式中的变量不会被解析。例如:
variables:
string1: 'regex-job1'
string2: 'regex-job2'
pattern: '/$string2/'
regex-job1:
script: echo "This job will NOT run, because the 'string1' variable inside the regex pattern is not resolved."
rules:
- if: '$CI_JOB_NAME =~ /$string1/'
regex-job2:
script: echo "This job will NOT run, because the 'string2' variable inside the 'pattern' variable is not resolved."
rules:
- if: '$CI_JOB_NAME =~ $pattern'
将变量表达式组合在一起
你可以使用 &&
(和)或 ||
(或)组合多个表达式,例如:
$VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"
$VARIABLE1 =~ /^content.*/ && $VARIABLE2 =~ /thing$/ && $VARIABLE3
$VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/ && $VARIABLE3
运算符的优先级遵循 Ruby 2.5 标准,所以 &&
在 ||
之前评估。
你可以使用括号将表达式组合在一起。括号优先于 &&
和 ||
,因此括号中的表达式首先评估,结果用于表达式的其余部分。
嵌套括号以创建复杂的条件,并且括号中的最内层表达式首先评估。例如:
($VARIABLE1 =~ /^content.*/ || $VARIABLE2) && ($VARIABLE3 =~ /thing$/ || $VARIABLE4)
($VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/) && $VARIABLE3
$CI_COMMIT_BRANCH == "my-branch" || (($VARIABLE1 == "thing" || $VARIABLE2 == "thing") && $VARIABLE3)
故障排除
使用 =~
进行正则表达式匹配时的意外行为
当使用 =~
字符时,请确保比较的右侧始终包含一个有效的正则表达式,并用 /
字符括起来。
如果比较的右侧不是一个用 /
字符括起来的有效正则表达式,表达式会以意想不到的方式进行评估。在这种情况下,比较会检查左侧是否是右侧的子字符串。例如,"23" =~ "1234"
评估为 true,这与 "23" =~ /1234/
相反,后者评估为 false。
你不应该将你的流水线配置为依赖于这种行为。