Jenkins声明式流水线中如何在自定义函数内读取全局变量值
问题根因
该报错本质是Jenkins流水线的Groovy作用域隔离导致的:
- 在pipeline块外层用
def FAILED_STAGE定义的变量,属于Groovy脚本的局部变量,不是WorkflowScript类的成员属性 - 流水线执行到pipeline内部的
script块时,CPS转换机制会将块内的变量赋值绑定到闭包的局部作用域,不会回写到外层脚本的局部变量 - 等到post块调用自定义函数
sendSlackNotifcation时,函数的作用域链中找不到这个局部变量,沙箱校验就会抛出groovy.lang.MissingPropertyException
解决方案
方案1:使用全局env环境变量存储(推荐)
Jenkins内置的env对象是跨所有流水线作用域全局共享的,不存在作用域隔离问题,是这类场景的首选实现方式。
具体修改点:
- 删除顶层的
def FAILED_STAGE定义 - 自定义函数中读取
env.FAILED_STAGE替代原变量 - 失败阶段的script块中,将赋值语句改为写入
env对象
修改后可直接运行的完整代码:
def sendSlackNotifcation() { if ( currentBuild.currentResult == "SUCCESS" ) { slackSend message: "${currentBuild.result}", channel: '#jenkins_bot2' } else { slackSend color : "#FF0000", message: "流水线失败于阶段:${env.FAILED_STAGE}", channel: '#jenkins_bot2' } } pipeline { agent any stages { stage('stage1') { steps{ echo "stage1" } } stage('stage2') { steps{ echo "stage2" } } stage("Stage 3") { steps { script { // 将失败阶段信息写入全局env变量 env.FAILED_STAGE = env.STAGE_NAME echo "${env.FAILED_STAGE}" error "failed for some reason." } } } } post { failure { sendSlackNotifcation() } } }
方案2:显式绑定类成员作用域
如果不希望使用env对象存储自定义变量,需要将变量从脚本局部变量改为WorkflowScript类的成员属性,赋值时明确指定作用域,避免被闭包截留。
具体修改点:
- 顶层定义变量时去掉
def,直接声明FAILED_STAGE = "",使其成为类的成员属性 - pipeline内部给变量赋值时,用
this.FAILED_STAGE显式绑定到类成员
关键修改代码片段:
// 直接声明类成员属性,不用def关键字 FAILED_STAGE = "" def sendSlackNotifcation() { if ( currentBuild.currentResult == "SUCCESS" ) { slackSend message: "${currentBuild.result}", channel: '#jenkins_bot2' } else { slackSend color : "#FF0000", message: "流水线失败于阶段:${FAILED_STAGE}", channel: '#jenkins_bot2' } } pipeline { agent any stages { // 其余阶段逻辑保持不变 stage("Stage 3") { steps { script { // 显式赋值给类成员属性,避免闭包作用域截留 this.FAILED_STAGE = env.STAGE_NAME echo "${this.FAILED_STAGE}" error "failed for some reason." } } } } post { failure { sendSlackNotifcation() } } }
内容的提问来源于stack exchange,提问作者Jesus Fernandez
相关产品推荐
相关产品推荐

