13

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 ?

StephenKing
  • 36,187
  • 11
  • 83
  • 112
Mikael Gibert
  • 355
  • 1
  • 3
  • 8
  • So what's your actual problem? Sending the email? – StephenKing Aug 02 '17 at 09:32
  • Sorry I realize that I was not that clear... my problem is that I would like to send an email on every failures, but only one when the status moves to success. I'd like to recover the feature "receive mail on failed builds and on fixed builds". – Mikael Gibert Aug 03 '17 at 15:51
  • 1
    In fact, my question was more generalist and about "how can I write conditions inside a post action block" – Mikael Gibert Aug 03 '17 at 16:00
  • You mentioned `changed` in your question. Why don't you use that? – StephenKing Aug 03 '17 at 16:30
  • I wanted to have notifications on every status except success (i.e, I want a new email at each failure). But you are right, I finally used exactly the snippet I posted and live with this. I have another use case where I need to perform some post actions only on certain branches, but your other response with script blocks solves this problem too! Thank you for your help! – Mikael Gibert Aug 04 '17 at 14:27
  • Just to throw it out there, you can also make use of the `fixed` and `regression` blocks. `fixed` is called when your build goes green after either failure or unstable, but not after aborted. `regression` is called when your build result is worse than the previous build (success -> unstable -> failure -> aborted, worse result to the right). It sounds like using `changed` with the custom function is what you were looking for specifically, but adding this just in case someone lands here searching for something similar. – Will Jan 17 '19 at 21:22

4 Answers4

17

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.

Jonas Masalskis
  • 1,206
  • 1
  • 15
  • 14
2

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.

psalvi21
  • 143
  • 5
  • Thanks for your answer. In fact, I would not like to receive a mail on each success but only on the first success following a non success build. – Mikael Gibert Aug 03 '17 at 15:54
0

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/

Benathmane
  • 19
  • 3
  • Thank you, that will do the trick, it looks complicated for what was a simple checkbox before, but it definitely solves my problem! – Mikael Gibert Aug 03 '17 at 15:55
  • 1
    Do you know if it is possible to write conditionals inside a post action ? "when" statement looks interesting but is not allowed inside a post block :( – Mikael Gibert Aug 03 '17 at 15:58
  • 1
    That's for scripted pipeline (use a `script` block in declarative). – StephenKing Aug 03 '17 at 16:09
0

@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"
        }
    }
}
t0r0X
  • 4,212
  • 1
  • 38
  • 34