AI辅助生成 Jenkins 流水线

引言

在现代软件开发中,持续集成和持续部署(CI/CD)已成为标准实践。对于需要在多个平台上运行的应用程序,确保代码在不同操作系统上的兼容性尤为重要。本文将介绍如何使用Jenkins和Jenkinsfile创建跨平台(Windows和Linux)的自动化测试流水线,帮助开发团队快速发现并解决平台特定的问题。

本文环境为 Windows11 和 WSL2。

在 AI 的辅助下,根据需求,可以快速生成一份 Jenkinsfile,再结合实际应用场景,不断地迭代完善。

效果展示:

Jenkins-test-linux

Jenkins-test-windows

Jenkins-test-allure-report

环境搭建:在WSL2中配置Jenkins

Docker Compose配置

首先,我们使用Docker在WSL2环境中部署Jenkins。以下是docker-compose.yml配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk17
container_name: jenkins
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
user: "1000:1000" # WSL2中通常使用1000:1000
environment:
- JENKINS_HOME=/var/jenkins_home
- JAVA_OPTS=-Xms512m -Xmx1g
- JENKINS_OPTS=--httpPort=8080
- TZ=Asia/Shanghai
- DOCKER_HOST=unix:///var/run/docker.sock
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8081/login || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 2G
cpus: '2.0'
reservations:
memory: 512M
cpus: '0.5'
restart: unless-stopped
networks:
- jenkins

networks:
jenkins:
driver: bridge

volumes:
jenkins_home:
driver: local

启动Jenkins容器

确保当前用户已添加到docker组,然后启动Jenkins容器:

1
2
sudo usermod -aG docker $USER
docker-compose up -d

初始化Jenkins

启动后,可以通过以下命令查看初始管理员密码:

1
docker logs -f jenkins

系统会生成一个初始密码,如:b91fb528a2ec464288d95a7783cc4fac,用于首次登录Jenkins。

安装必要插件

为了支持我们的流水线,需要安装以下插件:

  1. Git Parameter Plug-In:用于在构建时选择Git分支
  2. Allure Jenkins Plugin:用于生成测试报告

对于Allure插件,还需要在Jenkins的”Manage Jenkins”-“Tools”-“Allure Commandline installations”中添加Allure命令行工具。

跨平台测试流水线设计

我们的目标是创建两个独立但结构相似的流水线,分别针对Windows和Linux平台。这样可以:

  1. 并行测试不同平台,加快反馈速度
  2. 隔离平台特定的问题
  3. 确保代码在所有目标平台上正常工作

流水线共同特性

两个流水线共享以下特性:

  • 使用Git参数插件选择测试分支
  • 可配置测试目标路径
  • 自动检测代码变更并触发构建
  • 生成Allure测试报告
  • 构建命名包含平台、分支和提交信息
  • 错误处理和清理机制

Linux流水线详解

基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
pipeline {
agent {
label 'linux_label'
}

// 配置触发器 - 代码更新后自动触发
triggers {
// 轮询 SCM,检查代码变更(每2分钟检查一次,错开Windows流水线的触发时间)
pollSCM('1-59/2 * * * *')
}

// 定义可配置的参数
parameters {
// 分支选择参数
gitParameter(name: 'BRANCH', /* 其他配置 */)
// 测试目标参数
string(name: 'TEST_TARGET', defaultValue: 'tests/')
}

// 各个阶段...
}

关键阶段

  1. 平台检测:确认当前运行环境
1
2
3
4
5
6
7
8
stage('Platform Detection') {
steps {
script {
echo "=== Linux Platform Pipeline ==="
env.CURRENT_PLATFORM = 'linux'
}
}
}
  1. 获取Git信息:获取当前提交的详细信息
1
2
3
4
5
6
7
8
9
10
11
12
stage('Get Git Info') {
steps {
script {
// 获取Git提交信息的代码
gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
gitMessage = sh(returnStdout: true, script: 'git log -1 --pretty=format:"%s"').trim()

env.GIT_COMMIT_SHORT = gitCommit.length() > 7 ? gitCommit.take(7) : gitCommit
env.GIT_COMMIT_MESSAGE = gitMessage
}
}
}
  1. 设置构建名称:使用平台、分支和提交信息创建有意义的构建名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
stage('Set Build Name') {
steps {
script {
// 获取触发用户
def user = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause)?.userId ?: "Auto-Trigger"

// 处理分支名称
def branch_name = params.BRANCH ?: (env.GIT_BRANCH ? env.GIT_BRANCH.split('/').last() : 'main')

// 设置构建名称和描述
currentBuild.displayName = "#${BUILD_NUMBER}-Linux-${branch_name}-${env.GIT_COMMIT_SHORT}-${user}"
currentBuild.description = "Platform: Linux | Branch: ${branch_name} | Commit: ${env.GIT_COMMIT_MESSAGE}"
}
}
}
  1. 环境设置:配置Linux测试环境
1
2
3
4
5
6
7
8
9
10
11
12
stage('Setup Linux Environment') {
steps {
script {
sh '''
echo "=== Conda Environment Setup ==="
eval "$(conda shell.bash hook 2>/dev/null)" > /dev/null
conda activate env3.10
echo "Python: $(which python) ($(python --version))"
'''
}
}
}
  1. 运行单元测试:执行测试并生成报告
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
stage('Run Unit Tests on Linux') {
steps {
script {
// 清理之前的测试结果
sh '''
rm -rf allure-results
mkdir -p allure-results
'''

// 执行测试
try {
sh '''
eval "$(conda shell.bash hook 2>/dev/null)" > /dev/null
conda activate env3.10
python -m pytest ''' + params.TEST_TARGET + ''' -v -s --alluredir=allure-results
'''

currentBuild.result = 'SUCCESS'
} catch (Exception e) {
currentBuild.result = 'UNSTABLE'
echo "Unit tests have failed test cases on Linux: ${e.message}"
}
}
}
post {
always {
// 发布测试报告
allure results: [[path: 'allure-results']]
}
}
}

Windows流水线详解

关键差异

Windows流水线与Linux流水线结构相似,但有以下关键差异:

  1. 使用不同的执行器
1
2
3
agent {
label 'win_label'
}
  1. 不同的命令执行方式:使用bat而不是sh
1
2
3
4
5
// Linux中
gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()

// Windows中
gitCommit = bat(returnStdout: true, script: '@git rev-parse HEAD 2>nul').trim()
  1. Windows特定的环境设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
stage('Setup Windows Environment') {
steps {
script {
bat '''
echo Checking Python environment on Windows...
where python
python --version

echo Getting virtual environment activation script path...
python -c "import os, sys; print(os.path.join(os.path.dirname(sys.executable), 'Scripts', 'activate.bat'), end='')" > activate_path.txt
'''
}
}
}
  1. Windows特定的测试执行
1
2
3
4
5
6
7
bat '''
echo Starting unit tests on Windows...
set /p ACTIVATE_PATH=<activate_path.txt
call "%ACTIVATE_PATH%" envPy3.12
python --version
python -m pytest ''' + params.TEST_TARGET + ''' -v -s --alluredir=allure-results
'''
  1. Windows特定的文件操作
1
2
3
4
5
// Linux中
sh 'rm -rf allure-results'

// Windows中
bat 'if exist allure-results rmdir /s /q allure-results'

流水线高级特性

错开触发时间

为避免同时触发两个流水线导致资源竞争,我们错开了SCM轮询时间:

1
2
3
4
5
// Linux流水线
pollSCM('1-59/2 * * * *') // 奇数分钟触发

// Windows流水线
pollSCM('H/2 * * * *') // 每两分钟触发一次,时间由Jenkins决定

构建选项

两个流水线都配置了相同的构建选项:

1
2
3
4
5
6
7
8
9
10
options {
// 保留构建日志的策略
buildDiscarder(logRotator(numToKeepStr: '100', artifactNumToKeepStr: '50'))
// 超时处理
timeout(time: 60, unit: 'MINUTES')
// 跳过默认的 checkout
skipDefaultCheckout(false)
// 时间戳
timestamps()
}

构建后操作

根据构建结果执行不同的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
post {
success {
echo "Unit tests executed successfully! All test cases passed."
}
unstable {
echo "Unit tests completed, but some test cases failed. Please check the test report."
}
failure {
echo "Unit test execution failed. Please check build logs and test reports."
}
always {
// 清理临时文件
}
}

最佳实践与经验总结

  1. 平台特定代码隔离:将平台特定的命令和路径处理隔离在各自的流水线中
  2. 统一测试报告:使用Allure等工具统一不同平台的测试报告格式
  3. 错开触发时间:避免资源竞争
  4. 优雅处理失败:即使测试失败也生成报告,方便排查问题
  5. 清晰的构建命名:包含平台、分支和提交信息,便于快速识别
  6. 环境变量管理:使用环境变量传递信息,避免重复计算

常见问题及解决方案

在WSL环境中使用Jenkins时,可能会遇到一些网络或权限相关的问题。例如,在WSL命令行中无法下载agent.jar文件:

1
curl.exe -sO http://127.0.0.1:8081/jnlpJars/agent.jar  # 无法下载

这种情况可能是由于WSL的网络配置问题导致的,可以尝试从Windows下载后复制到WSL环境。

结论

通过使用Jenkins和Jenkinsfile创建跨平台测试流水线,我们可以:

  1. 自动化测试在不同平台上的执行
  2. 快速发现平台特定的兼容性问题
  3. 提高代码质量和可靠性
  4. 加速开发和发布周期

这种方法特别适合需要在多个平台上运行的应用程序,如跨平台桌面应用、库或框架。通过持续集成和自动化测试,开发团队可以更加专注于功能开发,同时保持高质量的代码库。