I am trying to create a Jenkins pipeline wherein a message is sent in Slack thread on every pass/fail after every stage (I have used nested stages and with parallel) but the pipeline shows irregular behavior.
I have deliberately put wrong command in Stage11
Snippet 1 - This code snippet has sleep in both stages. This code behaves as expected.
pipeline {
agent any
stages {
stage('Start') {
steps {
script {
slackResponse = slackSendMessage('STARTED')
}
}
}
stage("parallel1") {
parallel {
stage('Stage11') {
steps {
sh 'sleep 5'
sh 'data'
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
stage('Stage12') {
steps {
sh 'sleep 10'
sh 'date'
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
}
post {
always {
slackSendMessage(currentBuild.result, slackResponse, '', true)
}
}
}
def slackSendMessage(buildStatus = 'STARTED', slackResponse = null, currentStage = '', threadMessage = false) {
// build status of null means successful
buildStatus = buildStatus ?: 'SUCCESSFUL'
// used to tag on Slack
def userEmailId = ''
wrap([$class: 'BuildUser']) {
userEmailId = env.BUILD_USER_EMAIL
}
def userId = slackUserIdFromEmail(userEmailId)
buildTriggerBy = "<@$userId>"
def message = ''
if (currentStage.length() > 0) {
if (buildStatus == "FAILED") {
message = "${buildStatus}: Stage '${currentStage}' (${env.BUILD_URL}console)"
}
else {
message = "${buildStatus}: Stage '${env.STAGE_NAME}'"
}
}
else {
message = "${buildStatus}: Job '${env.JOB_NAME}' [${env.BUILD_NUMBER}] By ${buildTriggerBy}'\n(${env.BUILD_URL})"
}
// Send notifications
if (threadMessage == true) {
slackSend(channel: slackResponse.threadId, message: message)
}
else {
// slackResponse will be used to send message to same thread.
def getSlackResponse = slackSend(message: message)
return(getSlackResponse)
}
}
Output 1 - Image This works as expected behavior, Stage11 fails, Stage 12 passed and overall failure.
Snippet 1 - This code snippet does not have sleep. This code behaves differently.
pipeline {
agent any
stages {
stage('Start') {
steps {
script {
slackResponse = slackSendMessage('STARTED')
}
}
}
stage("parallel1") {
parallel {
stage('Stage11') {
steps {
// sh 'sleep 5'
sh 'data'
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
stage('Stage12') {
steps {
// sh 'sleep 10'
sh 'date'
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
}
post {
success {
slackSendMessage('SUCCESSFUL', slackResponse, env.STAGE_NAME, true)
}
failure {
slackSendMessage('FAILED', slackResponse, env.STAGE_NAME, true)
}
}
}
}
post {
always {
slackSendMessage(currentBuild.result, slackResponse, '', true)
}
}
}
def slackSendMessage(buildStatus = 'STARTED', slackResponse = null, currentStage = '', threadMessage = false) {
// build status of null means successful
buildStatus = buildStatus ?: 'SUCCESSFUL'
// used to tag on Slack
def userEmailId = ''
wrap([$class: 'BuildUser']) {
userEmailId = env.BUILD_USER_EMAIL
}
def userId = slackUserIdFromEmail(userEmailId)
buildTriggerBy = "<@$userId>"
def message = ''
if (currentStage.length() > 0) {
if (buildStatus == "FAILED") {
message = "${buildStatus}: Stage '${currentStage}' (${env.BUILD_URL}console)"
}
else {
message = "${buildStatus}: Stage '${env.STAGE_NAME}'"
}
}
else {
message = "${buildStatus}: Job '${env.JOB_NAME}' [${env.BUILD_NUMBER}] By ${buildTriggerBy}'\n(${env.BUILD_URL})"
}
// Send notifications
if (threadMessage == true) {
slackSend(channel: slackResponse.threadId, message: message)
}
else {
// slackResponse will be used to send message to same thread.
def getSlackResponse = slackSend(message: message)
return(getSlackResponse)
}
}
Output 2 - Image This does not work as expected. If you see the output Stage12 passed but since Stage11 failed so a repeated slack message was sent saying Stage12 failed which should not have come.
Operating System - Amazon AMI (ami-090fa75af13c156b4)
Jenkins - 2.346.2
Slack Plugin - 616.v03b_1e98d13dd