如何让Gitlab CI管道始终在合并请求上运行某些作业,而仅在合并请求上运行其他作业?

时间:2020-01-18 14:19:55

标签: continuous-integration gitlab merge-request

TL / DR: 我的目标是拥有一个Gitlab(CE-12.4.2)管道,该管道仅在合并请求上执行某些作业,而总是在合并请求上执行所有作业(在合并请求上以及在所有正常推送中)。 .gitlab-ci.yml看起来应该怎么做?

我的用例: 我有一条运行很多工作(测试,验证,dep,build,doc,...)的大型管道。现在,我添加了一个暂存环境(使用kubernetes),并让管道构建了一个新映像并将其部署在暂存环境中。这使我可以立即打开已更改的(Web)应用程序,并查看更改的行为和外观,而不必在本地进行检出。现在,构建映像并将其部署到暂存上对于每次推送来说都非常耗费资源,因此我只希望有人创建合并请求供我查看时才将暂存部署为暂存。

一个非常简单的示例:

install:
  script: ...

test:
  script: ...

build-image:
  script: ...
  only: [merge_requests]

deploy-staging:
  script: ...
  only: [merge_requests]

对于所有普通推送,应执行作业installtest

对于合并请求,应执行作业installtestbuild-imagedeploy-staging

我尝试过的操作:Gitlab具有此功能,可在作业上定义only: [merge_requests],这导致该作业仅在为合并请求执行管道时才执行。听起来就像我在寻找什么,但是有很大的收获。一旦将该属性应用于管道中的一个作业,在合并请求中执行该管道中不具有该属性的所有其他作业时,该其他作业将被从管道中删除。一开始对我来说这似乎是个错误,但实际上是documented behaviour

In the above example, the pipeline contains only a test job. Since the build and deploy jobs don’t have the only: [merge_requests] parameter, they will not run in the merge request.

为了将所有其他作业重新引入到管道中进行合并请求,我必须对所有其他作业应用only: [merge_requests]。这种方法的问题在于,现在对于常规的git-pushes不再执行这些常规作业。而且,由于Gitlab不支持only: [always]或类似的东西,因此我无法将这些常规作业重新引入到管道中进行正常的推送。

现在,我还注意到only语法是不推荐使用的语法,因此应该更喜欢rules语法,因此我对此进行了研究。这种方法存在多个问题:

  • 使用rules检测是否为合并请求执行了管道的唯一方法是评估与合并请求相关的变量,例如$CI_MERGE_REQUEST_ID。不幸的是,这些变量仅在使用only: [merge_requests]时存在,这将再次引发上述问题。
  • 规则仅允许有条件地应用其他属性,因此我仍然必须使用onlyexceptwhen属性来实际从管道中删除作业或向管道添加作业。不幸的是,Gitlab不支持only: [never]when: never之类的东西,因此我无法实际删除或添加作业。

我还尝试使用needdependencies属性使作业依赖于另一个作业,这似乎对作业是否包含在管道中没有影响。

我拼命尝试的最后一件事是始终包括所有作业,只需将它们标记为when: manual,即可通过按下按钮来手动触发。这在某种程度上是可行的,但是非常繁琐,因为到阶段的部署是一个多作业过程,每个作业都需要花费一些时间才能完成。因此,我将看到一个合并请求,按一下第一个任务的按钮,等待5分钟,按下一个按钮,再次等待5分钟,然后才可以使用暂存。对于许多小的合并请求,这将占用我很多时间,而且不是一个有效的解决方案。我也不能仅将这些作业中的第一个标记为手动,因为Gitlab然后将跳过该作业并按顺序执行以后的作业(同样,needsdependencies似乎对此没有影响处理手动触发的作业时。

让我有些困惑的是,在网上搜索后,我发现没有人遇到同样的问题。我是唯一希望仅对合并请求执行某些作业而不排除所有其他作业的Gitlab用户(似乎不太可能),或者我缺少明显的东西(似乎更有可能)。我是否缺少某些东西,或者Gitlab确实不支持此用例?

2 个答案:

答案 0 :(得分:5)

来自previous answer

<块引用>

但是有一个问题。此示例在创建 MR 后为每次推送启动两个管道。一种用于only: [branch],一种用于only: [merge_requests]

检查最后一个 GitLab 13.8(2021 年 1 月)是否有帮助:

<块引用>

同时使用分支和 MR 流水线,不重复

以前无法先为分支运行管道,然后在创建 MR 时切换到 merge requests pipelines

因此,对于某些配置,如果合并请求已在分支上打开,则推送到分支可能会导致重复的管道:分支上的一个管道和合并请求的另一个管道。

现在您可以在 CI 配置中使用新的 $CI_OPEN_MERGE_REQUESTS 预定义环境变量在适当的时间从分支管道切换到 MR 管道,并防止冗余管道。

https://about.gitlab.com/images/13_8/yaml_example_avoid_duplicate_pipelines.png -- Use both branch and MR pipelines without duplication

参见 DocumentationIssue

答案 1 :(得分:1)

可以向MR管道添加一些作业。我从这里得到了例子: https://docs.gitlab.com/ee/ci/merge_request_pipelines/index.html#excluding-certain-jobs

总体思路:您为每个作业定义only: [branch, merge_requests],并为部署作业用only: [merge_requests]重写它。

.only-default: &only-default
  only:
    - branches
    - merge_requests

build:
  stage: build
  tags:
    - build
  <<: *only-default
  script:
    - echo build

deploy mr:
  stage: deploy
  tags:
    - build
  only:
    - merge_requests
  script:
    - echo "deploy on MR"

但是有一个问题。创建MR后,此示例为每个推送启动两个管道。一个用于only: [branch],一个用于only: [merge_requests]only: [merge_requests]就是这样工作的,它会在每次MR变化时启动工作。新提交肯定是一个更改。

似乎没有解决方案只能针对某些事件(例如MR创建)启动管道。

但是我认为一些解决方法是可能的:

  1. 为每个管道部署临时工作
  2. 作业脚本检查是否为当前分支创建了MR
  3. 如果已创建MR,则为此MR设置脚本集标签,例如“已部署的登台”
  4. 如果此标签已经存在,或者未创建MR,则什么也不做。

GitLab API,curl和jq可以帮助解决这个问题。如果我有空闲时间,我一定会尝试写它的:)。