Jenkins Pipeline执行失败时如何将输出发送至Slack?
问题分析与解决方案
错误原因
你遇到的问题根源有三个:
- post阶段重复执行失败脚本:failure块里再次调用
shResult(),导致testing.py又执行一次,而原函数里的set -e会让sh步骤在脚本返回非0退出码时直接抛出异常,中断post阶段的通知流程。 - 判断逻辑错误:
if (shResult != 0)是把函数对象和0做比较,完全不符合预期,根本无法正确判断脚本是否失败。 - 未保存脚本输出:没有提前存储脚本的输出内容,导致失败时无法直接复用,只能重复执行脚本获取。
修正后的Pipeline代码
def slackChannel = "default-ops" def slackDetails = "${env.JOB_NAME} - (<${env.BUILD_URL}|Open>)" // 全局变量存储脚本输出和退出码,避免重复执行脚本 def scriptOutput = "" def scriptExitCode = 0 pipeline { agent any stages { stage('Execute testing.py') { steps { script{ // 一次性获取脚本输出和退出码,避免触发异常中断流程 def execResult = sh( script: 'python3 testing.py', returnStdout: true, returnStatus: true ) scriptExitCode = execResult.returnStatus scriptOutput = execResult.stdout.trim() echo scriptOutput // 根据实际退出码设置构建状态 if (scriptExitCode != 0) { currentBuild.result = 'FAILURE' } } } } } post { success { slackSend( color: '#00FF00', channel: slackChannel, message: "SUCCESSFUL: ${slackDetails}" ) } failure { slackSend( color: '#FF0000', channel: slackChannel, message: "FAILED: ${slackDetails}\n脚本输出:\n${scriptOutput}" ) } aborted { slackSend( color: '#808080', channel: slackChannel, message: "ABORTED: ${slackDetails}" ) } } }
关键修改点
- 新增全局变量
scriptOutput和scriptExitCode,一次性存储脚本的输出内容和退出码,避免重复执行脚本。 - 使用
sh步骤的returnStdout和returnStatus参数同时获取输出和退出码,既不会因为脚本失败抛出异常中断流程,又能拿到需要的信息。 - 移除原函数里的
set -e,改用退出码判断构建状态,逻辑更清晰可控。 - post阶段的failure块直接复用提前保存的
scriptOutput,无需再次执行脚本,避免触发新的异常。
兼容旧版Jenkins的替代写法
如果你的Jenkins版本不支持同时返回stdout和returnStatus的Map格式,可以通过文件中转存储输出:
stage('Execute testing.py') { steps { script{ // 执行脚本并把输出写入文件 scriptExitCode = sh( script: 'python3 testing.py > script_output.log 2>&1', returnStatus: true ) // 读取文件获取输出内容 scriptOutput = readFile('script_output.log').trim() echo scriptOutput if (scriptExitCode != 0) { currentBuild.result = 'FAILURE' } } } }
内容的提问来源于stack exchange,提问作者clarkus978
相关产品推荐
相关产品推荐

