Home > Software design >  Jenkins Pipeline: Which condition should I use to be notified about build failure?
Jenkins Pipeline: Which condition should I use to be notified about build failure?

Time:08-25

I have a Jenkins pipeline for automation tests in which it downloads the source from Git and builds it before starting to test.

I would like to have a slack notification when a Jenkins pipeline build fails.

Not if there are test errors - only if the code does not build.

The post conditions I found are as follows:

always  - Always, regardless of the outcome of stage/pipeline.

changed - If completion status differs from the previous run.

fixed   - When status went from failed or unstable to successful.

regression - When status was successful in the previous run but is failure, unstable or aborted now.

aborted - When the status is aborted.

failure - When the status is failure.

success - When the status is success.

unstable - When the status is unstable.

unsuccessful - When the status is not success, but any one of the others.

cleanup - Always, regardless of the outcome, but as the last one after all others have been run.

I don't see here a condition of build failure or something related.

Is there a way to achieve that? Does failure condition contains also build failures?

So far I used:

post{
    failure{
        slackSend( channel: "#my_alerts", token: "slack_webhook token", color: "good", message: "${custom_msg()}")
    }
}

but is it relevant to use failure condition?

CodePudding user response:

We have a setup like this:
enter image description here

If the whole build fails, then we will be notified by the failure step in the post section.

EDIT:

def onBuildAborted() {
    env.BUILD_STATUS = "build was aborted by user :stop_sign:";
    env.BUILD_TYPE = "INFO";
}

def onBuildSucceeded() {
    env.BUILD_STATUS = "build succeeded :check:";
    env.BUILD_TYPE = "SUCCESS";
}

def onBuildFailed() {
    env.BUILD_STATUS = "build failed :cross_mark:";
    env.BUILD_TYPE = "ERROR";
}

def onBuildSucceededButUnstable() {
    env.BUILD_STATUS = "build succeeded, but tests did not pass :prohibited:";
    env.BUILD_TYPE = "WARNING";
}

def notifyBuildEnd() {
    String buildStatus = env.BUILD_STATUS != null ? env.BUILD_STATUS : ""
    String resultType = env.BUILD_TYPE != null ? env.BUILD_TYPE : "";

    String buildDuration = currentBuild.durationString;
    buildDuration = buildDuration.replace(" and counting", "");
    // remove 'and counting' at end of string

    String messageHeader = "${buildStatus} in ${buildDuration}";
    String messageBody = env.BUILD_TESTRESULTS != null ? env.BUILD_TESTRESULTS : "";
    String stacktrace = env.BUILD_STACKTRACE != null ? env.BUILD_STACKTRACE : "";

    sendNotification(resultType, messageHeader, messageBody, stacktrace);
}

def sendNotification(String type = 'INFO', String header = 'update', String body = '', String stacktrace = '') {
    echo "preparing to send messaging platform notifications: type=${type}, header=${header}, body=${body}, stacktrace=${stacktrace}"

    // colors taken from bootstrap (see https://www.bitdegree.org/learn/bootstrap-colors)
    String color_neutral = '#17a2b8';  // teal
    String color_success = '#28a745';  // green
    String color_error = '#dc3545';    // red
    String color_warning = '#ffc107';  // yellow
    String color_default = ' #007bff'; // blue

    String messagecolor = color_default

    if ('SUCCESS' == type) {
        messagecolor = color_success;

    } else if ('INFO' == type) {
        messagecolor = color_neutral;

    } else if ('WARNING' == type) {
        messagecolor = color_warning;

    } else if ('ERROR' == type) {
        messagecolor = color_error;
    }

    def jobName = env.JOB_NAME;
    jobName = jobName.replace("/", "/");
    jobName = jobName.replace("#", "#");

    def jobIdentifier = "<${env.BUILD_URL}|${jobName} - build ${env.BUILD_NUMBER}>"

    header = "*${header}*"
    if ("" != stacktrace) {
        stacktrace = "```${stacktrace}```"
    }

    def attachmentsArr = [
            [
                    text : header,
                    color: messagecolor
            ],
            [
                    text : jobIdentifier,
                    color: messagecolor
            ],
            [
                    text : body,
                    color: color_neutral
            ],
            [
                    text : stacktrace,
                    color: color_neutral
            ]
    ];

    def markdownJobIdentifier = "[${jobName} - build #${env.BUILD_NUMBER}](${env.BUILD_URL})"
    zulipSend message: "${header}\n${markdownJobIdentifier}\n${body}", stream: 'jenkins', topic: 'some_zulip_channel'

    echo "messaging platform notifications sent"
}

This will give you messages like this:
enter image description here

The only thing you need to change is zulipSend to slackSend. If you need help with the slackSend command try this Stackoverflow answer.

CodePudding user response:

Any failure in the Pipeline will trigger the failure{} block. Even if your test execution throws an error the build will be marked as Failed. Basically at the end of the Pipeline Stage executions, based on currentBuild.result the relevant book will be executed.

Having said that, so the behavior really depends on how you have implemented your Pipeline. For example, if you don't want test execution to mark your build as a failure you will have to handle it explicitly. Something like below. So if the tests fail the build will be marked as Unstable and the unstable block will be executed.

stage('Test') { 
     steps {
        script {
            try {
                echo "Executing your tests here"
         
            } catch(e) {                                            
                currentBuild.result = "UNSTABLE"
            }
        }
    } 
}
  • Related