主题
Jenkins Pipeline语法进阶
一、Groovy
1.1 Groovy简介
Groovy是一种基于JVM的动态语言,它与Java有很高的兼容性,同时提供了更多的语法糖和动态特性。Jenkins Pipeline使用Groovy作为其脚本语言,这使得Pipeline脚本更加灵活和强大。
1.2 Groovy数据类型
1.2.1 String(字符串)
在Groovy中,字符串可以用单引号、双引号或三引号定义。双引号字符串支持插值(变量替换),而单引号字符串则是纯文本。
基本用法:
groovy
// 单引号字符串(不支持插值)
def singleQuoted = 'Hello World'
// 双引号字符串(支持插值)
def name = "Jenkins"
def doubleQuoted = "Hello ${name}"
// 三引号字符串(支持多行和插值)
def multiLine = """
This is a multi-line string
that spans multiple lines
and can contain ${name}
"""
字符串方法:
groovy
// 字符串长度
def length = "Hello".size()
// 字符串连接
def concat = "Hello" + " World"
// 字符串替换
def replaced = "Hello World".replace("World", "Jenkins")
// 字符串分割
def parts = "a,b,c".split(",")
Jenkins Pipeline示例:
groovy
pipeline {
agent any
environment {
PROJECT_NAME = "my-app"
VERSION = "1.0.0"
}
stages {
stage('String操作示例') {
steps {
script {
// 字符串插值
def message = "构建项目: ${PROJECT_NAME} 版本: ${VERSION}"
echo message
// 字符串操作
def upperCase = PROJECT_NAME.toUpperCase()
echo "项目名称大写: ${upperCase}"
// 多行字符串
def buildInfo = """
=========构建信息=========
项目名称: ${PROJECT_NAME}
版本号: ${VERSION}
构建编号: ${BUILD_NUMBER}
========================
"""
echo buildInfo
// 字符串判断
if (PROJECT_NAME.startsWith("my")) {
echo "项目名称以'my'开头"
}
// 字符串替换
def newName = PROJECT_NAME.replace("my", "our")
echo "新项目名称: ${newName}"
}
}
}
}
}
1.2.2 List(列表)
Groovy中的List是一个有序集合,可以存储不同类型的元素。
基本用法:
groovy
// 创建列表
def emptyList = []
def numbers = [1, 2, 3, 4]
def mixed = [1, "two", 3.0, true]
// 访问元素
def first = numbers[0] // 索引从0开始
def last = numbers[-1] // 负索引表示从末尾开始
// 添加元素
numbers.add(5)
numbers << 6 // 使用左移操作符添加元素
// 合并列表
def combined = numbers + [7, 8, 9]
// 列表切片
def slice = numbers[1..3] // 获取索引1到3的元素
列表方法:
groovy
// 列表长度
def size = numbers.size()
// 检查元素是否存在
def contains = numbers.contains(3)
// 查找元素索引
def index = numbers.indexOf(4)
// 排序
numbers.sort()
// 过滤
def evenNumbers = numbers.findAll { it % 2 == 0 }
// 映射
def doubled = numbers.collect { it * 2 }
Jenkins Pipeline示例:
groovy
pipeline {
agent any
stages {
stage('List操作示例') {
steps {
script {
// 创建服务器列表
def servers = ['prod-server1', 'prod-server2', 'prod-server3']
echo "服务器列表: ${servers}"
// 添加新服务器
servers << 'prod-server4'
echo "更新后的服务器列表: ${servers}"
// 遍历服务器列表
echo "开始部署到以下服务器:"
servers.each { server ->
echo "- 正在部署到 ${server}..."
}
// 过滤服务器
def backupServers = servers.findAll { it.contains('server2') || it.contains('server3') }
echo "备份服务器: ${backupServers}"
// 检查服务器是否在列表中
if (servers.contains('prod-server1')) {
echo "prod-server1在部署列表中"
}
// 使用join方法
def serverString = servers.join(', ')
echo "服务器列表字符串: ${serverString}"
// 列表排序
servers.sort()
echo "排序后的服务器列表: ${servers}"
}
}
}
}
}
1.2.3 Map(映射/字典)
Map是键值对的集合,在Groovy中非常灵活和强大。
基本用法:
groovy
// 创建Map
def emptyMap = [:]
def person = [name: 'John', age: 30, city: 'New York']
// 访问值
def name = person.name // 使用点符号
def age = person['age'] // 使用方括号
// 添加或更新键值对
person.job = 'Developer' // 添加新键值对
person['age'] = 31 // 更新现有键值对
// 检查键是否存在
def hasName = person.containsKey('name')
Map方法:
groovy
// 获取所有键
def keys = person.keySet()
// 获取所有值
def values = person.values()
// 获取键值对数量
def size = person.size()
// 遍历Map
person.each { key, value ->
println "$key: $value"
}
Jenkins Pipeline示例:
groovy
pipeline {
agent any
stages {
stage('Map操作示例') {
steps {
script {
// 创建配置Map
def config = [
app: 'my-application',
version: '1.2.3',
deploy: [
environment: 'production',
replicas: 3,
healthCheck: true
]
]
// 安全访问嵌套Map(避免空指针)
echo "应用名称: ${config.app}"
echo "部署环境: ${config.deploy?.environment ?: '未配置'}" // 安全导航 + 默认值
echo "副本数量: ${config.deploy?.replicas ?: 0}"
// 添加新配置
config.timeout = 300
config.deploy.strategy = 'rolling'
// 遍历配置(优化输出格式)
echo "完整配置:"
config.each { key, value ->
if (value instanceof Map) {
echo " ${key}:"
value.each { k, v ->
echo " ${k}: ${v}"
}
} else {
echo " ${key}: ${value}"
}
}
// 使用Map作为参数(定义闭包替代方法)
def deployOptions = [
environment: 'staging',
namespace: 'my-app',
wait: true,
timeout: 600
]
// 定义闭包(替代方法)
def deploy = { Map options -> // 关键修改:用闭包代替方法
echo "部署到 ${options.environment} 环境"
echo "命名空间: ${options.namespace}"
echo "等待完成: ${options.wait}"
echo "超时时间: ${options.timeout}秒"
}
// 调用闭包
deploy(deployOptions)
}
}
}
}
}
1.3 Groovy条件语句
1.3.1 if 语句
Groovy的if语句与Java类似,但更加灵活,可以使用更多类型的条件表达式。
基本语法:
groovy
if (condition) {
// 条件为真时执行
} else if (anotherCondition) {
// 第一个条件为假,第二个条件为真时执行
} else {
// 所有条件都为假时执行
}
Groovy中的真值判断:
- 非零数字为真
- 非空字符串为真
- 非空集合为真
- 非null对象为真
- true布尔值为真
Jenkins Pipeline示例:
groovy
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['dev', 'test', 'staging', 'production'], description: '选择部署环境')
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: '是否跳过测试')
}
stages {
stage('条件构建') {
steps {
script {
def selectedEnv = params.ENVIRONMENT
echo "选择的环境: ${selectedEnv}"
if (selectedEnv == 'production') {
echo "生产环境部署,需要额外审批"
// 使用 input 步骤触发人工审批(仅允许指定用户批准)
try {
// 输入提示信息,仅允许 admin 用户批准(可修改为其他用户/用户组)
def approver = input(
message: "⚠️ 确认要部署到生产环境吗?此操作不可逆!",
submitter: 'admin', // 允许审批的用户(支持用户组如 'dev-team')
submitterParameter: 'APPROVER' // 可选:将审批人存入变量
)
echo "审批通过,审批人:${approver}"
} catch (Exception e) {
// 用户拒绝或超时未审批时触发
error "❌ 生产环境部署被拒绝(审批人:${env.USER}),终止流程"
}
echo "继续执行生产环境部署..."
} else if (selectedEnv == 'staging') {
echo "部署到预发布环境,执行完整测试套件"
} else if (selectedEnv == 'test') {
echo "部署到测试环境,执行基本测试"
} else {
echo "部署到开发环境,跳过大部分测试"
}
// 测试控制逻辑
if (params.SKIP_TESTS) {
echo "根据用户选择,跳过测试阶段"
} else {
echo "执行测试阶段"
// sh 'mvn test' // 实际测试命令
}
// 每10次构建执行完整扫描
if (env.BUILD_NUMBER.toInteger() % 10 == 0) {
echo "🔍 每10次构建触发一次完整扫描(构建号:${env.BUILD_NUMBER})"
// sh 'scan-tool full-scan' // 实际扫描命令
}
// 部署类型标识
def deploymentType = (selectedEnv == 'production') ? '生产部署' : '非生产部署'
echo "部署类型: ${deploymentType}"
}
}
}
}
}
1.3.2 switch 语句
switch语句用于多条件分支判断,Groovy的switch比Java更强大,可以匹配各种类型的值。
基本语法:
groovy
switch (value) {
case value1:
// 当value等于value1时执行
break
case value2:
// 当value等于value2时执行
break
case valueList:
// 当value在valueList中时执行
break
case pattern:
// 当value匹配pattern时执行
break
default:
// 当没有匹配的case时执行
}
Jenkins Pipeline示例:
groovy
pipeline {
agent any
parameters {
choice(name: 'ACTION', choices: ['build', 'test', 'deploy', 'rollback', 'cleanup'], description: '选择操作类型')
string(name: 'VERSION', defaultValue: '1.0.0', description: '版本号')
}
stages {
stage('执行操作') {
steps {
script {
def action = params.ACTION
def version = params.VERSION
echo "执行操作: ${action}, 版本: ${version}"
switch (action) {
case 'build':
echo "构建应用版本 ${version}"
// 执行构建命令
sh "echo '模拟构建过程'"
break
case 'test':
echo "测试应用版本 ${version}"
// 执行测试命令
sh "echo '模拟测试过程'"
break
case 'deploy':
echo "部署应用版本 ${version}"
// 执行部署命令
sh "echo '模拟部署过程'"
break
case ['rollback', 'cleanup']:
// 多值匹配
echo "执行维护操作: ${action}"
sh "echo '模拟${action}过程'"
break
default:
error "未知操作: ${action}"
break
}
// 使用正则表达式匹配
switch (version) {
case ~/^\d+\.\d+\.\d+$/:
echo "标准版本格式: ${version}"
break
case ~/^\d+\.\d+\.\d+-SNAPSHOT$/:
echo "快照版本: ${version}"
break
default:
echo "非标准版本格式: ${version}"
break
}
}
}
}
}
}
1.4 Groovy异常处理
异常处理是处理程序运行时错误的机制。Groovy的异常处理与Java类似,但提供了更多的简化语法。
1.4.1 try-catch-finally
基本语法:
groovy
try {
// 可能抛出异常的代码
} catch (ExceptionType1 e) {
// 处理ExceptionType1类型的异常
} catch (ExceptionType2 e) {
// 处理ExceptionType2类型的异常
} finally {
// 无论是否发生异常都会执行的代码
}
Jenkins Pipeline示例:
groovy
pipeline {
agent any
stages {
stage("run") {
steps {
script { // 进入脚本模式(支持复杂 Groovy 逻辑)
try {
println(a) // 尝试打印未定义的变量 `a`(必然失败)
} catch (Exception e) { // 捕获所有 Exception 类型的异常
println(e) // 打印异常对象(实际输出异常信息)
// error "error..." // (注释中)主动抛出异常终止流程
} finally {
println("always....") // 无论是否异常都会执行
}
}
}
}
}
}
1.4.2 error 直接终止流程
Jenkins Pipeline 提供了内置的 error 步骤,专门用于终止流程并抛出错误
groovy
pipeline {
agent any
parameters {
string(name: 'VERSION', defaultValue: '1.0.0', description: '版本号')
}
stages {
stage('版本验证') {
steps {
script {
def version = params.VERSION
// 验证版本格式
if (!(version =~ /^\d+\.\d+\.\d+$/)) {
// 使用 Pipeline 内置的 error 步骤替代 throw
error "无效的版本格式: ${version},必须是 x.y.z 格式"
}
echo "版本格式有效: ${version}"
}
}
}
}
}
1.5 Groovy函数
Groovy函数(或方法)是可重用代码块,可以接受参数并返回值。在Jenkins Pipeline中,函数可以帮助组织和重用代码。
1.5.1 函数定义和调用
基本语法:
groovy
// 定义函数
def functionName(param1, param2) {
// 函数体
return result // 返回值(可选)
}
// 调用函数
def result = functionName(arg1, arg2)
Jenkins Pipeline示例:
groovy
pipeline {
agent any
stages {
stage('函数示例') {
steps {
script {
// 定义一个简单的函数
def greet = { name ->
return "Hello, ${name}!"
}
// 调用函数
def message = greet("Jenkins")
echo message
// 定义带有多个参数的函数
def calculateDeployTime = { environment, instanceCount ->
def baseTime = 0
switch (environment) {
case 'dev':
baseTime = 5
break
case 'test':
baseTime = 8
break
case 'production':
baseTime = 15
break
default:
baseTime = 10
}
return baseTime + (instanceCount * 2)
}
// 调用带有多个参数的函数
def devTime = calculateDeployTime('dev', 3)
def prodTime = calculateDeployTime('production', 5)
echo "开发环境部署预计耗时: ${devTime} 分钟"
echo "生产环境部署预计耗时: ${prodTime} 分钟"
}
}
}
}
}
1.5.2 闭包
闭包是Groovy中的一个重要概念,它是一个可以作为对象传递的代码块。
基本语法:
groovy
def closure = { param ->
// 闭包体
return result
}
Jenkins Pipeline示例:
groovy
pipeline {
agent any
stages {
stage('闭包示例') {
steps {
script {
// 定义部署步骤列表
def deploySteps = [
{ -> echo "1. 准备部署环境" },
{ -> echo "2. 停止旧版本服务" },
{ -> echo "3. 部署新版本" },
{ -> echo "4. 启动服务" },
{ -> echo "5. 健康检查" }
]
// 执行部署步骤
deploySteps.each { step ->
step() // 调用每个闭包
}
// 带参数的闭包
def verifyService = { serviceName, port ->
echo "验证服务 ${serviceName} 在端口 ${port}"
// 模拟验证过程
return true
}
// 调用带参数的闭包
def serviceOk = verifyService('web-service', 8080)
if (serviceOk) {
echo "服务验证通过"
}
}
}
}
}
}
二、Jenkins Pipeline开发技巧
2.1 编写测试Pipeline
使用Replay功能
- 在Jenkins UI中可以快速测试Pipeline修改
- 不需要提交到SCM就能测试改动
使用Pipeline Syntax生成器
- Jenkins提供了语法生成器
- 位于Pipeline job的"Pipeline Syntax"链接
分阶段验证
groovy
pipeline {
agent any
stages {
stage('Validate') {
steps {
sh 'echo "First, validate the app..."'
sh 'make validate'
}
}
stage('Test') {
steps {
sh 'echo "Next, test the app..."'
sh 'make test'
}
}
}
}
2.2 Pipeline问题排错思路
查看Pipeline Steps
- 使用Blue Ocean插件可视化查看步骤
- 检查每个步骤的日志输出
使用echo调试
groovy
steps {
script {
echo "DEBUG: Current environment is ${env.ENVIRONMENT}"
echo "DEBUG: Build number is ${env.BUILD_NUMBER}"
}
}
- 使用try-catch处理错误
groovy
steps {
script {
try {
sh 'some-command'
} catch (exc) {
echo 'Something failed, but I want to keep going'
}
}
}
2.3 Jenkinsfile的常见管理方式
源代码控制
- 将Jenkinsfile放在代码仓库的根目录
- 与应用代码一起版本控制
共享库
groovy
@Library('my-shared-library') _
pipeline {
agent any
stages {
stage('Example') {
steps {
mySharedFunction()
}
}
}
}
- 模板化
- 创建标准化的Pipeline模板
- 在不同项目中重用
groovy
// Template Jenkinsfile
def call(Map config) {
pipeline {
agent any
stages {
stage('Build') {
steps {
sh "${config.buildCommand}"
}
}
}
}
}
- 配置即代码
- 使用YAML或JSON配置文件
- Pipeline读取配置文件动态生成步骤
groovy
def config = readYaml file: 'jenkins-config.yml'
pipeline {
agent any
stages {
stage('Dynamic Stage') {
steps {
script {
config.steps.each { step ->
sh "${step}"
}
}
}
}
}
}
通过以上内容,你应该能够开始使用Jenkins Pipeline,并且了解如何编写、测试和管理Pipeline代码。记住,好的Pipeline应该是可维护的、可重用的,并且能够清晰地表达你的持续交付流程。