Gitlab管道启动,即使它应该在合并请求批准后启动



我在gitlab中创建了一个项目,在gitlab.yaml文件中有以下条目。在我推动项目中的任何更改后,管道就会启动。是否可以更改这一点,以便只有在用户提交合并请求并获得批准后管道才会统计?

这是我的.gitlab-ci.yaml文件:

stages:
- Test
- Staging
- Prod
Test:
stage: Test
tags:
- test
script:
- cd app_directory
- cd Test
- git checkout
- git pull
except:
- master
when: always
only:
- Test  
only:
- merge_requests
allow_failure: false    
Staging:
stage: Staging
tags:
- staging
script:
script:
- cd app_directory
- cd Staging
- git checkout
- git pull
except:
- master
when: always
only:
- Test  
only:
- merge_requests
allow_failure: false    
Prod:
stage: Prod
tags:
- Prod
script:
- cd app_directory
- cd Prod
- git checkout
- git pull
except:
- master
when: always
only:
- Test  
only:
- merge_requests
allow_failure: false    
variables:
GIT_STRATEGY: clone

有一种方法只能在合并请求获得批准时运行作业,但由于您必须与Approvals API交互,因此更为复杂。但是,只有付费客户才能访问Approvals API,无论是在gitlab.com上还是在自托管的gitlab实例上。

Approvals API具有获取合并请求的批准状态的操作(文档如下:https://docs.gitlab.com/ee/api/merge_request_approvals.html#get-合并请求的批准状态)。您可以使用:curl --header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/:project_id:/merge_requests/:merge_request_id:/approval_state"来调用它,其中$PRIVATE_TOKEN是至少具有api作用域的个人访问令牌。

:project_id字段是您的项目的ID,您可以从Gitlab CI提供的所有作业的预定义变量之一获取:$CI_PROJECT_ID:merge_request_id:是管道的特定合并请求的ID(如果有):$CI_MERGE_REQUEST_IID。有了这两个变量,curl命令现在是:curl --header "PRIVATE-TOKEN: ${PRIVATE_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/approval_state". Note: there are two predefined variables for merge request ID's. One is$CI_ERGE_REQUEST_ID, which is the gitlab-instance-wide ID, and the other is$CI_ERGERE_REQUEST_IID`,这是项目特定的ID。对于此操作,我们需要项目特定的IID变量。

";获得批准状态";操作包含所需审批者的数量(如果适用)、符合条件的审批者以及到目前为止已批准的人员等信息。它看起来像这样:

{
"approval_rules_overwritten": true,
"rules": [
{
"id": 1,
"name": "Ruby",
"rule_type": "regular",
"eligible_approvers": [
{
"id": 4,
"name": "John Doe",
"username": "jdoe",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/jdoe"
}
],
"approvals_required": 2,
"users": [
{
"id": 4,
"name": "John Doe",
"username": "jdoe",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/jdoe"
}
],
"groups": [],
"contains_hidden_groups": false,
"approved_by": [
{
"id": 4,
"name": "John Doe",
"username": "jdoe",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/0?s=80&d=identicon",
"web_url": "http://localhost/jdoe"
}
],
"source_rule": null,
"approved": true,
"overridden": false
}
]
}

一旦得到结果,就必须对其进行解析,以便使用这些信息来确定哪些作业将运行或不运行。jq是一个不错的选择。首先,将Approvals API的输出保存到一个文件中,然后我们可以使用jq。如果为合并请求启用了所需审批,则可以使用cat output | jq '.["rules"][]["approvals_required"]'获得所需的编号。要获得批准合并请求的人数,我们可以使用以下内容解析文件:cat output | jq '.["rules"][]["approved_by"] | length'您可以在手册中阅读有关jq的更多信息。

一旦你有了这些值,就由你来决定何时考虑合并请求;批准";是否。也许你需要所有必需的批准,或者只有一个批准人,或者由特定的人批准。

根据您只想为已批准的合并请求运行的作业数量,您可以在作业本身中运行所有这些作业,但如果您有许多作业未经批准就不应该运行,则将其放入每个作业可能会令人沮丧。幸运的是,还有另一个Gitlab CI功能可以帮助我们。从Gitlab 12.9版本开始,你可以将文件上传为artifact,它会将内容视为管道中后期的环境变量。

例如,让我们添加一个在管道中所有其他作业之前运行的作业,以访问Approvals API,使用jq解析输出,并决定是否运行作业。

stages:
- check_approvals
...
Check Merge Request Approvals:
stage: check_approvals
when:never
rules:
- if: "$CI_PIPELINE_SOURCE == 'merge_request_event'"
when: always
script:
- curl --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "https://your.gitlab.instance.com/api/v4/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/approval_state > approvals_output
- REQUIRED_APPROVALS = $(cat approvals_output | jq '.["rules"][]["approvals_required"]')
- APPROVALS_COUNT = $(cat approvals_output | jq '.["rules"][]["approved_by"] | length')
- RUN_PIPELINE=false; if ["$APPROVALS_COUNT" -ge "$REQUIRED_APPROVALS"] then
RUN_PIPELINE=true
fi
- echo "RUN_PIPELINE=${RUN_PIPELINE}" >> variables
artifacts:
reports:
dotenv: variables

dotenv报告类型允许我们在一个作业阶段定义变量,并在以后的所有阶段共享这些变量。通过将此作业放在第一阶段,管道中的所有其他阶段都可以访问$RUN_PIPELINE变量。对于上面的示例,在从API获得批准值后,我们将批准的数量与所需的数量进行比较。如果批准大于或等于所需的批准数量,我们将变量设置为true。否则就是假的。

默认情况下,我们将此作业设置为从不运行,但随后检查包含启动管道的事件的$CI_PIPELINE_SOURCE变量是否为merge_request_event。如果是,我们运行作业。这样可以确保设置$CI_MERGE_REQUEST_IID变量。

现在,在只有在Merge Request获得批准时才应该运行的所有其他作业中,我们可以检查变量的值:

Deploy to Prod:
stage: deploy
when: never
rules:
- if: "$CI_PIPELINE_SOURCE == 'merge_request_event' && $RUN_PIPELINE"
when: always
script:
- ...

首先,我们再次检查管道源,因为如果$RUN_PIPELINE变量不存在,它就不存在,然后我们检查$RUN_PIPELINE是否为真。如果是,我们将运行作业,否则默认为从不运行。

资源:

合并请求批准API

预定义变量

rules关键字

when关键字

dotenv报表类型

jq手动

根据您的需要,可以获得完全依赖合并审批或部分依赖合并审批的管道。就我个人而言,我有一组代码质量检查,我想在每次提交时无条件地运行,还有一些更全面的测试+候选构建工作,我希望在满足合并审批后运行。

这些管道的关键是在工作流规则或作业规则中使用变量CI_MERGE_REQUEST_APPROVED。遗憾的是,在完成合并请求审批之前,此变量根本不存在。则其值将为true。这意味着,如果你在工作流规则中使用它,可以阻止管道运行,就像今天GitLab的";管道";合并审批完成后,合并请求中的选项卡将无法手动运行。如果您的管道正在运行,并且其中有一个失败的作业,则会显示管道选项卡,您可以在审批完成后重新执行该作业以完成管道运行。

要启用此功能,您需要避免在工作流/作业规则中使用CI_MERGE_REQUEST_APPROVED,并在作业的脚本部分检查此变量,如果审批尚未完成,则要失败。脚本中的这一奇异行需要查看变量==true是否为true,如果不是,这一行需要返回值1。

我使用存储库中的一个文件来执行此操作,该文件在bash中创建了一个函数来检查该值,该函数将返回适当的值。

#!/bin/bash
function check_approvals {
if [ "$CI_MERGE_REQUEST_APPROVED" = 'true' ]; then printf "Merge Request is approved.n" && return 0; else printf "Merge Request not approved yet.n" && return 1; fi
}
check_approvals

我的包含此功能的脚本行是:source ./pipelines/mr-check-approvals.sh

GitLab有一个悬而未决的问题,这将有助于更好地启用此功能,并允许我们在工作流/管道规则中使用CI_MERGE_REQUEST_APPROVED。https://gitlab.com/gitlab-org/gitlab/-/issues/329787

最新更新