【问题标题】:Gitlab-CI: Specify that Job C should run after Job B if Job A failsGitlab-CI:如果作业 A 失败,则指定作业 C 应在作业 B 之后运行
【发布时间】:2021-01-20 03:06:39
【问题描述】:

假设您有以下管道:

Job A (deploy) -> Job B (test) -> Job C (remove test deployment)

管道应部署测试映像并在成功部署后对其进行测试。测试后,无论测试输出如何,我都想运行清理脚本,但前提是部署了测试映像(作业 A)。

总结一下:我希望 Gitlab 仅在作业 A 成功时执行作业 C,但在作业 B 之后

不起作用的事情:

  • when: on-failure(作业 A 或作业 B 可能失败,但只有作业 A 很重要)
  • when: always(可能作业 A 失败导致作业 C 失败)
  • when: on-success(要求所有作业都成功)

我知道 GitLab 有一个名为 DAG Pipelines 的功能,它允许您使用 needs 关键字指定对其他作业的多个依赖项,但遗憾的是,when 关键字始终适用于所有先前的作业。所以你不能说这样的话:

when:
    on-success: job-a
    always: job-b

我错过了什么还是没有办法实现这种行为?

【问题讨论】:

  • 澄清一下 - 即使作业 A(部署)失败,您想要作业 B(测试作业)运行?
  • 不,应该跳过。我想在作业 B 通过或失败后运行作业 C。但工作 A 应该已经过去了。

标签: gitlab gitlab-ci


【解决方案1】:

needs DAG 字段可用于在作业 B 失败或成功时有条件地执行清理(作业 C),但在作业 B 失败或因作业 A 失败而跳过时则不能。

创建 2 个符合以下布尔条件的清理作业:

  • (Job A succeeds and Job B succeeds):如果之前的所有任务都成功(作业 A 和作业 B),我们可以使用 when: on_success 运行清理。但是,如果作业 A 成功而作业 B 失败,这将不会触发。
  • (Job A succeeds and Job B fails):为了规避前面的未触发清理(作业 C)的场景,我们利用了一个事实,即如果作业 B 失败,这意味着作业 A 在管道中成功。通过创建重复的清理任务并在 Job B 和 when: on_failure 上指定 needs 标签,清理任务将仅在 Job A 成功且 Job B 失败时运行。

重申一下:如果(Job A succeeds and Job B succeeds)(Job A succeeds and Job B fails) 将运行清理作业,通过布尔表达式简化相当于(Job A succeeds)

这里有一个明显的警告,现在有 2 个清理作业显示在管道中;但是,它们是互斥的,只能执行一个。

这是一个示例配置:

stages:
  - deploy
  - test
  - cleanup

deploy_job:
  stage: deploy
  script:
    - echo Deployed
    - "true"
  when: always

test_job:
  stage: test
  script:
    - echo Executing tests
    - "true"
  when: on_success

# a YAML anchor reduces repetition
.cleanup_job: &cleanup_job
  stage: cleanup
  script:
    - echo Cleaned up deployment

cleanup_deployment_success:
  when: on_success
  <<: *cleanup_job

cleanup_deployment_failure:
  needs: ["test_job"]
  when: on_failure
  <<: *cleanup_job

在各种故意失败条件下,会产生以下管道状态:

  • 管道失败
  • 管道失败
  • 通过管道

从逻辑上讲,这表示无论作业 B 成功还是失败,只要作业 A 成功,作业 C 就会运行。此外,故障状态保留在整个管道中。

【讨论】:

  • 这不会导致管道处于通过状态,即使测试失败了?如果一项作业失败,我希望管道处于失败状态。
  • @Sebi2020 不幸的是,看起来是这样。如果作业失败但管道“通过”,则使用带有“通过”的橙色感叹号而不是绿色复选标记“通过”。我已经更新了我的答案以展示它的样子。 when 条件触发器在 GitLab CI 中不是很精细。我会再看一下,看看我是否可以解决管道故障状态,但我有一些严重的疑问。
  • @Sebi2020 我更新了利用 DAG 和 needs 标签的答案。让我知道这是否满足您的约束/条件。
  • 这是一种解决方法,我已经有了这个想法。但我希望有一种更清洁的方法来实现这一目标,因为这需要重复相同的工作只是为了规避缺席的“当工作范围”。
  • @Sebi2020 不幸的是,GitLab 的 CI 系统非常僵化了它的管道方法。对于这个指定的 3 阶段管道,这里唯一需要注意的是管道中出现重复的跳过清理作业。如果我找到另一个解决方案,我会更新我的答案。然而,在阅读了一个多小时的文档之后,我并不特别相信在 GitLab 为when 标签添加更高级的匹配之前会有一个更干净的解决方案。通常情况下,我的大多数 GitLab CI 配置都以肮脏的解决方案/黑客告终,因为它们对支持非平凡的用例不感兴趣。
【解决方案2】:

如果 Job B 失败或成功,则需要 DAG 字段可用于有条件地执行清理(Job C),但不是因为 Job A 失败而跳过它时。

GitLab 13.11(2021 年 4 月)可能会改变这种情况

CI/CD 管道中的可选 DAG('needs:')作业

GitLab CI/CD 中的有向无环图 (DAG) 允许您使用 needs 语法将作业配置为早于其阶段开始(一旦相关作业完成)。 > 我们还有 rulesonlyexcept 关键字,它们确定是否将作业添加到管道中。

很遗憾,如果您将 needs 与这些其他关键字结合使用,当相关作业未添加到管道时,您的管道可能会失败。

在此版本中,我们将 optional 关键字添加到 DAG 作业的 needs 语法中。

  • 如果依赖作业被标记为 optional存在于管道中,needs 作业将忽略它。
  • 如果作业是 optional 并且存在于管道中,则 needs 作业会在开始之前等待它完成。

这使得将 rulesonlyexcept 与 DAG 的日益流行安全结合起来变得更加容易。

参见DocumentationIssue

【讨论】:

    【解决方案3】:

    我想添加另一种选择。我目前正在寻求为 e2e 测试实现这个确切的用例,我的偏好可能是通过使用工件来延迟测试结果的报告。设置是这样的:

    Job A (deploy) -> Job B (run test, collect results into artifact) -> Job C (undeploy) -> Job D (publish test results from artifact)
    

    作业 B 将被配置为始终成功,并且仅将其发现保存为工件(例如 JUnit xml)。然后,作业 D 将发布结果,如果测试不成功,管道将在此处失败。这应该保留管道故障状态,即使作业 C 和作业 D 使用前面提到的使用多个 when: 条件复制作业的技术无条件地运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-28
      • 1970-01-01
      • 1970-01-01
      • 2021-03-08
      相关资源
      最近更新 更多