03-Jenkins_Pipeline语法详解
·
Jenkins Pipeline语法详解:从基础到高级应用的完整指南
1. Pipeline执行模型深度解析
1.1 Pipeline核心架构
Jenkins Pipeline是Jenkins 2.0引入的核心特性,它将CI/CD流程以代码形式定义,实现了"Pipeline as Code"的理念。Pipeline基于Groovy脚本语言构建,通过CPS(Continuation Passing Style)转换实现持久化和恢复能力。
技术原理说明:
| 组件 | 职责 | 技术实现 |
|---|---|---|
| CPS转换器 | 将Groovy脚本转换为可序列化的续体形式 | ASM字节码操作、Groovy AST转换 |
| FlowNode | Pipeline执行的最小单元,代表一个步骤或阶段 | 有向无环图(DAG)节点 |
| FlowGraph | Pipeline执行的完整流程图,记录节点间依赖关系 | 邻接表存储结构 |
| CpsFlowExecution | Pipeline执行的核心控制器,管理执行状态 | 状态机模式 |
1.2 CPS转换机制详解
CPS(Continuation Passing Style)是Pipeline能够实现持久化和恢复的核心技术。当Pipeline执行过程中Jenkins重启或发生中断时,CPS机制能够保存当前执行状态,并在恢复后继续执行。
/**
* CPS转换示例说明
*
* 原始Groovy代码:
* def result = compute(1, 2)
* println result
*
* CPS转换后(伪代码):
* compute(1, 2, new Continuation() {
* Object receive(Object result) {
* println result
* return null
* }
* })
*/
// Pipeline中的CPS限制示例
pipeline {
agent any
stages {
stage('CPS Demo') {
steps {
script {
// ✅ 正确:使用Pipeline兼容的语法
def result = sh(script: 'echo 42', returnStdout: true).trim()
echo "Result: ${result}"
// ❌ 错误:非CPS兼容的操作
// def file = new File('/tmp/test.txt')
// file.text = 'hello' // 文件操作在CPS中不支持
// ✅ 正确:使用Pipeline提供的文件操作Step
writeFile file: '/tmp/test.txt', text: 'hello'
}
}
}
}
}
1.3 FlowNode执行流程
FlowNode状态持久化机制:
// FlowNode状态持久化核心逻辑(源码解析)
public class FlowNode {
// 节点唯一标识
private final String id;
// 父节点引用(构成DAG)
private final List<FlowNode> parents;
// 节点执行状态
private FlowNodeStatus status;
// 持久化到磁盘
public void save() {
// 序列化节点状态到 build.xml
// 路径: JENKINS_HOME/jobs/{job}/builds/{build}/build.xml
getXStream().toXML(this, new FileOutputStream(getStateFile()));
}
// 从磁盘恢复
public static FlowNode load(String id) {
return (FlowNode) getXStream().fromXML(new FileInputStream(getStateFile()));
}
}
2. 声明式与脚本式Pipeline对比分析
2.1 两种范式对比
Jenkins Pipeline提供两种语法范式:声明式(Declarative) 和 脚本式(Scripted)。两种范式各有优劣,适用于不同场景。
2.2 详细对比表
| 特性维度 | 声明式Pipeline | 脚本式Pipeline |
|---|---|---|
| 语法结构 | 结构化、预定义块 | Groovy脚本、自由形式 |
| 学习曲线 | 低,易于上手 | 高,需要Groovy知识 |
| 错误检测 | 编译时检测,错误提示友好 | 运行时检测,调试困难 |
| 灵活性 | 受限,遵循规范 | 高,完全自由 |
| 代码可读性 | 高,结构清晰 | 依赖编码规范 |
| IDE支持 | 较好,有语法高亮 | 一般,Groovy支持 |
| 适用场景 | 标准CI/CD流程、团队协作 | 复杂逻辑、高级定制 |
| 重启恢复 | 完全支持 | 完全支持 |
| Blue Ocean | 完美支持 | 部分支持 |
2.3 声明式Pipeline完整示例
/**
* 声明式Pipeline完整示例
* 演示所有核心指令的使用方法
*
* 环境要求:
* - Jenkins LTS 2.400+
* - Pipeline: Declarative Plugin 2.40+
* - 相关Agent节点已配置
*/
pipeline {
// ==================== Agent配置 ====================
// 必选:定义Pipeline执行位置
// any: 任意可用节点
// none: 不指定,各stage单独指定
// label 'xxx': 指定标签节点
// docker { image 'xxx' }: Docker容器
// kubernetes { yaml '...' }: Kubernetes Pod
agent any
// ==================== 环境变量 ====================
// 可选:定义Pipeline级别环境变量
// 支持静态值、动态表达式、凭证注入
environment {
// 静态值定义
APP_NAME = 'my-application'
VERSION = '1.0.0'
// 动态表达式(Groovy语法)
BUILD_TIME = "${new Date().format('yyyy-MM-dd_HH-mm-ss')}"
GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD 2>/dev/null || echo "unknown"',
returnStdout: true
).trim()
// 凭证注入 - 用户名密码类型
// 自动创建: DB_CREDS_USR 和 DB_CREDS_PSW 变量
DB_CREDS = credentials('database-credentials')
// 凭证注入 - Secret Text类型
API_KEY = credentials('api-secret-key')
// 凭证注入 - 分别获取用户名密码
DB_USER = credentials('database-credentials').username
DB_PASS = credentials('database-credentials').password
}
// ==================== 构建参数 ====================
// 可选:定义构建参数,支持多种类型
parameters {
// 字符串参数
string(
name: 'BRANCH_NAME', // 参数名称(必选)
defaultValue: 'main', // 默认值(可选)
description: 'Git分支名称', // 描述(可选)
trim: true // 是否去除首尾空格(可选,默认false)
)
// 布尔参数
booleanParam(
name: 'DEPLOY_ENABLED',
defaultValue: false,
description: '是否执行部署'
)
// 选择参数
choice(
name: 'DEPLOY_ENV',
choices: ['development', 'staging', 'production'],
description: '部署环境选择'
)
// 密码参数(加密存储)
password(
name: 'SECRET_TOKEN',
defaultValue: '',
description: '安全令牌'
)
// 文本参数(多行文本)
text(
name: 'RELEASE_NOTES',
defaultValue: '',
description: '发布说明'
)
// 运行参数(选择其他构建)
run(
name: 'UPSTREAM_BUILD',
projectName: 'upstream-job-name',
description: '选择上游构建',
filter: 'SUCCESSFUL' // 可选值: ALL, SUCCESSFUL, FAILED, UNSTABLE
)
// 文件参数(上传文件)
file(
name: 'CONFIG_FILE',
description: '上传配置文件'
)
}
// ==================== 触发器配置 ====================
// 可选:定义自动触发规则
triggers {
// Cron定时触发
// 格式: 分 时 日 月 周
// H表示哈希值,避免同时触发
cron('H/15 * * * *') // 每15分钟执行一次
// SCM轮询触发
// 检测代码仓库变化时触发
pollSCM('H/5 * * * *') // 每5分钟检查一次
// 上游项目触发
// 当指定项目完成时触发
upstream(
upstreamProjects: 'build-job, test-job',
threshold: hudson.model.Result.SUCCESS // 触发阈值
)
// GitHub Webhook触发
githubPush()
// GitLab Webhook触发
gitlab(
triggerOnPush: true,
triggerOnMergeRequest: true,
branchFilterType: 'All'
)
// Bitbucket Webhook触发
bitbucketPush()
}
// ==================== 工具配置 ====================
// 可选:自动配置构建工具到PATH
// 需要在"全局工具配置"中预先定义
tools {
// Maven配置
maven 'Maven-3.9.5' // 全局工具配置中的名称
// JDK配置
jdk 'JDK-17'
// Gradle配置
gradle 'Gradle-8.4'
// Node.js配置
nodejs 'NodeJS-18'
// Git配置
git 'Git-2.42'
}
// ==================== Pipeline选项 ====================
// 可选:Pipeline级别配置选项
options {
// 构建超时设置
timeout(
time: 1,
unit: 'HOURS' // 可选值: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
)
// 失败重试次数
retry(3)
// 跳过默认的SCM检出
skipDefaultCheckout(true)
// 禁止并发构建
disableConcurrentBuilds(
abortPrevious: false // 是否中止前一个构建,默认false
)
// 构建历史管理
buildDiscarder(
logRotator(
numToKeepStr: '20', // 保留构建数量
daysToKeepStr: '30', // 保留天数
artifactNumToKeepStr: '5', // 保留制品数量
artifactDaysToKeepStr: '7' // 制品保留天数
)
)
// 时间戳输出
timestamps()
// ANSI颜色输出
ansiColor('xterm') // 可选值: xterm, vga, css, gnome-terminal
// 静默期(秒)
quietPeriod(10)
// 构建变为不稳定后跳过后续阶段
skipStagesAfterUnstable()
// 并行阶段快速失败
// 任一并行阶段失败立即中止其他
parallelsAlwaysFailFast()
// 构建速率限制
rateLimitBuilds(
throttle: [
count: 2,
durationName: 'hour',
userBoost: true // 用户手动触发是否豁免
]
)
// 资源锁定
lock(resource: 'deploy-lock')
// 自定义工作空间
customWorkspace('workspace/my-project')
}
// ==================== 输入配置 ====================
// 可选:Pipeline级别输入确认
input {
message "确认部署到生产环境?"
id "deploy-approval" // 唯一标识符
ok "确认部署" // 确认按钮文本
submitter "admin,ops-team" // 允许提交的用户/组
submitterParameter "APPROVER" // 提交者存入变量名
parameters {
string(name: 'DEPLOY_VERSION', defaultValue: '1.0.0')
booleanParam(name: 'SKIP_TESTS', defaultValue: false)
}
}
// ==================== 阶段定义 ====================
// 必选:定义构建阶段
stages {
stage('代码检出') {
// Stage级别选项
options {
timeout(time: 5, unit: 'MINUTES')
retry(2)
}
// Stage级别环境变量
environment {
GIT_URL = 'https://github.com/company/project.git'
}
steps {
script {
echo "开始检出代码: ${env.GIT_URL}"
}
checkout scm
}
}
stage('构建') {
agent {
docker {
image 'maven:3.9.5-eclipse-temurin-17'
args '-v $HOME/.m2:/root/.m2 -e MAVEN_OPTS=-Xmx2g'
}
}
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('测试') {
parallel {
stage('单元测试') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('集成测试') {
steps {
sh 'mvn verify -P integration-test'
}
post {
always {
junit '**/target/failsafe-reports/*.xml'
}
}
}
stage('代码质量') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
}
}
stage('部署') {
when {
allOf {
branch 'main'
expression { params.DEPLOY_ENABLED == true }
}
}
steps {
sh './deploy.sh ${params.DEPLOY_ENV}'
}
}
}
// ==================== 构建后处理 ====================
// 可选:定义构建后操作
post {
// 总是执行
always {
cleanWs() // 清理工作空间
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
// 成功时执行
success {
emailext(
subject: "✅ 构建成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
<h2>构建成功</h2>
<p><strong>项目:</strong> ${env.JOB_NAME}</p>
<p><strong>构建号:</strong> ${env.BUILD_NUMBER}</p>
<p><strong>持续时间:</strong> ${currentBuild.durationString}</p>
<p><a href="${env.BUILD_URL}">查看详情</a></p>
""",
to: 'team@company.com',
mimeType: 'text/html'
)
}
// 失败时执行
failure {
emailext(
subject: "❌ 构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "构建失败,请检查日志: ${env.BUILD_URL}console",
to: 'team@company.com'
)
}
// 不稳定时执行(测试失败等)
unstable {
echo '构建状态不稳定,请检查测试结果'
}
// 中止时执行
aborted {
echo '构建被中止'
}
// 结果改变时执行
changed {
echo "构建结果从 ${currentBuild.previousBuild?.result} 变为 ${currentBuild.result}"
}
// 从失败恢复时执行
fixed {
emailext(
subject: "🔧 构建已恢复: ${env.JOB_NAME}",
to: 'team@company.com'
)
}
// 从成功变为失败时执行
regression {
emailext(
subject: "⚠️ 构建回退: ${env.JOB_NAME}",
to: 'team@company.com'
)
}
// 清理(always之后执行)
cleanup {
deleteDir() // 删除整个工作空间
}
}
}
2.4 脚本式Pipeline完整示例
/**
* 脚本式Pipeline完整示例
* 演示Groovy语法的完整使用
*
* 注意事项:
* - 需要Groovy语法知识
* - 错误处理需要手动实现
* - 结构相对自由,需要自行规范
*/
// 定义节点
node('linux') {
// 定义全局变量
def appName = 'my-application'
def buildNumber = env.BUILD_NUMBER
// 设置构建名称
currentBuild.displayName = "Build-${buildNumber}"
currentBuild.description = "构建于 ${new Date().format('yyyy-MM-dd HH:mm:ss')}"
try {
// ==================== 代码检出阶段 ====================
stage('代码检出') {
echo "开始检出代码..."
// 检出代码
checkout([
$class: 'GitSCM',
branches: [[name: "*/${params.BRANCH_NAME ?: 'main'}"]],
userRemoteConfigs: [[
url: 'https://github.com/company/project.git',
credentialsId: 'git-credentials'
]]
])
// 获取Git信息
env.GIT_COMMIT = sh(
script: 'git rev-parse HEAD',
returnStdout: true
).trim()
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
echo "Git Commit: ${env.GIT_COMMIT_SHORT}"
}
// ==================== 构建阶段 ====================
stage('构建') {
echo "开始构建..."
// 使用Maven构建
sh 'mvn clean package -DskipTests'
// 检查构建产物
def artifacts = sh(
script: 'ls -la target/*.jar',
returnStdout: true
)
echo "构建产物:\n${artifacts}"
}
// ==================== 并行测试阶段 ====================
stage('测试') {
parallel(
// 单元测试
'单元测试': {
stage('单元测试') {
try {
sh 'mvn test'
} finally {
// 收集测试报告
junit '**/target/surefire-reports/*.xml'
}
}
},
// 集成测试
'集成测试': {
stage('集成测试') {
try {
sh 'mvn verify -P integration-test'
} finally {
junit '**/target/failsafe-reports/*.xml'
}
}
},
// 代码质量检查
'代码质量': {
stage('代码质量') {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
},
// 快速失败配置
failFast: true // 任一失败立即中止其他
)
}
// ==================== 部署阶段 ====================
stage('部署') {
// 条件判断
if (env.BRANCH_NAME == 'main' && params.DEPLOY_ENABLED) {
// 等待用户确认
input message: '确认部署到生产环境?', ok: '确认部署', submitter: 'admin,ops'
// 部署脚本
sh "./deploy.sh production"
echo "部署完成"
} else {
echo "跳过部署(分支: ${env.BRANCH_NAME}, 部署开关: ${params.DEPLOY_ENABLED})"
}
}
// 设置构建成功
currentBuild.result = 'SUCCESS'
} catch (Exception e) {
// 异常处理
currentBuild.result = 'FAILURE'
echo "构建失败: ${e.message}"
throw e
} finally {
// 清理工作空间
cleanWs()
// 发送通知
if (currentBuild.result == 'SUCCESS') {
emailext(
subject: "构建成功: ${env.JOB_NAME}",
to: 'team@company.com'
)
} else {
emailext(
subject: "构建失败: ${env.JOB_NAME}",
to: 'team@company.com'
)
}
}
}
3. 声明式Pipeline完整语法详解
3.1 Agent配置详解
Agent定义了Pipeline或Stage的执行位置,是Pipeline的核心配置。
Agent配置完整示例:
pipeline {
// ==================== Agent类型详解 ====================
// 类型1: any - 任意可用节点
agent any
// 类型2: none - 不指定(各Stage需单独指定)
agent none
// 类型3: label - 指定标签
agent { label 'linux && docker' }
// 类型4: node - 带额外配置
agent {
node {
label 'linux'
customWorkspace '/opt/workspace/my-project'
}
}
// 类型5: docker - Docker容器(完整参数)
agent {
docker {
// 必选参数
image 'maven:3.9.5-eclipse-temurin-17' // Docker镜像
// 可选参数
label 'docker' // 节点标签
args '-v $HOME/.m2:/root/.m2' // Docker运行参数
registryUrl 'https://registry.company.com' // 私有仓库URL
registryCredentialsId 'docker-creds' // 仓库凭证
alwaysPull true // 总是拉取最新镜像
reuseNode true // 重用节点工作空间
customWorkspace 'my-workspace' // 自定义工作空间
}
}
// 类型6: dockerfile - 从Dockerfile构建
agent {
dockerfile {
filename 'Dockerfile.build' // Dockerfile文件名
dir 'docker' // Dockerfile目录
label 'docker' // 节点标签
additionalBuildArgs '--build-arg VERSION=1.0' // 构建参数
registryUrl 'https://registry.company.com'
registryCredentialsId 'docker-creds'
}
}
// 类型7: kubernetes - Kubernetes Pod(完整配置)
agent {
kubernetes {
// YAML定义Pod模板
yaml '''
apiVersion: v1
kind: Pod
metadata:
labels:
app: jenkins-agent
spec:
containers:
- name: maven
image: maven:3.9.5-eclipse-temurin-17
command:
- cat
tty: true
resources:
limits:
memory: "4Gi"
cpu: "2"
requests:
memory: "2Gi"
cpu: "1"
volumeMounts:
- name: maven-cache
mountPath: /root/.m2
- name: docker
image: docker:24.0.5
command:
- cat
tty: true
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: maven-cache
persistentVolumeClaim:
claimName: maven-cache-pvc
- name: docker-sock
hostPath:
path: /var/run/docker.sock
'''
// 默认容器
defaultContainer 'maven'
// YAML文件路径(替代内联YAML)
yamlFile 'kubernetes/pod-template.yaml'
// 连接超时
connectTimeout 60
// Pod保留时间
podRetention never // never, onFailure, always
// 服务账户
serviceAccount 'jenkins-agent'
// 命名空间
namespace 'jenkins-ci'
}
}
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
}
}
3.2 Environment环境变量详解
pipeline {
agent any
environment {
// ============ 静态值 ============
APP_NAME = 'my-application'
VERSION = '1.0.0'
// ============ 动态表达式 ============
// 使用Groovy表达式
BUILD_TIMESTAMP = "${new Date().format('yyyy-MM-dd_HH-mm-ss')}"
// 使用Shell命令
GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD 2>/dev/null || echo "unknown"',
returnStdout: true
).trim()
// 使用环境变量组合
ARTIFACT_NAME = "${APP_NAME}-${VERSION}-${BUILD_TIMESTAMP}"
// ============ 凭证注入 ============
// 用户名密码类型 - 自动创建 DB_CREDS_USR 和 DB_CREDS_PSW
DB_CREDS = credentials('database-credentials')
// Secret Text类型
API_KEY = credentials('api-secret-key')
// Secret File类型 - 返回文件路径
SSH_KEY_PATH = credentials('ssh-private-key-file')
// 证书类型
CLIENT_CERT = credentials('client-certificate')
// SSH私钥类型
GIT_SSH_KEY = credentials('git-ssh-key')
// ============ 凭证属性访问 ============
// 分别获取用户名和密码
DB_USERNAME = credentials('database-credentials').username
DB_PASSWORD = credentials('database-credentials').password
// ============ 跨Stage共享 ============
DEPLOY_ENV = "${params.ENVIRONMENT ?: 'development'}"
}
stages {
stage('Environment Demo') {
// Stage级别环境变量
environment {
STAGE_VAR = 'stage-specific-value'
}
steps {
script {
// 访问环境变量
echo "应用名称: ${env.APP_NAME}"
echo "构建时间: ${env.BUILD_TIMESTAMP}"
echo "Git提交: ${env.GIT_COMMIT_SHORT}"
// 使用凭证(注意:敏感信息会被掩码)
echo "数据库用户: ${env.DB_CREDS_USR}"
// echo "数据库密码: ${env.DB_CREDS_PSW}" // 会被掩码显示
}
}
}
}
}
环境变量优先级(从高到低):
4. 核心Step完整参数详解
4.1 文件操作Step
pipeline {
agent any
stages {
stage('File Operations') {
steps {
// ============ stash/unstash - 文件暂存与恢复 ============
/**
* stash - 暂存文件
*
* @param name 暂存名称(必选),用于后续unstash引用
* @param includes 包含文件模式(可选),默认"**",支持通配符
* @param excludes 排除文件模式(可选),默认无
* @param allowEmpty 允许空暂存(可选),默认false
* @param useDefaultExcludes 是否使用默认排除规则(可选),默认true
*
* 默认排除规则: .git, .svn, target, node_modules等
*/
stash(
name: 'source-code',
includes: 'src/**,pom.xml,config/**',
excludes: 'src/test/**,**/*.log',
allowEmpty: false,
useDefaultExcludes: true
)
/**
* unstash - 恢复暂存文件
*
* @param name 暂存名称(必选),对应stash的name
* @param dir 恢复到子目录(可选),默认根目录
* @param quiet 静默模式(可选),默认false
*/
unstash(
name: 'source-code',
dir: 'restored',
quiet: false
)
// ============ dir/ws - 目录切换 ============
/**
* dir - 切换工作目录
* 在指定目录下执行闭包中的操作
*/
dir('subdirectory') {
sh 'ls -la'
writeFile file: 'test.txt', text: 'Hello World'
}
/**
* ws - 创建临时工作空间
* 在新的工作空间目录下执行操作
*/
ws('temp-workspace') {
sh 'pwd'
echo "当前工作空间: ${pwd()}"
}
// ============ 文件读写 ============
/**
* readFile - 读取文件内容
*
* @param file 文件路径(必选),相对或绝对路径
* @param encoding 文件编码(可选),默认UTF-8
*/
def fileContent = readFile(
file: 'config.json',
encoding: 'UTF-8'
)
echo "文件内容: ${fileContent}"
/**
* writeFile - 写入文件
*
* @param file 文件路径(必选)
* @param text 写入内容(必选)
* @param encoding 文件编码(可选),默认UTF-8
*/
writeFile(
file: 'output.txt',
text: 'Hello Jenkins Pipeline',
encoding: 'UTF-8'
)
// ============ JSON处理 ============
/**
* readJSON - 读取JSON文件或文本
*
* @param file JSON文件路径(二选一)
* @param text JSON文本内容(二选一)
*/
def config = readJSON(file: 'config.json')
echo "配置项: ${config.key}"
def jsonData = readJSON(text: '{"name":"test","value":123}')
echo "名称: ${jsonData.name}, 值: ${jsonData.value}"
/**
* writeJSON - 写入JSON文件
*
* @param file 输出文件路径(必选)
* @param json JSON对象(必选)
* @param pretty 格式化输出(可选),默认false
*/
writeJSON(
file: 'output.json',
json: [
name: 'test',
version: '1.0.0',
dependencies: ['lib1', 'lib2']
],
pretty: 2 // 缩进空格数
)
// ============ YAML处理 ============
/**
* readYaml - 读取YAML文件
*/
def yamlConfig = readYaml(file: 'config.yaml')
echo "YAML配置: ${yamlConfig}"
/**
* writeYaml - 写入YAML文件
*/
writeYaml(
file: 'output.yaml',
data: [
application: [
name: 'my-app',
version: '1.0.0'
]
]
)
// ============ Properties文件处理 ============
/**
* readProperties - 读取Properties文件
*/
def props = readProperties file: 'gradle.properties'
echo "版本: ${props.version}"
// ============ 文件检查 ============
/**
* fileExists - 检查文件是否存在
*/
if (fileExists('pom.xml')) {
echo 'Maven项目'
} else if (fileExists('build.gradle')) {
echo 'Gradle项目'
}
/**
* isUnix - 检查是否为Unix系统
*/
if (isUnix()) {
sh 'chmod +x script.sh'
} else {
bat 'echo Windows'
}
}
}
}
}
4.2 Shell执行Step
pipeline {
agent any
stages {
stage('Shell Execution') {
steps {
// ============ sh - Shell脚本执行 ============
/**
* sh - 执行Shell脚本
*
* @param script 脚本内容(必选)
* @param returnStdout 返回标准输出(可选),默认false
* @param returnStatus 返回状态码(可选),默认false
* @param encoding 输出编码(可选),默认UTF-8
* @param label 日志标签(可选)
*/
// 基本用法
sh 'echo "Hello World"'
// 多行脚本
sh '''
#!/bin/bash
set -e # 遇错即停
set -x # 打印执行的命令
echo "开始构建..."
mvn clean package
echo "构建完成"
'''
// 获取输出
def output = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
echo "Git提交: ${output}"
// 获取状态码
def status = sh(
script: 'test -f pom.xml',
returnStatus: true
)
if (status == 0) {
echo 'pom.xml存在'
} else {
echo 'pom.xml不存在'
}
// 带标签
sh(
script: 'mvn test',
label: '执行单元测试'
)
// ============ bat - Windows批处理 ============
/**
* bat - 执行Windows批处理命令
* 参数与sh相同
*/
bat '''
@echo off
echo Building on Windows...
mvn clean package
'''
// ============ powershell - PowerShell脚本 ============
/**
* powershell - 执行PowerShell脚本
*/
powershell '''
Write-Host "Building with PowerShell..."
mvn clean package
'''
}
}
}
}
4.3 流程控制Step
pipeline {
agent any
stages {
stage('Flow Control') {
steps {
// ============ withEnv - 临时环境变量 ============
/**
* withEnv - 设置临时环境变量
* 仅在闭包内有效
*
* 语法: withEnv([变量列表]) { 闭包 }
*
* 特殊语法:
* - PATH+XXX: 在PATH前面添加
* - PATH+XXX=值: 添加到PATH前面
*/
withEnv([
'MAVEN_OPTS=-Xmx2g -XX:+HeapDumpOnOutOfMemoryError',
'PATH+MAVEN=/opt/maven/bin',
'CUSTOM_VAR=custom_value'
]) {
sh 'echo $MAVEN_OPTS'
sh 'mvn package'
}
// ============ catchError - 错误捕获 ============
/**
* catchError - 捕获错误并继续执行
*
* @param buildResult 捕获后设置的构建结果(可选)
* @param stageResult 捕获后设置的阶段结果(可选)
* @param message 错误消息(可选)
* @param catchInterruptions 是否捕获中断(可选),默认true
*/
catchError(
buildResult: 'UNSTABLE',
stageResult: 'FAILURE',
message: '构建步骤失败,但继续执行',
catchInterruptions: false
) {
sh 'exit 1' // 这个错误会被捕获
}
echo '继续执行后续步骤'
// ============ retry - 重试 ============
/**
* retry - 失败重试
*
* @param count 重试次数
*/
retry(3) {
sh '''
# 模拟不稳定的操作
if [ $((RANDOM % 3)) -eq 0 ]; then
echo "操作成功"
else
echo "操作失败,将重试"
exit 1
fi
'''
}
// ============ timeout - 超时控制 ============
/**
* timeout - 超时控制
*
* @param time 超时时间
* @param unit 时间单位(可选)
* NANOSECONDS, MICROSECONDS, MILLISECONDS
* SECONDS, MINUTES, HOURS, DAYS
*/
timeout(time: 10, unit: 'MINUTES') {
sh 'long-running-task.sh'
}
// ============ waitUntil - 等待条件 ============
/**
* waitUntil - 等待条件满足
*
* @param initialRecurrencePeriod 初始等待时间(毫秒,可选)
* @param quiet 静默模式(可选),默认false
*/
waitUntil(
initialRecurrencePeriod: 5000,
quiet: false
) {
def response = sh(
script: 'curl -s -o /dev/null -w "%{http_code}" http://service:8080/health',
returnStdout: true
)
return response == '200'
}
// ============ sleep - 休眠 ============
/**
* sleep - 暂停执行
*
* @param time 休眠时间
* @param unit 时间单位(可选),默认SECONDS
*/
sleep(time: 10, unit: 'SECONDS')
// ============ error - 主动抛出错误 ============
/**
* error - 主动抛出错误并终止构建
*/
script {
def validation = sh(script: 'validate-config.sh', returnStatus: true)
if (validation != 0) {
error("配置验证失败,终止构建")
}
}
// ============ unstable - 设置不稳定状态 ============
/**
* unstable - 将构建标记为不稳定
*/
script {
def testFailures = sh(
script: 'grep -c "FAILURE" test-report.xml || echo 0',
returnStdout: true
).trim().toInteger()
if (testFailures > 0) {
currentBuild.result = 'UNSTABLE'
echo "存在 ${testFailures} 个测试失败"
}
}
}
}
}
}
4.4 锁定资源Step
pipeline {
agent any
stages {
stage('Resource Locking') {
steps {
// ============ lock - 锁定共享资源 ============
/**
* lock - 锁定资源,防止并发冲突
*
* @param resource 资源名称(二选一)
* @param label 资源标签(二选一)
* @param quantity 资源数量(可选),默认1
* @param variable 锁ID存储变量(可选)
* @param inversePrecedence 是否反向优先(可选),默认false
* @param skipIfLocked 如果已锁定则跳过(可选),默认false
*/
// 按资源名称锁定
lock(resource: 'deploy-server') {
sh './deploy.sh'
}
// 按标签锁定
lock(label: 'production-servers', quantity: 1) {
sh './deploy.sh'
}
// 完整参数示例
lock(
resource: 'database-migration',
quantity: 1,
variable: 'LOCK_ID',
inversePrecedence: false,
skipIfLocked: false
) {
echo "获取锁ID: ${LOCK_ID}"
sh 'flyway migrate'
}
// 如果资源已锁定则跳过
lock(resource: 'optional-resource', skipIfLocked: true) {
sh 'optional-operation.sh'
}
}
}
}
}
4.5 HTTP请求Step
pipeline {
agent any
stages {
stage('HTTP Requests') {
steps {
// ============ httpRequest - HTTP请求 ============
/**
* httpRequest - 执行HTTP请求
*
* @param url 请求URL(必选)
* @param httpMode HTTP方法(可选)
* GET, POST, PUT, DELETE, PATCH, HEAD
* @param authentication 凭证ID(可选)
* @param contentType 内容类型(可选)
* @param requestBody 请求体(可选)
* @param customHeaders 自定义请求头(可选)
* @param timeout 超时时间(秒,可选)
* @param validResponseCodes 有效响应码(可选)
* @param validResponseContent 响应内容匹配(可选)
* @param quiet 静默模式(可选)
* @param consoleLogResponseBody 打印响应体(可选)
*/
// GET请求
def getResponse = httpRequest(
url: 'https://api.example.com/data',
httpMode: 'GET',
authentication: 'api-credentials',
validResponseCodes: '200:299'
)
echo "响应状态: ${getResponse.status}"
echo "响应内容: ${getResponse.content}"
// POST请求(完整参数)
def postResponse = httpRequest(
url: 'https://api.example.com/submit',
httpMode: 'POST',
authentication: 'api-credentials',
contentType: 'APPLICATION_JSON',
requestBody: '''
{
"name": "test",
"version": "1.0.0"
}
''',
customHeaders: [
[name: 'X-Custom-Header', value: 'custom-value'],
[name: 'Authorization', value: 'Bearer token']
],
timeout: 60,
validResponseCodes: '200:201',
validResponseContent: '"success":true',
quiet: false,
consoleLogResponseBody: true
)
// 处理JSON响应
def jsonData = readJSON(text: postResponse.content)
echo "返回数据: ${jsonData}"
}
}
}
}
4.6 通知Step
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
}
post {
always {
// ============ 邮件通知 ============
/**
* mail - 发送邮件
*
* @param to 收件人(必选)
* @param subject 邮件主题(必选)
* @param body 邮件正文(必选)
* @param from 发件人(可选)
* @param cc 抄送(可选)
* @param bcc 密送(可选)
* @param replyTo 回复地址(可选)
* @param mimeType 内容类型(可选)
* text/plain, text/html
*/
mail(
to: 'team@company.com',
cc: 'manager@company.com',
subject: "构建通知: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
构建完成!
项目: ${env.JOB_NAME}
构建号: ${env.BUILD_NUMBER}
结果: ${currentBuild.result}
URL: ${env.BUILD_URL}
""",
mimeType: 'text/plain'
)
// ============ 扩展邮件 ============
/**
* emailext - 扩展邮件功能
* 支持模板、附件、收件人解析等高级功能
*/
emailext(
to: 'team@company.com',
subject: "构建${currentBuild.result}: ${env.JOB_NAME}",
body: '''${SCRIPT, template="groovy-html.template"}''',
attachLog: true,
compressLog: true,
attachmentsPattern: 'target/*.jar',
mimeType: 'text/html',
recipientProviders: [
[$class: 'DevelopersRecipientProvider'],
[$class: 'CulpritsRecipientProvider'],
[$class: 'RequesterRecipientProvider']
]
)
// ============ Slack通知 ============
/**
* slackSend - 发送Slack消息
*/
slackSend(
color: currentBuild.result == 'SUCCESS' ? 'good' : 'danger',
message: """
构建通知
项目: ${env.JOB_NAME}
构建: #${env.BUILD_NUMBER}
结果: ${currentBuild.result}
URL: ${env.BUILD_URL}
""",
channel: '#builds',
tokenCredentialId: 'slack-token',
baseUrl: 'https://hooks.slack.com/services/'
)
// ============ 企业微信通知 ============
/**
* dingtalk - 发送钉钉消息
*/
dingtalk(
robot: 'jenkins-robot-id',
type: 'MARKDOWN',
title: '构建通知',
text: [
"## 构建结果: ${currentBuild.result}",
"- **项目**: ${env.JOB_NAME}",
"- **构建号**: #${env.BUILD_NUMBER}",
"- **持续时间**: ${currentBuild.durationString}",
"- **[查看详情](${env.BUILD_URL})**"
],
at: [
'user1',
'user2'
],
atAll: false
)
// ============ 飞书通知 ============
/**
* lark - 发送飞书消息
*/
lark(
webhook: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx',
message: """
构建完成
项目: ${env.JOB_NAME}
结果: ${currentBuild.result}
""",
title: 'Jenkins构建通知'
)
// ============ Microsoft Teams通知 ============
/**
* office365ConnectorSend - 发送Teams消息
*/
office365ConnectorSend(
webhookUrl: 'https://outlook.office.com/webhook/xxx',
message: "构建完成: ${env.JOB_NAME} - ${currentBuild.result}",
status: currentBuild.result,
color: currentBuild.result == 'SUCCESS' ? '00FF00' : 'FF0000'
)
}
}
}
5. 构建触发器完整配置
5.1 Generic Webhook Trigger详解
/**
* Generic Webhook Trigger完整配置
*
* 支持从任意Webhook触发构建
* 可解析JSON/XML请求体和HTTP头
*/
properties([
pipelineTriggers([
GenericTrigger(
// ============ 变量定义 ============
/**
* genericVariables - 从请求体提取变量
*
* @param key 变量名
* @param value JSONPath表达式
* @param expressionType 表达式类型
* JSONPath, XPath
* @param regexpFilter 正则过滤(可选)
*/
genericVariables: [
[
key: 'ref',
value: '$.ref',
expressionType: 'JSONPath',
regexpFilter: 'refs/heads/(.*)'
],
[
key: 'action',
value: '$.action',
expressionType: 'JSONPath'
],
[
key: 'sender',
value: '$.sender.login',
expressionType: 'JSONPath'
],
[
key: 'repository',
value: '$.repository.name',
expressionType: 'JSONPath'
]
],
/**
* genericHeaderVariables - 从HTTP头提取变量
*/
genericHeaderVariables: [
[
key: 'X-GitHub-Event',
regexpFilter: ''
],
[
key: 'X-GitHub-Delivery',
regexpFilter: ''
]
],
// ============ 触发配置 ============
/**
* causeString - 构建原因描述
* 支持变量替换
*/
causeString: 'Triggered by $sender via $X-GitHub-Event',
/**
* token - 触发令牌
* 用于验证Webhook请求
*/
token: 'my-secret-token',
/**
* tokenCredentialId - 令牌凭证ID
* 使用Jenkins凭证存储令牌
*/
tokenCredentialId: 'webhook-token-credentials',
// ============ 调试选项 ============
/**
* printContributedVariables - 打印提取的变量
*/
printContributedVariables: true,
/**
* printPostContent - 打印请求体
*/
printPostContent: true,
// ============ 响应配置 ============
/**
* silentResponse - 静默响应
* 不返回详细信息
*/
silentResponse: false,
/**
* shouldNotFlatten - 不展平变量
*/
shouldNotFlatten: false,
// ============ 过滤配置 ============
/**
* regexFilterText - 过滤文本
* 用于条件触发
*/
regexFilterText: '$ref $action',
/**
* regexFilterExpression - 过滤正则
* 只有匹配时才触发构建
*/
regexFilterExpression: 'refs/heads/(main|develop) (push|opened)'
)
])
])
pipeline {
agent any
stages {
stage('Webhook Build') {
steps {
script {
echo "触发事件: ${env.X_GitHub_Event}"
echo "触发分支: ${env.ref}"
echo "触发用户: ${env.sender}"
echo "仓库: ${env.repository}"
echo "动作: ${env.action}"
}
}
}
}
}
5.2 Webhook URL格式
# 基本URL格式
https://jenkins.example.com/generic-webhook-trigger/invoke
# 带Token的URL
https://jenkins.example.com/generic-webhook-trigger/invoke?token=my-secret-token
# GitHub Webhook配置示例
# Content-Type: application/json
# URL: https://jenkins.example.com/generic-webhook-trigger/invoke?token=my-secret-token
# Secret: (可选,用于签名验证)
# Events: Push, Pull request, etc.
6. 构建后操作详解
6.1 制品归档与指纹
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
}
post {
success {
// ============ archiveArtifacts - 归档制品 ============
/**
* archiveArtifacts - 归档构建制品
*
* @param artifacts 文件模式(必选),支持通配符
* @param allowEmptyArchive 允许空归档(可选),默认false
* @param caseSensitive 大小写敏感(可选),默认true
* @param defaultExcludes 使用默认排除(可选),默认true
* @param excludes 排除模式(可选)
* @param fingerprint 生成指纹(可选),默认false
* @param onlyIfSuccessful 仅成功时归档(可选),默认false
*/
archiveArtifacts(
artifacts: 'target/*.jar, target/*.war',
allowEmptyArchive: false,
caseSensitive: true,
defaultExcludes: true,
excludes: '*-sources.jar, *-javadoc.jar',
fingerprint: true,
onlyIfSuccessful: true
)
// ============ 指纹追踪 ============
/**
* 指纹用于追踪制品的使用关系
* 可查看哪些构建使用了特定制品
*/
echo "制品指纹已生成,可在构建页面查看"
}
}
}
6.2 构建触发器
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn package'
}
}
}
post {
success {
// ============ build - 触发下游构建 ============
/**
* build - 触发其他Job构建
*
* @param job Job名称(必选)
* @param parameters 构建参数(可选)
* @param wait 是否等待完成(可选),默认true
* @param propagate 是否传播失败(可选),默认true
* @param quietPeriod 静默期(可选)
*/
// 基本触发
build job: 'downstream-deploy-job'
// 带参数触发
build job: 'deploy-job',
parameters: [
string(name: 'ENVIRONMENT', value: 'staging'),
string(name: 'VERSION', value: env.BUILD_NUMBER),
booleanParam(name: 'RUN_TESTS', value: false)
],
wait: true,
propagate: true
// 异步触发(不等待)
build job: 'notification-job',
parameters: [
string(name: 'BUILD_URL', value: env.BUILD_URL)
],
wait: false
// 条件触发
if (env.BRANCH_NAME == 'main') {
build job: 'production-deploy',
parameters: [
string(name: 'VERSION', value: env.BUILD_NUMBER)
],
wait: true
}
}
}
}
6.3 JUnit测试报告
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
// ============ junit - 发布测试报告 ============
/**
* junit - 发布JUnit格式测试报告
*
* @param testResults 测试报告文件模式(必选)
* @param allowEmptyResults 允许空结果(可选),默认false
* @param healthScaleFactor 健康度因子(可选),默认1.0
* @param keepLongStdio 保留长输出(可选),默认false
* @param skipPublishingChecks 跳过检查发布(可选)
*/
junit(
testResults: '**/target/surefire-reports/*.xml',
allowEmptyResults: false,
healthScaleFactor: 1.0,
keepLongStdio: true
)
// 集成测试报告
junit(
testResults: '**/target/failsafe-reports/*.xml',
allowEmptyResults: true
)
}
}
}
}
}
7. when条件完整语法
7.1 when条件完整示例
pipeline {
agent any
stages {
// ============ 分支条件 ============
stage('Branch Conditions') {
when {
// 精确匹配
branch 'main'
// 通配符匹配
branch pattern: 'release/*', comparator: 'GLOB'
// 正则匹配
branch pattern: 'release/\\d+\\.\\d+', comparator: 'REGEXP'
}
steps {
echo '分支条件满足'
}
}
// ============ 环境变量条件 ============
stage('Environment Condition') {
when {
environment name: 'DEPLOY_ENV', value: 'production'
}
steps {
echo '部署到生产环境'
}
}
// ============ 表达式条件 ============
stage('Expression Condition') {
when {
expression {
// Groovy布尔表达式
return params.DEPLOY_ENABLED &&
env.BRANCH_NAME == 'main' &&
currentBuild.previousBuild?.result != 'SUCCESS'
}
}
steps {
echo '表达式条件满足'
}
}
// ============ 变化检测条件 ============
stage('Changeset Condition') {
when {
// 检测文件变化
changeset '**/*.java'
// 带正则的变化检测
changeset pattern: 'src/(main|test)/.*', comparator: 'REGEXP'
}
steps {
echo '代码有变化'
}
}
// ============ 变更请求条件 ============
stage('Change Request Condition') {
when {
// 任意PR
changeRequest()
// 指定目标分支
changeRequest target: 'main'
// 指定PR ID
changeRequest id: '123'
// 指定作者
changeRequest author: 'username'
// 指定标题模式
changeRequest title: 'JENKINS-\\d+'
// 组合条件
changeRequest target: 'main', author: 'username'
}
steps {
echo 'PR条件满足'
}
}
// ============ 触发原因条件 ============
stage('Trigger Condition') {
when {
// SCM触发
triggeredBy 'SCMTrigger'
// 定时触发
triggeredBy 'TimerTrigger'
// 用户触发
triggeredBy cause: 'UserIdCause', detail: 'admin'
// 上游项目触发
triggeredBy 'UpstreamCause'
}
steps {
echo '触发条件满足'
}
}
// ============ 标签条件 ============
stage('Tag Condition') {
when {
// 通配符标签
tag 'v*'
// 正则标签
tag pattern: 'v\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP'
}
steps {
echo '标签条件满足'
}
}
// ============ 条件组合 ============
stage('Combined Conditions') {
when {
// 所有条件都满足
allOf {
branch 'main'
environment name: 'DEPLOY_ENV', value: 'production'
expression { params.DEPLOY_ENABLED }
}
}
steps {
echo '所有条件满足'
}
}
stage('AnyOf Conditions') {
when {
// 任一条件满足
anyOf {
branch 'main'
branch 'develop'
branch pattern: 'release/*'
}
}
steps {
echo '任一条件满足'
}
}
stage('Not Condition') {
when {
// 条件取反
not {
branch 'feature/*'
}
}
steps {
echo '非feature分支'
}
}
stage('Nested Conditions') {
when {
allOf {
branch 'main'
anyOf {
environment name: 'DEPLOY_ENV', value: 'staging'
environment name: 'DEPLOY_ENV', value: 'production'
}
not {
changeset 'docs/**'
}
}
}
steps {
echo '嵌套条件满足'
}
}
// ============ 执行时机配置 ============
stage('Before Agent') {
when {
beforeAgent true // 在分配Agent前评估条件
branch 'main'
}
agent { label 'production-server' }
steps {
echo '条件满足后才分配Agent'
}
}
stage('Before Input') {
when {
beforeInput true // 在等待输入前评估条件
branch 'main'
}
input {
message "确认部署?"
}
steps {
echo '条件满足后才等待输入'
}
}
stage('Before Options') {
when {
beforeOptions true // 在应用选项前评估条件
branch 'main'
}
options {
timeout(time: 30, unit: 'MINUTES')
}
steps {
echo '条件满足后才应用选项'
}
}
}
}
8. 最佳实践与性能优化
8.1 Pipeline设计最佳实践
/**
* Pipeline最佳实践示例
*
* 设计原则:
* 1. 单一职责:每个Stage只做一件事
* 2. 快速失败:尽早发现问题
* 3. 幂等性:可重复执行
* 4. 可读性:清晰的命名和注释
*/
pipeline {
agent none // 全局不指定,各Stage单独指定
// 全局选项配置
options {
// 构建历史管理
buildDiscarder(logRotator(
numToKeepStr: '20',
artifactNumToKeepStr: '5'
))
// 超时控制
timeout(time: 30, unit: 'MINUTES')
// 禁止并发
disableConcurrentBuilds()
// 跳过默认检出
skipDefaultCheckout()
// 时间戳
timestamps()
// ANSI颜色
ansiColor('xterm')
}
// 环境变量
environment {
APP_NAME = 'my-application'
// 使用凭证
DOCKER_CREDS = credentials('docker-registry')
}
stages {
// ============ 检出阶段 ============
stage('Checkout') {
agent { label 'linux' }
steps {
script {
// 清晰的日志输出
echo "========== 开始检出代码 =========="
}
// 检出代码
checkout scm
// 暂存代码供后续使用
stash name: 'source', includes: '**', excludes: '.git/**'
script {
echo "========== 代码检出完成 =========="
}
}
}
// ============ 构建阶段 ============
stage('Build') {
agent {
docker {
image 'maven:3.9.5-eclipse-temurin-17'
args '-v $HOME/.m2:/root/.m2' // Maven缓存
}
}
steps {
unstash 'source'
script {
echo "========== 开始构建 =========="
}
// 并行构建
sh 'mvn clean package -DskipTests -T 4'
// 暂存制品
stash name: 'artifacts', includes: 'target/*.jar'
script {
echo "========== 构建完成 =========="
}
}
}
// ============ 测试阶段(并行) ============
stage('Test') {
parallel {
stage('Unit Tests') {
agent {
docker {
image 'maven:3.9.5-eclipse-temurin-17'
args '-v $HOME/.m2:/root/.m2'
}
}
steps {
unstash 'source'
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Integration Tests') {
agent {
docker {
image 'maven:3.9.5-eclipse-temurin-17'
args '-v $HOME/.m2:/root/.m2'
}
}
steps {
unstash 'source'
sh 'mvn verify -P integration-test'
}
post {
always {
junit '**/target/failsafe-reports/*.xml'
}
}
}
stage('Code Quality') {
agent { label 'sonar' }
steps {
unstash 'source'
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
}
}
// ============ 部署阶段 ============
stage('Deploy') {
agent { label 'deploy' }
when {
allOf {
branch 'main'
expression { params.DEPLOY_ENABLED }
}
}
// 部署前确认
input {
message "确认部署到生产环境?"
submitter "admin,ops"
}
steps {
unstash 'artifacts'
script {
echo "========== 开始部署 =========="
}
// 部署脚本
sh './deploy.sh production'
script {
echo "========== 部署完成 =========="
}
}
}
}
// ============ 构建后处理 ============
post {
always {
// 清理工作空间
cleanWs()
}
success {
script {
// 成功通知
emailext(
subject: "✅ 构建成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
<h2>构建成功</h2>
<p><strong>项目:</strong> ${env.JOB_NAME}</p>
<p><strong>构建号:</strong> ${env.BUILD_NUMBER}</p>
<p><strong>持续时间:</strong> ${currentBuild.durationString}</p>
<p><a href="${env.BUILD_URL}">查看详情</a></p>
""",
to: 'team@company.com',
mimeType: 'text/html'
)
}
}
failure {
script {
// 失败通知
emailext(
subject: "❌ 构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
<h2>构建失败</h2>
<p><strong>项目:</strong> ${env.JOB_NAME}</p>
<p><strong>构建号:</strong> ${env.BUILD_NUMBER}</p>
<p><a href="${env.BUILD_URL}console">查看日志</a></p>
""",
to: 'team@company.com',
mimeType: 'text/html'
)
}
}
}
}
8.2 性能优化技巧
pipeline {
agent none
options {
// 优化1: 限制构建历史
buildDiscarder(logRotator(numToKeepStr: '10'))
// 优化2: 设置超时防止挂起
timeout(time: 30, unit: 'MINUTES')
// 优化3: 并行阶段快速失败
parallelsAlwaysFailFast()
}
stages {
stage('Optimized Build') {
agent {
docker {
image 'maven:3.9.5-eclipse-temurin-17'
// 优化4: 挂载缓存目录
args '-v $HOME/.m2:/root/.m2 -v $HOME/.gradle:/root/.gradle'
}
}
steps {
// 优化5: 跳过不必要的步骤
script {
// 检查是否有代码变化
def changes = sh(
script: 'git diff --name-only HEAD~1',
returnStdout: true
).trim()
if (changes.isEmpty()) {
echo '无代码变化,跳过构建'
return
}
}
// 优化6: 增量构建
sh 'mvn package -DskipTests -T 4 -Dmaven.test.skip=true'
// 优化7: 使用stash/unstash传递文件
stash name: 'artifacts', includes: 'target/*.jar', allowEmpty: true
}
}
stage('Parallel Tests') {
// 优化8: 并行执行测试
parallel {
stage('Fast Tests') {
agent { label 'test-node' }
steps {
unstash 'artifacts'
sh 'mvn test -Dtest=*FastTest'
}
}
stage('Slow Tests') {
agent { label 'test-node' }
steps {
unstash 'artifacts'
sh 'mvn test -Dtest=*SlowTest'
}
}
}
}
}
post {
always {
// 优化9: 清理工作空间
cleanWs()
}
}
}
总结
本文详细介绍了Jenkins Pipeline的语法体系,包括:
- 执行模型:深入解析了CPS转换机制和FlowNode执行流程
- 语法对比:全面对比了声明式和脚本式两种Pipeline范式
- 完整语法:详细讲解了声明式Pipeline的所有指令和参数
- 核心Step:提供了所有常用Step的完整参数说明和示例
- 触发器配置:详解了Generic Webhook等高级触发器配置
- 条件语法:完整介绍了when条件的所有用法
- 最佳实践:提供了性能优化和设计模式建议
通过本文的学习,读者可以全面掌握Jenkins Pipeline的语法体系,能够编写高质量、可维护的CI/CD流水线。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)