Skip to content

Send notifications to Slack

Valentina-Camelia Bojan edited this page Nov 10, 2019 · 14 revisions

A good practice in DevOps is to integrate your tools with each other. In our case, one step can be to integrate Jenkins with Slack and have your builds sending notifications to Slack. The notification could contain the build progress and its final status: passed or failed.

Install Slack Notification plugin

Slack Notification is the plugin you'll have to install. Here you can find the steps to install a Jenkins plugin.

Configure Slack to use the JenkinsCI app

Before start using the plugin, we need to do some Slack configurations:

  • create a Slack channel (eg. jenkins-pipeline-workshop)
  • go to Customize Slack
  • go to Configure Apps -> Apps
  • select Jenkins CI app
  • click Add to Slack
  • choose the newly created channel and click Add Jenkins CI integration
  • copy the generated token

You'll have to use the generated token when configuring the Slack Notification plugin. From security point of view, it's not a good idea to specify the token as clear text. The recommended approach is to use store it using the Jenkins credentials and refer to that credential when configuring the plugin. Here you can find how to create Jenkins credentials.

Configure Slack Notification plugin

Let's configure the Slack notification plugin:

  • go to Jenkins -> Manage Jenkins -> Configure System
  • go to -> Slack section
  • complete your Slack workspace
  • select the previously created Slack integration credential
  • test the connection
  • if success, save the configuration

Configure Slack Plugin

Send notifications to Slack from your Jenkins build

You send have each one of the stages you configured in the Jenkins pipeline sending notifications to slack. This will keep track of the build progress.

Most probably, your Build stage currently looks like this:

stage('Build') {
    steps {
        withMaven(maven: MAVEN_INSTALLATION, mavenSettingsConfig: MAVEN_SETTINGS_CONFIG) {
            sh 'mvn -DskipTests clean package'
        }
    }
}

You'll have to call the slackSend method to whenever you want to send a notification to Slack. You can pass the message as parameter, but also some additional details, such as a color for that message. This is a valid code to fulfil this purpose.

slackSend message: 'Build stage', color: '#0000ff'

However, in most cases, you'll want to send more details in the notification, such as the build number, the job name, the branch for which the build was executed, the failure reason etc.

The available Jenkins environment variables can cover most of these details. If you want to have a look at all available environment variable, just add the following line in one of the stages from the Jenkins pipeline:

sh 'printenv'

One example of more detailed notification for your Build stage could be the following code snippet. Notice that you'll have to use the script directive because there is a variable defined inside it.

stage('Build') {
    steps {
        withMaven(maven: MAVEN_INSTALLATION, mavenSettingsConfig: MAVEN_SETTINGS_CONFIG) {
            sh 'mvn -DskipTests clean package'
        }
        script {
            statusComment = "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> ${env.STAGE_NAME} stage completed succesfully for ${env.GIT_BRANCH}"
            slackSend message: statusComment, color: '#0000ff'
        }
    }
}

You can use exactly the same script directive and it's content for the Test stage.

Send notifications to Slack from an interactive stage

Because Deploy is an interactive stage you would like to know who was that approved or not the stage. To do this, you'll have to change a bit the way you use the input step and specify a value for submitterParameter. This way after someone approves or declines the inout step, the submitter name will be filled into the specified value for submitterParameter.

The Deploy stage will look like this:

stage('Deploy') {
    input{
        message 'Do you want to deploy?'
        submitterParameter 'responder'
    }
    steps {
        echo "Deploying application..."
        script {
            statusComment = "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> ${env.STAGE_NAME} stage was approved by ${responder} for ${env.GIT_BRANCH}"
            slackSend color: '#0000ff', message: statusComment
        }
    }
}

Send notifications to Slack when your build ends

If you want to notify Slack when the build ended, you can rely on post section. It has blocks for all possible reasons why a build can end. For example, you can have the following clock next to all the defined stages in the Jenkins pipeline. Have a look here for more details.

post {
    success {
        ...
    }
    failure {
        ...
    }
    aborted {
        ...
    }
    ...
}

Let's suppose we want to send a notification when the build ended successfully. The syntax is pretty straight-forward based on what we know already:

success {
    script {
        statusComment = "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> completed succesfully for ${env.GIT_BRANCH} :tada:"
        slackSend color: 'good', message: statusComment
    }
}

If someone declines to proceed with the interactive Deploy stage, the build will be marked as aborted. You would like to know who was that approved or not the stage. To do this, you'll define a Groovy function in your Jenkinsfile. Pay attention to put your new function outside the pipeline definition.

String getBuildUser() {
    return currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
}
aborted {
    script {
        statusComment = "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> for ${env.GIT_BRANCH} was aborted by ${getBuildUser()}"
        slackSend message: statusComment
    }
}

The build can fail because of various reasons, but most probably it will fail because of some failing tests. In this case, it would be useful for the notification to contain how many tests failed ad made the build to fail as well. This information can be retrieved by defining a new Groovy function:

String getTestResultsMessage() {
    AbstractTestResultAction testResultAction = currentBuild.rawBuild.getAction(AbstractTestResultAction.class)
    if (testResultAction != null) {
        def total = testResultAction.totalCount
        def failed = testResultAction.failCount
        def skipped = testResultAction.skipCount
        return "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> had test failures for ${env.GIT_BRANCH}.\n  Total: ${total}, Failed: ${failed}, Skipped: ${skipped}"
    } else {
        return "[${env.JOB_NAME}] <${env.BUILD_URL}|#${env.BUILD_NUMBER}> failed for ${env.GIT_BRANCH}"
    }
}

You can now use the result of this function in the snippet below:

failure {
    script {
        statusComment = getTestResultsMessage()
        slackSend color: 'danger', message: statusComment
    }
}

If everything went well and the build ended successfully, the generated notifications will look like this:

Notifications for green build

If you have at least 1 test failing, the generated notifications will look like this:

Notifications for red build

Final Jenkinsfile

You can have a look here to see the final form of the Jenkinsfile.