GitlabCI.在主分支生成期间获取合并请求ID



每次合并新的pull请求时,都会构建master分支。在这一阶段,将进行以下步骤:

  1. 将创建一个新的Git标记(版本将自动递增)
  2. 库已发布到注册表
  3. 将向所有正在跟踪新版本的用户发送一封新电子邮件

我想在邮件中添加合并请求的直接链接,该请求已合并并触发了此版本。虽然我可以在合并请求构建过程中获得信息(MR ID),但我不明白合并MR后如何检索它。

有什么办法可以克服这个问题吗?

我刚刚解决了类似的问题,每个人都建议使用API,我的管道使用API。

我的管道有两个阶段:阶段1阶段2

Stage1 is triggered when MR is created (MR status: open)
Stage2 is triggered when MR (MR status: open) is merged (MR status: merged)

现在的问题是,这两个阶段是在不同的管道中触发的。不同的管道意味着GitLab的所有可变世界都局限于管道本身。什么都没发生。

然后我使用了gitlab-api。Stage1会影响api列表中第一个最新打开的合并请求id,这显然是触发Stage1的MR。由于一旦MR的状态变为"0",阶段1流水线就开始执行;打开";,所以这总是打开先生列表中的第一位

与我在Stage2中所做的相同;合并的";合并请求id。一切都很好,但使用api的问题是定时:(

它有一个窗口,当gitlab api用新的最新合并id更新时,可能会出现问题,而您的Stage1尚未从gitlab api获取合并id,无论何时,它都会为合并id获取新值。这个问题适用于使用gitlab pi进行合并id的两个阶段。

由于这两个阶段都在不同的管道中,他们为他们旋转了单独的docker容器,这个时间窗口直到阶段将执行,并从gitlabapi中影响合并id是问题所在。

所以gitlabapi数据在这种情况下是不可靠的。然后我转向gitlab的可变世界。

我从变量CI_MERGE_REQUEST_IID中获得了Stage1中的合并id

第一阶段表现不错

现在,Stage2在一个新的管道中运行,该管道显示CI_MERGE_REQUEST_IID为空。在检查了尽可能多的CI变量的值后,我在GitLab中使用了export命令。

我将export添加到.gitlab-ci.yml:

script:
- export

export分发了一切!!

export命令给出了所有变量及其值的列表,可供当前管道中的阶段使用。

我比较了Satge1和Satge2的变量列表。然后我找到

CI_COMMIT_MESSAGE 

尽管它的值在两个阶段之间有不同,但我在Stage2中发现了合并id

因此,对于我的问题,这是新管道中唯一可用的变量,它有一些引用来合并id,并且在Stage2的新管道的变量世界中可用。

尽管管线不同,但它们连接到SAME合并请求,并在其不同事件(如)上触发

merge_request_status = "open"
merge_request_status = "merged"

默认情况下,CI_COMMIT_MESSAGE具有值:

Merge branch '%{source_branch}' into '%{target_branch}'
%{title}
%{issues}
See merge request %{reference}

此消息来自默认模板(更多信息)。

默认模板中的%{reference}变量的值是合并id的路径。所以我从CI_COMMIT_MESSAGE中分割了合并id

merge_id=$(echo $CI_COMMIT_MESSAGE|awk -F! '{print $2}')

所以现在,我的两个管道都在变量中证明了合并id,供两个阶段使用。所以现在管道不再依赖gitlabapi的第一条信息。相反,现在他们已经有了merge id,从此他们可以轻松地使用gitlab api浏览其下的所有内容,如管道、提交、作业等,并且数据可靠。

merge-id是一种在使用gitlab-api进行数据处理时连接到所有管道、提交、作业等的父变量,而这个变量在MR的merged事件中很难找到。这是一个重要的变量,应该在触发管道的所有类型的事件中都可用。

希望这能有所帮助。

我设法发现的唯一方法是通过REST API请求合并请求。在这种情况下,我可以根据状态和创建日期对它们进行筛选。所以最新的merged就是我需要的MR。

这里有一个假设的查询:

/api/v4/projects/:projectId/merge_requests?state=merged&created_after=:day_before_now

接收到的数组中的第一个合并请求是目标合并请求。

附言:created_after=:day_before_now属性只是减少了HTTP接收的数据量。你可以省略它,不会改变行为。

如公认的答案所示,使用API获取最新的合并管道是个好主意,但它不是防故障的:如果几个MR快速合并,则您要查找的可能不是最新的。

幸运的是,我认为有一个更简单的解决方案:查看最新的提交消息。只要确保在项目的设置中,您有合并提交的默认模板:请参阅Gitlab文档。

您的最新提交将如下所示:

commit 20780d95bd026e04d409d5c47c045915c6883333
Merge: e4368ba 4hfa518
Author: My Name <my-email>
Date:   Some-Timestamp
Merge branch 'my-branch' into 'main'

My commit message

See merge request my-group/my-project!52

这里的MR iid是52;然后你可以很容易地自动抓取它。

初步实现:我不是regex/glob向导,但我认为这很有效:

matched_line="$(git log -1 --pretty=%B | grep 'See merge request')"
mr_iid=${matched_line##*!}

我的另一个答案是有效的,但我想添加一个更可靠的答案,因为它不依赖于合并提交消息模板(请参阅文档)。

这个答案是对";获取最新合并的管道";(已接受的答案),如果快速合并多个MR,则这不是防故障的。

解决方案

查找其merge_commit_shaCI_COMMIT_SHA匹配的MR。

注意:这假设在项目的设置(常规/合并请求)中;合并方法";被设置为"0";合并提交"(默认值)。

实施细节

  1. 获取当前构建的提交sha:只需使用预定义的变量CI_COMMIT_SHA(我认为git rev-parse HEAD也应该工作)
  2. 获取所有合并的MR的列表(使用合并请求API)
  3. 查找其merge_commit_shaCI_COMMIT_SHA匹配的MR。(使用类似jq的工具)

这里有一个完整的脚本可以工作:

API_MR_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests"
curl --header "PRIVATE-TOKEN: ${YOUR_API_TOKEN}" "${API_MR_URL}?scope=all&state=merged" > mrs.json
yq '.[] | select(.merge_commit_sha == strenv(CI_COMMIT_SHA)) | .iid' mrs.json

就是这样!

注意:我使用的是yq工具,而不是更标准的jq,但这只是因为我更熟悉它。无论如何,为了实现这一点,你需要在脚本的开头安装jq/yq,或者选择一个有它的映像来运行你的作业。

寻呼警告

令人恼火的是,Gitlab API每"1"只返回有限数量的结果;页面";(默认为20,最大为100)。如果你运气不好,你要找的MR可能不在第一页上。因此,对于一个完全防故障的脚本,我们需要遍历所有页面。我们开始了:

total_pages="$( curl --include --header "PRIVATE-TOKEN: ${YOUR_API_TOKEN}" "${API_MR_URL}?scope=all&state=merged&per_page=100" | egrep '^X-Total-Pages' | egrep -o '[0-9]+' )"
page=1
while [[ "${page}" -le "${total_pages}" ]] ; do
curl --header "PRIVATE-TOKEN: ${CTE_DBT_API_TOKEN}" "${API_MR_URL}?scope=all&state=merged&per_page=100&page=${page}" > mrs.json
mr_iid="$(yq '.[] | select(.merge_commit_sha == strenv(CI_COMMIT_SHA)) | .iid' mrs.json)"
if [[ "${mr_iid}" -gt 0 ]] ; then
echo "Found matching MR: ${mr_iid}"
break
fi
page=$((page + 1))
done

最新更新