Issue
I have a Python script that I'm running in my pipeline that is forced to fail. I'm trying to send the failure output to Slack.
testing.py
import sys
print("Hello World")
sys.exit(1)
pipeline
def slackChannel = "default-ops"
def slackDetails = "${env.JOB_NAME} - (<${env.BUILD_URL}|Open>)"
def shResult() {
script {
sh script: 'set -e; python3 testing.py', returnStdout: true
}
}
pipeline {
agent any
stages {
stage('Execute testing.py') {
steps {
script{
echo "${shResult()}".trim()
if (shResult != 0) {
currentBuild.result = 'FAILURE'
}
}
}
}
}
post {
success {
slackSend(color: '#00FF00',
channel: "${slackChannel}",
message: "SUCCESSFUL: " + slackDetails)
}
failure {
slackSend(color: '#FF0000',
channel: "${slackChannel}",
message: "FAILED: " + slackDetails + shResult())
}
aborted {
slackSend(color: '#808080',
channel: "${slackChannel}",
message: "ABORTED: " + slackDetails)
}
}
}
This results in the following error:
Error when executing failure post condition:
hudson.AbortException: script returned exit code 1
at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.handleExit(DurableTaskStep.java:659)
at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.check(DurableTaskStep.java:605)
at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.run(DurableTaskStep.java:549)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
How do I send the output "Hello World" to Slack?
Solution
First of all the line message: "FAILED: " + slackDetails + shResult())
executes the script again, which is probably not what you want.
The second thing is that returnStdout: true
does not return the status code, but the stdout output. So in this case only "Hello World". Use returnStatus: true
to get 0 or 1.
Sadly you can't return both stdout and the status. One way of doing it would be to only use returnStatus: true
and pipe stdout to a file.
The pipeline would look something like this:
def slackChannel = "default-ops"
def slackDetails = "${env.JOB_NAME} - (<${env.BUILD_URL}|Open>)"
def shResult() {
script {
sh script: 'set -e; python3 testing.py > /tmp/somefile 2>&1', returnStatus: true
}
}
pipeline {
agent any
stages {
stage('Execute testing.py') {
steps {
script{
status = shResult()
if (status != 0) {
currentBuild.result = 'FAILURE'
errorMsg = readFile '/tmp/somefile'
}
}
}
}
}
post {
success {
slackSend(color: '#00FF00',
channel: "${slackChannel}",
message: "SUCCESSFUL: " + slackDetails)
}
failure {
slackSend(color: '#FF0000',
channel: "${slackChannel}",
message: "FAILED: " + slackDetails + errorMsg
}
aborted {
slackSend(color: '#808080',
channel: "${slackChannel}",
message: "ABORTED: " + slackDetails)
}
}
}
I can't test this pipeline right now but it should work.
Answered By - Michael
Answer Checked By - David Marino (JavaFixing Volunteer)