Wednesday, December 13, 2017

Marking Jenkins builds with Badges


We can adjust the status of a Jenkins job to Unstable, Failed or Successful, and we can add handy badges to the builds to signal warnings or errors.  All from the Groovy PostBuild Plugin. 

Jenkins is like your older uncle who helps you get through college: Dependable but a little clunky, stuffy but also necessary.  Turns out uncle is wearing a brightly patterned sports coat at times, in the shape of build badges:



What is also nice is that a Jenkins build can have final status other than failed (red ball) or passed (blue ball).  You may have seen NOT_BUILD (grey ball) and broken your head over UNSTABLE (yellow ball).

Aside: What is unstable supposed to mean, you ask?  In Jenkins' slightly warped view of the world, if the build step is successful (ie. the compiler did its job) but the tests failed, a job is unstable.  In normal agile terms, that is just a plain fail.  To add to the confusion, only certain post-build actions are able to move the status to unstable, so you may rarely encounter this.  But it is a great status to (ab)use if you want to show alerts on your job.

Setting build status and badges

So how can we access all this goodness?  Groovy is the answer here.  Note that I am applying groovy to any style Jenkins jobs, not only pipeline jobs that already groovy-fied.

You want to add the Groovy postbuild plugin to your Jenkins and then create a Groovy post-build action.  Here is some sample code that unconditionally set the build to Unstable.   Run it and you should see a yellow ball and an unstable outcome.
   import hudson.model.*
   def build = manager.build
   build.@result = hudson.model.Result.UNSTABLE
   manager.addErrorBadge("That really wasn't very stable")
   return


There are lots of other ways to do the same, and other things you can do, see the documentation for this plugin.  For example, you can also use 'manager.buildUnstable()' instead of that last line.

The Jenkins interface has an nice 'run in sandbox' checkbox, which you really want to check because it limits the abilities of your Groovy scripts.  However, it didn't work for me:  I basically could not run any Groovy code with this set.  The docs say that all the methods we used above are whitelisted, but apparently things have changed (or my Jenkins version is out of date).

Reading and checking build files


For my problem, I needed to get slightly more fancy and tests a few files in the current job.  Note that it is much easier to test for log lines in the current build, the method 'manager.logContains(REGEXP)' can help you with that.

To test for certain files in the current build directory, you can use:
def build = manager.build
def workspace = manager.getEnvVariable('WORKSPACE')

if (new File(workspace + '/mySpecialFile').exists()) {
   manager.buildUnstable()
   manager.addErrorBadge("Unit tests were not run")
   manager.listener.logger.println("Marked unstable")
else {
   manager.listener.logger.println("All well") }

return

This checks for the presence of 'mySpecialFile' under the project root.  If you build has produced such a file, it will be marked unstable and a log line will be emitted.


Getting a list of all variables available to you

How did I find out about the workspace variable?  I ran this piece of code, modified from one of the comments in the Groovy PostBuild Plugin page:

def build = Thread.currentThread().executable
def buildMap = build.getBuildVariables()
buildMap.keySet().each { var -> 
       manager.listener.logger.println( var + "= " + buildMap.get(var)) }
def envVarsMap = build.parent?.lastBuild.properties.get("envVars")
envVarsMap.keySet().each { var -> 
       manager.listener.logger.println( var + ": " + envVarsMap.get(var)) }

This will show the build variables (parameters to the build) and the environment variables.  My result (slightly redacted; no build variables):

BUILD_DISPLAY_NAME: #29
BUILD_ID: 29
BUILD_NUMBER: 29
BUILD_TAG: jenkins-test-29
BUILD_URL: http://localhost:8080/job/test/29/
CLASSPATH: 
DERBY_HOME: /usr/lib/jvm/java-8-oracle/db
EXECUTOR_NUMBER: 1
HOME: /var/lib/jenkins
HUDSON_HOME: /var/lib/jenkins
HUDSON_SERVER_COOKIE: 7......d
HUDSON_URL: http://localhost:8080/
J2REDIR: /usr/lib/jvm/java-8-oracle/jre
J2SDKDIR: /usr/lib/jvm/java-8-oracle
JAVA_HOME: /usr/lib/jvm/java-8-oracle
JENKINS_HOME: /var/lib/jenkins
JENKINS_SERVER_COOKIE: 7.....d
JENKINS_URL: http://localhost:8080/
JOB_BASE_NAME: test
JOB_DISPLAY_URL: http://localhost:8080/job/test/display/redirect
JOB_NAME: test
JOB_URL: http://localhost:8080/job/test/
LANG: en_US.UTF-8
LOGNAME: jenkins
MAIL: /var/mail/jenkins
MANPATH: /opt/OpenPrinting-Gutenprint/man:/opt/OpenPrinting-Gutenprint/man:/usr/local/man:/usr/local/share/man:/usr/share/man:/usr/lib/jvm/java-8-oracle/man
NLSPATH: /usr/dt/lib/nls/msg/%L/%N.cat
NODE_LABELS: master
NODE_NAME: master
NODE_PATH: /usr/lib/nodejs:/usr/lib/node_modules:/usr/share/javascript
PATH: /opt/OpenPrinting-Gutenprint/sbin:/opt/OpenPrinting-Gutenprint/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
PATH+CHROMEDRIVER: /var/lib/jenkins/tools/chromedriver
PWD: /var/lib/jenkins
QT_QPA_PLATFORMTHEME: appmenu-qt5
RUN_CHANGES_DISPLAY_URL: http://localhost:8080/job/test/29/display/redirect?page=changes
RUN_DISPLAY_URL: http://localhost:8080/job/test/29/display/redirect
SHELL: /bin/bash
SHLVL: 1
USER: jenkins
WORKSPACE: /var/lib/jenkins/workspace/test
XDG_RUNTIME_DIR: /run/user/125
XDG_SESSION_COOKIE: f...........0
XDG_SESSION_ID: c20
XFILESEARCHPATH: /usr/dt/app-defaults/%L/Dt

You can check this output against http://localhost:8080/env-vars.html.



 Hope you can use this in your work with Jenkins!

No comments:

Post a Comment