三国杀测试服手机版
1.61GB · 2025-12-21
2025年11月16日
平常使用的CI/CD主要是用Jenkins,git的本地hook,但是对于代码上传后执行差异代码优化这个技术场景流程场景来说:
因此为了优化这一块的流水线,避免上述2个问题,我打算通过git合入时通过git 的CI/CD,执行脚本分析差异化文件
(本文因为离职后所有消息记录会被删除,因此图片是没有的,请见谅)
gitlab自带部署runner文档 docs.gitlab.cn/docs/jh/ins… ,同时csdn也有对应的文档可以借鉴 blog.csdn.net/qq_39826207… 不过实际上我在开发时也遇到了一点问题,所以也可以通过以下方式部署:
准备Linux环境(Centos为例)
通过wget或者离线等方式获取gitlab runner的安装包
# 创建专用用户(不创建 home 目录)
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner
# 创建 runner 工作目录
sudo mkdir /home/gitlab-runner/runner
sudo chown gitlab-runner:gitlab-runner /home/gitlab-runner/runner
初始化并启动 GitLab Runner(作为服务)
虽然使用二进制,但建议以系统服务方式运行。
创建 systemd 服务文件
sudo tee /etc/systemd/system/gitlab-runner.service <<EOF
[Unit]
Description=GitLab Runner
After=syslog.target network.target
ConditionFileIsExecutable=/usr/local/bin/gitlab-runner
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/usr/local/bin/gitlab-runner run --working-directory /home/gitlab-runner/runner
SuccessExitStatus=0 143
Restart=always
RestartSec=5
KillMode=mixed
WorkingDirectory=/home/gitlab-runner/runner
User=gitlab-runner
Group=gitlab-runner
Environment=PATH=/bin:/usr/local/bin:/usr/bin
CacheDirectory=gitlab-runner
CacheDirectoryMode=0750
[Install]
WantedBy=multi-user.target
EOF
重载 systemd 并启动服务
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable gitlab-runner
sudo systemctl start gitlab-runner
检查服务状态
sudo systemctl status gitlab-runner
注册GitLab Runner 到 GitLab 实例
(如果是多次注册,则需要优先按照第一步切换成对应的gitlab用户进行命令操作,整个的安装流程,我按照官方流程没成功,和当前流程唯一的差别就是官方没有切换到gitlab用户)
获取注册令牌 登录 GitLab Web 界面。 进入你的项目 → Settings → CI / CD → Runners。 复制 Registration token(项目级 Runner)。 或者在 Admin Area → Overview → Runners 获取实例级令牌。
运行注册命令: 切换到 gitlab-runner 用户并注册:
sudo -u gitlab-runner -H /usr/local/bin/gitlab-runner register
按提示输入:
按提示输入:
验证注册: 在 GitLab Web 界面的 Runners 页面,应看到新注册的 Runner 处于“在线”状态。
有时候可能是安装错误,可能是需要迁移业务,需要现在原有的环境的服务,可以按照以下步骤
停止并禁用服务
sudo systemctl stop gitlab-runner
sudo systemctl disable gitlab-runner
删除服务文件
sudo rm /etc/systemd/system/gitlab-runner.service
sudo systemctl daemon-reload
删除二进制文件和用户
sudo rm /usr/local/bin/gitlab-runner
# -r 删除用户主目录
sudo userdel -r gitlab-runner
清理残留文件(可选)
sudo rm -rf /home/gitlab-runner
这个是仓库全局的git CI/CD的配置文件,根据触发阶段可以执行对应的script相关的脚本,在该脚本可以执行更多shell脚本,方便管理
该例子是合入时执行2个脚本,可供参考
stages:
- check
# 全局变量
variables:
GIT_DEPTH: "" # 完整克隆
# 只在 Merge Request 时触发流水线(即“合入前检查”)
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- when: never
check:
stage: check
interruptible: true # 可中断:当 MR 更新时取消旧流水线
script:
# 脚本1:权限/配置检查
- chmod +x ./cloud/env/install/script/config_checkstyle.sh
- ./cloud/env/install/script/config_checkstyle.sh ucs-server $GITLAB_USER_EMAIL $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
# 脚本2:另一个检查脚本(示例)
- chmod +x ./cloud/env/install/script/another_check.sh
- ./cloud/env/install/script/another_check.sh
# 只在 MR 中运行
only:
- merge_requests
tags:
- ucs_server
# 可选:指定 MR 的目标分支(比如只对 main/develop 的合入做检查)
# rules:
# - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(main|develop)$/
用于验证合入时两个分支之间的差异文件,对差异文件进行checkstyle(通过执行jar包)有问题就返回0,无问题会返回1,gitlab合并检测会根据返回值判定流水线成功/失败
原有脚本已经遗失,判断逻辑应当是jar包产生的输出,应当只看[WARN][ERROR]开头的的行是否>0,有则有问题(需要jar包启动checkstyle,需要xml配置文件进行规则配置)
Java程序的checkstyle需要以不同版本为大前提创建各自环境,其他的如本地执行hook,Jenkins执行,git CI/CD执行流程,需要的各种静态资源需要一致
#!/bin/bash
# ================== 参数校验 ==================
if [ $# -ne 4 ]; then
echo "Usage: $0 <namespace> <email> <source_branch> <target_branch>"
echo "Example: $0 ucs-server [email protected] feature/add-config main"
exit 1
fi
NAMESPACE=$1
EMAIL=$2
SOURCE_BRANCH=$3
TARGET_BRANCH=$4
# ================== 配置区 ==================
# Checkstyle jar 包路径(请根据实际路径修改)
CHECKSTYLE_JAR="./cloud/env/install/script/checkstyle.jar"
# Checkstyle 配置文件路径(checkstyle.xml)
CHECKSTYLE_CONFIG="./cloud/env/install/script/checkstyle.xml"
# 临时文件用于保存 Checkstyle 输出
CHECKSTYLE_LOG="/tmp/checkstyle_output_$$_$(date +%s).txt"
# ===========================================
echo "Analyzing Java files changed between '$SOURCE_BRANCH' and '$TARGET_BRANCH'..."
# 1. 确保远程分支存在
if ! git rev-parse --verify "origin/$SOURCE_BRANCH" > /dev/null 2>&1; then
echo "Error: Remote branch 'origin/$SOURCE_BRANCH' not found."
echo "Available branches:"; git branch -r
exit 1
fi
if ! git rev-parse --verify "origin/$TARGET_BRANCH" > /dev/null 2>&1; then
echo "Error: Remote branch 'origin/$TARGET_BRANCH' not found."
echo "Available branches:"; git branch -r
exit 1
fi
# 2. 获取两个分支之间变更的 Java 文件
CHANGED_JAVA_FILES=()
while IFS= read -r file; do
if [[ "$file" == *.java ]] && [ -f "$file" ]; then
CHANGED_JAVA_FILES+=("$file")
fi
done < <(git diff --name-only "origin/$TARGET_BRANCH"...origin/$SOURCE_BRANCH)
# 3. 检查是否有变更的 Java 文件
if [ ${#CHANGED_JAVA_FILES[@]} -eq 0 ]; then
echo "No Java files changed between 'origin/$TARGET_BRANCH' and 'origin/$SOURCE_BRANCH'."
echo "No Java changes detected." | mail -s "$NAMESPACE: No Java changes" "$EMAIL"
exit 0 # 无变更视为通过
fi
echo "Found ${#CHANGED_JAVA_FILES[@]} Java file(s) to check:"
printf ' %sn' "${CHANGED_JAVA_FILES[@]}"
# 4. 执行 Checkstyle 检查(一次性传入所有文件)
echo "Running Checkstyle..."
# 使用 -c 指定配置,-f xml 或 summary 可选,这里使用简洁格式
# 如果你希望详细输出,可以使用 -f xml 并用 xmllint 格式化
if java -jar "$CHECKSTYLE_JAR" -c "$CHECKSTYLE_CONFIG" "${CHANGED_JAVA_FILES[@]}" > "$CHECKSTYLE_LOG" 2>&1; then
# Checkstyle 命令执行成功(语法正确),但不代表无警告/错误
OUTPUT=$(cat "$CHECKSTYLE_LOG")
echo "$OUTPUT"
# 检查输出中是否包含违规信息(Checkstyle 通常会在有违规时输出内容)
if [[ -s "$CHECKSTYLE_LOG" && "$(echo "$OUTPUT" | grep -v '^$' | wc -l)" -gt 0 ]]; then
echo "Checkstyle found issues in changed Java files."
echo "Checkstyle Report:" | mail -s "[FAIL] $NAMESPACE: Checkstyle failed" "$EMAIL" -A "$CHECKSTYLE_LOG"
rm -f "$CHECKSTYLE_LOG"
exit 1 # 有违规 → 失败
else
echo "All changed Java files passed Checkstyle."
echo "No checkstyle violations found." | mail -s "[OK] $NAMESPACE: Checkstyle passed" "$EMAIL"
rm -f "$CHECKSTYLE_LOG"
exit 0 # 无违规 → 成功
fi
else
# Checkstyle 命令执行失败(如 jar 报错、配置错误等)
echo "Checkstyle execution failed!"
cat "$CHECKSTYLE_LOG"
echo "Checkstyle execution failed. See details." | mail -s "[ERROR] $NAMESPACE: Checkstyle execution error" "$EMAIL" -A "$CHECKSTYLE_LOG"
rm -f "$CHECKSTYLE_LOG"
exit 1
fi
与上面的Java验证类似,就是查询差异文件yml与yaml,checkstyle有问题就返回0,无问题会返回1,gitlab合并检测会根据返回值判定流水线成功/失败
(如果是spring可以跳过所有的application.yml文件,因为yml 验证主要是为了交付给运维同事配置文件才会有的流水线步骤)
原有脚本已经遗失,判断逻辑应当通过yamllint进行验证,根据输出产生行数>0则有问题(需要ymlconf文件作为配置规则)
#!/bin/bash
if [ $# -ne 2 ]; then
echo "Usage: $0 <namespace> <email>"
exit 1
fi
NAMESPACE=$1
EMAIL=$2
# ================== 配置区 ==================
TARGET_BRANCH="main" # 目标合并分支,可根据需要改为 dev、release 等
CONFIG_FILE="./cloud/env/install/script/ymlconf"
# ===========================================
echo " Checking YAML files changed between current branch and '$TARGET_BRANCH'..."
# 1. 获取当前分支相对于目标分支的差异文件(仅新增或修改)
# 注意:GitLab CI 会自动 fetch 所有分支,可以直接使用
CHANGED_YAML_FILES=()
while IFS= read -r file; do
if [[ "$file" == *.yml || "$file" == *.yaml ]]; then
if [ -f "$file" ]; then # 确保文件存在(避免删除的文件)
CHANGED_YAML_FILES+=("$file")
fi
fi
done < <(git diff --name-only "origin/$TARGET_BRANCH"...HEAD)
# 2. 检查是否有变更的 YAML 文件
if [ ${#CHANGED_YAML_FILES[@]} -eq 0 ]; then
echo " No YAML files changed. Skipping yamllint."
echo "No YAML changes detected." | mail -s "$NAMESPACE: No YAML changes" "$EMAIL"
exit 0
fi
echo " Found ${#CHANGED_YAML_FILES[@]} YAML file(s) to check:"
printf ' %sn' "${CHANGED_YAML_FILES[@]}"
# 3. 对差异文件逐个运行 yamllint
ERRORS_FOUND=""
for file in "${CHANGED_YAML_FILES[@]}"; do
echo " linting $file"
if ! yamllint -c "$CONFIG_FILE" "$file" > /tmp/yamllint.log 2>&1; then
echo " yamllint failed on $file"
ERRORS_FOUND+="$file:n"
ERRORS_FOUND+=$(cat /tmp/yamllint.log)
ERRORS_FOUND+="nn"
fi
done
# 4. 处理结果
if [ -n "$ERRORS_FOUND" ]; then
echo "YAML file has syntax errors!"
echo -e "$ERRORS_FOUND"
echo -e "$ERRORS_FOUND" | mail -s "$NAMESPACE YAML file has syntax errors!" "$EMAIL"
rm -f /tmp/yamllint.log
exit 1
else
echo " All changed YAML files are valid."
echo "All changed YAML files passed lint." | mail -s "$NAMESPACE: YAML lint passed" "$EMAIL"
rm -f /tmp/yamllint.log
exit 0
fi
在 shell executor 模式下,GitLab Runner 的工作方式如下:
直接在宿主机(Centos)上执行命令:Runner 会以运行它的用户身份(如 gitlab-runner 用户),在系统 shell 中直接执行 .gitlab-ci.yml 中定义的 script 命令。
资源占用特点:
建议:
实现方式:
启用“合并前必须通过流水线”:
保护目标分支(如 main / develop):(这个对于有规模的开发团队,已经有CMO进行配置过了)
Settings > Repository > Protected Branches
对目标分支设置:
结果:
注册:Runner 向 GitLab Server 注册,获得唯一 token,并绑定到项目或 group。
轮询/长连接:Runner 定期向 GitLab Server 的 /jobs/request API 发起请求(默认每几秒一次),询问是否有待处理的 job。
领取任务:当有匹配标签(tags)的 job 到来,Runner 领取任务(包含 .gitlab-ci.yml 中的 script、variables、artifacts 等信息)。
执行任务 :
释放资源:任务结束,清理临时文件(除非配置保留)。
GitLab 自动注入大量 预定义 CI/CD 变量(Predefined Variables),你可以在脚本中直接使用,例如:
常用内置变量示例:
| 变量 | 说明 |
|---|---|
| CI_COMMIT_REF_NAME | 当前分支或 tag 名(如 main, v1.0) |
| CI_PROJECT_DIR | CI 任务的工作目录(代码被 clone 到这里) |
| GITLAB_USER_EMAIL | 触发 pipeline 的用户邮箱 |
其他的像是两个分支的分支hash也可以通过git提供的参数获取到,用于差异文件的排查。更多的可以看官网 docs.gitlab.com/ci/variable…
GitLab 的规则非常明确: 始终使用 source branch(源分支)中的 .gitlab-ci.yml 文件
详细说明:
| 情况 | 使用哪个 .gitlab-ci.yml? |
|---|---|
| feature 有,main 有 | 用 feature 的 |
| feature 有,main 没有 | 用 feature 的 |
| feature 没有,main 有 | pipeline 不会触发(因为 source branch 没有 .gitlab-ci.yml) |
| 两者都没有 | 无 CI pipeline |
推荐将大资源(如git CI/CD可以接入通过checkstyle.jar执行checkstyle,对应的jar文件)放在服务器上,其他的则可以放在各自的代码仓库内
当你通过官方方式安装 GitLab Runner(如 yum install gitlab-runner 或 dpkg -i gitlab-runner_xxx.deb),安装脚本会自动:
所以如果手动的安装,可能会错过这一步,最终导致无法注册runner到gitlab上面
答案:GitLab 会完整克隆(checkout)源分支(source branch)的代码,并使用该分支中的 .gitlab-ci.yml 文件
这个过程包括:
所以,“完整克隆”在这里的意思是:
不是只复制 .gitlab-ci.yml 文件,而是把整个源分支的代码仓库完整拉下来,确保 CI 配置和代码版本严格一致。
为什么重要?
GitLab Runner 在拉取代码时,确实支持“不同深度”的克隆(clone depth),但没有“只拉代码 / 拉全部信息”这种二元级别。
你可以通过以下方式控制 拉取多少 Git 历史(commit history):
注意:无论哪种方式,都会拉取完整的当前 commit 的文件内容(即“代码”)。
所谓“只拉代码”其实是误解 —— 代码文件总是完整的,区别只在 历史记录是否完整。 浅拷贝,深拷贝的在各个方面的不同
| 配置 | 行为 | 适用场景 |
|---|---|---|
| GIT_DEPTH: 1(默认) | 浅克隆:只拉当前 commit + 最近 1 层历史 | 快速构建、节省带宽 |
| GIT_DEPTH: 0 或未设置 | 深克隆:拉取完整仓库历史(等价于 git clone --mirror) | 需要 git log、git describe、计算版本号等 |
| GIT_DEPTH: 10 | 拉最近 10 个 commit 的历史 | 折中方案 |
不同的配置推荐场景如下:
| 场景 | 推荐配置 |
|---|---|
| 普通构建、测试、部署 | GIT_DEPTH: 1(默认,最快) |
| 需要生成版本号(如 v1.2.3-5-gabc123) | GIT_DEPTH: 0 + git fetch --tags |
| 需要分析 commit 差异(如 changelog) | GIT_DEPTH: 0 |
| 使用 Lerna / Nx 等工具依赖 Git 历史 | GIT_DEPTH: 0 |
| 节省 CI 时间和带宽 | 保持默认(GIT_DEPTH: 1) |
会!完全不受影响。
无论你用浅克隆还是深克隆,以下内容都 正常可用
GitLab CI 通过一个内置变量 GIT_DEPTH 控制克隆深度:
如:
variables:
GIT_DEPTH: 0 # 拉取完整历史
build:
script:
- git log --oneline -n 5 # 只有 GIT_DEPTH > 1 或 =0 时才有多个 commit
- git describe --tags # 需要完整 tag 历史
GIT_DEPTH: 1(浅克隆,高效)