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

3
我将尝试配置我的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. 或者 在 GitLab UI 上触发管道时执行此步骤
  3. 或者 如果直接将提交推送到 develop 分支,则执行此步骤
  4. 并且 存储库中存在 $MY_FILE 文件

与预期不同,以下情况不会执行该步骤:

  1. 推送操作
  2. 将 Branch_X 合并到 develop 分支
  3. 通过 GitLab UI 手动触发

相应的文件已经存在于存储库中。

如果我改回以下内容,则该步骤可以正常工作:

  only:
    - develop

但是我无法设置文件必须存在的条件。


当你说“通过Gitlab UI手动触发”时,你是指“点击具有when: manual的作业的播放按钮”,实际上是“触发器”,还是“运行管道”按钮?它们是不同的事情,对于CI_PIPELINE_SOURCE变量具有不同的值。 - Adam Marshall
我的意思是“运行管道”按钮。但那不是重要的情况。如果它在 develop 分支上合并或者在 develop 分支上进行新的推送时能够工作,那就足够了。但是它既不能在合并分支上工作,也不能在 develop 分支上的新推送上工作。 - Michael Schulz
1个回答

4
你遇到的问题之一是某些预定义变量仅存在于特定类型的流水线中。例如,变量CI_COMMIT_TAG,它保存标签名称,只在"标签流水线"(在创建标签后运行)中存在。然而,如果标签指向的提交是Merge Request源分支的HEAD,则它仍然只是一个"标签流水线",因此不存在任何Merge Request特定的变量。
因此,你的条件将会更加复杂,因为我们需要更多的括号或更多的if子句来处理rules部分。
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子句并使用更多的括号来编写此代码。

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

首先,“push”和“web”管道源在流水线的运行方式以及可用的预定义变量方面几乎是相同的。

其次,变量$CI_COMMIT_BRANCH仅在某些管道中可用。最明显的是,只有当存在分支时才存在该变量。如果管道运行的是标签,则该变量不存在,它不仅仅是空的。如果是合并请求事件,则该变量也不存在。$CI_COMMIT_REF_NAME更可靠,即使它可能具有更多的值(提交SHA、分支名称或标签名称)。

第三,“merge_request_event”源与我们在此处理的其他源完全不同。可用的预定义变量完全不同,因为现在有两个分支(源和目标)。另外,如果您的流水线定义中有用于“merge_request_event”的规则,“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

以下是针对除了develop分支的普通Push事件的作业输出:
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

注意:只有第一个任务运行,因为分支不是develop。如果分支是develop并且a_file存在,则两个任务都会运行,输出相同。
这是针对“web”源的任务输出,针对除develop之外的分支:
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分支并且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

最后,如果我们将源分支推送到一个以 develop 为目标的合并请求中,并且在代码库中有一个名为 a_file 的文件,则会触发 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

这里是有关合并请求管道的文档,提供更多信息。


谢谢,所以我的方法并不差。但似乎exists $MY_FILE存在问题。这个变量似乎没有被解析。如果我使用例如exists filename.txt,它就像预期的一样工作。此外,我面临的问题是,当分支合并时,这一步的分离管道会运行。这是我需要调查和修复的问题。 - Michael Schulz
可能取决于您声明变量的位置。如果它在管道内部,则对于任何rules定义都不起作用,因为在管道启动之前就会运行/确定rules,因此它将引用尚不存在的变量。 - Adam Marshall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接