I am using Jenkins declarative pipeline and want to perform some post build actions depending on the build status.
To be more precise, I want to send an email when the build status changed (from success to failure, or success to unstable, or failure to success).
Here is my pipeline:
pipeline {
agent none
stages {
stage('test') {
agent any
steps {
sh './tests.sh'
}
}
}
post {
changed {
// Send different emails depending on build status
// Success -> anything else
// Anything else -> Success
}
}
}
Any idea ?
For writing conditions you can define your own methods.
For example, if you want to send an email only when the build status changes:
def notifyStatusChangeViaEmail(buildStatus) {
def status
switch (buildStatus) {
case 'SUCCESS':
status = 'is now green again!'
break
case 'UNSTABLE':
status = 'has become unstable..'
break
case 'FAILURE':
status = 'has turned RED :('
break
}
emailext (
subject: "Job '${env.JOB_NAME}' ${status}",
body: "See ${env.BUILD_URL} for more details",
recipientProviders: [
[$class: 'DevelopersRecipientProvider'],
[$class: 'RequesterRecipientProvider']
]
)
}
pipeline {
...
post {
changed {
// Will trigger only when job status changes: GREEN -> RED, RED -> GREEN, etc
notifyStatusChangeViaEmail(currentBuild.currentResult)
}
}
}
Ideally, you would also want to put notifyStatusChangeViaEmail method definiton in your shared pipeline library so that it could be re-used in other jobs/pipelines.
Refer to this pipeline:
post {
success {
emailext (
subject: '${DEFAULT_SUBJECT}'+'SUCESSFUL',
body: '${DEFAULT_CONTENT}',
to: '${EMAIL_RECIPIENTS}'
);
slackSend (color: 'good', message: ":csp_operational: ${env.JOB_NAME} - #${env.BUILD_NUMBER} Success (<${env.BUILD_URL}|Open>)");
}
failure {
emailext (
subject: '${DEFAULT_SUBJECT}'+'FAILED!',
body: '${DEFAULT_CONTENT}',
to: '${EMAIL_RECIPIENTS}'
);
slackSend (color: 'danger', message: ":x: ${env.JOB_NAME} - #${env.BUILD_NUMBER} Failure (<${env.BUILD_URL}|Open>)");
}
}
You can set the Default Email parameters using Extended Email Plugin, Jenkins-> Configure Jenkins -> Extended Email Configuration.
Exemple : failure & unstable to success
if (currentBuild.result == 'SUCCESS') { if(hudson.model.Result.FAILURE.equals(currentBuild.rawBuild.getPreviousBuild()?.getResult()) || hudson.model.Result.UNSTABLE.equals(currentBuild.rawBuild.getPreviousBuild()?.getResult())) {
SEND MAIL()
}
}
for send email : https://jenkins.io/blog/2017/02/15/declarative-notifications/
#psalvi was imho on the right track, but #mikael-gibert wanted in his comment to get notifications only for the first fixed build. Jenkins declarative pipelines can do that, see https://www.jenkins.io/doc/book/pipeline/syntax/#post. Here an example:
pipeline {
// [...]
post {
always {
script {
// Examples of stuff you could do, based on some custom parameters and functions
if (params.buildAndPublish && branchIsMain()) {
currentBuild.description = 'NOT promoted '
}
currentBuild.description = (currentBuild.description ?: '') + '[' + (params.customArtifactVersion ?: mavenArtifactVersion) + ']'
if (params.buildAndPublish) {
// Tell Bitbucket about this build and its result
notifyBitbucket(credentialsId: config.credentialsId)
// Archive test results
junit(allowEmptyResults: true, testResults: "**/target/surefire-reports/**.xml,**/target/failsafe-reports/**.xml")
}
}
}
failure {
emailext recipientProviders: [culprits(), requestor()],
subject: "[Jenkins] Build failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Hello,\n\nBuild failed: ${env.JOB_NAME} / ${env.BRANCH_NAME} #${env.BUILD_NUMBER}.\nDetails: ${env.BUILD_URL}\n\nJenkins"
}
fixed {
emailext recipientProviders: [culprits(), requestor()],
subject: "[Jenkins] Build fixed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Hello,\n\nBuild fixed: ${env.JOB_NAME} / ${env.BRANCH_NAME} #${env.BUILD_NUMBER}.\nDetails: ${env.BUILD_URL}\n\nJenkins"
}
}
}
Related
I'm trying to send an email when a Pipeline build on Jenkins fails. An example can be found here: https://github.com/jenkinsci/pipeline-examples/blob/master/jenkinsfile-examples/nodejs-build-test-deploy-docker-notify/Jenkinsfile
My concrete groovy script looks as follows:
#!groovy
node('') {
def env = ["JAVA_HOME=${tool 'jdk1.8.0_131'}", "PATH+MAVEN=${tool 'maven_3.1.1'}/bin:${env.JAVA_HOME}/bin", "PATH+GRADLE=${tool 'gradle_4.1'}/bin:${env.JAVA_HOME}/bin" ]
def err = null
currentBuild.result = "SUCCESS"
try {
stage('errorStage') {
dir('error') {
git url: "unknown", branch: "master"
withEnv(env) {
sh "mvn -Pjenkins-build clean deploy"
}
}
}
} catch (caughtError) {
println "caught error :" + caughtError
err = caughtError
currentBuild.result = "FAILURE"
mail (body:
"Pipeline error: ${err}\nFix me.",
from: 'jenkins#x.com',
subject: 'Pipeline build failed',
to: 'recipient#x.com')
} finally {
/* Must re-throw exception to propagate error */
if (err) {
throw err
}
}
}
Actually, nothing ever happens, although the exception is being caught correctly and the build fails. Is there anything required to be able to use mail?! Maybe another Jenkins plugin or something?
I was able to fix it myself by using emailext plugin on Jenkins instead of mail. The code looks as follows now:
emailext body: "Pipeline error: ${err}\nPlease go to ${BUILD_URL} and verify the build",
recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']],
subject: "'${JOB_NAME}' (${BUILD_NUMBER}) failed",
to: '...'
In my build job on Jenkins via pipeline, I need a post-build steps which depend on the build status. If the job was successful then do 'this'. Otherwise do 'that'.
How can I retrieve the build job status, using pipeline, and save it e.g. in an environment variable for using it in the post-build steps?
Define color in top of pipeline (easy to track success/failure)
and add post action after stages section
def COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger']
pipeline {
agent any
options {
ansiColor('xterm')
}
stages {
stage("Build") {
}
stage("Deploy") {
}
} //end of stages
post {
always {
slackSend (color: COLOR_MAP[currentBuild.currentResult], message: "Job: *${env.JOB_NAME}, build #${env.BUILD_NUMBER}* is *`${currentBuild.currentResult}`* \nRun in ${currentBuild.durationString} - <${env.BUILD_URL}|Go to this job>")
}
}
}
Configure slack integration in https://plugins.jenkins.io/slack
You can use the post block to perform actions based on build status as shown below:
post {
success {
emailext (
subject: '${DEFAULT_SUBJECT}'+'SUCESSFUL',
body: '${DEFAULT_CONTENT}',
to: '${EMAIL_RECIPIENTS}'
);
slackSend (color: 'good', message: ":csp_operational: ${env.JOB_NAME} - #${env.BUILD_NUMBER} Success (<${env.BUILD_URL}|Open>)");
}
failure {
emailext (
subject: '${DEFAULT_SUBJECT}'+'FAILED!',
body: '${DEFAULT_CONTENT}',
to: '${EMAIL_RECIPIENTS}'
);
slackSend (color: 'danger', message: ":x: ${env.JOB_NAME} - #${env.BUILD_NUMBER} Failure (<${env.BUILD_URL}|Open>)");
}
}
I have the following post failure section:
post {
failure {
mail subject: "\u2639 ${env.JOB_NAME} (${env.BUILD_NUMBER}) has failed",
body: """Build ${env.BUILD_URL} is failing!
|Somebody should do something about that""",
to: "devel#example.com",
replyTo: "devel#example.com",
from: 'jenkins#example.com'
}
}
I would like to include the reasons why the build failed in the body of the error message.
How can I do that?
If not, is there a way to attach the build log file to the email?
I don't know of a way to retrieve the failure reason automatically out of thin air.
However, you can use "post{ failure {" blocks in each phase to capture at least the phase in which it failed into a environment variable (e.g. env.FAILURE_REASON), and access that env var in the final (global scope) notification block.
For more granularity, you can reuse the same mechanism of the global env variable, but use try { } catch { } blocks to capture which specific step failed.
A generic example would be:
pipeline {
stages {
stage('Build') {
steps {
...
}
post {
failure {
script { env.FAILURE_STAGE = 'Build' }
}
}
}
stage('Deploy') {
steps {
...
}
post {
failure {
script { env.FAILURE_STAGE = 'Deploy' }
}
}
}
...
}
post {
failure {
mail subject: "\u2639 ${env.JOB_NAME} (${env.BUILD_NUMBER}) has failed",
body: """Build ${env.BUILD_URL} is failing in ${env.FAILURE_STAGE} stage!
|Somebody should do something about that""",
to: "devel#example.com",
replyTo: "devel#example.com",
from: 'jenkins#example.com'
}
}
}
Technically, you can even do some automated triage based on the failing stage and send a more targeted notification, or even create specific (e.g. Jira) tickets.
For attaching the console log to the email notification, you'd want to look at
emailext and the 'attachLog: true' attribute
I am having problems receiving email notifications for a pipeline I have setup like so:
#!groovy
pipeline {
agent any
stages {
stage('Build Prep') {
steps {
sh '...'
}
}
stage('Build') {
steps {
sh '...'
}
}
stage('Tests') {
steps {
parallel (
"Jasmine": {
sh '...'
},
"Mocha": {
sh '...'
}
)
}
}
stage('Deploy') {
steps {
sh "..."
}
}
}
post {
success {
emailext to:"me#me.com", subject:"SUCCESS: ${currentBuild.fullDisplayName}", body: "Yay, we passed."
}
failure {
emailext to:"me#me.com", subject:"FAILURE: ${currentBuild.fullDisplayName}", body: "Boo, we failed."
}
unstable {
emailext to:"me#me.com", subject:"UNSTABLE: ${currentBuild.fullDisplayName}", body: "Huh, we're unstable."
}
changed {
emailext to:"me#me.com", subject:"CHANGED: ${currentBuild.fullDisplayName}", body: "Wow, our status changed!"
}
}
}
The build logs confirm an email is sent, but I dont get anything in my inbox, nothing in spam either.
I have come across this https://jenkins.io/blog/2016/07/18/pipline-notifications/
But I am unsure if I can use using the syntax I have, I don't have any nodes defined, should I?
Your script works fine. I did receive the email using the above code. Please check your other settings or if you had created a rule for Jenkins emails. You can make your code look easier by adding your notifications to the Jenkins shared library. Please take a look at the below link.
https://jenkins.io/doc/book/pipeline/shared-libraries/
I have a pipeline groovy script in Jenkins v2.19. Also I have a
"Slack Notification Plugin" v2.0.1 and "Groovy Postbuild Plugin" installed.
I can successfully send "build started" and "build finished" messages.
When a build fails, how can I send the "Build failed" message to a Slack channel?
You could do something like this and use a try catch block.
Here is some example Code:
node {
try {
notifyBuild('STARTED')
stage('Prepare code') {
echo 'do checkout stuff'
}
stage('Testing') {
echo 'Testing'
echo 'Testing - publish coverage results'
}
stage('Staging') {
echo 'Deploy Stage'
}
stage('Deploy') {
echo 'Deploy - Backend'
echo 'Deploy - Frontend'
}
} catch (e) {
// If there was an exception thrown, the build failed
currentBuild.result = "FAILED"
throw e
} finally {
// Success or failure, always send notifications
notifyBuild(currentBuild.result)
}
}
def notifyBuild(String buildStatus = 'STARTED') {
// build status of null means successful
buildStatus = buildStatus ?: 'SUCCESSFUL'
// Default values
def colorName = 'RED'
def colorCode = '#FF0000'
def subject = "${buildStatus}: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'"
def summary = "${subject} (${env.BUILD_URL})"
// Override default values based on build status
if (buildStatus == 'STARTED') {
color = 'YELLOW'
colorCode = '#FFFF00'
} else if (buildStatus == 'SUCCESSFUL') {
color = 'GREEN'
colorCode = '#00FF00'
} else {
color = 'RED'
colorCode = '#FF0000'
}
// Send notifications
slackSend (color: colorCode, message: summary)
}
Complete snippet can be found here Jenkinsfile Template
Just in case if in Declarative Syntax,
Now, Jenkins provides post. You can check result at the end of pipeline.
https://jenkins.io/doc/book/pipeline/syntax/#post-example
Using like:
pipeline {
stages { ... }
post {
// only triggered when blue or green sign
success {
slackSend ...
}
// triggered when red sign
failure {
slackSend ...
}
// trigger every-works
always {
slackSend ...
}
}
}
It would be used in every stage also. See the document link please.
Based on Liam Newman's blog post, have a look at this cleaned up snippet for Slack only in scripted pipelines (declarative pipeline users scroll down). It uses original Jenkins results, message formatting, better colors (based on EclEmma), and some Groovy features like default arguments:
def notifySlack(String buildStatus = 'STARTED') {
// Build status of null means success.
buildStatus = buildStatus ?: 'SUCCESS'
def color
if (buildStatus == 'STARTED') {
color = '#D4DADF'
} else if (buildStatus == 'SUCCESS') {
color = '#BDFFC3'
} else if (buildStatus == 'UNSTABLE') {
color = '#FFFE89'
} else {
color = '#FF9FA1'
}
def msg = "${buildStatus}: `${env.JOB_NAME}` #${env.BUILD_NUMBER}:\n${env.BUILD_URL}"
slackSend(color: color, message: msg)
}
node {
try {
notifySlack()
// Existing build steps.
} catch (e) {
currentBuild.result = 'FAILURE'
throw e
} finally {
notifySlack(currentBuild.result)
}
}
The output will be something like this (play around with different formatting styles here):
Maybe env.JOB_NAME contains encoded slashes (%2F) which can be fixed with replaceAll("%2F", "/"). Check out this Gist to see how to notify HipChat as well.
If you have a declarative pipeline, have a look at the Jenkins documentation on "Cleaning up and notifications" or Liam Newman's follow-up post "Declarative Pipeline: Notifications and Shared Libraries".