Search code examples
jenkinscontinuous-integrationbitbucketbcbsn

Setting Jenkins to email a build notification to the BitBucket user who pushed a branch


A project repository has been successfully connected to a Jenkins server using the BitBucket plugin, and a project set up such that:

  • Each push to a branch in BitBucket will trigger a webhook sent to the Jenkins server
  • When the Jenkins server receives the webhook it will build the changed branch (by specifying branch name as ** in the config)
  • After the build is complete a notification is sent back to BitBucket of the build status using the BitBucket notifier

Each of these has been easy to set up with just the instructions in the plugin and a few quick Googles. However I've now run into a problem which is maybe more a matter of wanting to run in an unconventional manner than anything else.

Using the normal emailer plugin or the Email-ext plugin it's possible to set emails to send to people involved in the creation of a build. For example the Email-ext plugin allows choice of:

  • Requester
  • Developers (all people who have commits in the build based off its last version)
  • Recipient list (a pre-set list)
  • Various "blame" settings for broken builds

The development process being followed involves each project being worked on by one developer in a named branch, e.g. userA/projectB. Obviously other developers could check that out and push to make changes but that's frowned upon. Even in that instance, the user who pushes the change to BitBucket should be notified.

None of the current settings support this. Requester is the closest, but that only works for manual builds. It seems a very simple requirement that the push to SCM that triggered a build should notify the user who pushed, but this is not documented anywhere that is easy to find.


Solution

  • After a lot of searching it seems the only way to accomplish this is by using a Pre-send script. This is added to the Advanced setting of the Email-ext post-build step, and takes the form of code written in Groovy which is a Java extension.

    The script can take advantage of Environment variables, but is hard to test as there's no way to run the script with these in place. You can test simple Groovy scripts from Home -> Manage Jenkins -> Script console.

    One important "gotcha" with the environment variables is that they are "included" in the script, rather than variables or constants. E.g. before the script compiles and runs, the content of the variable is pasted in place of its $NAME. In the example below the multi-line string syntax is used to include the BitBicket payload, whereas it might be expected that def payload = $BITBUCKET_PAYLOAD would simply work.

    import javax.mail.Message.RecipientType
    import javax.mail.Address
    import javax.mail.internet.InternetAddress
    import javax.mail.internet.MimeMessage
    import groovy.json.JsonSlurper
    
    def jsonSlurper = new JsonSlurper()
    
    def bitbucket = jsonSlurper.parseText('''
       $BITBUCKET_PAYLOAD'''
    )
    
    switch (bitbucket.actor.username){
      case "userA":
        msg.setRecipients(MimeMessage.RecipientType.TO, InternetAddress.parse("user.a@domain.com"));
      break;
      case "userB":
        msg.setRecipients(MimeMessage.RecipientType.TO, InternetAddress.parse("user.b@domain.com"));
      break;
    }
    

    The setRecipients command overwrites any existing recipient. Thus the recipient list or other email configuration should be set as a fallback for if the user is not recognised. Additionally, if there is nobody selected to send the email to, the script won't run at all. As added debugging, including the username in the body might help.

    If the script fails, stack traces should be printed to the console log output of the test, and the build pass/fail shouldn't be affected, but the normal email address setup will be used instead. In stack traces look for lines with Script() in them, as that's the container which evaluates the Groovy script.