Jenkins 多分支流水线配置教程
一、多分支流水线概述
1.1 什么是多分支流水线
多分支流水线(Multibranch Pipeline)是 Jenkins 针对多分支项目设计的自动化构建方案,能够自动发现代码仓库中的所有分支(如 main、dev、feature/* 等),并为每个分支自动创建独立的流水线实例,分支新增/删除时会自动同步,无需手动配置单个分支任务。
1.2 为什么使用多分支流水线
适用于以下场景:
- 项目存在多个开发分支(如主分支、开发分支、功能分支),需要对每个分支独立构建、测试;
- 团队协作开发,需确保每个分支的代码提交后能快速验证稳定性;
- 需实现分支级别的差异化配置(如主分支定时构建、功能分支仅提交触发)。
1.3 相对于自由风格/普通流水线的优势
| 对比维度 | 多分支流水线 | 自由风格项目 | 普通流水线(单分支) |
|---|---|---|---|
| 分支管理 | 自动发现、同步所有分支 | 需手动为每个分支创建独立项目 | 仅支持单个分支,多分支需重复配置 |
| 配置维护 | 统一配置,分支共享核心逻辑 | 每个分支独立配置,维护成本高 | 多分支需复制多个流水线,配置冗余 |
| 灵活性 | 支持分支级差异化配置(定时、触发规则) | 配置分散,差异化需手动调整 | 不支持分支差异化,需额外编写逻辑 |
| 自动化程度 | 提交/合并自动触发对应分支构建 | 需手动绑定分支与触发规则 | 仅能触发单个分支,多分支需额外配置 |
| 版本控制 | 流水线脚本(Jenkinsfile)纳入代码管理 | 配置存储在 Jenkins 服务器,无版本控制 | 脚本可版本控制,但仅对应单个分支 |
二、前置准备:GitHub PAT 凭证配置
多分支流水线需通过 GitHub 个人访问令牌(PAT)访问私有仓库,步骤如下:
2.1 创建 GitHub PAT(个人访问令牌)
- 登录 GitHub → 右上角头像 →
Settings→Developer settings→Personal access tokens→Generate new token; - 配置令牌信息:
- 填写
Note(如Jenkins 多分支流水线访问); - 勾选权限:
repo(所有子权限,用于访问私有仓库)、read:org(可选,组织仓库需勾选);
- 填写
- 点击
Generate token,生成后立即复制保存(仅显示一次)。
2.2 在 Jenkins 中添加 PAT 凭证
- 进入 Jenkins →
Manage Jenkins→Manage Credentials→全局→添加凭证; - 选择凭证类型:
Username with password; - 填写配置:
- Username:你的 GitHub 用户名;
- Password:步骤 2.1 生成的 PAT;
- ID:自定义凭证 ID(如
github-pat),方便后续引用;
- 点击
OK保存,凭证将用于仓库代码拉取和分支发现。
三、核心配置:分支源(Branch Source)选项详解
分支源是多分支流水线的核心配置,用于连接代码仓库、筛选分支、配置拉取规则。进入多分支流水线 → 配置 → 分支源 → 添加源 → GitHub,展开配置后,重点选项说明如下:
3.1 Within repository(仓库内分支/标签发现)
3.1.1 Discover branches(发现分支)
- 作用:自动发现仓库中的所有分支,为有 Jenkinsfile 的分支创建流水线;
- 用法 :
- 勾选后默认发现所有分支;
- 可选择
Exclude branches that do not contain the Jenkinsfile(仅发现包含流水线脚本的分支,推荐);
- 场景:避免为无构建需求的分支(如废弃分支)创建流水线实例。
3.1.2 Discover pull requests from forks(发现 Fork 仓库的 PR)
- 作用:自动发现来自 Fork 仓库的 Pull Request(PR),并创建临时构建实例;
- 用法:勾选后可配置 PR 构建规则(如仅构建已审核的 PR);
- 场景:开源项目或跨团队协作,需验证 Fork 仓库的 PR 稳定性。
3.1.3 Discover pull requests from origin(发现本仓库的 PR)
- 作用:自动发现仓库内的 PR,支持 PR 合并前的预构建验证;
- 用法 :勾选后可选择构建策略(如
Merge PR head with base branch,将 PR 分支与目标分支合并后构建); - 场景:团队内部协作,确保 PR 合并后不影响目标分支稳定性。
3.1.4 Discover tags(发现标签)
- 作用 :自动发现仓库中的标签(如
v1.0.0),为标签创建构建实例; - 用法:勾选后可配置标签筛选规则;
- 场景:版本发布时,标签提交后自动触发构建、打包。
3.1.5 Filter by name (with regular expression)(按正则筛选分支/标签)
- 作用:通过正则表达式筛选需要构建的分支/标签,仅匹配的分支会被发现;
- 用法 :
Include:填写正则表达式(如^(main|dev|feature/.*)$,仅保留 main、dev 和 feature 前缀分支);Exclude:填写需排除的正则(如^feature/old-.*$,排除 old- 前缀的 feature 分支);
- 注意 :正则匹配区分大小写,需准确编写表达式(如
^Dev$不匹配dev)。
3.1.6 Filter by name (with wildcards)(按通配符筛选分支/标签)
- 作用:通过通配符快速筛选分支/标签,比正则更简单易用;
- 用法 :
Include:用*匹配任意字符(如main,dev,feature/*,保留 main、dev 和所有 feature 分支);Exclude:排除不需要的分支(如release/*,排除所有 release 分支);
- 场景:快速筛选特定前缀的分支,无需编写复杂正则。
3.1.7 Ignore pull requests marked as drafts(忽略草稿 PR)
- 作用:跳过标记为「草稿」的 PR,不触发构建;
- 用法:直接勾选;
- 场景:避免 PR 未完成时频繁触发无效构建。
3.2 General(通用拉取/构建配置)
3.2.1 Advanced checkout behaviours(高级检出行为)
- 作用:配置代码检出后的额外操作(如检出到指定目录、设置超时);
- 常用选项 :
Check out to matching local branch:检出到与远程分支同名的本地分支(默认检出到 detached HEAD 状态);Timeout:设置检出超时时间(如 10 分钟,避免网络卡顿导致卡死);
- 用法 :点击
添加选择对应行为,按需配置。
3.2.2 Advanced clone behaviours(高级克隆行为)
- 作用:优化 Git 克隆逻辑(加速克隆、缓存复用、大文件处理),详细配置见「第四章」;
- 核心选项:浅克隆、参考仓库、克隆超时等。
3.2.3 Advanced sub-modules behaviours(高级子模块行为)
- 作用:若仓库包含 Git 子模块(submodule),配置子模块的拉取规则;
- 常用选项 :
Recursively update submodules:递归拉取所有子模块;Use credentials for submodules:为子模块单独配置访问凭证;
- 场景:项目依赖子模块(如公共组件库),需同步拉取子模块代码。
3.2.4 Check out to matching local branch(检出到匹配的本地分支)
- 作用:将远程分支检出为本地同名分支(默认检出为「分离头指针」状态);
- 用法:直接勾选;
- 场景 :需在构建中执行
git push等操作(分离头指针状态不支持提交)。
3.2.5 Checkout over SSH(通过 SSH 检出)
- 作用:强制使用 SSH 协议拉取代码(默认根据仓库 URL 自动选择协议);
- 用法:勾选后需配置 SSH 凭证(需提前在 Jenkins 中添加 SSH 私钥凭证);
- 场景:仓库仅支持 SSH 访问,或需避免 HTTPS 协议的 SSL 问题。
3.2.6 Clean after checkout(检出后清理)
- 作用:代码检出后,清理工作空间中的未跟踪文件(如构建产物、临时文件);
- 用法:直接勾选;
- 场景:避免旧构建产物影响新构建(如测试报告、日志文件残留)。
3.2.7 Clean before checkout(检出前清理)
- 作用:检出代码前,清空整个工作空间(比「检出后清理」更彻底);
- 用法:直接勾选;
- 场景:需确保工作空间完全干净(如依赖包缓存冲突、配置文件篡改),但会增加构建时间。
3.2.8 Custom user name/e-mail address(自定义用户名/邮箱)
- 作用:覆盖 Git 提交的用户名和邮箱(默认使用 Jenkins 节点的 Git 配置);
- 用法 :勾选后填写自定义的
Name和E-mail; - 场景:构建过程中需提交代码(如自动更新版本号),需指定提交人身份。
3.2.9 First Build Changelog(首次构建变更日志)
- 作用:首次构建时生成完整的变更日志(默认首次构建无变更记录);
- 用法 :勾选后选择日志生成规则(如
Include all commits); - 场景:需追溯首次构建的代码基线。
3.2.10 Git LFS pull after checkout(克隆后拉取 LFS 大文件)
- 作用:若仓库使用 Git LFS(大文件存储,如安装包、测试资源),自动拉取 LFS 跟踪的大文件;
- 用法:直接勾选(需 Jenkins 节点已安装 Git LFS 工具);
- 场景:项目包含超过 100MB 的大文件(Git 原生不适合存储大文件)。
3.2.11 Job display name strategy(任务显示名称策略)
- 作用:自定义分支流水线实例的显示名称(默认显示分支名);
- 用法 :选择策略(如
Branch name直接显示分支名,Repository name - Branch name显示仓库+分支名); - 场景:多仓库多分支场景,避免任务名称重复。
3.2.12 Prune stale remote-tracking branches(清理过期远程跟踪分支)
- 作用:构建时清理本地已不存在的远程分支(如远程分支已删除,本地残留的跟踪分支);
- 用法:直接勾选;
- 场景:避免过期分支占用工作空间,保持本地分支与远程同步。
3.2.13 Prune stale tags(清理过期标签)
- 作用:清理本地已不存在的远程标签(如远程标签已删除,本地残留标签);
- 用法:直接勾选;
- 场景:版本发布后删除旧标签,避免本地标签冗余。
3.2.14 Sparse Checkout paths(稀疏检出路径)
- 作用:仅拉取仓库中的指定目录/文件(无需克隆整个仓库),加速拉取;
- 用法 :
- 勾选后点击
添加,填写需要检出的路径(如src/、jenkins/);
- 勾选后点击
- 场景:仓库体积大,但构建仅依赖部分目录(如仅需拉取源代码目录,无需文档、资源文件)。
3.2.15 Use commit author in changelog(变更日志中使用提交作者)
- 作用:构建日志的「变更记录」中显示代码提交者的姓名和邮箱(默认显示 Jenkins 凭证用户);
- 用法:直接勾选;
- 场景:需追溯代码变更的实际提交人,方便问题定位。
3.2.16 Wipe out repository & force clone(清空仓库并强制克隆)
- 作用:每次构建前删除本地仓库,重新强制克隆(解决本地仓库缓存冲突);
- 用法:直接勾选;
- 注意 :会大幅增加构建时间,仅在本地仓库损坏(如
git操作失败)时临时启用。
3.2.17 Configure remote name(配置远程仓库名称)
- 作用 :自定义远程仓库的名称(默认远程名称为
origin); - 用法 :填写自定义名称(如
upstream); - 场景:仓库需关联多个远程仓库(如上游开源仓库+本地私有仓库)。
3.2.18 Specify ref specs(指定引用规范)
- 作用:自定义 Git 拉取的引用范围(如仅拉取特定分支、标签的提交);
- 用法 :填写 ref spec 格式(如
+refs/heads/*:refs/remotes/origin/*,默认拉取所有分支;+refs/tags/*:refs/tags/*拉取所有标签); - 场景:需限制拉取的分支/标签范围,减少数据传输量。
四、Advanced clone behaviours 详细配置
高级克隆行为用于优化代码拉取效率,尤其适合大仓库或网络不稳定场景,配置步骤:
进入多分支流水线 → 配置 → 分支源 → Advanced → Behaviours → 添加 → Advanced clone behaviours,展开后配置如下:
4.1 常用配置项(按优先级排序)
| 配置项 | 作用 | 用法/推荐值 | 适用场景 |
|---|---|---|---|
| Shallow clone(浅克隆) | 仅拉取最新提交,不下载完整历史 | 勾选,配合「Shallow clone depth」使用 | 测试、构建无需历史记录(如冒烟测试) |
| Shallow clone depth | 浅克隆深度(拉取最近 N 个提交) | 1-50(推荐 1,仅最新提交) | 加速克隆,减少数据传输 |
| Reference repository | 复用本地缓存仓库,仅拉取差异数据 | 勾选,填写本地镜像路径(如 D:\Jenkins\reference\SuuntoTest.git) |
同一节点多次拉取同一仓库 |
| Clone timeout | 克隆超时时间(避免无限等待) | 勾选,设置 10-30 分钟 | 网络不稳定(如跨国访问 GitHub) |
| Fetch only the reference branch | 仅拉取当前分支,不拉取其他分支引用 | 勾选 | 多分支流水线,无需其他分支数据 |
| Use credentials for every fetch | 每次拉取都使用凭证 | 勾选 | 私有仓库,避免凭证缓存失效 |
| Skip SSL verification | 忽略 HTTPS SSL 证书验证 | 仅 SSL 报错时勾选(测试环境) | 内网节点无法获取公开 SSL 证书 |
| LFS pull after clone | 克隆后自动拉取 Git LFS 大文件 | 仓库有 LFS 大文件时勾选 | 项目包含安装包、测试资源等大文件 |
4.2 关键配置说明
4.2.1 浅克隆(Shallow clone)
- 优势:拉取速度提升 50%-90%,尤其适合大仓库;
- 注意:浅克隆无法执行
git log --oneline(查看早期提交)、git diff(跨历史版本对比),若构建需依赖历史,请勿启用。
4.2.2 参考仓库(Reference repository)
-
需提前在 Jenkins 节点创建本地镜像(仅执行 1 次):
bash# Windows 节点(Git Bash 执行) git clone --mirror https://github.com/YourTest.git D:\Jenkins\reference\YourTest.git -
配置路径时使用 Windows 反斜杠(
\)或双斜杠(\\),确保 Jenkins 有读写权限。
4.2.3 克隆超时(Clone timeout)
- 单位:分钟,推荐 10 分钟(小仓库)或 30 分钟(大仓库);
- 超时后构建会失败,避免因网络卡顿占用 Jenkins 资源。
4.3 推荐配置组合(适配你的场景)
Shallow clone: ✅
Shallow clone depth: 1
Reference repository: ✅ → 路径:D:\Jenkins\reference\SuuntoTest.git
Clone timeout: ✅ → 10 分钟
Fetch only the reference branch: ✅
Use credentials for every fetch: ✅
五、流水线脚本:节点标签筛选(单个/多个标签)
多分支流水线通过 agent 配置指定执行节点,支持单个标签、多个标签(且/或关系)筛选,语法如下:
5.1 核心语法
Jenkins 标签筛选支持逻辑运算:
- 「且」关系:
标签A && 标签B(节点必须同时具备两个标签); - 「或」关系:
标签A 标签B(空格分隔,节点具备任一标签); - 「非」关系:
标签A && !标签B(节点有 A 标签但无 B 标签)。
5.2 配置示例(写入 Jenkinsfile)
groovy
pipeline {
// 节点标签筛选核心配置
agent {
// 方案 1:多个标签「且」关系(必须同时有 Android 和 Ng 标签)
label 'Android && Ng'
// 方案 2:单个标签(节点有 master 标签即可)
// label 'master'
// 方案 3:「或」关系(节点有 Android 或 iOS 标签)
// label 'Android iOS'
// 方案 4:参数化标签(优先使用用户输入,默认 Android && Ng)
// label params.NODE_LABEL ?: 'Android && Ng'
}
parameters {
// 可选:参数化标签,支持用户手动指定
string(name: 'NODE_LABEL', defaultValue: '', description: '执行节点标签(如 Android && Ng)')
}
stages {
stage('Test') {
steps {
echo "当前执行节点:${env.NODE_NAME}"
echo "节点标签:${env.NODE_LABELS}"
}
}
}
}
5.3 注意事项
- 标签大小写敏感:
Android≠android,Ng≠NG,需与节点配置的标签完全一致; - 节点配置标签:进入 Jenkins →
Manage Jenkins→节点→ 目标节点 →配置→Labels,填写标签(如master Android Ng)。
六、流水线脚本:定时任务配置
无需额外插件,直接在 Jenkinsfile 中通过 triggers 块配置定时构建,支持分支级差异化定时。
6.1 核心语法(Cron 表达式)
格式:分 时 日 月 周(空格分隔),支持通配符和逻辑运算:
*:任意值(如*表示每分钟/每小时);*/N:每 N 个单位(如*/5表示每 5 分钟);N-M:范围(如1-5表示周一至周五);N,M:多个值(如8,18表示 8 点和 18 点)。
6.2 常用 Cron 示例
| 需求 | Cron 表达式 | 说明 |
|---|---|---|
| 每天早上 8:00 执行 | 0 8 * * * |
分=0,时=8,日/月/周=任意 |
| 每周一至周五 9:30 执行 | 30 9 * * 1-5 |
周=1(周一)至 5(周五) |
| 每 6 小时执行一次 | 0 */6 * * * |
时=每 6 小时(0、6、12、18 点) |
| 每天 8:00、18:00 执行 | 0 8,18 * * * |
时=8 和 18 点(逗号分隔) |
6.3 配置示例(写入 Jenkinsfile)
groovy
pipeline {
agent { label 'Android && Ng' }
triggers {
// 方案 1:固定定时(每天 8 点执行)
cron('0 8 * * *')
// 方案 2:分支差异化定时(仅 main 分支定时,其他分支不定时)
// cron(env.BRANCH_NAME == 'main' ? '0 8 * * *' : '')
}
parameters {
// 定时执行时自动使用默认参数
string(name: 'TEST_MARKER', defaultValue: 'SMOKE and not NG')
string(name: 'UPGRADE', defaultValue: 'True')
}
stages {
stage('定时构建测试') {
steps {
echo "定时构建触发,分支:${env.BRANCH_NAME}"
echo "测试标签:${params.TEST_MARKER}"
}
}
}
}
6.4 验证定时生效
- 提交 Jenkinsfile 到代码仓库,多分支流水线自动扫描更新;
- 进入分支的流水线实例 →
配置→构建触发器,可看到自动生成的定时规则; - 临时测试:将 Cron 改为
*/5 * * * *(每 5 分钟执行),观察构建历史是否自动触发。
七、Poll SCM 实现代码 Push 触发构建
当 Jenkins 部署在内网(GitHub 无法通过 WebHook 访问)时,使用 Poll SCM 轮询方案(安装Poll SCM插件):Jenkins 定时检查代码仓库是否有新提交,有变更则自动触发对应分支构建。
7.1 配置步骤
- 进入多分支流水线 →
配置→分支源→Behaviours→添加→Poll SCM; - 填写
Schedule(轮询频率),示例:*/5 * * * *:每 5 分钟检查一次(实时性高,适合测试环境);*/15 * * * *:每 15 分钟检查一次(平衡实时性和服务器压力);
- 保存配置,Jenkins 会按频率扫描所有分支,有新提交则触发对应分支构建。
7.2 优势与注意事项
- 优势:无需外网访问,配置简单,适配内网 Jenkins 场景;
- 注意:
- 轮询频率越短,实时性越高,但会增加 Jenkins 和 GitHub 的 API 调用压力;
- 若仓库分支较多,建议配合「分支过滤」(如仅轮询 main、dev 分支),减少无效扫描。
7.3 补充:WebHook 实时触发(外网可访问场景)
若 Jenkins 可被 GitHub 访问,推荐使用 WebHook 实现实时触发(替代 Poll SCM):
- Jenkins 配置:进入多分支流水线 →
配置→构建触发器→ 勾选GitHub Hook Trigger for GITScm polling; - GitHub WebHook 配置:
- 仓库 →
Settings→Webhooks→Add webhook; Payload URL:http://Jenkins地址:端口/github-webhook/(末尾/必须保留);Content type:application/json;Which events:选择Just the push event;
- 仓库 →
- 提交代码后,GitHub 会立即通知 Jenkins,触发对应分支构建(延迟 < 10 秒)。
八、jenkinsFile示例
groovy
pipeline {
agent {
label params.NODE_LABEL ?: 'Android'
}
environment {
// 统一工作空间目录
WORKSPACE_DIR = "${env.WORKSPACE}\\SuuntoTest"
// 实时打印 Python 输出
PYTHONUNBUFFERED = true
// Windows 命令行 UTF-8 编码
CMD_ENCODING = "chcp 65001 > nul 2>&1"
}
parameters {
string(name: 'GIT_REPO_URL', defaultValue: 'git@github.com:Test.git', description: 'Git SSH 地址')
string(name: 'PLATFORM', defaultValue: 'android', description: '测试平台 (android/android+ng/android+dilu)')
string(name: 'TESTCASE', defaultValue: 'testcase_android/app/', description: '测试用例目录')
string(name: 'TEST_MARKER', defaultValue: 'SMOKE and not NG', description: '''
根据mark标签选择测试 适配-m 参数:
示例:
SMOKE
SMOKE and not NG
''')
string(name: 'TEST_NAME_EXPR', defaultValue: '', description: '''
根据测试函数/类名匹配选择测试 适配-k 参数:
示例:
test_week_tab
TestCalendar
''')
string(name: 'RERUNS', defaultValue: '1', description: '重试次数')
credentials(name: 'GIT_SSH_CRED', credentialType: 'ssh', defaultValue: 'github-ssh', description: 'SSH凭证用于拉取代码-私钥Jenkins配置的凭据ID')
string(name: 'SEND_METHOD', defaultValue: 'test', description: '新钉钉群需要配置')
string(name: 'UPGRADE', defaultValue: 'True', description: '是否升级,True or False')
string(name: 'NODE_LABEL', defaultValue: 'Android', description: '执行构建的节点标签(需配置 android_devices_id 环境变量)')
string(name: 'TITLE', defaultValue: 'Android每日冒烟', description: '测试任务标题')
}
stages {
stage('参数校验') {
steps {
script {
echo "======================================"
echo "📋 开始参数校验"
echo "======================================"
if (!env.android_devices_id) {
error "❌ 选中的节点(标签:${params.NODE_LABEL})未配置 android_devices_id 环境变量!\n请在 Jenkins 节点配置 → 节点属性 → 环境变量 中添加。"
}
echo "✅ 从节点环境变量获取 DEVICE_ID:${env.android_devices_id}"
}
}
}
stage('Checkout Code') {
steps {
script {
echo "======================================"
echo "📥 准备拉取代码到目录: ${env.WORKSPACE_DIR}"
echo "======================================"
withCredentials([sshUserPrivateKey(credentialsId: params.GIT_SSH_CRED, keyFileVariable: 'GIT_KEY')]) {
dir("${env.WORKSPACE_DIR}") {
// 判断是否为首次拉取(.git文件夹是否存在)
def isFirstCheckout = !fileExists(".git")
if (isFirstCheckout) {
echo "首次拉取代码,执行初始克隆..."
// 首次拉取:直接用原生git步骤克隆代码
git(
url: params.GIT_REPO_URL,
branch: env.BRANCH_NAME,
credentialsId: params.GIT_SSH_CRED,
changelog: true,
poll: false
)
bat """
@echo on
${env.CMD_ENCODING}
cd /d "${env.WORKSPACE_DIR}"
echo "首次拉取:设置 skip-worktree 防止后续操作覆盖"
git update-index --skip-worktree jenkins/jenkins_config.json
git update-index --skip-worktree jenkins/result.json
"""
} else {
try {
bat """
@echo on
set GIT_SSH_COMMAND=ssh -i "%GIT_KEY%"
cd /d "${env.WORKSPACE_DIR}"
echo "设置 skip-worktree 防止后续操作覆盖"
git update-index --skip-worktree jenkins/jenkins_config.json
git update-index --skip-worktree jenkins/result.json
echo "切换分支到 ${env.BRANCH_NAME}"
git checkout ${env.BRANCH_NAME}
echo "强制同步远程最新提交"
git fetch origin ${env.BRANCH_NAME}
git reset --hard origin/${env.BRANCH_NAME}
echo "清理未跟踪文件"
git clean -fd
echo "拉取最新代码"
git pull origin ${env.BRANCH_NAME}
"""
} catch (Exception e) {
echo "⚠️ 警告:git 操作失败,但继续执行后续步骤: ${e.getMessage()}"
}
}
}
}
}
}
}
stage('Initialize Config') {
steps {
script {
echo "======================================"
echo "⚙️ 初始化配置并写入 jenkins_config.json"
echo "======================================"
// 整合所有配置参数(DEVICE_ID 从节点环境变量获取)
def JENKINS_CONFIG = [
GIT_REPO_URL: params.GIT_REPO_URL,
BRANCH: env.BRANCH_NAME,
WORKSPACE_DIR: env.WORKSPACE_DIR,
PLATFORM: params.PLATFORM,
DEVICE_ID: env.android_devices_id,
TESTCASE: params.TESTCASE,
TEST_MARKER: params.TEST_MARKER,
TEST_NAME_EXPR: params.TEST_NAME_EXPR,
RERUNS: params.RERUNS,
JENKINS_BUILD_URL: env.BUILD_URL,
NOTIFY_EMAIL: params.NOTIFY_EMAIL,
JOB_URL: env.JOB_URL,
SEND_METHOD: params.SEND_METHOD,
BUILD_URL: env.BUILD_URL,
BUILD_NUMBER: env.BUILD_NUMBER,
JOB_NAME: env.JOB_NAME,
NODE_LABELS: env.NODE_LABELS,
NODE_NAME: env.NODE_NAME,
UPGRADE: params.UPGRADE,
TITLE: params.TITLE
]
def CONFIG_PATH = "${env.WORKSPACE_DIR}\\jenkins\\jenkins_config.json"
// 确保jenkins目录存在
writeJSON file: CONFIG_PATH, json: JENKINS_CONFIG
echo "✅ 配置文件已写入:${CONFIG_PATH}"
}
bat 'set'
}
}
stage('Setup Virtual Environment') {
steps {
script {
echo "======================================"
echo "🐍 设置虚拟环境并安装依赖"
echo "======================================"
dir("${env.WORKSPACE_DIR}") {
bat """
@echo on
${env.CMD_ENCODING}
set PYTHONIOENCODING=utf-8
set PYTHONPATH=${env.WORKSPACE_DIR}
echo "创建Python虚拟环境"
python -m venv .venv
echo "升级pip并安装pipenv"
.venv\\Scripts\\python.exe -m pip install --upgrade pip
.venv\\Scripts\\python.exe -m pip install pipenv
echo "通过pipenv安装项目依赖"
.venv\\Scripts\\python.exe -m pipenv install
"""
}
}
}
}
stage('Update Config') {
steps {
script {
echo "======================================"
echo "🔄 执行配置更新"
echo "======================================"
dir("${env.WORKSPACE_DIR}") {
bat """
@echo on
${env.CMD_ENCODING}
set PYTHONIOENCODING=utf-8
set PYTHONPATH=${env.WORKSPACE_DIR}
.venv\\Scripts\\python.exe jenkins\\config_manager.py
"""
}
}
}
}
stage('Generate Commit Report') {
steps {
script {
echo "======================================"
echo "📊 生成Git Commit历史报告"
echo "======================================"
dir("${env.WORKSPACE_DIR}") {
bat """
@echo on
${env.CMD_ENCODING}
set PYTHONIOENCODING=utf-8
set PYTHONPATH=${env.WORKSPACE_DIR}
.venv\\Scripts\\python.exe jenkins\\git_commit_report.py . commit_history.html
"""
// 归档报告(可选,在Jenkins界面查看)
archiveArtifacts artifacts: 'commit_history.html', allowEmptyArchive: true
echo "✅ Commit报告已生成并归档"
}
}
}
}
stage('Run Tests') {
steps {
script {
echo "======================================"
echo "🧪 开始执行测试用例"
echo "======================================"
echo "测试平台:${params.PLATFORM}"
echo "设备ID:${env.android_devices_id}"
echo "测试用例:${params.TESTCASE}"
echo "测试标签:${params.TEST_MARKER}"
try {
dir("${env.WORKSPACE_DIR}") {
bat """
@echo on
${env.CMD_ENCODING}
set PYTHONIOENCODING=utf-8
set PYTHONPATH=${env.WORKSPACE_DIR}
.venv\\Scripts\\python.exe jenkins\\executor.py
"""
}
echo "✅ 测试执行完成"
} catch (Exception e) {
currentBuild.result = 'FAILURE'
echo "❌ 测试执行失败:${e.getMessage()}"
throw e // 抛出异常,让Pipeline标记为失败
}
}
}
}
}
post {
success {
echo "======================================"
echo "✅ 流水线执行成功!"
echo "构建地址:${env.BUILD_URL}"
echo "======================================"
}
failure {
echo "======================================"
echo "❌ 流水线执行失败!"
echo "构建地址:${env.BUILD_URL}"
echo "======================================"
// 发送失败通知
dir("${env.WORKSPACE_DIR}") {
bat """
@echo on
${env.CMD_ENCODING}
set PYTHONIOENCODING=utf-8
set PYTHONPATH=${env.WORKSPACE_DIR}
.venv\\Scripts\\python.exe jenkins\\notification_sender.py --status failed
"""
}
}
}
}