Gitlab CI 仅 CD 运行 满足特定条件时的流水线步骤

Gitlab CI CD only run Pipeline Step when certain criteria is met

我正在尝试配置我的 CI/CD 管道,以便仅在满足某些条件时才执行特定步骤。

我当前的规则定义如下所示:

 rules:
    - if: '($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "merge_request_event") && $CI_COMMIT_BRANCH == "develop" '
      exists:
        - $MY_FILE          

我想达到的目标:

  1. 仅当从 branch_x 合并到 develop
  2. 时才执行步骤
  3. 当管道在 GitLab 上触发时执行步骤 UI
  4. 如果提交直接推送到 develop
  5. 则执行步骤
  6. 并且 $MY_FILE 中的文件存在于存储库中

与预期不同,该步骤

上执行
  1. 推送
  2. 合并 Branch_X 进入开发
  3. 通过 GitLab 手动触发 UI

存储库中存在相应的文件。

步骤工作是如果我改回

  only:
    - develop

但是我无法设置文件需要存在的条件。

您 运行 遇到的部分问题是某些预定义变量仅存在于特定类型的管道中。例如,保存标签名称的 CI_COMMIT_TAG 变量仅在管道是“标签管道”时才存在(创建标签后 运行 )。但是,如果标记指向作为合并请求源的 b运行ch 的 HEAD 的提交,它仍然只是标记管道,因此合并请求特定变量的 none将存在。

因此,您的条件会变得稍微复杂一些,因为我们需要更多的括号,或者我们的 rules 部分需要更多的 if 子句:

rules:
  - if: ($CI_PIPELINE_SOURCE == 'push' || $CI_PIPELINE_SOURCE == 'web') && $CI_COMMIT_REF_NAME == 'develop'
    exists:
      - $MY_FILE
    when: always
  - if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'develop'
    exists:
      - $MY_FILE
    when: always
  - when: never

注意: 你可以只使用一个 if 子句来写这个,只需要使用更多的括号。

让我们一一看看这些变化。

首先,pushweb 管道源在管道如何 运行 以及哪些预定义变量可用方面或多或少相同。

其次,变量$CI_COMMIT_BRANCH仅在某些管道中可用。最值得注意的是,它仅在存在 B运行ch 时存在。如果管道 运行s 用于标记,则该变量将不存在,它不仅仅是空的。如果是合并请求事件,变量将不存在。 $CI_COMMIT_REF_NAME 更可靠,即使它可以有更多的值(提交 SHA、B运行ch 名称或标记名称)。

第三,与我们在这里处理的其他来源相比,merge_request_event 来源是一种完全不同的动物。可用的预定义变量完全不同,因为现在有两个 b运行ches(源和目标)。此外,如果您在 merge_request_event 的管道定义中有 rules,则 merge_request_event 管道只能 运行。

我 运行 使用此规则场景和此管道定义进行了一些测试:

stages:
  - run

Run Job:
  stage: run
  image: alpine:latest
  script:
    - echo $CI_PIPELINE_SOURCE
    - echo $CI_COMMIT_REF_NAME
    - echo $CI_COMMIT_BRANCH
    - echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
    - echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

Second Run Job:
  stage: run
  image: alpine:latest
  rules:
    - if: ($CI_PIPELINE_SOURCE == 'push' || $CI_PIPELINE_SOURCE == 'web') && $CI_COMMIT_REF_NAME == 'develop'
      exists:
        - 'a_file'
      when: always
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'new_branch'
      exists:
        - 'a_file'
      when: always
    - when: never  
  script:
    - echo $CI_PIPELINE_SOURCE
    - echo $CI_COMMIT_REF_NAME
    - echo $CI_COMMIT_BRANCH
    - echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
    - echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

这是正常 Push 事件到 develop 以外的 b运行ch 的作业输出:

Executing "step_script" stage of the job script
00:02
$ echo $CI_PIPELINE_SOURCE
push
$ echo $CI_COMMIT_REF_NAME
other_branch
$ echo $CI_COMMIT_BRANCH
other_branch
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

注意:只有第一份工作 运行s 因为 b运行ch 不是 develop。如果 b运行ch develop a_file 存在,则两个作业 运行,输出相同。

这是 'web' 源的作业输出到 develop 以外的 b运行ch:

Executing "step_script" stage of the job script
00:00
$ echo $CI_PIPELINE_SOURCE
web
$ echo $CI_COMMIT_REF_NAME
other_branch
$ echo $CI_COMMIT_BRANCH
other_branch
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

同样,在这种情况下,管道中只有一项工作。相反,如果我们为 develop b运行ch 命中 运行 管道并且 a_file 存在,我们 运行 两个作业和输出是相同的:

Executing "step_script" stage of the job script
00:00
$ echo $CI_PIPELINE_SOURCE
web
$ echo $CI_COMMIT_REF_NAME
develop
$ echo $CI_COMMIT_BRANCH
develop
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME

最后,如果我们推送到 b运行ch,它是存储库中针对 developa_file 的合并请求的 source,我们会得到 merge_request_event,但由于合并请求管道的工作方式,只能获得第二份工作:

Executing "step_script" stage of the job script
00:01
$ echo $CI_PIPELINE_SOURCE
merge_request_event
$ echo $CI_COMMIT_REF_NAME
some_other_branch
$ echo $CI_COMMIT_BRANCH
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
some_other_branch
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
new_branch

这里是 Merge Request Pipelines 的文档以获取更多信息。