# `.codechina-ci.yml`文件的关键字参考 本文档包含`.codechina-ci.yml`文件中的配置选项。 当你在编辑`.codechina-ci.yml`的过程中,你可以通过 [CI Lint](/docs/ci/lint) 工具进行验证。 ## 流水线任务关键字 流水线任务是由一系列定义了流水线任务行为的关键词组成的。 可用于流水线任务的关键字包括: | 关键字 | 描述 | | :-----------------------------------|:------------| | [`after_script`](#after_script) | 覆盖在流水线任务后执行的一组命令 | | [`allow_failure`](#allow_failure) | 允许流水线任务失败,失败的流水线任务不会导致流水线运行失败 | | [`artifacts`](#artifacts) | 成功时附加到流水线任务的文件和目录列表 | | [`before_script`](#before_script) | 覆盖在流水线任务之前执行的一组命令 | | [`cache`](#cache) | 缓存的可用于后续运行的文件列表 | | [`coverage`](#coverage) | 给定流水线任务的代码覆盖率设置 | | [`dependencies`](#dependencies) | 通过提供要从中获取`artifacts`的流水线任务列表来限制将哪些`artifacts`传递给特定任务 | | [`environment`](#environment) | 流水线任务部署到的环境的名称 | | [`except`](#only-except) | 控制何时不创建流水线任务 | | [`extends`](#extends) | 配置当前流水线任务继承自的配置条目 | | [`image`](#image) | 使用 Docker 镜像 | | [`include`](#include) | 引用外部的 yaml 文件 | | [`inherit`](#inherit) | 选择所有流水线任务继承的全局默认值 | | [`interruptible`](#interruptible) | 定义当新的运行变得多余时是否可以取消该流水线任务 | | [`needs`](#needs) | 在 stage 排序之前执行流水线任务 | | [`only`](#only-except) | 控制何时创建流水线任务 | | [`pages`](#pages) | 上传流水线任务的结果与 CODE CHINA Pages 一起使用 | | [`parallel`](#parallel) | 并行运行的流水线任务实例数量 | | [`release`](#release) | 指导 runner 生成一次发布 | | [`resource_group`](#resource_group) | 限制流水线任务的并发 | | [`retry`](#retry) | 在失败的情况下可以自动重试流水线任务的次数 | | [`rules`](#rules) | 用于评估和确定流水线任务的选定属性以及它是否已创建的条件列表 | | [`script`](#script) | 需要由 Runner 执行的 Shell 脚本 | | [`secrets`](#secrets) | CI/CD 隐藏流水线任务的 `needs` | | [`services`](#services) | 使用 Docker 服务镜像 | | [`stage`](#stage) | 定义流水线任务的阶段 | | [`tags`](#tags) | 用于选择 runner 的标签列表 | | [`timeout`](#timeout) | 定义优先于项目范围设置的自定义流水线任务超时时间(任务级别) | | [`trigger`](#trigger) | 定义下游流水线的触发器 | | [`variables`](#variables) | 定义流水线任务级别的变量 | | [`when`](#when) | 何时运行流水线任务 | ### 不可用的流水线任务名称 以下关键词不可用作流水线任务的名称: - `image` - `services` - `stages` - `types` - `before_script` - `after_script` - `variables` - `cache` - `include` ### 自定义默认关键字值 你可以为某些关键字设置全局默认值。未定义一个或多个所列关键字的流水线任务使用`default:`中定义的值。 以下这些流水线任务关键字可以在`default:`部分中定义: - [`after_script`](#after_script) - [`artifacts`](#artifacts) - [`before_script`](#before_script) - [`cache`](#cache) - [`image`](#image) - [`interruptible`](#interruptible) - [`retry`](#retry) - [`services`](#services) - [`tags`](#tags) - [`timeout`](#timeout) 以下示例将`ruby:3.0`镜像设置为流水线中所有流水线任务的默认值,而`rspec 2.7`流水线任务则不使用默认值,因为它使用特定于流水线任务的`image:`部分覆盖了默认值: ```yaml default: image: ruby:3.0 rspec: script: bundle exec rspec rspec 2.7: image: ruby:2.7 script: bundle exec rspec ``` ## 全局关键字 某些关键字在流水线任务中未定义,这些关键字控制流水线的行为或者导入额外的流水线配置: | 关键字 | 描述 | |-------------------------|:------------| | [`stages`](#stages) | 流水线阶段的名称和顺序 | | [`workflow`](#workflow) | 控制运行的流水线类型 | | [`include`](#include) | 从其他 YAML 文件导入配置 | ### `stages`[](#stages) 使用 stages 来定义该阶段中包含的流水线任务组。stages 是为流水线全局定义的。在流水线任务中使用 stage 以定义流水线任务属于哪个阶段。 stages 的顺序定义了流水线任务的执行顺序: - 同一阶段的流水线任务并行运行 - 下一阶段的流水线任务在上一阶段的流水线任务成功完成后运行 例如: ```yaml stages: - build - test - deploy ``` 1. `build` 中所有的流水线任务并行执行。 2. 如果 `build` 中的所有流水线任务都成功,则`test`中的流水线任务并行执行。 3. 如果 `test` 中的所有流水线任务都成功,则`deploy`中的流水线任务并行执行。 4. 如果 `deploy` 中的所有流水线任务都成功,则流水线标记为通过。 如果任何流水线任务失败,流水线将被标记为 `failed` 并且后续阶段的流水线任务不会启动。当前阶段的流水线任务不会停止并继续运行。 如果 `.codechina-ci.yml` 文件中没有定义 stages,则 `build`,`test`和 `deploy` 是默认的流水线阶段。 如果流水线任务未指定 `stage`,则将该流水线任务分配至`test`阶段。 如果定义了一个 stage ,但没有流水线任务使用它,则该阶段在流水线中不可见。这对于合规性流水线配置很有用,因为: - stage 可以在合规性配置中定义,但如果不使用则保持隐藏。 - 当开发人员在流水线任务定义中使用它们时,定义的 stage 变得可见。 要使流水线任务更早开始并忽略 stage 顺序,请使用[`needs`](#needs)关键字。 ### `workflow`[](#workflow) 使用`workflow:`以确定流水线是否被创建。在顶层定义此关键字,使用`rules:`类似于`rules:`在流水线任务中定义的单个关键字。 你可以使用`workflow:rules`模板导入预配置的`workflow: rules`条目。 `workflow: rules` 接受以下这些关键字: - [`if`](#rulesif):检查此 `rules` 以确定何时运行流水线。 - [`when`](#when):指定当 if `rules` 评估为真时要做什么。 - 要运行流水线,请设置为 always。 - 要防止流水线运行,请设置为 never。 - [`variables`](#workflowrulesvariables): 如果未定义,则使用别处定义的变量。 当没有 `rules` 评估为真时,流水线不会运行。 `workflow: rules`的一些示例`if`条款: | 示例 `rules` | 描述 | |------------------------------------------------------|--------------| | `if: '$CI_PIPELINE_SOURCE == "merge_request_event"'` | 控制合并请求流水线何时运行 | | `if: '$CI_PIPELINE_SOURCE == "push"'` | 控制分支流水线和 Tag 流水线何时运行 | | `if: $CI_COMMIT_TAG` | 控制 Tag 流水线何时运行 | | `if: $CI_COMMIT_BRANCH` | 控制分支流水线何时运行 | 有关更多示例,请参阅[通用 if rules 条款](#common-if-clauses-for-rules)。 在以下示例中,流水线针对所有 push 事件(对分支和新标签的更改)运行。提交消息中含`-draft`的推送事件不会运行流水线,因为它们被设置为`when: never`。计划或合并请求的流水线也不会运行,因为没有 `rules` 对它们评估为真: ```yaml workflow: rules: - if: $CI_COMMIT_MESSAGE =~ /-draft$/ when: never - if: '$CI_PIPELINE_SOURCE == "push"' ``` 这个例子有严格的 `rules` ,流水线不会在其他任何情况下运行。 或者,所有 `rules` 都可以`when: never`,并带有最终 `when: always` `rules` 。符合`when: never` `rules` 的流水线不会运行,所有其他流水线类型运行: ```yaml workflow: rules: - if: '$CI_PIPELINE_SOURCE == "schedule"' when: never - if: '$CI_PIPELINE_SOURCE == "push"' when: never - when: always ``` 以上示例中,阻止了计划或push(分支和标签)流水线的流水线运行。最终`when: always` `rules` 运行所有其他流水线类型,包括合并请求流水线。 如果你的 `rules` 同时匹配分支流水线和合并请求流水线,则可能会出现重复的流水线。 #### `workflow:rules:variables`[](#workflowrulesvariables) 你可以在 `workflow:rules:` 中使用 `variables` 来定义特定流水线条件的变量。 例如: ```yaml variables: DEPLOY_VARIABLE: "default-deploy" workflow: rules: - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH variables: DEPLOY_VARIABLE: "deploy-production" # Override globally-defined DEPLOY_VARIABLE - if: $CI_COMMIT_REF_NAME =~ /feature/ variables: IS_A_FEATURE: "true" # Define a new variable. - when: always # Run the pipeline in other cases job1: variables: DEPLOY_VARIABLE: "job1-default-deploy" rules: - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH variables: # Override DEPLOY_VARIABLE defined DEPLOY_VARIABLE: "job1-deploy-production" # at the job level. - when: on_success # Run the job in other cases script: - echo "Run script with $DEPLOY_VARIABLE as an argument" - echo "Run another script if $IS_A_FEATURE exists" job2: script: - echo "Run script with $DEPLOY_VARIABLE as an argument" - echo "Run another script if $IS_A_FEATURE exists" ``` 当分支是默认分支时: - `job1DEPLOY_VARIABLE`是`job1-deploy-production` - `job2DEPLOY_VARIABLE`是`deploy-production` 当分支是`feature`时: `job1DEPLOY_VARIABLE`是`job1-default-deploy`,IS_A_FEATURE 是`true` `job2DEPLOY_VARIABLE`是`default-deploy`,IS_A_FEATURE 是`true` 当分支是其它分支时: `job1DEPLOY_VARIABLE`是`job1-default-deploy` `job2DEPLOY_VARIABLE`是`default-deploy` #### workflow:rules 模板[](#workflowrules-templates) 我们为一些常见场景提供了 `workflow: rules` 设置的模板。这些模板有助于防止重复运行流水线。 [`Branch-Pipelines` 模板](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/Branch-Pipelines`.codechina-ci.yml`)可以使你的流水线为分支和 Tags 运行。 分支流水线状态显示在使用分支作为源的合并请求中。但是,这种流水线类型不支持合并请求流水线提供的任何功能 ,例如合并结果流水线或合并列车。此模板有意避免使用这些功能。 可以通过以下方式引用它: ```yaml include: - template: 'Workflows/Branch-Pipelines`.codechina-ci.yml`' ``` [`MergeRequest-Pipelines` 模板](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/MergeRequest-Pipelines`.codechina-ci.yml`)可以使你的流水线针对默认分支、Tags 和所有类型的合并请求运行流水线。如果使用任何合并请求功能的流水线,请使用此模板。 可以通过以下方式引用它: ```yaml include: - template: 'Workflows/MergeRequest-Pipelines`.codechina-ci.yml`' ``` #### 在分支流水线和合并请求流水线之间切换 要在创建合并请求后将流水线从分支流水线切换到合并请求流水线,在 ``.codechina-ci.yml`` 文件中添加 `workflow: rules` 部分。 如果同时使用两种流水线类型,则可能会同时运行重复的流水线。为防止重复运行流水线,请使用`CI_OPEN_MERGE_REQUESTS`变量。 以下示例适用于仅运行分支和合并请求流水线,但不为任何其他情况运行流水线的项目: - 当分支没有打开合并请求时运行分支流水线 - 当分支的合并请求打开时运行合并请求流水线 ```yaml workflow: rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS' when: never - if: '$CI_COMMIT_BRANCH' ``` 如果流水线由以下因素触发: - 合并请求,运行合并请求流水线。例如,合并请求流水线可以通过推送到具有关联打开合并请求的分支来触发。 - 对分支的更改,但该分支的合并请求已打开,请不要运行分支流水线。 - 对分支的更改,但没有任何打开的合并请求,运行分支流水线。 你还可以向现有`workflow`部分添加 `rules` ,以便在创建合并请求时从分支流水线切换到合并请求流水线。 将此 `rules` 添加到该`workflow`部分的顶部,然后是已经存在的其他 `rules` : ```yaml workflow: rules: - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" when: never - ... # Previously defined workflow rules here ``` 在分支上运行的流水线触发器有一个`$CI_COMMIT_BRANCH` 集合,可能会被类似的 `rules` 阻止。触发流水线的流水线源为`trigger`或`pipeline`,因此`&& $CI_PIPELINE_SOURCE == "push"`确保 `rules` 不会阻止触发流水线。 ### `include`[](#include) 用于`include`在 CI/CD 配置中包含外部 YAML 文件。你可以将一个长的`codechina-ci.yml`文件分解为多个文件以提高可读性,或减少同一配置在多个位置的重复。 你还可以将模板文件存储在中央存储库中,并通过`include`将它们存储在项目中。 `include`要求外部 YAML 文件具有扩展名`.yml`或`.yaml`,否则不引用外部文件。 你不能在不同 YAML 文件之间通过使用 YAML 锚点的方式来 `include` `.yaml`。你只能引用同一文件中的锚点。要重用来自不同 YAML 文件的配置,请使用[`!reference` 标签](#reference-tags) 或 [`extends` 关键字](#extends)。 `include` 支持以下引用方法: | 关键词 | 方法 | |:--------------------------------|:---------------------------| | [`local`](#includelocal) | 引用本地项目存储库中的文件 | | [`file`](#includefile) | 引用来自不同项目存储库的文件 | | [`remote`](#includeremote) | 引用来自远程 URL 的文件,必须可以公开访问。 | | [`template`](#includetemplate) | 引用模板 | 流水线启动时,`.codechina-ci.yml`会评估所有方法引用的文件配置。配置是一个及时的快照并储存在数据库中。`.codechina-ci.yml`在下一个流水线启动之前,不会同步对引用文件配置的任何更改。 这些`include`文件是: - 与`.codechina-ci.yml`文件中的那些深度合并 = `.codechina-ci.yml`无论`include`关键字的位置如何,始终首先评估并与文件内容合并。 > 使用合并本地配置的 CI/CD 配置的方法来自定义和覆盖引用的配置。`.codechina-ci.yml`文件中的本地配置会覆盖引用的配置。 #### `include`变量[](#variables-with-include) 你可以 在文件的部分中使用一些预定义的变量`include` `.codechina-ci.yml`: ```yaml include: project: '$CI_PROJECT_PATH' file: '.compliance-codechina-ci.yml' ``` #### `include:local` 使用`include:local`引用在同一个存储库中的`.codechina-ci.yml`文件。使用相对于根目录 (/) 的完整路径。 如果使用`include:local`,请确保`.codechina-ci.yml`文件和本地文件位于同一分支上。 你不能通过 Git 子模块路径包含本地文件。 所有嵌套的包含都在同一个项目的范围内执行,因此可以使用本地、项目、远程或模板引用。 例子: ```yaml include: - local: '/templates/.codechina-ci-template.yml' ``` 你还可以使用较短的语法来定义路径: ```yaml include: '.codechina-ci-production.yml' ``` 使用本地引用而不是符号链接。 ##### `include:local`带通配符文件路径 你可以在`include:local`中使用通配符路径(`*`和`**`)。 例子: ```yaml include: 'configs/*.yml' ``` 当流水线运行时: - 将`.yml`目录中的所有文件添加`configs`到流水线配置中。 - 不在`.yml`目录的子文件夹中添加文件`configs`。为此,请添加以下配置: ```yaml # This matches all `.yml` files in `configs` and any subfolder in it. include: 'configs/**.yml' # This matches all `.yml` files only in subfolders of `configs`. include: 'configs/**/*.yml' ``` #### `include:file` 要引用来自另一个私有项目的文件,请使用`include:file`。你仅可以将`include:file`与`include:project`组合使用。使用相对于根目录 (/)的完整路径。 例如: ```yaml include: - project: 'my-group/my-project' file: '/templates/.gitlab-ci-template.yml' ``` 你还可以指定一个`ref`, 如果不指定值,则 `ref` 默认为项目的 `HEAD`: ```yaml include: - project: 'my-group/my-project' ref: main file: '/templates/.gitlab-ci-template.yml' - project: 'my-group/my-project' ref: v1.0.0 file: '/templates/.gitlab-ci-template.yml' - project: 'my-group/my-project' ref: 787123b47f14b552955ca2786bc9542ae66fee5b # Git SHA file: '/templates/.gitlab-ci-template.yml' ``` 所有[嵌套的引用]((#nested-includes))都在目标项目的范围内执行。你可以使用本地(相对于目标项目)、项目、远程或模板引用。 ##### 一个项目中的多个文件 你可以引用来自同一项目的多个文件: ```yaml include: - project: 'my-group/my-project' ref: main file: - '/templates/.builds.yml' - '/templates/.tests.yml' ``` #### `include:remote`[](#includeremote) `include:remote`与完整 URL 一起使用,可以引用来自不同位置的文件。因为不支持远程 URL 中的身份验证,远程文件必须可通过 HTTP/HTTPS `GET`请求公开访问。例如: ```yaml include: - remote: 'https://codechina.csdn.net/example-project/-/raw/main/.codechina-ci.yml' ``` 所有嵌套引用都以公共用户身份在没有上下文的情况下执行,因此你只能使用`include`公共项目或模板。 #### `include:template`[](#includetemplate) 使用`include:template` 引用 `.codechina-ci.yml`模板。 例如: ```yaml # File sourced from the GitLab template collection include: - template: Auto-DevOps.codechina-ci.yml ``` 多个include:template文件: ```yaml include: - template: Android-Fastlane.codechina-ci.yml - template: Auto-DevOps.codechina-ci.yml ``` 所有[嵌套引用](#nested-includes)仅在用户许可的情况下执行,因此可以使用项目、远程或模板引用。 #### 嵌套引用[](#nested-includes) 使用嵌套引用来组成一组引用。最多可以有 100 个引用,但不能有重复的引用,解析所有文件的时间限制为 30 秒。 ## 关键字详情[](#keyword-details) 接下来,我们介绍如何通过关键字来配置 CI/CD 流水线。 ### `image`[](#image) 使用`image`指定用于流水线任务的 Docker 镜像。 更多: - 用法示例,请参见`.codechina-ci.yml`文件中的 定义 `image` 。 - 详细使用信息,参考 Docker 集成文档。 #### `image:name` 一个扩展 Docker 配置选项。 有关更多信息,请参阅 的可用设置image。 #### `image:entrypoint` 一个扩展 Docker 配置选项。 有关更多信息,请参阅 的可用设置image。 #### `services`[](#services) 使用`services`指定 Docker 镜像,链接到指定的基本镜像。 更多: - 用法示例,请参见`.codechina-ci.yml`文件中的定义`services`。 - 详细使用信息,参考Docker集成文档。 - 示例服务,请参阅GitLab CI/CD 服务。 ##### `services:name` 一个扩展 Docker 配置选项。 ##### `services:alias` 一个扩展 Docker 配置选项。 ##### `services:entrypoint` 一个扩展 Docker 配置选项。 ##### `services:command` 一个扩展 Docker 配置选项。 ### `script`[](#script) 使用`script`为 Runner 指定要执行的 shell 脚本。 除[触发器](#trigger)流水线任务外的所有流水线任务都需要一个`script`关键字。 例如: ```yaml job: script: "bundle exec rspec" ``` 你可以使用 YAML 锚点的 `script`. `script`关键字也可以包含一组命令: ```yaml job: script: - uname -a - bundle exec rspec ``` 有时,`script`命令必须用单引号或双引号括起来。例如,包含冒号 ( :) 的命令必须用单引号 ( ')括起来。YAML 解析器需要将文本解释为字符串而不是“键:值”对。 例如,此脚本中使用了冒号: ```yaml job: script: - curl --request POST --header 'Content-Type: application/json' "https://gitlab/api/v4/projects" ``` 要被视为有效的 YAML,你必须将整个命令用单引号括起来。如果命令已使用单引号,则应将它们更改为双引号 ( "): ```yaml job: script: - 'curl --request POST --header "Content-Type: application/json" "https://gitlab/api/v4/projects"' ``` 你可以使用[CI Lint](/docs/ci/lint)工具验证语法是否有效。 使用这些字符时也要小心: - `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` `` 如果任何脚本命令返回零以外的退出代码,则流水线任务失败并且不会执行进一步的命令。将退出代码存储在变量中以避免这种行为: ```yaml job: script: - false || exit_code=$? - if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi; ``` #### `before_script` 使用`before_script`定义应在每次流水线任务之前运行的命令组,但需要在`artifacts`恢复后。 你在 `before_script` 其中指定的脚本与你在 main `script` 中指定的任何脚本连接在一起。组合后的脚本在单个 shell 中一起执行。 `before_script`如果在流水线任务中定义它,则可以覆盖全局定义: ```yaml default: before_script: - echo "Execute this script in all jobs that don't already have a before_script section." job1: script: - echo "This script executes after the global before_script." job: before_script: - echo "Execute this script instead of the global before_script." script: - echo "This script executes after the job's `before_script`" ``` 可以在`before_script`中使用 YAML 锚点。 #### `after_script` 使用`after_script`定义每个流水线任务后运行命令组,包括失败的流水线任务。 如果流水线任务超时或被取消,则`after_script`不会执行。 你指定的`after_script`脚本在新 shell 中执行,与任何 `before_script`或`script`脚本分开 。通过这样: - 将当前流水线任务目录设置回默认值。 - 无法访问 `before_script` 或 `script` 中定义的脚本所做的更改,包括: - `script`脚本中导出的命令别名和变量。 - 工作树之外的更改(取决于运行程序执行程序),例如由 `before_script` 或 `script` 脚本安装的软件。 - 有一个单独的超时,它被硬编码为 5 分钟。 - 不影响流水线任务的退出代码。如果该`script`部分成功并且 `after_script`超时或失败,则流水线任务将退出并显示代码`0`( `Job Succeeded`)。 ```yaml default: after_script: - echo "Execute this script in all jobs that don't already have an after_script section." job1: script: - echo "This script executes first. When it completes, the global after_script executes." job: script: - echo "This script executes first. When it completes, the job's `after_script` executes." after_script: - echo "Execute this script instead of the global after_script." ``` 可以在`after_script`中使用 YAML 锚点。 #### `Script` 语法 你可以在`script`中使用语法来: - 将长命令拆分为多行命令。 - 使用颜色代码使流水线任务日志更易于查看。 - 创建自定义可折叠部分以简化流水线任务日志输出。 ### `stage`[](#stage) 使用`stage`定义在哪一个阶段运行流水线任务。流水线任务在同一 `stage` 可以并行执行(某些条件下)。 没有`stage`条目的流水线任务默认使用`test`阶段。如果没有在流水线中定义`stages` ,则可以使用 5 个默认阶段,它们按以下顺序执行: - [`.pre`](#pre-and-post) - `build` - `test` - `deploy` - [`.post`](#pre-and-post) 例如: ```yaml stages: - build - test - deploy job 0: stage: .pre script: make something useful before build stage job 1: stage: build script: make build dependencies job 2: stage: build script: make build artifacts job 3: stage: test script: make test job 4: stage: deploy script: make deploy job 5: stage: .post script: make something useful at the end of pipeline ``` #### 使用你自己的 Runner 当你使用自建的 Runner 时,默认情况下每个 Runner 一次仅运行一项流水线任务。如果流水线任务在不同的 Runner 上运行,它们可以并行运行。 如果你只有一个 Runner ,并且 Runner 的 `concurrent` 设置大于 1,则流水线任务可以并行运行。 #### `.pre` 和 `.post` 将`pre`和`post`用于需要在流水线中首先或最后运行的流水线任务。 - `.pre` 保证始终是流水线中的第一阶段。 - `.post` 保证始终是流水线中的最后阶段。 用户定义的阶段将在 `.pre` 之后和 `.post` 之前执行。 你必须在`.pre`或`.post`以外的至少一个阶段有一个流水线任务。 你不能更改 `.pre` 和 `.post` 的顺序,即使你在`.codechina-ci.yml`文件中不按顺序定义它们。例如,以下配置是等效的: ```yaml stages: - .pre - a - b - .post ``` ```yaml stages: - a - .pre - b - .post ``` ```yaml stages: - a - b ``` ### `extends`[](#extends) 使用 `extends` 重用配置部分。它是YAML 锚点的替代品, 并且更加灵活、有更强的可读性。你可以使用`extends`从引用的配置文件中重用配置。 在以下示例中,`rspec` 流水线任务使用 `.tests` 模板流水线任务中的配置。 系统会: - 根据键执行反向深度合并。 - 将 `.tests` 内容与 `rspec` 流水线任务合并。 - 不合并键的值。 ```yaml .tests: script: rake test stage: test only: refs: - branches rspec: extends: .tests script: rake rspec only: variables: - $RSPEC ``` 结果 `rspec` 的流水线任务是: ```yaml rspec: script: rake rspec stage: test only: refs: - branches variables: - $RSPEC ``` `.tests` 在这个例子中是一个[隐藏流水线任务](#hide-jobs),但也可以从常规流水线任务扩展配置。 `extends` 支持多级继承。你应该避免使用三个以上的级别,但你仍可以使用多达 11 个级别。以下示例具有两个继承级别: ```yaml .tests: only: - pushes .rspec: extends: .tests script: rake rspec rspec 1: variables: RSPEC_SUITE: '1' extends: .rspec rspec 2: variables: RSPEC_SUITE: '2' extends: .rspec spinach: extends: .tests script: rake spinach ``` 你也可以为 `extends` 设置多个父级。 #### 合并请求详情 你可以将 `extends` 用于合并散列但不能用于数组。用于合并的算法是“最接近的范围获胜”,因此来自最后一个成员的键值总是覆盖其他级别上定义的任何内容。例如: ```yaml .only-important: variables: URL: "http://my-url.internal" IMPORTANT_VAR: "the details" only: - main - stable tags: - production script: - echo "Hello world!" .in-docker: variables: URL: "http://docker-url.internal" tags: - docker image: alpine rspec: variables: GITLAB: "is-awesome" extends: - .only-important - .in-docker script: - rake rspec ``` 结果 `rspec` 的流水线任务是: ```yaml rspec: variables: URL: "http://docker-url.internal" IMPORTANT_VAR: "the details" GITLAB: "is-awesome" only: - main - stable tags: - docker image: alpine script: - rake rspec ``` 在这个例子中: - 这些`variables`部分合并,但`URL: "http://docker-url.internal"` 覆盖 `URL: "http://my-url.internal"` - `tags: ['docker']` 覆盖 `tags: ['production']` - `script` 不合并,但 `script: ['rake rspec']` 覆盖 `script: ['echo "Hello world!"']`。你可以使用YAML 锚点来合并数组。 #### `extends` 和 `include` 一起使用 要重用来自不同配置文件的配置,你可以将 `extends` 和 `include` 结合起来使用。 在以下示例中,`script` 在`included.yml`文件中定义了`a` 。然后,在`.codechina-ci.yml`文件中,`extends`引用了以下`script`内容: - `included.yml`: ```yaml .template: script: - echo Hello! ``` - `. codechina-ci.yml`: ```yaml include: included.yml useTemplate: image: alpine extends: .template ``` ### `rules`[](#rules) `rules` 用于在流水线中添加或排除流水线任务。 `rules` 按顺序评估,直到第一次匹配。找到匹配项后,会将该流水线任务包含在流水线中或从流水线中排除,取决于具体的配置。流水线任务还可以添加[某些属性](#rules-attributes)。 `rules` 替换 [`only/except`](#only--except) ,并且它们不能在同一个流水线任务中一起使用。如果你在一个流水线任务配置为使用这两个关键字,则 `linter` 会返回 `key may not be used with rules` 的错误提示。 #### Rules attributes[](#rules-attributes) `rules` 中你可以使用的流水线任务属性是: - `when`: 如果未定义,则默认为 `when: on_success`。 - 如果用作`when: delayed`,`start_in`也是必需的。 - `allow_failure`: 如果未定义,则默认为 `allow_failure: false`。 - `variables`: 如果未定义,则使用别处定义的变量。 如果 `rules` 评估为真,并且 `when` 具有除 `never` 之外的任何值,则流水线任务将包含在流水线中。 例如: ```yaml docker build: script: docker build -t my-image:$CI_COMMIT_REF_SLUG . rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: delayed start_in: '3 hours' allow_failure: true ``` #### `Rules` 条款 可用的`Rules` 条款有: | 条款 | 描述 | |---------|----------| | [`if`](#rulesif) | 通过评估`if`语句向流水线中添加或排除流水线任务。类似于 [`only:variables`](#onlyvariables--exceptvariables) | | [`changes`](#ruleschanges) | 根据更改的文件从流水线中添加或排除流水线任务。与 [`only:changes`](#onlychanges--exceptchanges) 相同 | | [`exists`](#rulesexists) | 根据特定文件的存在与否向流水线中添加或排除流水线任务 | `rules` 按顺序进行评估,直到找到匹配项。如果找到匹配项,则会检查属性以查看是否应将流水线任务添加到流水线中。如果未定义属性,则默认值为: - `when: on_success` - `allow_failure: false` 流水线任务被添加到流水线中: - 如果 `rules` 匹配并且具有 `when: on_success`, `when: delayed` 或 `when: always` - 如果没有 `rules` 匹配,但最后一个子句是 `when: on_success`, `when: delayed` 或 `when: always`(没有 `rules` ) 流水线任务未添加到流水线中: - 如果没有 `rules` 匹配,并且没有独立的 `when: on_success`,`when: delayed` 或 `when: always` - 如果 `rules` 匹配,并且具有 `when: never` 作为属性 以下示例用于`if`严格限制流水线任务何时运行: ```yaml 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` (默认) - 在所有其他情况下,没有规则匹配,因此不会将流水线任务添加到任何其他流水线。 或者,你可以定义一组在少数情况下排除流水线任务的 `rules`,但在所有其他情况下运行它们: ```yaml 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`。 > 如果你使用 `when:` 条款作为最终规则(不包括 `when: never`),则可能会同时启动两个流水线。推送流水线和合并请求流水线都可以由同一事件触发(推送到源分支以获取开放合并请求)。 #### 避免重复的流水线[](#avoid-duplicate-pipelines) 如果流水线任务使用rules,则单个操作(例如将提交推送到分支)可以触发多个流水线。你不必为多种类型的流水线显式配置规则来意外触发它们。 例如: ```yaml job: script: echo "This job creates double pipelines!" rules: - if: '$CUSTOM_VARIABLE == "false"' when: never - when: always ``` 当`$CUSTOM_VARIABLE` 是 `false`时此流水线任务不运行,但它在所有其他流水线中运行,包括推(分支)和合并请求两个流水线。使用此配置,每次推送到开放合并请求的源分支都会导致重复的流水线。 为避免重复流水线,你可以: - 使用 `CI_OPEN_MERGE_REQUESTS` CI/CD 变量 `workflow:rules` 在分支和合并请求流水线之间进行切换,而不产生重复的流水线。你还可以在单​​个流水线任务规则中使用此变量。 - 使用 `workflow` 指定只在分支流水线或只在合并请求流水线中运行。 - 重写规则以仅在非常特定的情况下运行流水线任务,并避免最终的 `when:` 规则: ```yaml job: script: echo "This job does NOT create double pipelines!" rules: - if: '$CUSTOM_VARIABLE == "true" && $CI_PIPELINE_SOURCE == "merge_request_event"' ``` 你还可以通过更改流水线任务规则来避免重复流水线,以避免推送(分支)流水线或合并请求流水线。但是,如果你使用没有规则` workflow: rules` 的 `- when: always`,系统仍会显示流水线警告。 例如,以下不会触发双流水线,但不推荐没有`workflow: rules`: ```yaml job: script: echo "This job does NOT create double pipelines!" rules: - if: '$CI_PIPELINE_SOURCE == "push"' when: never - when: always ``` 你不应在同一流水线任务中同时包含推送和合并请求流水线的 `workflow:rules`,以免防止重复流水线: ```yaml 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` 可能会导致一些难以解决的问题: ```yaml 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` 在除合并请求之外的所有情况下都会运行。 #### `rules:if` 使用 `rules:if` 条款指定何时向流水线添加流水线任务: - 如果if语句为真,则将流水线任务添加到流水线中。 - 如果某个if语句为真,但与 `when: never` 结合使用,则不会将流水线任务添加到流水线中。 - 如果没有任何if语句为真,则不会将流水线任务添加到流水线中。 `rules:if` 与 `only:variables` 略有不同,它的每个规则只接受一个表达式字符串而不是数组。任何一组要计算的表达式都可以通过使用 `&&` 或 `||` ,以及变量匹配运算符 (`==`, `!=`, `=~` 和 `!~`) 连成一个表达式。 与 `script` 中的变量不同,规则表达式中的变量始终格式为 `$VARIABLE`。 `if:` 条款根据预定义 CI/CD 变量 或自定义 CI/CD 变量的值进行评估。 例如: ```yaml job: script: echo "Hello, Rules!" rules: - if: '$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' 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 ``` 有关确定 `when` 流水线任务的逻辑的一些详细信息: - 如果提供的规则都不匹配,则流水线任务将设置为 `when: never` 并且不包含在流水线中。 - 没有任何条款的规则,例如 `when` 或 `allow_failure` 规则没有 `if` 或者没有 `changes`,总是匹配,并且总是在符合时使用。 - 如果规则匹配到并且未定义 `when`,则使用 `when` 规则定义的流水线任务,,且未定义的情况下默认为 `on_success`。 - 你可以为每个规则定义一次 `when`,也可以在流水线任务级别定义一次,这将适用于所有规则。你不能在流水线任务级别 `when` 与规则 `when` 混合使用。 ##### `rules` 的通用 `if` 条款 对于类似于 `only/except` 关键字的行为,你可以检查 `$CI_PIPELINE_SOURCE` 变量的值: | 值 | 描述| |-----|-----------| | `api` | 由 pipelines API 触发的流水线 | | `chat` | 使用 GitLab ChatOps 命令创建的流水线 | | `external` | 当你使用 GitLab 以外的 CI 服务 | | `external_pull_request_event` | 在 GitHub 上创建或更新外部拉取请求时 | | `merge_request_event` | 对于在创建或更新合并请求时创建的流水线。需要启用合并请求流水线、合并结果流水线和 `merge trains` | | `parent_pipeline` | 对于由带有 `rules` 的父/子流水线触发的流水线。在子流水线配置中使用此流水线源,以便它可以由父流水线触发 | | `pipeline` | 对于通过使用带有`CI_JOB_TOKEN`的API创建的多项目流水线,或[ `trigger`](#trigger) 关键字 | | `push` | 对于由“git push”事件触发的流水线,包括分支和标签 | | `schedule` | 计划流水线 | | `trigger` | 对于使用 `trigger token` 创建的流水线 | | `web` | 对于使用 UI 中的 **流水线** 按钮创建的流水线,来自项目的 **Devops > 流水线** 部分 | | `webide` | 对于使用 `WebIDE` 创建的流水线 | 以下示例在计划的流水线或推送中将流水线任务作为手动流水线任务运行流水线(到分支或标签),带有 `when: on_success`(默认)。它不会将流水线任务添加到任何其他流水线类型。 ```yaml job: script: echo "Hello, Rules!" rules: - if: '$CI_PIPELINE_SOURCE == "schedule"' when: manual allow_failure: true - if: '$CI_PIPELINE_SOURCE == "push"' ``` 以下示例中当 `when: on_success` 时将在合并请求流水线和计划流水线运行流水线任务 。它不会在任何其他流水线类型中运行。 ```yaml 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: '$CUSTOM_VARIABLE !~ /regex-expression/'`: 如果自定义变量 `CUSTOM_VARIABLE` **不** 匹配正则表达式。 - `if: '$CUSTOM_VARIABLE == "value1"'`:如果自定义变量 `CUSTOM_VARIABLE` 值 正是`value1`。 #### `rules:changes` 使用 `rules:changes` 当改特定文件时将流水线任务添加到流水线。 `rules: changes` 的工作方式与 [`only: changes` 和 `except: changes`](#onlychanges--exceptchanges) 相同。它接受一组路径。你应该只对分支使用 `rules: changes` 流水线或合并请求流水线。例如,通常对合并请求流水线使用`rules: changes`: ```yaml 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 ``` 在这个例子中: - 如果流水线是合并请求流水线,将检查 `Dockerfile` 是否有更改。 - 如果 `Dockerfile` 已更改,则将流水线任务作为手动流水线任务添加到流水线中,并且流水线 即使流水线任务没有被触发(`allow_failure: true`)也会继续运行。 - 如果 `Dockerfile` 没有改变,则不会向任何流水线添加流水线任务(与 `when: never` 相同)。 要将 `rules: changes` 用于分支流水线而不是合并请求流水线,将之前示例中的 `if:` 子句更改为: ```yaml rules: - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH ``` 要实现类似于 [`except:changes`](#onlychanges--exceptchanges) 的规则, 使用 `when: never`。 > 你可以将 `rules: changes` 与其他流水线类型一起使用,但不推荐使用。因为当没有 Git `push` 事件时,`rules: changes` 总是评估为 `true`。标记流水线、计划流水线等**没有**有 Git `push` 事件 与他们有关。`rules: changes` 流水线任务**始终**添加到这些流水线中,如果没有 `if:` 语句将流水线任务限制为分支或合并请求流水线的话。 ##### `rules:changes` 中的变量 你可以在 `rules:changes` 表达式中使用 CI/CD 变量来确定何时向流水线添加流水线任务: ```yaml docker build: variables: DOCKERFILES_DIR: 'path/to/files/' script: docker build -t my-image:$CI_COMMIT_REF_SLUG . rules: - changes: - $DOCKERFILES_DIR/* ``` 你可以将 `$` 字符用于变量和路径。例如,如果 `$DOCKERFILES_DIR` 变量存在,它的值被使用。如果不存在,则 `$` 被解释为路径的一部分。 #### `rules:exists` 当存储库中存在某些文件时,使用 `exists` 来运行流水线任务。你可以使用一组路径。 在以下示例中,如果存储库中的任何位置存在 `Dockerfile`,`job` 就会运行: ```yaml job: script: docker build -t my-image:$CI_COMMIT_REF_SLUG . rules: - exists: - Dockerfile ``` `exists` 的路径相对于项目目录 (`$CI_PROJECT_DIR`),不能直接链接到项目目录之外。 你可以使用 [glob](https://en.wikipedia.org/wiki/Glob_(programming)) 的模式在存储库中匹配任何目录中的多个文件: ```yaml job: script: bundle exec rspec rules: - exists: - spec/**.rb ``` Glob 模式用 Ruby 解释 [`File.fnmatch`](https://docs.ruby-lang.org/en/2.7.0/File.html#method-c-fnmatch) 带有标志 `File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB`。 出于性能原因,最多匹配 10,000 个 `exists` 模式。在第 10,000 次检查之后,带有 glob 的规则将始终匹配。 #### `rules:allow_failure` 你可以在 `rules:` 中使用 [`allow_failure: true`](#allow_failure) 来允许流水线任务失败,或等待一个手动流水线任务的操作,而不停止流水线本身。所有使用 `rules:` 的流水线任务在你没有定义 `allow_failure:`的情况下默认为 `allow_failure: false`。 规则级别的 `rules:allow_failure` 选项覆盖流水线任务级别 [`allow_failure`](#allow_failure) 选项,仅在特定规则触发流水线任务后进行。 ```yaml job: script: echo "Hello, Rules!" rules: - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' when: manual allow_failure: true ``` 在此示例中,如果第一条规则匹配,则流水线任务具有 `when: manual` 和 `allow_failure: true`。 #### `rules:variables` 在 `rules:` 中使用 [`variables`](#variables) 来定义特定条件的变量。 例如: ```yaml job: variables: DEPLOY_VARIABLE: "default-deploy" rules: - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH variables: # Override DEPLOY_VARIABLE defined DEPLOY_VARIABLE: "deploy-production" # at the job level. - if: $CI_COMMIT_REF_NAME =~ /feature/ variables: IS_A_FEATURE: "true" # Define a new variable. script: - echo "Run script with $DEPLOY_VARIABLE as an argument" - echo "Run another script if $IS_A_FEATURE exists" ``` #### 复杂规则条款 要将 `if` 、 `changes` 和 `exists` 条款用 `AND` 连接起来,并用在同一条规则中。 在以下示例中: - 如果 `Dockerfile` 文件或 `/docker/scripts` 中的任何文件发生了变化,并且 `$VAR` == "string value",则流水线任务手动运行 - 否则,流水线任务不包含在流水线中。 ```yaml docker build: script: docker build -t my-image:$CI_COMMIT_REF_SLUG . rules: - if: '$VAR == "string value"' changes: # Include the job and set to when:manual if any of the follow paths match a modified file. - Dockerfile - docker/scripts/* when: manual # - "when: never" would be redundant here. It is implied any time rules are listed. ``` 诸如 `branches` 或 `refs` 之类的关键字可用于 `only`/`except`,但在 `rules` 中不可用。 你可以使用括号 `[]` 和 `&&` 和 `||` 来构建更复杂的变量表达式。 ```yaml job1: script: - echo This rule uses parentheses. rules: if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE ``` ### `only` / `except`[](#only--except) 你可以使用 `only` 和 `except` 来控制何时向流水线添加流水线任务。 - 使用 `only` 来定义流水线任务何时运行。 - 使用 `except` 定义流水线任务何时 **不** 运行。 四个关键字可以与 `only` 和 `except` 一起使用: - [`refs`](#onlyrefs--exceptrefs) - [`变量`](#onlyvariables--exceptvariables) - [`changes`](#onlychanges--exceptchanges) - [`kubernetes`](#onlykubernetes--exceptkubernetes) #### `only:refs` / `except:refs` 使用 `only:refs` 和 `except:refs` 关键字来控制何时将流水线任务添加到基于分支名称或流水线类型的流水线。 **关键字类型**:流水线任务关键字。你只能将其用作流水线任务的一部分。 **可能的输入**:包含任意数量的数组: - 分支名称,例如`main` 或`my-feature-branch`。 - 正则表达式匹配分支名称,例如`/^feature-.*/`。 - 以下关键词: | **关键词** | **说明** | | -------------------------|-----------------| | `api` | 对于由 pipelines API 触发的流水线 | | `branches` | 当流水线的 Git 引用是分支时 | | `chat` | 对于使用 ChatOps命令创建的流水线 | | `external` | 当你使用 GitLab 以外的 CI 服务时 | | `external_pull_requests` | 在 GitHub 上创建或更新外部拉取请求时 | | `merge_request` | 对于在创建或更新合并请求时创建的流水线。启用合并请求流水线、合并的结果流水线 和 `merge trains` | | `pipelines` | 对于通过使用带有`CI_JOB_TOKEN`的API创建的多项目流水线,或[ `trigger`](#trigger) 关键字 | | `push` | 对于由“git push”事件触发的流水线,包括分支和标签 | | `schedules` | 计划流水线 | | `tags` | 当流水线的 Git 引用是标签时 | | `triggers` | 对于使用 `trigger token` 创建的流水线 | | `web` | 对于使用 UI 中的 **流水线** 按钮创建的流水线,来自项目的 **DevOps > 流水线** 部分 | **`only:refs` 和 `except:refs` 示例**: ```yaml job1: script: echo only: - main - /^issue-.*$/ - merge_requests job2: script: echo except: - main - /^stable-branch.*$/ - schedules ``` **更多细节:** - 计划流水线在特定分支上运行,因此流水线任务配置为 `only: branch` 也可以计划流水线上运行。添加 `except: schedules` 以防止使用 `only: branch` 的流水线任务在预定流水线上运行。 - `only` 或 `except` 不使用任何其他关键字等价于 `only: refs` 或 `except: refs`。比如下面两个job的配置是一样的行为: ```yaml job1: script: echo only: - branches job2: script: echo only: refs: - branches ``` - 如果流水线任务不使用 `only`、`except` 或 [`rules`](#rules),则 `only` 默认设置为 `branches` 和`tag`。 例如,`job1` 和 `job2` 是等价的: ```yaml job1: script: echo 'test' job2: script: echo 'test' only: - branches - tags ``` #### `only:variables` / `except:variables` 使用 `only:variables` 或 `except:variables` 关键字来控制何时添加流水线任务 到流水线,基于 [CI/CD 变量](/docs/ci/vaiables) 的状态。 **关键字类型**:流水线任务关键字。你只能将其用作流水线任务的一部分。 **可能的输入**:[CI/CD 变量表达式](/docs/ci/variabless#cicd-variable-expressions) 的数组。 **`only:variables` 示例**: ```yaml deploy: script: cap staging deploy only: variables: - $RELEASE == "staging" - $STAGING ``` #### `only:changes` / `except:changes` 当 Git 推送事件修改文件时,使用 `changes` 关键字和 `only` 来运行一个流水线任务,或者使用 `except` 来跳过一个流水线任务。 在具有以下引用的流水线中使用`changes`: - `分支` - `external_pull_requests` - `merge_requests` **关键字类型**:流水线任务关键字。你只能将其用作流水线任务的一部分。 **可能的输入**:包含任意数量的数组: - 文件路径。 - 单个目录的通配符路径,例如`path/to/directory/*`,或一个目录及其所有子目录,例如`path/to/directory/**/*`。 - 通配符 ([glob](https://en.wikipedia.org/wiki/Glob_(programming))) 所有路径具有相同扩展名或多个扩展名的文件,例如 `*.md` 或 `path/to/directory/*.{rb,py,sh}`。 - 根目录或所有目录中文件的通配符路径,用双引号括起来。例如`"*.json"` 或`"**/*.json"`。 **`only:changes` 示例**: ```yaml docker build: script: docker build -t my-image:$CI_COMMIT_REF_SLUG . only: refs: - branches changes: - Dockerfile - docker/scripts/* - dockerfiles/**/* - more_scripts/*.{rb,py,sh} ``` **更多细节**: - 如果你使用除 `branches`、`external_pull_requests` 或 `merge_requests` 以外的引用,`changes` 无法确定给定文件是新文件还是旧文件,并且总是返回 `true`。 - 如果你将 `only: changes` 与其他引用一起使用,流水线任务将忽略更改并始终运行。 - 如果你将 `except: changes` 与其他引用一起使用,流水线任务将忽略更改并且 #### `only:kubernetes` / `except:kubernetes` 当 Kubernetes 服务在项目中处于活动状态时,使用 `only:kubernetes` 或 `except:kubernetes` 来控制是否将流水线任务添加到流水线中。 **关键字类型**:特定于流水线任务。你只能将其用作流水线任务的一部分。 **可能的输入**:`kubernetes` 策略只接受 `active` 关键字。 **`only:kubernetes` 示例**: ```yaml deploy: only: kubernetes: active ``` 在此示例中,`deploy` 流水线任务仅在 Kubernetes 服务处于活动状态时运行在项目中。 ### `needs`[](#needs) 使用 `needs:` 来乱序执行流水线任务。流水线任务之间的关系可使用 `needs` 可视化为有向无环图。 你可以忽略阶段排序并运行一些流水线任务,而无需等待其他流水线任务完成。多个阶段的流水线任务可以同时运行。 以下示例创建四个执行路径: - Linter:`lint` 流水线任务立即运行,无需等待 `build` 阶段完成,因为它没有需求(`needs: []`)。 - Linux 路径:`linux:rspec` 和 `linux:rubocop` 流水线任务在 `linux:build` 运行后立即运行,流水线任务无需等待`mac:build`完成即可完成。 - macOS 路径:`mac:rspec` 和 `mac:rubocop` 流水线任务在 `mac:build` 运行后立即运行,流水线任务完成,无需等待 `linux:build` 完成。 - `production` 流水线任务在所有先前流水线任务完成后立即运行,即:`linux:build`、`linux:rspec`、`linux:rubocop`、`mac:build`、`mac:rspec`、`mac:rubocop`。 ```yaml linux:build: stage: build mac:build: stage: build lint: stage: test needs: [] linux:rspec: stage: test needs: ["linux:build"] linux:rubocop: stage: test needs: ["linux:build"] mac:rspec: stage: test needs: ["mac:build"] mac:rubocop: stage: test needs: ["mac:build"] production: stage: deploy ``` #### 要求和限制 - 在 GitLab 13.9 及更早版本中,如果 `needs:` 指的是因 `only`、`except` 或 `rules` 等可能不会添加到的流水线任务,则流水线可能无法创建。 - `needs:` 数组中单个流水线任务可以需要的最大流水线任务数是有限的,限制是:50。 - 如果 `needs:` 是指使用 [`parallel`](#parallel) 关键字的流水线任务,这取决于并行创建的所有流水线任务,而不仅仅是一项流水线任务。它也下载默认情况下来自所有并行流水线任务的 `artifacts`。如果 `artifacts` 有相同的名称,它们会相互覆盖,并且只保存最后下载的一个。 - `needs:` 类似于 `dependencies:`,因为它必须使用先前阶段的流水线任务,这意味着不可能创建循环依赖项。根据流水线任务当前阶段也不可能。 - 必须为所有有关键字 `needs:` 或被其引用的流水线任务明确定义阶段。 #### 使用 `needs` 下载 `artifacts` 当流水线任务使用 `needs` 时,默认情况下它不再下载前一阶段的所有 `artifacts`,因为具有 `medds` 的流水线任务可以在早期阶段完成之前开始。当存在 `needs` 时,你只能从 `needs:` 配置中列出的流水线任务下载 `artifacts`。 使用 `artifacts: true`(默认值)或 `artifacts: false` 在出现在使用 `needs` 的流水线任务中来控制何时下载 `artifacts`。 在以下示例中,`rspec` 流水线任务下载了 `build_job` 的 `artifacts`,但是`rubocop` 流水线任务不会: ```yaml build_job: stage: build artifacts: paths: - binaries/ rspec: stage: test needs: - job: build_job artifacts: true rubocop: stage: test needs: - job: build_job artifacts: false ``` 在以下示例中,`rspec` 流水线任务从所有三个 `build_jobs` 中下载 `artifacts`。其中 `artifacts` 设置为: - 对 `build_job_1` 设置为 `true`。 - 对于 `build_job_2` 和 `build_job_3`,默认为 `true`。 ```yaml rspec: needs: - job: build_job_1 artifacts: true - job: build_job_2 - build_job_3 ``` #### `needs` 跨项目下载 `artifacts` 流水线中使用 `needs` 从最多五个流水线任务下载 `artifacts`: - [在同一项目中的其他 ref](#artifact-downloads-between-pipelines-in-the-same-project) - 在不同的项目、组和命名空间中 ```yaml build_job: stage: build script: - ls -lhR needs: - project: namespace/group/project-name job: build-1 ref: main artifacts: true ``` `build_job` 从 `group/project-name` 项目的 `main` 分支上最新成功的 `build-1` 流水线任务下载 `artifacts`。如果项目在 相同的组或命名空间,你可以从 `project:` 关键字中省略它们。例如, `project: group/project-name` 或 `project: project-name`。 运行流水线的用户必须至少具有对组或项目的`Reporter`访问权限,或者组/项目是公开可见的。 ##### 同一项目中流水线间的 `artifacts` 下载 使用 `needs` 从当前项目中的不同流水线下载 `artifacts`。将 `project` 关键字设置为当前项目的名称,并指定一个 `ref`。 在以下示例中,`build_job` 从 ref 为 `other-ref` 的 `build-1` 流水线任务下载最新成功的 `artifacts`: ```yaml build_job: stage: build script: - ls -lhR needs: - project: group/same-project-name job: build-1 ref: other-ref artifacts: true ``` `project:`、`job:` 和 `ref` 也支持 CI/CD 变量形式的参数。 例如: ```yaml build_job: stage: build script: - ls -lhR needs: - project: $CI_PROJECT_PATH job: $DEPENDENCY_JOB_NAME ref: $ARTIFACTS_DOWNLOAD_REF artifacts: true ``` 你无法从 [`parallel:`](#parallel) 中运行的流水线任务下载 `artifacts`。 要在父子流水线之间下载 `artifacts`,使用 [`needs:pipeline`](#artifact-downloads-to-child-pipelines)。 你不应从相同的 ref 下正在运行的流水线下载 `artifacts`,在同一个 ref 上运行的流水线可能会覆盖 `artifacts`。 ##### `artifacts` 下载到子流水线 子流水线可以从它的父流水线或同一父流水线中的另一个子流水线流水线任务中下载 `artifacts`。 例如,以下是一个会创建一些 `artifacts` 的父流水线: ```yaml create-artifact: stage: build script: echo 'sample artifact' > artifact.txt artifacts: paths: [artifact.txt] child-pipeline: stage: test trigger: include: child.yml strategy: depend variables: PARENT_PIPELINE_ID: $CI_PIPELINE_ID ``` 子流水线中的流水线任务可以从父流水线:`create-artifact` 流水线任务中下载 `artifacts`: ```yaml use-artifact: script: cat artifact.txt needs: - pipeline: $PARENT_PIPELINE_ID job: create-artifact ``` `pipeline` 接受一个流水线 ID,它必须是一个存在于给定流水线的相同父流水线层次结构中的流水线。 `pipeline` 不接受当前的流水线 ID (`$CI_PIPELINE_ID`)。如果要从当前流水线中的流水线任务下载 `artifacts`,请使用 `needs` 的基本形式。 #### 可选 `needs` 如果需要的是流水线中有时不存在的流水线任务,请在 `needs` 配置中添加 `optional: true`。如果未定义,`optional: false` 是默认值。 使用 [`rules`](#rules)、[`only` 或 `except`](#only--except) 的流水线任务可能并不总是存在于流水线中。当流水线启动时,在运行之前它会检查 `needs` 的关系。如果没有设置`optional: true`,且需要的关系指向不存在的流水线任务时会阻止流水线启动并导致流水线产生一个类似如下错误: - `'job1' job needs 'job2' job, but it was not added to the pipeline` 在下面这个例子中: - 当分支为默认分支时,流水线中存在 `build` 流水线任务,`rspec` 流水线任务在开始之前等待它完成。 - 当分支不是默认分支时,流水线中不存在 `build` 流水线任务。`rspec` 流水线任务立即运行(类似于 `needs: []`),因为它的 `needs` 与 `build` 流水线任务的关系是可选的。 ```yaml build: stage: build rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH rspec: stage: test needs: - job: build optional: true ``` ### `tags`[](#tags) 使用 `tags` 从所有的 Runner 列表中选择一个特定的可用于项目的 Runner。 当你注册 Runner 时,你可以指定 Runner 的 tag,比如`ruby`、`postgres`、`development`等。 在以下示例中,流水线任务由同时定义了 `ruby` 和 `postgres` tag 的 Runner 运行。 ```yaml job: tags: - ruby - postgres ``` 你可以使用 tag 在不同平台上运行不同的流水线任务。比如,如果你有一个带有 `osx` 标签的 OS X Runner 和一个带有 `windows` 标签的 Windows Runner,你可以通过以下设置在每个平台上运行一个流水线任务: ```yaml windows job: stage: - build tags: - windows script: - echo Hello, %USERNAME%! osx job: stage: - build tags: - osx script: - echo "Hello, $USER!" ``` ### `allow_failure`[](#allow_failure) 当你想让流水线任务失败而不影响 CI 组合的其余部分时,请使用 `allow_failure`。它的默认值为 `false`,[manual](#whenmanual) 使用 `when: manual` 语法时除外。 在使用 [`rules:`](#rules) 的流水线任务中,所有流水线任务默认为 `allow_failure: false`,*包括* `when: manual` 流水线任务。 当 `allow_failure` 设置为 `true` 并且流水线任务失败时,流水线任务会在 UI 中显示橙色警告。但是,流水线的逻辑流仍会将流水线任务视为 成功/通过,并且该流水线不会被 block。 假设所有其他流水线任务都成功,​​流水线任务的 stage 及其流水线显示相同的橙色警告。但是,与之关联的提交被标记为 `passed`,并且没有警告提示。 在以下示例中,`job1` 和 `job2` 并行运行,如果 `job1` 失败,它不会停止下一个阶段的运行,因为它被标记为 `allow_failure: true`: ```yaml job1: stage: test script: - execute_script_that_will_fail allow_failure: true job2: stage: test script: - execute_script_that_will_succeed job3: stage: deploy script: - deploy_to_staging ``` #### `allow_failure:exit_codes` 使用 `allow_failure:exit_codes` 动态控制是否应该允许流水线任务失败。你可以列出哪些退出代码不被视为失败。对于任何其他退出代码,流水线任务失败: ```yaml test_job_1: script: - echo "Run a script that results in exit code 1. This job fails." - exit 1 allow_failure: exit_codes: 137 test_job_2: script: - echo "Run a script that results in exit code 137. This job is allowed to fail." - exit 137 allow_failure: exit_codes: - 137 - 255 ``` ### `when`[](#when) 使用 `when` 来实现在失败或不管失败的情况下运行的流水线任务。 `when` 的有效值为: 1. `on_success`(默认)- 只有在早期阶段的所有流水线任务都成功时才执行流水线任务,或者当它们设置了 `allow_failure: true` 时,总是视作成功的。 1. `on_failure` - 仅在较早阶段的至少一项流水线任务失败时才执行流水线任务。 1. `always` - 无论早期阶段的流水线任务状态如何,都执行流水线任务。 1. `manual` - [手动](#whenmanual) 执行流水线任务。 1. `delayed` - [延迟流水线任务的执行](#whendelayed) 指定的持续时间。 1. `never`: - 使用流水线任务 [`rules`](#rules),不执行流水线任务。 - 使用 [`workflow:rules`](#workflow),不运行流水线。 在以下示例中,脚本代码: 1. 只有当 `build_job` 失败时才执行 `cleanup_build_job`。 1. 始终执行 `cleanup_job` 作为流水线的最后一步,不管成功或失败。 1. 在 UI 中手动运行时执行 `deploy_job`。 ```yaml stages: - build - cleanup_build - test - deploy - cleanup build_job: stage: build script: - make build cleanup_build_job: stage: cleanup_build script: - cleanup build when failed when: on_failure test_job: stage: test script: - make test deploy_job: stage: deploy script: - make deploy when: manual cleanup_job: stage: cleanup script: - cleanup after jobs when: always ``` #### `when:manual`[](#whenmanual) 手动流水线任务是一种不会自动执行的流水线任务,它必须由用户启动。你可能希望将手动流水线任务用于部署到生产之类的事情。 要实现一个手动的流水线,请将 `when: manual` 添加到其配置中。 流水线启动时,手动流水线任务显示为已跳过且不会自动运行。它们可以从流水线、流水线任务、环境和部署视图中启动执行。 手动流水线任务可以是可选的或阻塞的: - **可选**:手动流水线任务默认设置为 [`allow_failure: true](#allow_failure) 并且被认为是可选的。可选手工流水线任务的状态并不影响整体的流水线状态。即使所有手动流水线任务都失败,流水线也可以成功运行。 - **阻塞**:要将手动流水线任务设置为阻塞,请将 `allow_failure: false` 添加到其配置中。阻塞的手动流水线任务会在其被定义的下一阶段停止流水线的进一步执行。要让流水线继续运行,请单击阻塞手动流水线任务上的 **{play}** 按钮。 项目中设置了流水线成功时合并的合并请求在有流水线阻塞的情况下无法合并。阻塞的流水线显示 **阻塞** 的状态。 当你使用 [`rules:`](#rules) 时,`allow_failure` 的值默认为 `false`,包括手动流水线任务。 要触发手动流水线任务,用户必须具有合并到指定分支的权限。你可以使用 [保护分支](/docs/user/project/protected-branch) 来更限制未经授权的用户运行[保护手动部署](#protecting-manual-jobs)。 ##### 保护手工流水线任务[](#protecting-manual-jobs) 使用受保护的环境定义授权运行手动流水线任务的用户列表。你只能授权与受保护环境关联以触发手动流水线任务的用户,这样做的目的是: - 更精确地限制可以部署到环境的人员。 - 阻止流水线,直到获得批准的用户“批准”它。 要保护手动流水线任务: 1. 为流水线任务添加一个 `environment`。例如: ```yaml deploy_prod: stage: deploy script: - echo "Deploy to production server" environment: name: production url: https://example.com when: manual only: - main ``` 2. 在受保护的环境设置中,选择环境(本例中为 `production`)并添加用户、角色或组到被授权触发手动流水线任务到 **Allowed to Deploy** 列表。只有那些在此列表可以触发此手动流水线任务。 你可以使用具有阻止手动流水线任务的受保护环境来获得用户列表允许批准以后的流水线阶段。将 `allow_failure: false` 添加到受保护的手动流水线任务和流水线的下一阶段仅在手动流水线任务被由授权用户触发后运行。 #### `when:delayed`[](#whendelayed) 使用 `when: delay` 在等待期后执行脚本,或者如果你想避免流水线任务立即进入 `pending` 状态。 你可以使用 `start_in` 关键字设置时间范围。`start_in` 的值是以秒为单位的时间范围,除非提供了时间单位。`start_in` 必须小于或等于 1 周。有效值的示例包括: - `'5'` - `5 seconds` - `30 minutes` - `1 day` - `1 week` > Delay 设置的时间不计算在流水线用量中,但默认流水线超时时间为60分钟,建议不要设置过长,否则会因为超时导致流水线的失败。 当阶段包含延迟流水线任务时,流水线在延迟流水线任务完成之前不会进行。你可以使用此关键字在不同阶段之间插入延迟。 延迟流水线任务的计时器在前一阶段完成后立即启动。与其他类型的流水线任务类似,除非前一阶段通过,否则延迟流水线任务的计时器不会启动。 以下示例创建了一个名为 `timed rollout 10%` 的流水线任务,该流水线任务在前一阶段完成 30 分钟后执行: ```yaml timed rollout 10%: stage: deploy script: echo 'Rolling out 10% ...' when: delayed start_in: 30 minutes ``` 要停止延迟流水线任务的活动计时器,请单击 **{time-out}** (**Unschedule**) 按钮。之后,将无法再安排此流水线任务自动运行。但是,你可以手动执行流水线任务。 要立即开始延迟流水线任务,请单击 **play** 按钮。很快,Runner 将接手并开始工作。 ### `environment`[](#environment) 使用 `environment` 定义流水线任务部署到的环境。 例如: ```yaml deploy to production: stage: deploy script: git push production HEAD:main environment: production ``` 你可以使用以下方法为 `environment` 关键字进行赋值: - 纯文本,如 `production`。 - 变量,包括 CI/CD 变量、预定义、安全或变量,在`.codechina-ci.yml` 文件中定义。 你不能使用在 `script` 部分中定义的变量。 如果你指定了一个 `environment` 且不存在具有该名称的环境,就会新建这个环境。 #### `environment:name`[](#environmentname) 为 `environment` 设置名称。例如: ```yaml deploy to production: stage: deploy script: git push production HEAD:main environment: name: production ``` 常见的环境名称是 `qa`、`staging` 和 `production`,但你可以使用任何你想要的名字。 你可以使用以下命令为 `name` 关键字进行赋值: - 纯文本,如`staging`。 - 变量,包括在`.codechina-ci.yml` 文件中定义的 CI/CD 变量、预定义、安全或变量。 你不能使用在 `script` 部分中定义的变量。 环境 `name` 可以包含: - Letters - Digits - Spaces - `-` - `_` - `/` - `$` - `{` - `}` #### `environment:url`[](#environmenturl) 为 `environment` 设置 URL。例如: ```yaml deploy to production: stage: deploy script: git push production HEAD:main environment: name: production url: https://prod.example.com ``` 流水线任务完成后,你可以使用合并请求中的按钮访问 URL,环境或部署页面。 你可以使用以下方法为 `url` 关键字进行赋值: - 纯文本,如`https://prod.example.com`。 - 变量,包括在`.codechina-ci.yml` 文件中定义 CI/CD 变量、预定义、安全或变量。 你不能使用在 `script` 部分中定义的变量。 #### `environment:on_stop` 关闭(停止)环境可以在 `environment` 下定义使用 `on_stop` 关键字来实现。它声明了一个不同的流水线任务来关闭环境。 阅读 `environment:action` 部分的示例。 #### `environment:action`[](#environmentaction) 使用 `action` 关键字来指定准备、启动或停止环境的流水线任务。 | **值** | **说明** | |-----------|------------------------------------ -------------------------------------------------- -------------------------------------------------- ---------------| | `start` | 默认值。表示流水线任务启动环境。部署是在流水线任务启动后创建的 | | `prepare` | 表示流水线任务只准备环境。它不会触发部署 | | `stop` | 表示流水线任务停止部署。请参阅下面的示例 | 举个例子: ```yaml review_app: stage: deploy script: make deploy-app environment: name: review/$CI_COMMIT_REF_NAME url: https://$CI_ENVIRONMENT_SLUG.example.com on_stop: stop_review_app stop_review_app: stage: deploy variables: GIT_STRATEGY: none script: make delete-app when: manual environment: name: review/$CI_COMMIT_REF_NAME action: stop ``` 在上面的例子中,`review_app` 流水线任务部署到 `review` 环境。在 `on_stop` 下列出了一个新的 `stop_review_app` 流水线任务。在 `review_app` 流水线任务完成后,它会基于 `when` 下定义的内容触发 `stop_review_app` 流水线任务。在这个例子中,它被设置为 `manual`,所以它需要一个 [manual action](#whenmanual) 并从 UI 中手动运行。 在示例中,`GIT_STRATEGY` 设置为 `none`。如果 `stop_review_app` 流水线任务是自动触发,删除分支后,运行程序不会尝试检查代码。 该示例还覆盖了全局变量。如果你的 `stop` `environment` 流水线任务取决于在全局变量上,在设置 `GIT_STRATEGY` 时使用 [anchor variables](#yaml-anchors-for-variables)在不覆盖全局变量的情况下更改流水线任务。 `stop_review_app` 流水线任务**需要**定义以下关键字: - `when`,定义于: - [流水线任务级别](#when)。 - [在规则条款中](#rules)。如果你使用 `rules:` 和 `when: manual`,你还应该设置 [`allow_failure: true`](#allow_failure) 以便可以完成流水线即使流水线任务没有运行。 - `environment:name` - `environment:action` 此外,每个流水线任务都应该有匹配的 [`rules`](#only--except) 或 [`only/except`](#only--except) 配置。 在上面的示例中,如果配置不相同: - `stop_review_app` 流水线任务可能不会包含在所有引用了`review_app` 流水线任务的流水线中。 - 无法触发 `action: stop` 来自动停止环境。 #### `environment:auto_stop_in` `auto_stop_in` 关键字用于指定环境的生命周期,当过期时,系统会自动停止它们。 例如, ```yaml review_app: script: deploy-review-app environment: name: review/$CI_COMMIT_REF_NAME auto_stop_in: 1 day ``` 当为 `review_app` 创建环境时,环境的生命周期设置为 “1 天”。每次部署审查应用程序时,该生命周期也会重置为 “1 天”。 #### `environment:kubernetes` 使用 `kubernetes` 关键字将部署配置为与你的项目相关联的 `Kubernetes cluster` 。 例如: ```yaml deploy: stage: deploy script: make deploy-app environment: name: production kubernetes: namespace: production ``` 此配置使用 `production` [Kubernetes 命名空间](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/),将 `deploy` 流水线任务部署到 `production`环境。 > Kubernetes 配置不支持由 GitLab 管理的 Kubernetes cluster。 #### `environment:deployment_tier` 使用 `deployment_tier` 关键字指定部署环境的层级: ```yaml deploy: script: echo environment: name: customer-portal deployment_tier: production ``` #### 动态环境 使用 CI/CD [变量](/docs/ci/variables) 来动态命名环境。 例如: ```yaml deploy as review app: stage: deploy script: make deploy environment: name: review/$CI_COMMIT_REF_NAME url: https://$CI_ENVIRONMENT_SLUG.example.com/ ``` 在这个例子中,`deploy as review app` 流水线任务被标记为动态部署创建 `review/$CI_COMMIT_REF_NAME` 环境。`$CI_COMMIT_REF_NAME` 是由 Runner 设置的 [CI/CD 变量](/docs/ci/variables)。`$CI_ENVIRONMENT_SLUG` 变量基于环境名称,可适用于 URL 中。如果 `deploy as review app` 流水线任务在名为 `pow` 的分支中运行,则这个环境可以通过 `https://review-pow.example.com/` 这样的 URL 访问。 常见的用法是为分支创建动态环境并使用它们作为审查应用程序。你可以在以下位置查看使用 Review Apps 的示例 。 ### `cache`[](#cache) 使用 `cache` 指定流水线任务之间要使用的文件和目录列表的缓存。你只能使用本地工作副本中的路径。 如果在流水线任务范围之外定义了 `cache`,则它会是一个全局设置并且所有流水线任务都将使用该配置。 缓存在流水线和流水线任务之间共享。缓存在 [artifacts](#artifacts) 之前恢复。 #### ``cache:paths`` 使用 `paths` 命令选择要缓存的文件或目录。路径相对于项目目录 (`$CI_PROJECT_DIR`),不能直接链接到项目目录之外。你可以使用使用 [glob](https://en.wikipedia.org/wiki/Glob_(programming)) 的通配符模式。 缓存 `binaries` 中以 `.apk` 文件结尾和 `.config`文件结尾的所有文件: ```yaml rspec: script: test cache: paths: - binaries/*.apk - .config ``` 本地定义的缓存覆盖全局定义的选项。以下例子中 `rspec` 流水线任务只缓存 `binaries/`: ```yaml cache: paths: - my/files rspec: script: test cache: key: rspec paths: - binaries/ ``` 缓存在流水线任务之间是共享的,因此如果你使用不同的不同流水线任务的路径,你还应该设置不同的 `cache:key`,否则缓存内容可能会被覆盖。 #### `cache:key` `key` 关键字定义了流水线任务之间缓存的亲和性。你可以为所有流水线任务使用一个缓存,或者为流水线任务生成缓存,或为每个分支生成缓存,或任何其他适合你工作流程的方式来生成缓存。你可以微调缓存,包括在不同流水线任务甚至不同分支之间缓存数据。 `cache:key` 变量可以使用任何[预定义变量](/docs/ci/variables)。如果不是 设置,默认值只是字面上的 `default`,这意味着默认情况下一切缓存都在流水线和流水线任务之间共享。 比如,要为每个分支启用缓存: ```yaml cache: key: "$CI_COMMIT_REF_SLUG" paths: - binaries/ ``` 如果你使用 **Windows Batch** 运行你的 shell 脚本,则需要替换 `$` 和 `%`: ```yaml cache: key: "%CI_COMMIT_REF_SLUG%" paths: - binaries/ ``` `cache:key` 变量不能包含 `/` 字符或等效字符 URI 编码的 `%2F`,也禁止仅由点(`.`、`%2E`)组成的值。 如果未找到指定的 `cache:key`,你可以指定使用 [fallback 缓存键](#fallback-cache-key) 。 ##### 多个缓存 你最多可以有四个缓存: ```yaml test-job: stage: build cache: - key: files: - Gemfile.lock paths: - vendor/ruby - key: files: - yarn.lock paths: - .yarn-cache/ script: - bundle install --path=vendor - yarn install --cache-folder .yarn-cache - echo Run tests... ``` 如果多个缓存与一个 [Fallback 缓存键](#fallback-cache-key) 组合在一起,如果未找到多个缓存,则多次获取回退。 #### 回退缓存键 你可以使用`$CI_COMMIT_REF_SLUG` [variable](#variables) 来指定你的[`cache:key`](#cachekey)。例如,如果你的 `$CI_COMMIT_REF_SLUG` 是 `test` 你可以设置一个流水线任务 下载标有 `test` 的缓存。 如果没有找到带有这个标签的缓存,也就是缓存不存在时,你可以指定使用`CACHE_FALLBACK_KEY`。 在下面的例子中,如果未找到 `$CI_COMMIT_REF_SLUG`,则流水线任务使用通过`CACHE_FALLBACK_KEY`变量定义的键: ```yaml variables: CACHE_FALLBACK_KEY: fallback-key cache: key: "$CI_COMMIT_REF_SLUG" paths: - binaries/ ``` ##### `cache:key:files` `cache:key:files` 关键字扩展了 `cache:key` 功能,使其可以更容易重用一些缓存,并减少重建它们的频率,从而加快后续流水线运行。 当你引用了 `cache:key:files` 时,你还必须列出用于生成密钥的项目文件(最多两个文件)。缓存 `key` 是根据指定文件的最近提交(最多两个,如果列出了两个文件)计算的 SHA 校验的。如果指定文件在任何提交中都没有更改,那么后退键是 `default`。 ```yaml cache: key: files: - Gemfile.lock - package.json paths: - vendor/ruby - node_modules ``` 这个例子中,为 `Ruby` 和 `Node.js` 依赖项创建缓存,并与当前版本的 `Gemfile.lock` 和 `package.json` 文件相关联。每当这些文件发生变化时,会计算新的缓存键并创建新的缓存。未来任何流水线任务运行使用了由相同的 `Gemfile.lock` 和 `package.json` 的 `cache:key:files` 都使用新的缓存,而不是重建这些依赖项。 ##### `cache:key:prefix` 当你想将前缀与通过 `cache:key:files` 计算的 SHA 结合起来时,将 `prefix` 关键字与 `key:files` 一起使用。例如,如果添加了 `test` 作为 `prefix`,结果 key 为`test-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5`。如果给定文件在任何提交中都没有更改,则会在 `default` 上添加前缀,因此示例中的 key 是 `test-default`。 像`cache:key`一样,`prefix`可以使用任何[预定义变量](/docs/ci/variables),但不能包括: - `/` 字符(或等效的 URI 编码的 `%2F`) - 仅由 `.` 组成的值(或等效的 URI 编码的 `%2E`) ```yaml cache: key: files: - Gemfile.lock prefix: ${CI_JOB_NAME} paths: - vendor/ruby rspec: script: - bundle exec rspec ``` 例如,添加了 `$CI_JOB_NAME` 的 `prefix` 后密钥看起来像:`rspec-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5`,并且流水线任务缓存在不同的分支之间共享。如果某个分支中的 `Gemfile.lock` 发生变化,则该分支对 `cache:key:files` 有一个新的 SHA 校验并生成一个新的缓存 key,并为该键创建一个新的缓存。如果没有找到 `Gemfile.lock`,则将前缀添加到 `default`,因此示例中的 key 会是 `rspec-default`。 #### `cache:untracked` 设置 `untracked: true` 以缓存 Git 中未跟踪的所有文件存储库: ```yaml rspec: script: test cache: untracked: true ``` 缓存所有 Git 未跟踪文件和 `binaries` 中的文件: ```yaml rspec: script: test cache: untracked: true paths: - binaries/ ``` #### `cache:when` `cache:when` 根据流水线任务的状态来定义何时保存缓存。你可以将 `cache:when` 设置为: - `on_success`(默认):仅在流水线任务成功时保存缓存。 - `on_failure`:仅在流水线任务失败时保存缓存。 - `always`:始终保存缓存。 例如,无论流水线任务是否成功,都要存储缓存: ```yaml rspec: script: rspec cache: paths: - rspec/ when: 'always' ``` #### `cache:policy` 缓存流水线任务的默认行为是在开始执行时下载文件,并在最后重新上传它们。任何流水线任务的更改将保留以供将来运行。这种行为被称为`pull-push`缓存政策。 如果你知道该流水线任务不会更改缓存文件,则可以跳过上传步骤,通过在流水线任务中设置 `policy: pull`。可以在较早的阶段中添加普通缓存流水线任务以确保缓存保持更新: ```yaml stages: - setup - test prepare: stage: setup cache: key: gems paths: - vendor/bundle script: - bundle install --deployment rspec: stage: test cache: key: gems paths: - vendor/bundle policy: pull script: - bundle exec rspec ... ``` 当你有许多使用缓存并行执行的流水线任务时,请使用 `pull` 策略。该策略可以加速流水线任务执行并减少缓存服务器上的负载。 如果你的流水线任务无条件地重新创建缓存,参考之前的内容,可以跳过下载步骤。为此,可以将 `policy: push` 添加到流水线任务中。 ### `artifacts`[](#artifacts) 使用 `artifacts` 指定文件和目录列表。当它 [succeeds, fails, or always](#artifactswhen) 时附加到流水线任务中。 流水线任务完成后, `artifacts`将发送到 codechina。如果他们的大小不超过 500M (目前设置的最大 `artifacts` 大小),就可以在 UI 中进行下载。 默认情况下,后期的流水线任务会自动下载所有通过早期阶段的流水线任务创建的 `artifacts`。你可以使用 [`dependencies`](#dependencies) 命令控制流水线任务中的 `artifacts`下载行为。 使用 [`needs`](#artifact-downloads-with-needs) 关键字时,流水线任务只能下载来自在 `needs` 配置中定义的流水线任务的 `artifacts`。 默认情况下,仅为成功的流水线任务收集流水线任务 `artifacts`,并且在 [caches](#cache) 之后恢复 `artifacts`。 #### `dependencies` 默认情况下,前一阶段的所有 `artifacts` 将传递给每个流水线任务。但是,你可以使用 `dependencies` 关键字来定义要从中获取 `artifacts` 的有限流水线任务列表。你还可以设置一个完全不下载任何 `artifacts`流水线任务。 要使用此功能,请在流水线任务上下文中定义 `dependencies` 并提供一个应从先前流水线任务中下载 `artifacts`的流水线任务列表。 你可以在当前阶段之前执行的阶段定义流水线任务。如果你从当前或即将到来的阶段定义流水线任务,则会发生错误。 要防止流水线任务下载 `artifacts`,请定义一个空数组。 当你使用 `dependencies` 时,并不考虑上一个流水线任务的状态。如果流水线任务失败或者是未触发的手动流水线任务,则不会发生错误。 以下示例定义了两个带有 `artifacts`的流水线任务:`build:osx` 和 `build:linux`。当 `test:osx` 执行时,`build:osx` 中的 `artifacts` 在构建的上下文中下载和提取。同样的事情发生于 `test:linux` 和来自 `build:linux` 的 `artifacts`。 流水线任务 `deploy` 下载所有先前流水线任务的 `artifacts`,因为 [stage](#stages) 优先级: ```yaml build:osx: stage: build script: make build:osx artifacts: paths: - binaries/ build:linux: stage: build script: make build:linux artifacts: paths: - binaries/ test:osx: stage: test script: make test:osx dependencies: - build:osx test:linux: stage: test script: make test:linux dependencies: - build:linux deploy: stage: deploy script: make deploy ``` ##### 当依赖流水线任务失败时 如果设置为依赖项的流水线任务 `artifacts`是 [`过期的`](#artifactsexpire_in) 或 `已删除`,则 依赖流水线任务失败。 #### `artifacts:exclude` `exclude` 可以防止将文件添加到 `artifacts`中。 类似于 [`artifacts:paths`](#artifactspaths),`exclude` 路径是相对于项目目录的。你可以使用通配符 [glob](https://en.wikipedia.org/wiki/Glob_(programming)) 或 [`doublestar.PathMatch`](https://pkg.go.dev/github.com/bmatcuk/doublestar@v1.2.2?tab=doc#PathMatch) 模式。 例如,要存储在 `binaries/` 中的所有文件,而不存储 `binaries/` 中的子目录 `*.o` 文件: ```yaml artifacts: paths: - binaries/ exclude: - binaries/**/*.o ``` 与 [`artifacts:paths`](#artifactspaths) 不同,`exclude` 路径不是递归的。要排除目录的所有内容,你可以显式匹配它们而不是匹配目录本身。 例如,要存储 `binaries/` 中的所有文件,但不包括位于 `temp/` 子目录中的文件: ```yaml artifacts: paths: - binaries/ exclude: - binaries/temp/**/* ``` [`artifacts:untracked`](#artifactsuntracked) 匹配的文件也可以使用`artifacts:exclude` 来排除。 #### `artifacts:expire_in` 使用 `expire_in` 指定流水线任务的 `artifacts` 在它们过期并被删除之前存储多长时间。`expire_in` 设置不会影响到: - 来自最新流水线任务的 `artifacts`,除非保留最新的流水线任务 `artifacts`是在项目级别禁用的。 - 流水线 `artifacts`。以下情况的到期日期将无法指定: - 来自最新流水线的流水线 `artifacts`将永远保留。 - 其它一周后删除 `artifacts` 的流水线。 `expire_in` 的值是以秒为单位的时间范围,除非提供了单位。有效值包括: - `'42'` - `42 seconds` - `3 mins 4 sec` - `2 hrs 20 min` - `2h20min` - `6 mos 1 day` - `47 yrs 6 mos and 4d` - `3 weeks and 2 days` - `never` 要在上传后一周使 `artifacts`过期,你可以这样设置: ```yaml job: artifacts: expire_in: 1 week ``` 当 `artifacts`上传并存储之后,到期时间段开始启动计时。如果到期时间未定义,则默认为 30 天。 要覆盖到期日期并保护 `artifacts`不被自动删除,你可以这样做: - 使用流水线任务页面上的**保留**按钮。 - 将 `expire_in` 的值设置为 `never`。 过期后, `artifacts` 默认每小时删除一次(使用 cron 流水线任务),并且不再可以进行访问。 #### `artifacts:expose_as` 使用 `expose_as` 关键字在[合并请求](/docs/user/project/merge-request) UI 中公开流水线任务的 `artifacts`。 例如,要匹配单个文件: ```yaml test: script: ["echo 'test' > file.txt"] artifacts: expose_as: 'artifact 1' paths: ['file.txt'] ``` 在进行了如上的配置后,会在相关的合并请求中添加一个 **artifact 1** 的链接并指向 `file1.txt`。要访问链接,在合并请求概述中的流水线图下方选择 **查看暴露的 `artifacts`**即可。 匹配整个目录的示例: ```yaml test: script: ["mkdir test && echo 'test' > test/file.txt"] artifacts: expose_as: 'artifact 1' paths: ['test/'] ``` 注意事项: - 使用变量定义 `artifacts:paths` 时,不会在合并请求 UI 中显示 `artifacts`。 - 每个合并请求最多可以显示 10 个流水线任务的 `artifacts`。 - 不支持全局模式。 - 如果指定了目录,并且目录中不止一个文件的话,则链接到流水线任务 `artifacts` 浏览器。 - 对于带有`.html`、`.htm`、`.txt`、`.json`、`.xml` 和 `.log` 扩展名,且[Pages](/docs/pages) : - 启用,则自动呈现 `artifacts`。 - 未启用,文件显示在 `artifacts` 浏览器中。 #### `artifacts:name` 使用 `name` 命令定义创建的 `artifacts`的名称。你可以为每个存档指定唯一的名称。`artifacts:name` 变量可以使用任何[预定义变量](/docs/ci/variables)。默认名称是`artifacts`,下载后会变成`artifacts.zip`。 要使用当前流水线任务的名称创建存档,你可以这样做: ```yaml job: artifacts: name: "$CI_JOB_NAME" paths: - binaries/ ``` 使用当前分支或标记的名称创建存档,仅包含 `binaries` 目录中的文件,你可以这样做: ```yaml job: artifacts: name: "$CI_COMMIT_REF_NAME" paths: - binaries/ ``` 如果你的分支名称包含 `/`(例如`feature/my-feature`)建议使用 `$CI_COMMIT_REF_SLUG` 而不是`$CI_COMMIT_REF_NAME` 来命名 `artifacts`。 使用当前流水线任务和当前分支的名称或 tag 创建存档,并且仅包含 `binaries` 目录中的文件,你可以这样做: ```yaml job: artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME" paths: - binaries/ ``` 要使用当前 [stage](#stages) 和分支名称的名称创建存档,你可以这样做: ```yaml job: artifacts: name: "$CI_JOB_STAGE-$CI_COMMIT_REF_NAME" paths: - binaries/ ``` --- 如果你使用 **Windows Batch** 运行你的 shell 脚本,则需要替换 `$` 和 `%`: ```yaml job: artifacts: name: "%CI_JOB_STAGE%-%CI_COMMIT_REF_NAME%" paths: - binaries/ ``` 如果你使用 **Windows PowerShell** 运行你的 shell 脚本,则需要替换 `$` 和 `$env:`: ```yaml job: artifacts: name: "$env:CI_JOB_STAGE-$env:CI_COMMIT_REF_NAME" paths: - binaries/ ``` #### `artifacts:paths` 路径是相对于项目目录(`$CI_PROJECT_DIR`)的,不能直接设置项目外面的链接。你可以使用使用 [glob](https://en.wikipedia.org/wiki/Glob_(programming)) 的通配符模式和 [`doublestar.Glob`](https://pkg.go.dev/github.com/bmatcuk/doublestar@v1.2.2?tab=doc#Match) 模式。 要限制特定流水线任务从哪些流水线任务获取 `artifacts`,请参阅 [dependencies](#dependencies)。 要包含 `binaries` 和 `.config` 中的所有文件,你可以这样做: ```yaml artifacts: paths: - binaries/ - .config ``` 要禁用 `artifacts` 传递,请使用空 [dependencies](#dependencies) 来定义流水线任务: ```yaml job: stage: build script: make build dependencies: [] ``` 你可能只想为发行版创建 `artifacts` 以避免使用太多的临时 `artifacts` 去占用构建服务器的存储。 仅为发行版创建 `artifacts`(`default-job` 不创建 `artifacts`),你可以这样做: ```yaml default-job: script: - mvn test -U except: - tags release-job: script: - mvn package -U artifacts: paths: - target/*.war only: - tags ``` 你也可以对目录使用通配符。例如,如果你想获取所有以 `xyz` 结尾的目录中的文件: ```yaml job: artifacts: paths: - path/*xyz/* ``` #### `artifacts:public` 使用 `artifacts:public` 来确定流水线任务的 `artifacts` 是否公开可用。 `artifacts:public` 的默认值为 `true`,这意味着匿名和访客用户可以下载公共流水线中的 `artifacts`: ```yaml artifacts: public: true ``` 拒绝匿名用户和访客用户对公共流水线中 `artifacts`的读取访问,可以将 `artifacts:public` 设置为 `false`: ```yaml artifacts: public: false ``` #### `artifacts:reports`[](#artifactsreports) 使用 [`artifacts:reports`](#artifactsreports)从流水线任务中收集测试报告、代码质量报告和安全报告。它还会在合并请求和流水线视图的 UI 中公开这些报告。 无论流水线任务结果如何(成功或失败),都会收集测试报告。你可以使用 [`artifacts:expire_in`](#artifactsexpire_in) 来设置过期时间。 如果你还希望能够浏览报告输出文件,请使用[`artifacts:paths`](#artifactspaths) 关键字。 ##### `artifacts:reports:cobertura` `cobertura` 报告收集 Cobertura 覆盖 XML 文件。收集的 Cobertura 覆盖率报告作为 `artifacts` 上传并显示在合并请求中。 Cobertura 最初是为 Java 开发的,但也有很多其他语言(如 JavaScript、Python、Ruby 等)的第三方端口。 ##### `artifacts:reports:codequality` `codequality` 报告收集代码质量问题。 收集的代码质量报告作为 `artifacts` 上传到并在合并请求中汇总。 ##### `artifacts:reports:dotenv` `dotenv` 报告收集一组环境变量作为 `artifacts`。 收集的变量被注册为流水线任务的运行时创建的变量,这对于在流水线任务完成后设置动态环境 URL 会非常有用。 [原始 dotenv 规则](https://github.com/motdotla/dotenv#rules) 有几个例外: - 变量键只能包含字母、数字和下划线 (`_`)。 - `.env` 文件的最大大小为 5 KB。 - 最大继承变量数为 20。 - 不支持`.env` 文件中的变量替换。 - `.env` 文件不能有空行或注释(以 `#` 开头)。 - `env` 文件中的键值不能有空格或换行符 (`\n`),包括使用单引号或双引号时。 - 不支持在解析过程中引用转义 (`key = 'value'` -> `{key: "value"}`)。 ##### `artifacts:reports:junit` `junit` 报告收集 [JUnit 报告格式 XML 文件](https://www.ibm.com/support/knowledgecenter/en/SSQ2R2_14.1.0/com.ibm.rsar.analysis.codereview.cobol.doc/topics/cac_useresults_junit.html) 作为 `artifacts`。虽然 JUnit 最初是用 Java 开发的,但有很多第三方端口用于其他JavaScript、Python、Ruby 等语言。 有关更多详细信息和示例,请参阅单元测试报告。下面是从 Ruby 的 RSpec 测试工具收集 JUnit 报告格式 XML 文件的示例: ```yaml rspec: stage: test script: - bundle install - rspec --format RspecJunitFormatter --out rspec.xml artifacts: reports: junit: rspec.xml ``` 收集到的单元测试报告作为 `artifacts` 上传并显示在合并请求中。 如果你使用的 JUnit 工具导出到多个 XML 文件,请指定单个流水线任务中的多个测试报告路径 将它们连接成一个文件。使用文件名模式(`junit: rspec-*.xml`),文件名数组(`junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]`),或其组合(`junit: [rspec.xml, test-results/TEST-*.xml]`)的方式。 ##### `artifacts:reports:terraform` `terraform` 报告获取 Terraform `tfplan.json` 文件。收集到的计划报告作为 `artifacts`上传并显示在合并请求中。 #### `artifacts:untracked` 使用 `artifacts:untracked` 将所有 Git 未跟踪文件添加为 `artifacts`(以及使用 `artifacts:paths` 中定义的路径)。`artifacts:untracked` 忽略配置在存储库 `.gitignore` 中的文件。 发送所有 Git 未跟踪文件: ```yaml artifacts: untracked: true ``` 发送所有 Git 未跟踪文件和 `binaries` 中的文件: ```yaml artifacts: untracked: true paths: - binaries/ ``` 发送所有未跟踪的文件,但 [排除](#artifactsexclude) `*.txt` 文件: ```yaml artifacts: untracked: true exclude: - "*.txt" ``` #### `artifacts:when` 使用 `artifacts:when` 在流水线任务失败或不论失败与否时上传 `artifacts` 。 `artifacts:when` 可以设置为以下值之一: 1. `on_success`(默认):仅在流水线任务成功时上传 `artifacts`。 1. `on_failure`:仅在流水线任务失败时上传 `artifacts`。 2. `always`:始终上传 `artifacts`。例如,当需要上传 `artifacts` 对失败的测试进行故障排除时会非常有用。 例如,仅在流水线任务失败时上传 `artifacts`: ```yaml job: artifacts: when: on_failure ``` ### `coverage`[](#coverage) 使用 `coverage` 配置如何从流水线任务输出。 正则表达式是此处预期的唯一有效值。所以,使用 `/` 包裹是强制性的,以一致且明确地表示 一个正则表达式字符串。如果需要的话,你必须转义特殊字符以从字面上匹配它们。 例如: ```yaml job1: script: rspec coverage: '/Code coverage: \d+\.\d+/' ``` 当流水线任务输出中至少有一行与正则表达式匹配时,则覆盖率会显示在 UI 中。如果流水线任务输出中有多个匹配的行,则使用最后一行。对于匹配的行,第一次出现 `\d+(\.\d+)?` 是代码覆盖率。前面的空内容会被删除。 子流水线的覆盖率输出并未记录或显示 ### `retry`[](#retry) 使用 `retry` 配置一个流水线任务失败时的重试次数。 当一个流水线任务失败时,该流水线任务会被重新处理,直至达到由 `retry` 关键字指定限制的次数。 如果 `retry` 设置为 `2`,并且流水线任务在第二次运行(第一次重试)中成功,则不会再次重试。`retry` 值必须是一个正整数,从 `0` 到 `2`(最多重试两次,总共运行三次)。 以下示例重试所有失败情况: ```yaml test: script: rspec retry: 2 ``` 默认情况下,在所有失败情况下都会重试流水线任务。为了更好地控制重试失败,`retry` 可以是具有以下键的散列: - `max`:最大重试次数。 - `when`:要重试的失败 case。 当 Runner 系统故障时最多重试两次,你可以这样做: ```yaml test: script: rspec retry: max: 2 when: runner_system_failure ``` 如果除了 Runner 系统故障之外还有其他故障,流水线任务不会重试。 要重试多个失败 cases,`when` 也可以是一个失败 cases 数组: ```yaml test: script: rspec retry: max: 2 when: - runner_system_failure - stuck_or_timeout_failure ``` `when` 的可能值为: - `always`:在任何失败时重试(默认)。 - `unknown_failure`:失败原因未知时重试。 - `script_failure`:脚本失败时重试。 - `api_failure`:API 失败时重试。 - `stuck_or_timeout_failure`:当流水线任务卡住或超时时重试。 - `runner_system_failure`:如果存在运行器系统故障(例如,流水线任务设置失败),则重试。 - `missing_dependency_failure`:如果缺少依赖项,则重试。 - `runner_unsupported`:如果 Runner 不受支持,则重试。 - `stale_schedule`:如果无法执行延迟的流水线任务,则重试。 - `job_execution_timeout`:如果脚本超过为流水线任务设置的最大执行时间,则重试。 - `archived_failure`:如果流水线任务已存档且无法运行,则重试。 - `unmet_prerequisites`:如果流水线任务未能完成先决任务,则重试。 - `scheduler_failure`:如果调度程序未能将流水线任务分配给运行程序,则重试。 - `data_integrity_failure`:如果检测到结构完整性问题,则重试。 你可以使用变量指定[特定流水线任务执行阶段的重试次数](/docs/ci/runners#job-stages-attempts)。 ### `timeout`[](#timeout) 使用 `timeout` 为特定流水线任务配置超时。例如: ```yaml build: script: build.sh timeout: 3 hours 30 minutes test: script: rspec timeout: 3h 30m ``` 流水线任务级超时可以超过[项目级超时时间](/docs/ci/pipelines/settings#timeout) ,但不能 超过 Runner 设置的超时时间。 ### `parallel`[](#parallel) 使用 `parallel` 配置要并行运行的流水线任务实例的数量。该值可以是 2 到 50。 `parallel` 关键字创建并行运行的同一流水线任务的 N 个实例。它们的命名顺序是从 `job_name 1/N` 到 `job_name N/N`: ```yaml test: script: rspec parallel: 5 ``` 每个并行流水线任务都有一个 `CI_NODE_INDEX` 和 `CI_NODE_TOTAL` [预定义 CI/CD 变量](/docs/ci/variables#predefined-cicd-variables) 设置。 不同的语言和测试套件有不同的方法来实现并行。例如,使用 [Semaphore Test Boosters](https://github.com/renderedtext/test-boosters)和 RSpec 并行运行 Ruby 测试: ```ruby # Gemfile source 'https://rubygems.org' gem 'rspec' gem 'semaphore_test_boosters' ``` ```yaml test: parallel: 3 script: - bundle - bundle exec rspec_booster --job $CI_NODE_INDEX/$CI_NODE_TOTAL ``` > 警告: > > Test Boosters 会向其作者报告使用统计数据。 然后,你可以导航到新流水线构建的 **流水线任务** 选项卡,这时你会发现 RSpec 的流水线任务已经分为三个独立的流水线任务。 #### 并行 `matrix` 流水线任务 使用 `matrix:` 在单个流水线中并行运行流水线任务多次,但每个流水线任务实例都有不同的变量值。可以有 2 到 50 个流水线任务。 流水线任务只有在有多个 Runner 或单个 Runner 被配置为同时运行多个流水线任务时才能并行运行。 每个流水线任务都获得相同的 `CI_NODE_TOTAL` [CI/CD 变量](/docs/ci/variables#predefined-cicd-variables) 值和唯一的 `CI_NODE_INDEX` 值。 ```yaml deploystacks: stage: deploy script: - bin/deploy parallel: matrix: - PROVIDER: aws STACK: - monitoring - app1 - app2 - PROVIDER: ovh STACK: [monitoring, backup, app] - PROVIDER: [gcp, vultr] STACK: [data, processing] ``` 上面的例子生成了 10 个并行的 `deploystacks` 流水线任务,对于 `PROVIDER` 和 `STACK`每个流水线任务具有不同的值: ```plaintext deploystacks: [aws, monitoring] deploystacks: [aws, app1] deploystacks: [aws, app2] deploystacks: [ovh, monitoring] deploystacks: [ovh, backup] deploystacks: [ovh, app] deploystacks: [gcp, data] deploystacks: [gcp, processing] deploystacks: [vultr, data] deploystacks: [vultr, processing] ``` ##### 一维 `matrix` 流水线任务 你还可以在单​​个流水线任务中使用一维矩阵: ```yaml deploystacks: stage: deploy script: - bin/deploy parallel: matrix: - PROVIDER: [aws, ovh, gcp, vultr] ``` ##### 并行 `matrix` 触发流水线任务 使用 `matrix:` 在单个流水线中多次并行运行 [trigger](#trigger) 流水线任务,但每个流水线任务实例都有不同的变量值。 ```yaml deploystacks: stage: deploy trigger: include: path/to/child-pipeline.yml parallel: matrix: - PROVIDER: aws STACK: [monitoring, app1] - PROVIDER: ovh STACK: [monitoring, backup] - PROVIDER: [gcp, vultr] STACK: [data] ``` 此示例生成 6 个并行的 `deploystacks` 触发器流水线任务,对于 `PROVIDER` 和 `STACK` 每个流水线任务具有不同的值,它们使用这些变量创建了 6 个不同的子流水线。 ```plaintext deploystacks: [aws, monitoring] deploystacks: [aws, app1] deploystacks: [ovh, monitoring] deploystacks: [ovh, backup] deploystacks: [gcp, data] deploystacks: [vultr, data] ``` ### `trigger`[](#trigger) 使用 `trigger` 定义下游流水线触发器。当开始一个 `trigger` 流水线任务时,会创建下游流水线。 带有`trigger` 的流水线任务只能使用有限的关键字集。例如,你不能用 [`script`](#script),[`before_script`](#before_script),或 [`after_script`](#after_script)。 你可以使用此关键字创建两种不同类型的下游流水线: - 多项目流水线 - 子流水线 你可以查看哪个流水线任务触发了下游流水线。在[流水线图](/docs/ci/pipelines#visualize-pipelines)中,并将鼠标悬停在下游流水线流水线任务上即可查看。 你可以在与 `trigger` 相同的流水线任务中使用 [`when:manual`](#whenmanual)。 #### 多项目流水线的基本 `trigger` 语法 你可以使用 `trigger` 关键字和下游项目的完整路径配置下游触发器: ```yaml rspec: stage: test script: bundle exec rspec staging: stage: deploy trigger: my/deployment ``` #### 多项目流水线的复杂 `trigger` 语法 你可以配置一个用分支名称来创建的具有以下功能的下游流水线: ```yaml rspec: stage: test script: bundle exec rspec staging: stage: deploy trigger: project: my/deployment branch: stable ``` 要从触发的流水线镜像状态: ```yaml trigger_job: trigger: project: my/project strategy: depend ``` 要从上游流水线镜像状态: ```yaml upstream_bridge: stage: test needs: pipeline: other/project ``` #### 子流水线的 `trigger` 语法 要创建子流水线,请指定包含子流水线配置的 YAML 文件路径: ```yaml trigger_job: trigger: include: path/to/child-pipeline.yml ``` 类似于多项目流水线,可以从触发的流水线中镜像状态: ```yaml trigger_job: trigger: include: - local: path/to/child-pipeline.yml strategy: depend ``` ##### 使用生成的配置文件触发子流水线 你还可以通过动态生成的配置文件触发子流水线: ```yaml generate-config: stage: build script: generate-ci-config > generated-config.yml artifacts: paths: - generated-config.yml child-pipeline: stage: test trigger: include: - artifact: generated-config.yml job: generate-config ``` `generated-config.yml` 是从 `artifacts` 中提取出来的,并被用作触发子流水线的配置。 ##### 使用来自另一个项目的文件触发子流水线 使用来自同一私有项目的文件触发子流水线实例,使用 [`include:file`](#includefile): ```yaml child-pipeline: trigger: include: - project: 'my-group/my-pipeline-library' ref: 'main' file: '/path/to/child-pipeline.yml' ``` #### 使用 `trigger:strategy` 链接流水线[]((#linking-pipelines-with-triggerstrategy)) 默认情况下,一旦创建了下游流水线,`trigger` 流水线任务就会以 `success` 状态完成。 要强制 `trigger` 流水线任务等待下游(多项目或子)流水线完成,请配置 `strategy: depend`。此设置使触发流水线任务以 `running` 状态等待,直到触发流水线完成。此时,`trigger` 流水线任务与下游流水线任务完成并显示。 此设置有助于保持流水线的线性执行。在以下示例中,来自后续阶段的流水线任务在开始之前会等待触发的流水线成功完成,这样做可以减少并行化。 ```yaml trigger_job: trigger: include: path/to/child-pipeline.yml strategy: depend ``` #### 通过 API 调用触发流水线 要强制重建特定分支、 tag 或提交,你可以使用触发 `token` 调用 API 。 触发 `token` 不同于 [`trigger`](#trigger) 关键字。 ### `interruptible`[](#interruptible) `interruptible` 表示如果新的流水线运行变得多余,则应取消正在运行的流水线任务。默认为`false`(不可中断)。尚未开始(`pending`)的流水线任务被认为是可中断的并且可以安全的取消。此值仅在 [自动取消冗余流水线功能](/docs/ci/pipelines/settings#auto-cancel-redundant-pipelines)启用时可用。 启用后,如果以下任一情况为真,则在同一分支上启动新流水线时会立即取消流水线: - 流水线中的所有流水线任务都设置为可中断的。 - 任何不间断的流水线任务尚未开始。 将流水线任务设置为可以在启动后安全取消的可中断流水线任务(例如,构建流水线任务)。 在以下示例中,新流水线运行会导致现有运行流水线变为: - 取消,如果只有 `step-1` 正在运行或 pending。 - 不会取消,一旦 `step-2` 开始运行。 不间断流水线任务开始运行后,流水线无法取消。 ```yaml stages: - stage1 - stage2 - stage3 step-1: stage: stage1 script: - echo "Can be canceled." interruptible: true step-2: stage: stage2 script: - echo "Can not be canceled." step-3: stage: stage3 script: - echo "Because step-2 can not be canceled, this step can never be canceled, even though it's set as interruptible." interruptible: true ``` ### `resource_group`[](#resource_group) 有时在一个环境中同时运行多个流水线任务或流水线可能会导致部署过程中出现错误。 为避免这些错误,请使用 `resource_group` 属性来确保 Runner 不会同时运行某些流水线任务。资源组的行为与其他编程语言中的信号量极为相似。 当在 `.codechina-ci.yml` 文件中为流水线任务定义了 `resource_group` 关键字时,同一项目的不同流水线中的流水线任务执行是相互排斥的。如果属于同一资源组的多个流水线任务同时进入队列,Runner 只选择其中一项流水线任务并运行。其他流水线任务需要等到 `resource_group` 空闲后才开始运行。 例如: ```yaml deploy-to-production: script: deploy resource_group: production ``` 在这种情况下,两个独立流水线中的 `deploy-to-production` 流水线任务永远不能同时运行。因此,你可以确保在生产环境中永远不会发生并发部署。 你可以为每个环境定义多个资源组。例如,部署到物理设备时,你可能有多个物理设备。可以部署到每台设备,但在任何给定时间内每个设备只能有一个部署。 `resource_group` 值只能包含字母、数字、`-`、`_`、`/`、`$`、`{`、`}`、`.` 和空格。它不能以`/`开头或结尾。 #### 具有跨项目/父子流水线的流水线级并发控制 你可以为对并发敏感的下游流水线定义`resource_group`。[`trigger` 关键字](#trigger) 可以触发下游流水线。[`resource_group` 关键字](#resource_group) 可以与它​​共存。这有助于控制部署流水线的并发性,同时运行非敏感的流水线任务。 以下示例在一个项目中有两个流水线配置。当流水线开始运行时,非敏感流水线任务首先执行,不受其他并发执行的流水线影响。但是,在这之前系统会确保没有其他部署流水线在运行触发部署(子)流水线。如果其他部署流水线正在运行,系统会等到这些流水线完成,然后再运行另一个。 ```yaml # .codechina-ci.yml (parent pipeline) build: stage: build script: echo "Building..." test: stage: test script: echo "Testing..." deploy: stage: deploy trigger: include: deploy.codechina-ci.yml strategy: depend resource_group: AWS-production ``` ```yaml # deploy.codechina-ci.yml (child pipeline) stages: - provision - deploy provision: stage: provision script: echo "Provisioning..." deployment: stage: deploy script: echo "Deploying..." ``` 你必须使用`trigger` 关键字定义 [`strategy:depend`](#linking-pipelines-with-triggerstrategy)。这将确保在下游流水线完成之前不会释放锁。 ### `release`[](#release) 使用 `release` 创建一个 [release](/docs/user/project/releases)。需要 [`release-cli`](https://gitlab.com/gitlab-org/release-cli/-/tree/master/docs) 在你的 Runner Docker 或 shell 执行器中可用。 `release` 支持以下这些关键字: - [`tag_name`](#releasetag_name) - [`description`](#releasedescription) - [`name`](#releasename) (可选) - [`ref`](#releaseref) (可选) - [`milestones`](#releasemilestones) (可选) - [`released_at`](#releasereleased_at) (可选) - [`assets:links`](#releaseassetslinks) (可选) 仅当流水线任务处理没有错误时才会创建 release。如果 Rails API在 release 创建期间返回错误,则 `release` 流水线任务失败。 #### `release-cli` Docker 镜像 你必须指定用于 `release-cli` 的 Docker 镜像: ```yaml image:registry.gitlab.com/gitlab-org/release-cli:latest ``` #### shell 执行程序的`release-cli` 对于 Runner shell 执行程序,你可以为你的 [支持的操作系统和架构] (https://release-cli-downloads.s3.amazonaws.com/latest/index.html) 手动下载并安装 `release-cli`,安装后完成后就可以使用`release` 关键字了。 **在 Unix/Linux 上安装** 1. 下载适用于你系统的二进制文件,以下示例适用于 amd64 系统: ```shell curl --location --output /usr/local/bin/release-cli "https://release-cli-downloads.s3.amazonaws.com/latest/release-cli-linux-amd64" ``` 1. 赋予其执行权限: ```shell sudo chmod +x /usr/local/bin/release-cli ``` 1. 验证 `release-cli` 是否可用: ```shell $ release-cli -v release-cli version 0.6.0 ``` **在 Windows PowerShell 上安装** 1. 在你系统的某处创建一个文件夹,例如`C:\CSDN\Release-CLI\bin` ```shell New-Item -Path 'C:\CSDN\Release-CLI\bin' -ItemType Directory ``` 1.下载可执行文件: ```shell PS C:\> Invoke-WebRequest -Uri "https://release-cli-downloads.s3.amazonaws.com/latest/release-cli-windows-amd64.exe" -OutFile "C:\CSDN\Release-CLI\bin\release-cli.exe" Directory: C:\CSDN\Release-CLI Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 3/16/2021 4:17 AM bin ``` 1. 将目录添加到你的环境变量 `$env:PATH` 中: ```shell $env:PATH += ";C:\GitLab\Release-CLI\bin" ``` 1. 验证`release-cli` 是否可用: ```shell PS C:\> release-cli -v release-cli version 0.6.0 ``` #### 使用自定义 SSL CA 证书 当 `release-cli` 使用带有自定义证书的 HTTPS 请求通过API 创建 release 时,你可以使用 `ADDITIONAL_CA_CERT_BUNDLE` CI/CD 变量来配置自定义 SSL CA 证书并将它用于验证。`ADDITIONAL_CA_CERT_BUNDLE` 值应包含[text representation of the X.509 PEM public-key certificate](https://tools.ietf.org/html/rfc7468#section-5.1)或包含证书颁发机构的 `path/to/file`。例如,要在 `.codechina-ci.yml` 文件中配置此值,请使用以下命令: ```yaml release: variables: ADDITIONAL_CA_CERT_BUNDLE: | -----BEGIN CERTIFICATE----- MIIGqTCCBJGgAwIBAgIQI7AVxxVwg2kch4d56XNdDjANBgkqhkiG9w0BAQsFADCB ... jWgmPqF3vUbZE0EyScetPJquRFRKIesyJuBFMAs= -----END CERTIFICATE----- script: - echo "Create release" release: name: 'My awesome release' tag_name: '$CI_COMMIT_TAG' ``` `ADDITIONAL_CA_CERT_BUNDLE` 值也可以配置为[UI 中的自定义变量](/docs/ci/variables#custom-cicd-variables), 要么是一个 `file`,它需要证书的路径;要么是一个变量,它需要证书的文本内容。 #### `script` 除 [trigger](#trigger) 流水线任务之外的所有流水线任务都必须具有 `script` 关键字。一个 `release`流水线任务可以使用脚本命令的输出,但在你不需要的时候你也可以使用占位符脚本: ```yaml script: - echo 'release job' ``` 一个流水线可以有多个 `release` 流水线任务,例如: ```yaml ios-release: script: - echo 'iOS release job' release: tag_name: v1.0.0-ios description: 'iOS release v1.0.0' android-release: script: - echo 'Android release job' release: tag_name: v1.0.0-android description: 'Android release v1.0.0' ``` #### `release:tag_name` 你必须为 release 指定一个 `tag_name`。该 tag 可以引用现有的 Git tag 或者你可以指定一个新的 tag。 当存储库中不存在指定的 tag 时,将从流水线的关联 SHA 创建一个新的 tag。 例如,从 Git tag 创建发布时: ```yaml job: release: tag_name: $CI_COMMIT_TAG description: 'Release description' ``` 也可以创建任何唯一的标签,在这种情况下,`only: tags` 不是强制性的。比如下方的示例: ```yaml job: release: tag_name: ${MAJOR}_${MINOR}_${REVISION} description: 'Release description' ``` - 只有当流水线任务的主脚本成功时才会创建发布。 - 如果发布已经存在,则不会更新并且带有`release` 关键字的流水线任务失败。 - `release` 在 `script` 之后、 `after_script` 之前执行。 #### `release:name` 版本名称。如果省略,则使用 `release: tag_name` 的值填充。 #### `release:description` 指定发布的详细描述。你还可以指定一个包含描述内容的文件。 ##### Read description from a file 你可以在 `$CI_PROJECT_DIR` 中指定一个包含描述的文件。该文件路径必须是相对于项目目录(`$CI_PROJECT_DIR`)的,如果文件是一个符号链接,它就不能驻留在 `$CI_PROJECT_DIR` 之外。`./path/to/file` 和文件名不能包含空格。 ```yaml job: release: tag_name: ${MAJOR}_${MINOR}_${REVISION} description: './path/to/CHANGELOG.md' ``` #### `release:ref` 如果 `release: tag_name` 还不存在,则从 `ref` 创建 release。`ref` 可以是提交 SHA、另一个 tag 名称或分支名称。 #### `release:milestones` 与 release 相关的每个里程碑的标题。 #### `release:released_at` release 准备就绪的日期和时间。如果未定义的话则默认使用当前日期和时间。应该用引号引起来并用符合 ISO 8601 格式来表示。 ```json released_at: '2021-03-15T08:00:00Z' ``` #### `release:assets:links` 在发布中包含[资产链接](/docs/user/project/releases#release-assets)。 > 注意:需要 `release-cli` 版本 v0.4.0 或更高版本。 ```yaml assets: links: - name: 'asset1' url: 'https://example.com/assets/1' - name: 'asset2' url: 'https://example.com/assets/2' filepath: '/pretty/url/1' # optional link_type: 'other' # optional ``` #### `release` 的完整示例 如果你结合之前的 `release` 例子,你会得到两个选项,这取决于你如何生成 tag 。你不能同时使用这些选项,因此请选择一个来使用: - 在推送 Git tag 或添加 Git tag 时创建 release : ```yaml release_job: stage: release image: registry.gitlab.com/gitlab-org/release-cli:latest rules: - if: $CI_COMMIT_TAG # Run this job when a tag is created manually script: - echo 'running release_job' release: name: 'Release $CI_COMMIT_TAG' description: 'Created using the release-cli $EXTRA_DESCRIPTION' # $EXTRA_DESCRIPTION must be defined tag_name: '$CI_COMMIT_TAG' # elsewhere in the pipeline. ref: '$CI_COMMIT_TAG' milestones: - 'm1' - 'm2' - 'm3' released_at: '2021-05-29T14:05:00Z' # Optional, is auto generated if not defined, or can use a variable. assets: # Optional, multiple asset links links: - name: 'asset1' url: 'https://example.com/assets/1' - name: 'asset2' url: 'https://example.com/assets/2' filepath: '/pretty/url/1' # optional link_type: 'other' # optional ``` - 要在提交推送至默认分支或合并到默认分支时自动创建 release,使用一个用变量定义的新 Git tag: > 注意:在 `before_script` 或 `script` 中设置的环境变量不可扩展到同一份流水线任务中使用。 ```yaml prepare_job: stage: prepare # This stage must run before the release stage rules: - if: $CI_COMMIT_TAG when: never # Do not run this job when a tag is created manually - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch script: - echo "EXTRA_DESCRIPTION=some message" >> variables.env # Generate the EXTRA_DESCRIPTION and TAG environment variables - echo "TAG=v$(cat VERSION)" >> variables.env # and append to the variables.env file artifacts: reports: dotenv: variables.env # Use artifacts:reports:dotenv to expose the variables to other jobs release_job: stage: release image: registry.gitlab.com/gitlab-org/release-cli:latest needs: - job: prepare_job artifacts: true rules: - if: $CI_COMMIT_TAG when: never # Do not run this job when a tag is created manually - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch script: - echo 'running release_job for $TAG' release: name: 'Release $TAG' description: 'Created using the release-cli $EXTRA_DESCRIPTION' # $EXTRA_DESCRIPTION and the $TAG tag_name: '$TAG' # variables must be defined elsewhere ref: '$CI_COMMIT_SHA' # in the pipeline. For example, in the milestones: # prepare_job - 'm1' - 'm2' - 'm3' released_at: '2021-05-29T14:05:00Z' # Optional, is auto generated if not defined, or can use a variable. assets: links: - name: 'asset1' url: 'https://example.com/assets/1' - name: 'asset2' url: 'https://example.com/assets/2' filepath: '/pretty/url/1' # optional link_type: 'other' # optional ``` #### 将资产发布为通用包 你可以使用通用包来托管你的发布资产。 #### `release-cli` 命令行 `release` 节点下的条目被转换为 `bash` 命令行并发送到包含了 [release-cli](https://gitlab.com/gitlab-org/release-cli)的 Docker 容器,你也可以直接从 `script` 条目调用 `release-cli`。 例如,如果你使用上方例子中的 YAML: ```shell release-cli create --name "Release $CI_COMMIT_SHA" --description "Created using the release-cli $EXTRA_DESCRIPTION" --tag-name "v${MAJOR}.${MINOR}.${REVISION}" --ref "$CI_COMMIT_SHA" --released-at "2020-07-15T08:00:00Z" --milestone "m1" --milestone "m2" --milestone "m3" --assets-link "{\"name\":\"asset1\",\"url\":\"https://example.com/assets/1\",\"link_type\":\"other\"} ``` ### `secrets`[](#secrets) 使用 `secrets` 指定流水线任务需要的 CI/CD Secrets。它应该是一个 hash 值,键应该是可供流水线任务使用的变量的名称。每个秘密的值都保存在一个临时文件中。这个文件的路径存储在这些变量中。 ### `pages` 使用 `pages` 将静态内容上传到 CODE CHINA 中。内容会作为网站发布。你必须: - 将任何静态内容放在 `public/` 目录中。 - 定义 [`artifacts`](#artifacts) 和 `public/` 目录的路径。 以下示例将所有文件从项目的根目录移动到 `public/` 目录。`.public` 在 `cp` 时将不会复制 `public/`,以避免陷入无限循环: ```yaml pages: stage: deploy script: - mkdir .public - cp -r * .public - mv .public public artifacts: paths: - public only: - main ``` > 注,目前 CODE CHINA 单独提供了 Pages 服务,不再支持通过 CI YAML 文件触发的 Pages 部署,具体可参考 [Pages 帮助文档](/docs/user/pages)。 ### `inherit`[](#inherit) 使用 `inherit:` 来控制全局定义继承和变量。 要启用或禁用所有 `default:` 或 `variables:` 关键字的继承,请使用: - `default: true` 或 `default: false` - `variables: true` 或 `variables: false` 要仅继承 `default:` 关键字或 `variables:` 的子集,请指定你想继承的内容。任何未列出的内容都**不**会集成。请使用以下格式中的一种: ```yaml inherit: default: [keyword1, keyword2] variables: [VARIABLE1, VARIABLE2] ``` 或者: ```yaml inherit: default: - keyword1 - keyword2 variables: - VARIABLE1 - VARIABLE2 ``` 在以下示例中: - `rubocop`: - 继承:没有继承任何内容。 - `rspec`: - 继承:默认的 `image` 和 `WEBHOOK_URL` 变量。 - **不** 继承:默认的 `before_script` 和 `DOMAIN` 变量。 - `capybara`: - 继承:默认的 `before_script` 和 `image`。 - **不** 继承:`DOMAIN` 和 `WEBHOOK_URL` 变量。 - `karma`: - 继承:默认的`image` 和 `before_script`,以及 `DOMAIN` 变量。 - **不** 继承:`WEBHOOK_URL` 变量。 ```yaml default: image: 'ruby:2.4' before_script: - echo Hello World variables: DOMAIN: example.com WEBHOOK_URL: https://my-webhook.example.com rubocop: inherit: default: false variables: false script: bundle exec rubocop rspec: inherit: default: [image] variables: [WEBHOOK_URL] script: bundle exec rspec capybara: inherit: variables: false script: bundle exec capybara karma: inherit: default: true variables: [DOMAIN] script: karma ``` ## `variables`[](#variables) [CI/CD 变量](/docs/ci/variables)是一些传递给流水线任务的可配置值。它们可以在全局以及每个流水线任务中设置。 有两种类型的变量。 - [自定义变量](/docs/ci/variables#custom-cicd-variables): 你可以在 CODE CHINA UI 中的 `.codechina-ci.yml` 文件中定义它们的值,或通过 API 来定义。你还可以在[手动运行流水线](/docs/ci/pipelines#run-a-pipeline-manually)中输入变量。 - 预定义变量:这些值由 Runner 自己设置。比如 `CI_COMMIT_REF_NAME`,它是指构建项目的分支或 tag。 定义好变量后,你可以在所有执行的中使用它。 变量用于非敏感的项目配置,例如: ```yaml variables: DEPLOY_SITE: "https://example.com/" deploy_job: stage: deploy script: - deploy-script --url $DEPLOY_SITE --path "/" deploy_review_job: stage: deploy variables: REVIEW_PATH: "/review" script: - deploy-review-script --url $DEPLOY_SITE --path $REVIEW_PATH ``` 变量的名称和值只能使用整数和字符。 如果在 `.codechina-ci.yml` 文件的顶部定义了一个变量,那么这个变量就是全局的,这意味着它适用于所有流水线任务。如果是在某个流水线任务重定义的变量,则它只可用于该流水线任务。 如果为特定流水线任务定义了与全局变量同名的变量,则[特定于流水线任务的变量将覆盖全局变量](/docs/ci/variables#cicd-variable-precedence)。 所有 YAML 中定义的变量对关联的 Docker 服务容器同样生效。 你可以使用 [YAML 变量锚点](#yaml-anchors-for-variables)。 ### 在手动流水线中预填充变量[](#prefill-variables-in-manual-pipelines) 当[手动运行流水线](/docs/ci/pipelines#run-a-pipeline-manually)时可使用 `value` 和 `description` 预先填充的[流水线级(全局)变量](/docs/ci/pipelines#prefill-variables-in-manuapipe): ```yaml variables: DEPLOY_ENVIRONMENT: value: "staging" # Deploy to staging by default description: "The deployment target. Change this variable to 'canary' or 'production' if needed." ``` 当你手动运行流水线时,你无法将对流水线任务级别的变量进行预填充操作。 ### 使用变量配置 Runner 行为 你可以使用 [CI/CD variables](/docs/ci/variables) 来配置运行程序如何处理 Git 请求: - [`GIT_STRATEGY`](/docs/ci/runners#git-strategy) - [`GIT_SUBMODULE_STRATEGY`](/docs/ci/runners#git-submodule-strategy) - [`GIT_CHECKOUT`](/docs/ci/runners#git-checkout) - [`GIT_CLEAN_FLAGS`](/docs/ci/runners#git-clean-flags) - [`GIT_FETCH_EXTRA_FLAGS`](/docs/ci/runners#git-fetch-extra-flags) - [`GIT_DEPTH`](/docs/ci/runners#shallow-cloning)(浅克隆) - [`GIT_CLONE_PATH`](#custom-build-directories)(自定义构建目录) - [`TRANSFER_METER_FREQUENCY`](/docs/ci/runners#artifact-and-cache-settings)( `artifacts`/缓存更新频率) - [`ARTIFACT_COMPRESSION_LEVEL`](/docs/ci/runners#artifact-and-cache-settings)( `artifacts`存档器压缩级别) - [`CACHE_COMPRESSION_LEVEL`](/docs/ci/runners#artifact-and-cache-settings)(缓存归档压缩级别) 你还可以使用变量来配置 Runner 的次数[尝试流水线任务执行的某些阶段](/docs/ci/runners#job-stages-attempts)。 ## YAML 特定的功能[](#yaml-specific-features) 在你的 `.codechina-ci.yml` 文件中,你可以使用一些 YAML 特定的特性,比如锚点(`&`)、别名(`*`)、和 map 合并(`<<`)。使用这些特性可以减少 `.codechina-ci.yml` 文件中的代码复杂性。 点击阅读更多有关各种 [YAML 功能](https://learnxinyminutes.com/docs/yaml/) 的信息。 在大多数情况下,[`extends` 关键字](#extends) 对用户更友好,你应该尽可能地使用它。 你可以使用 YAML 锚点来合并 YAML 。 ### 锚[](#anchors) YAML 有一个叫做“锚点”的功能,可以允许你在整个文档中复制内容。 使用锚点复制或继承属性。将锚点与[隐藏的流水线任务](#hide-jobs) 结合起来用作你的流水线任务模板。当有重复的键,系统会基于键执行反向深度合并。 当使用 [`include`](#include) 时,你将无法跨文件使用 YAML 锚点关键词。锚只在定义它们的文件中生效。如果要在不同的 YAML 文件中重用配置,你可以使用 [`!reference` tags](#reference-tags) 或 [`extends` 关键词](#extends)。 以下示例中,使用锚点和合并映射。它创建了 `test1` 和 `test2` 两个流水线任务,并继承了 `.job_template` 的配置,每个流水线任务都定义了自己的自定义 `script`: ```yaml .job_template: &job_configuration # Hidden yaml configuration that defines an anchor named 'job_configuration' image: ruby:2.6 services: - postgres - redis test1: <<: *job_configuration # Merge the contents of the 'job_configuration' alias script: - test1 project test2: <<: *job_configuration # Merge the contents of the 'job_configuration' alias script: - test2 project ``` `&` 设置了锚点的名称(`job_configuration`),`<<` 表示“合并给定 hash 到当前的 hash 中,然后 `*` 引用了锚点(还是`job_configuration`)。这个例子的扩展版本是: ```yaml .job_template: image: ruby:2.6 services: - postgres - redis test1: image: ruby:2.6 services: - postgres - redis script: - test1 project test2: image: ruby:2.6 services: - postgres - redis script: - test2 project ``` 你可以使用锚点来定义两组不同的服务。例如,`test:postgres`和 `test:mysql` ,他们共享 `.job_template` 中定义的 `script`,但使用不同的 `services`,可以这样定义 `.postgres_services` 和 `.mysql_services` : ```yaml .job_template: &job_configuration script: - test project tags: - dev .postgres_services: services: &postgres_configuration - postgres - ruby .mysql_services: services: &mysql_configuration - mysql - ruby test:postgres: <<: *job_configuration services: *postgres_configuration tags: - postgres test:mysql: <<: *job_configuration services: *mysql_configuration ``` 上面这个例子的扩展版本是: ```yaml .job_template: script: - test project tags: - dev .postgres_services: services: - postgres - ruby .mysql_services: services: - mysql - ruby test:postgres: script: - test project services: - postgres - ruby tags: - postgres test:mysql: script: - test project services: - mysql - ruby tags: - dev ``` 你可以看到将隐藏的流水线任务用作模板时使用起来非常方便,并且 `tags: [postgres]` 覆盖 `tags: [dev]`。 #### 脚本的 YAML 锚点[](#yaml-anchors-for-variables) 你可以在 [script](#script)、[`before_script`](#before_script)、以及 [`after_script`](#after_script) 中使用 [YAML 锚点](#anchors) ,让其在多个流水线任务中使用预定义的命令: ```yaml .some-script-before: &some-script-before - echo "Execute this script first" .some-script: &some-script - echo "Execute this script second" - echo "Execute this script too" .some-script-after: &some-script-after - echo "Execute this script last" job1: before_script: - *some-script-before script: - *some-script - echo "Execute something, for this job only" after_script: - *some-script-after job2: script: - *some-script-before - *some-script - echo "Execute something else, for this job only" - *some-script-after ``` #### 变量的 YAML 锚点 使用 [YAML 锚点](#anchors) 和 `variables` 给跨多个流水线任务的变量重复赋值。当流水线任务需要一个特定的 `variables` 块时,你也可以使用 YAML 锚点,以避免会覆盖全局变量。 以下示例显示如何在不影响 `SAMPLE_VARIABLE` 变量使用的情况下覆盖 `GIT_STRATEGY` 变量: ```yaml # global variables variables: &global-variables SAMPLE_VARIABLE: sample_variable_value ANOTHER_SAMPLE_VARIABLE: another_sample_variable_value # a job that must set the GIT_STRATEGY variable, yet depend on global variables job_no_git_strategy: stage: cleanup variables: <<: *global-variables GIT_STRATEGY: none script: echo $SAMPLE_VARIABLE ``` ### 隐藏的流水线任务 如果你想暂时禁用一个流水线任务,并且不希望使用注释掉所有的定义流水线任务的行这种方式: ```yaml # hidden_job: # script: # - run test ``` 这样情况下,你可以用一个点(`.`)开始它的名字,它不会被 CI/CD 处理。在下面的例子中,`.hidden_​​job` 将被忽略: ```yaml .hidden_job: script: - run test ``` 使用此功能来忽略流水线任务,或使用 [YAML 特性功能](#yaml-specific-features)将隐藏流水线任务转换成模板。 ### `!reference` tags 使用 `!reference` 自定义 YAML 标签,可以从其他流水线任务中选择关键字配置部分并在当前部分中重用它。与 [YAML 锚点](#anchors) 不同,你可以使用 `!reference` 标签重用 [included](#include) 配置,包括其中的配置文件也可以重用。 在以下示例中,来自两个不同位置的 `script` 和 `after_script` 在 `test` 流水线任务中被重用: - `setup.yml`: ```yaml .setup: script: - echo creating environment ``` - `.codechina-ci.yml`: ```yaml include: - local: setup.yml .teardown: after_script: - echo deleting environment test: script: - !reference [.setup, script] - echo running my own command after_script: - !reference [.teardown, after_script] ``` 在下面的例子中,`test-vars-1` 重用了 `.vars` 中的所有变量,而 `test-vars-2` 选择一个特定的变量并将其作为新的 `MY_VAR` 变量重用。 ```yaml .vars: variables: URL: "http://my-url.internal" IMPORTANT_VAR: "the details" test-vars-1: variables: !reference [.vars, variables] script: - printenv test-vars-2: variables: MY_VAR: !reference [.vars, variables, IMPORTANT_VAR] script: - printenv ``` 你不能重复使用已经包含 `!reference` 标签的部分。只支持一层嵌套。 ## 跳过流水线 要在不触发流水线的情况下推送提交,请在你的提交消息中添加 `[ci skip]` 或 `[skip ci]`,支持大写。 或者,如果你使用 Git 2.10 或更高版本,请使用 `ci.skip` Git push option。`ci.skip` 推送选项不会跳过合并请求流水线。 ## 处理 Git 推送 当在单个 `git push` 调用中推送多个更改时,系统将最多创建四个分支流水线或 tag 流水线。 此限制不会影响任何更新的合并请求流水线。所有更新的合并请求在创建时都使用的是合并请求流水线的流水线。 ## 弃用的关键字 以下关键字已弃用。 ### 全局定义的`types` > 警告:`types` 已弃用,可能会在未来版本中删除。请使用 [`stages`](#stages) 代替。 ### 流水线任务定义的`type` > 警告:`type` 已弃用,可能会在未来的某一版本中删除。请使用 [`stage`](#stage) 代替。 ### 全局定义的`image`、`services`、`cache`、`before_script`、`after_script` 不推荐在全局范围内定义 `image`、`services`、`cache`、`before_script` 和 `after_script`。可能会从未来的版本中删除支持。 使用 [`default:`](#custom-default-keyword-values) 代替。例如: ```yaml default: image: ruby:3.0 services: - docker:dind cache: paths: [vendor/] before_script: - bundle config set path vendor/bundle - bundle install after_script: - rm -rf tmp/ ```