前言
前面我们已经部署了 SonarQube,并加入了 sonar-cxx
插件,实现了 C/C++ 代码扫描,同时打通了 Windows AD 域,实现了 AD 用户登录与权限管控。
原计划本篇(第四篇)完成 Jenkins + Gerrit + Sonar 的 CI 部分集成,但回顾发现,自己对 Jenkins + Gerrit 集成已经忘得七七八八,很多人可能也不太清楚 Jenkins 如何与 Gerrit 仓库集成。因此,本篇我们先单独讲 Jenkins 与 Gerrit 的集成过程,复习一下操作方法,同时演示如何实现自动任务,也给自己记录一下,最后实现自动触发 Jenkins 任务,通过以下三种方式
- Freestyle Job(Git 源码管理)
- Freestyle Job(无 源码管理,仅执行自定义 Bash)
- Pipeline Job(带条件触发和 Gerrit 事件信息传递)
下一篇我们再详细讲 Jenkins + Sonar 的集成,下下篇再讲如何分析需求并构建完整 CI 流程。
前期准备
在正式操作之前,需要确保以下环境已经就绪:
-
Gerrit 仓库
- 已部署 Gerrit 并可访问。
- Jenkins 所在机器能访问 Gerrit 服务。
-
Jenkins
-
已安装并启动。
-
已安装插件:
- Gerrit Trigger Plugin(用于监听 Gerrit 事件)
- Git Plugin(用于拉取 Gerrit 仓库代码)
- Pipeline Plugin(用于定义 Pipeline Job)
-
-
账号与权限
- Jenkins 需要在 Gerrit 上有一个用户账号,能读取项目、下载 patch等权限。
也就是在 Gerrit 服务器的测试仓库上给该账号配置了 Read、Label Code-Review、Label Verified 等权限 - Gerrit 上应配置相应的 HTTP 或 SSH 访问权限。
- Jenkins 需要在 Gerrit 上有一个用户账号,能读取项目、下载 patch等权限。
原理解析
Jenkins 与 Gerrit 的集成主要依赖 Gerrit Trigger Plugin。其原理如下:
-
Gerrit 事件
- 当开发者向 Gerrit 提交 patch(Change)或评论时,Gerrit 会发送事件通知。
- 事件类型包括:Patchset Created、Change Merged、Comment Added 等。
-
Jenkins 接收事件
- Jenkins 安装 Gerrit Trigger Plugin 后,会监听这些事件。
- 根据预设的规则触发相应 Job,例如 Freestyle Job 或 Pipeline Job。
-
代码拉取与执行
- Jenkins Job 根据 Refspec 下载对应的 patch 或分支代码。
- Job 可以执行构建、单元测试、静态扫描(如 SonarQube)等操作。
- 执行结果可反馈给 Gerrit,例如自动打分或发表评论。
Jenkins 与 Gerrit 集成操作步骤
Jenkins 与 Gerrit 集成靠 Jenkins 的 Gerrit Trigger Plugin 插件。
配置 Gerrit Trigger Plugin
-
进入 Jenkins 管理 → 插件管理 → 安装 Gerrit Trigger Plugin。
-
安装完成后,进入 Jenkins 系统设置 → Gerrit Trigger → 添加 Gerrit 服务器:
- Name :自定义(如
gerrit.example.com:8080
) - Hostname:gerrit.example.com
- Frontend URL:http://gerrit.example.com:8080/
- SSH Port:默认 29418
- Username :Jenkins 用于访问 Gerrit 的账号(我这里用
jenkins
账号) - E-mail : Gerrit 用户邮箱(我这里用
jenkins@example.com
邮箱) - SSH Keyfile:私钥路径(Jenkins 生成)
注:这里是要对应的公钥,是要提前上传到 Gerrit 对应
jenkins
账号 ssh 配置里,说白了就是通过 ssh 密钥实现 gerrit 与 jenkins 关联。 - Name :自定义(如
其他的则按需配置。
Jenkins 任务配置
实现功能:
- 自动通过钩子,由 Gerrit 行为自动触发 Jenkins 任务。
- 指定某仓库某分支下,若新建 Patch 或 Patch 评论出现关键字,就触发了 Jenkins 任务。
以下操作中,仓库我使用
TestProject
、分支使用TestBranch
。
1、创建 Freestyle Job(Git 源码管理)
-
新建 Freestyle 项目。
-
在 源码管理 选择 Git:
- Repository URL:
http://jenkins@gerrit.example.com:8080/TestProject
- Credentials:(选择 jenkins 连 gerrit 的账号密码)
- Refspec:
+refs/changes/*:refs/changes/*
(在高级选项,用于拉取 Gerrit Patch) - Branches to build:
${GERRIT_REFSPEC}
(指定分支,变量由 Gerrit Trigger 提供) - Wipe out repository & force clone:(在新增下面添加,用于清空仓库)
- Repository URL:
-
在 构建触发器 中勾选 Gerrit event:
- Repository URL:(勾选前面配置的 gerrit 服务器)
- Patchset Created:(Trigger on 新增,新建 Patch 即触发)
- Comment Added Contains Regular Expression:Value 输入 sonar-scan (Trigger on 新增,Patch 里出现 sonar-scan 触发)
- Gerrit Project:(Project:TestProject,Branch:TestBranch,监控的仓库和分支)
-
构建步骤(Build Steps)可执行
shell
脚本或调用构建工具,如make
等。
效果:开发者提交 Patch 或 Patch 出现关键字,Job 自动触发,拉取 patch 并执行构建。
简要说明:
- 配置了 Git 源码管理,可以让 Jenkins 任务在执行任务时先行下载代码再执行后续步骤。
- Git 源码管理配置 Refspec 和 Branches to build 为的是下 Patch(未合并)的内容,若不配置,则下的是已合并的最新版本。
- 只有配置了 Gerrit event 才能实现自动触发任务。
- Git 源码管理(下代码)也可以通过执行 Shell 替换。
2、创建 Freestyle Job(无源码管理)
配置几乎和上面一样,实现一样的效果,但是不配置 Git 源码管理。
通过 Shell 编写命令 git clone 去下载 Patch(未合并)的内容。
- 新建 Freestyle 项目。
- 在 源码管理 选择 无:
- 在 构建触发器 中勾选 Gerrit event :
- Repository URL:(勾选前面配置的 gerrit 服务器)
- Patchset Created:(Trigger on 新增,新建 Patch 即触发)
- Comment Added Contains Regular Expression:Value 输入 sonar-scan (Trigger on 新增,Patch 里出现 sonar-scan 触发)
- Gerrit Project:(Project:TestProject,Branch:TestBranch,监控的仓库和分支)
- 构建步骤(Build Steps)-执行
shell
脚本,执行下载代码编译等,参考如下:
bash
#!/bin/bash
USERNAME="jenkins"
PASSWORD="jenkins"
GERRIT_SERVER="gerrit.example.com:8080" # 替换为真实的 Gerrit 服务器地址和端口
REPO_URL="http://${USERNAME}:${PASSWORD}@${GERRIT_SERVER}/TestProject "
# === 清理工作区 (模拟 Wipe out) ===
echo "清理工作区..."
rm -rf ./* || true
rm -rf ./.git || true
# === 初始化仓库并下载代码 ===
echo "初始化仓库并设置远程..."
git init .
git remote add origin "${REPO_URL}"
# 关键:检查 $GERRIT_REFSPEC 是否存在(由Gerrit事件触发)
if [ -n "${GERRIT_REFSPEC}" ]; then
echo "触发自Gerrit事件,使用 REFSPEC: ${GERRIT_REFSPEC}"
# 拉取Gerrit特定的 change ref
git fetch origin "${GERRIT_REFSPEC}"
# 检出该 Patchset 代码
git checkout FETCH_HEAD
else
echo "非Gerrit事件触发 (可能是手动触发),使用默认分支(例如:master/TestBranch)"
# 获取默认分支(可以根据需要调整)
DEFAULT_BRANCH="master" # 或者 "TestBranch"
git fetch origin "${DEFAULT_BRANCH}"
git checkout -b "${DEFAULT_BRANCH}" "origin/${DEFAULT_BRANCH}" # 或直接 git checkout FETCH_HEAD
fi
# ===(后续是你的构建步骤,例如:执行Maven、SonarQube扫描等)===
echo "代码检出完成。当前工作区内容:"
ls -la
效果:开发者提交 Patch 或 Patch 出现关键字,Job 自动触发,拉取 patch 并执行构建等(与上边用 Git 源码管理效果一致)
注:
上面 USERNAME、PASSWORD 等变量这些可以在 freestyle job 的
创建话构建过程
上面自定义,然后 bash 直接调用 ,并且密码类型可以选择密码参数
,这样就不会明文显示密码、密钥这些了。
3、创建 Pipeline Job
- 新建 流水线 项目(Pipeline)。
- 在 构建触发器 中勾选 Gerrit event :
- Repository URL:(勾选前面配置的 gerrit 服务器)
- Patchset Created:(Trigger on 新增,新建 Patch 即触发)
- Comment Added Contains Regular Expression:Value 输入 sonar-scan (Trigger on 新增,Patch 里出现 sonar-scan 触发)
- Gerrit Project:(Project:TestProject,Branch:TestBranch,监控的仓库和分支)
- 配置 流水线 - Pipeline script,如下:
pipline
pipeline {
agent { label 'test1' }
environment {
REPO_URL = "http://gerrit.example.com:8080/IT/it_test1"
// 使用WithCredentials绑定的变量名
GIT_CREDENTIALS = credentials('32598744-3xxx-xxxx-xx...') // 这会生成 GIT_CREDENTIALS_USR 和 GIT_CREDENTIALS_PSW
}
stages {
stage('Checkout') {
steps {
cleanWs()
sh '''
# 使用凭证环境变量
git init .
git remote add origin http://$GIT_CREDENTIALS_USR:$GIT_CREDENTIALS_PSW@gerrit.example.com:8080/TestProject
if [ -n "${GERRIT_REFSPEC}" ]; then
echo "Gerrit Triggered: ${GERRIT_REFSPEC}"
git fetch origin "${GERRIT_REFSPEC}"
git checkout FETCH_HEAD
pwd
ls -l
else
echo "Manual build, using default branch"
git fetch origin TestBranch
git checkout FETCH_HEAD
pwd
ls -l
fi
'''
}
}
}
}
效果:开发者提交 Patch 或 Patch 出现关键字,Job 自动触发,拉取 patch 并执行构建等(与上边效果一致)
简要说明:
- agent { label 'test1' },我是放在 test1 节点上运行
- GIT_CREDENTIALS = credentials('32598744-3xxx-xxxx-xx...'),后面那串是 Jenkins 系统保存密码的对应 ID,路径:Credentials → System → Global credentials → 在凭据列表中查看 ID 列 ,使用
credentials()
方法,会自动生成会自动生成 GIT_CREDENTIALS_USR和 GIT_CREDENTIALS_PSW变量,并且凭据变量仅在当前 stage或 withEnv块内有效,退出后自动销毁。- Pipeline 亦可通过变量的形式调用参数,如:Gerrit 服务器地址,仓库名,分支名等,均可在
创建话构建过程
上面自定义。- 其他则执行 shell 实现完整流水线。
总结
上面演示的方法很多,但管理起来最方便肯定是第二第三种的,任何复杂不复杂的变动都可以靠自己写shell或其他脚本去执行
但是如果是新部署jenkins,要加入jenkins的节点特别特别多,总不可能每台机都一台一台手动加入jenkins节点(输密码账号什么的,我也不确定能不能批量加入),特别是java版本不匹配的情况下还得给这个节点单独装一个java,这样特别麻烦,
但是,我可以在所有节点上面加一个ansiblie,jenkins的节点只要有一个或者两个ansible就好了,jenkins任务就调用ansblie的一个通用脚本(传不同参数做不同的事情),ansible再去调用指定设备去执行一些任务,后续管理只需要再ansible上做就好了,不用专门维护多个地方,并且这些设备只要被ssh过去就行,还不用安装什么软件,方便得很。缺点就是,一个是能在jenkins上看到节点在线状态,ansible就不行。
下一篇我就讲一下,Jenkins与Sonar+gerrit集成,通过Sonar+gerrit的方式集成进来,自动打分加评论,同时说一下sonar社区版有什么区别,jenkins上面有一个叫gerrit-sonar的插件,但是得对应sonar开发或商业版,我只能找社区版本的解决方案。
思路延伸
上面演示了三种方法,但管理起来最方便的还是 第二种 和 第三种 方式。无论需求复杂还是简单,都可以通过自定义 Shell 或脚本灵活实现,减少对 Jenkins 固有功能的依赖。
不过在实际部署中,如果需要批量加入大量 Jenkins 节点,就会遇到不少麻烦:无法逐一手动添加节点,还要处理各节点 Java 版本不一致的问题,甚至还可能需要额外安装 Java。对此,可以对所有节点上统一部署 Ansible 来简化运维。
只需在 Jenkins 中保留一到两个节点作为 Ansible 控制端,再由 Job 调用一个 通用脚本
(传递参数的方式实现不同功能),最后让 Ansible 去执行具体任务即可。这样一来,后续管理集中在 Ansible 端即可,节点只要能被 SSH 访问就能纳入体系,不需要额外安装软件,维护起来更加轻量。
管理人员只需要维护这个
通用脚本
就行了。
当然缺点是 Jenkins 无法直接显示节点的在线状态,需要通过其他方式来监控。
总结
下一篇文章会说下 Jenkins 与 Sonar + Gerrit 的集成,包括如何通过 Sonar + Gerrit 的方式实现自动打分和评论反馈。同时也会分析 SonarQube 社区版与开发版/商业版的区别。
Jenkins 上的 Sonar Gerrit Plugin 插件可以解决实现这些功能,但该插件需要对应 Sonar 的开发版或商业版才能使用(或旧版本)。所以后面会重点说下当前最新社区版(LTS 9.9x)与 Jenkins 和 Gerrit 集成的解决方案和思路。