如何编写GitLab CI定时脚本自动合并符合条件的Merge Request
方案合理性与可选实现方案
纯curl+sed/awk的方案可以实现基础功能,但维护性较差:GitLab API返回的是JSON结构,用文本解析的方式只要API返回格式稍有调整(比如新增嵌套字段、字段顺序变化)就会出现解析错误,更推荐用Shell脚本结合jq做JSON解析,或者用Python实现,逻辑更清晰也方便后续扩展准入条件校验。
Shell脚本实现方案(适合轻量化场景)
将核心逻辑抽成独立Shell脚本,用jq做结构化JSON解析,避免文本解析的不稳定问题:
修改后gitlab-ci.yml配置
variables: GROUPID: 6 stages: - cleanup cleanup-code-job: stage: cleanup image: curlimages/curl:latest # 内置curl和jq,无需额外安装依赖 tags: - build before_script: - chmod +x auto_merge_mr.sh script: - ./auto_merge_mr.sh only: - schedules # 仅定时任务触发时运行,避免代码提交时误执行
auto_merge_mr.sh脚本内容
#!/bin/sh set -e # 校验必要环境变量,GITLAB_PRIVATE_TOKEN需提前存入项目CI/CD变量中,不要硬编码 if [ -z "$GITLAB_PRIVATE_TOKEN" ] || [ -z "$CI_API_V4_URL" ] || [ -z "$GROUPID" ]; then echo "缺少必要CI变量" exit 1 fi # 1. 拉取群组下所有项目ID project_ids=$(curl -s --header "PRIVATE-TOKEN:$GITLAB_PRIVATE_TOKEN" \ "$CI_API_V4_URL/groups/$GROUPID/projects" | jq -r '.[].id') for project_id in $project_ids; do echo "处理项目ID: $project_id" # 2. 拉取项目下所有开放MR的IID mr_iids=$(curl -s --header "PRIVATE-TOKEN:$GITLAB_PRIVATE_TOKEN" \ "$CI_API_V4_URL/projects/$project_id/merge_requests?state=opened" | jq -r '.[].iid') for mr_iid in $mr_iids; do echo "尝试合并MR IID: $mr_iid 所属项目ID: $project_id" # 此处可扩展准入条件校验:调用MR详情接口判断是否满足流水线通过、已审批等要求 # 3. 调用合并接口 merge_resp=$(curl -s -o /dev/null -w "%{http_code}" --request PUT \ --header "PRIVATE-TOKEN:$GITLAB_PRIVATE_TOKEN" \ "$CI_API_V4_URL/projects/$project_id/merge_requests/$mr_iid/merge") if [ "$merge_resp" = "200" ]; then echo "合并成功" else echo "合并失败,状态码: $merge_resp" fi done done
30分钟定时任务配置
进入CI项目的「设置」->「CI/CD」->「计划」,新建定时任务,Cron表达式填写*/30 * * * *即可。
Python实现方案(适合复杂准入条件场景)
curl命令转Python可以直接用curlconverter工具,输入curl命令即可生成对应的requests代码,手动转换也只需对应HTTP方法、请求头、请求地址参数即可。
auto_merge_mr.py代码
import os import requests GITLAB_PRIVATE_TOKEN = os.getenv("GITLAB_PRIVATE_TOKEN") CI_API_V4_URL = os.getenv("CI_API_V4_URL") GROUPID = os.getenv("GROUPID") HEADERS = {"PRIVATE-TOKEN": GITLAB_PRIVATE_TOKEN} if not all([GITLAB_PRIVATE_TOKEN, CI_API_V4_URL, GROUPID]): raise Exception("缺少必要环境变量") # 1. 拉取群组下所有项目ID group_url = f"{CI_API_V4_URL}/groups/{GROUPID}/projects" projects_resp = requests.get(group_url, headers=HEADERS) projects_resp.raise_for_status() project_ids = [p["id"] for p in projects_resp.json()] for project_id in project_ids: print(f"处理项目ID: {project_id}") # 2. 拉取项目下所有开放MR的IID mr_url = f"{CI_API_V4_URL}/projects/{project_id}/merge_requests?state=opened" mr_resp = requests.get(mr_url, headers=HEADERS) mr_resp.raise_for_status() mr_iids = [m["iid"] for m in mr_resp.json()] for mr_iid in mr_iids: # 此处扩展准入条件校验,示例:判断MR是否已审批、流水线是否成功 # mr_detail = requests.get(f"{CI_API_V4_URL}/projects/{project_id}/merge_requests/{mr_iid}", headers=HEADERS).json() # if not mr_detail.get("approved") or mr_detail.get("pipeline", {}).get("status") != "success": # print(f"MR {mr_iid} 不满足准入条件,跳过") # continue print(f"尝试合并MR {mr_iid}") # 3. 调用合并接口 merge_url = f"{CI_API_V4_URL}/projects/{project_id}/merge_requests/{mr_iid}/merge" merge_resp = requests.put(merge_url, headers=HEADERS) if merge_resp.status_code == 200: print("合并成功") else: print(f"合并失败,状态码{merge_resp.status_code},返回内容:{merge_resp.text}")
对应gitlab-ci.yml配置
variables: GROUPID: 6 stages: - cleanup cleanup-code-job: stage: cleanup image: python:3.10-slim tags: - build before_script: - pip install requests script: - python auto_merge_mr.py only: - schedules
注意:PRIVATE_TOKEN对应的账号需要有对应项目的Maintainer及以上权限才能执行合并操作。
内容的提问来源于stack exchange,提问作者Sameer Atharkar
相关产品推荐
相关产品推荐

