Jenkins build number drop-down

As a bit of background, the basic setup I have is one build job in Jenkins that’s triggered by a GitHub checkin, and then a deployment job for each environment which in turn use Puppet to do the actual transfer of files to the respective servers and service restarts etc. What I wanted was a drop-down for each deployment job which has a list of available builds so that my entire deployment process is:

  1. Click “Build Now”
  2. Choose build to deploy from drop-down
  3. Click “Build”

(Build in this case just means running the deployment job, not actually re-building the artifacts etc)

As far as I could see there isn’t a Jenkins plugin for this and as a relative newcomer to Jenkins I think I’ll leave writing the plugin for a bit later (read “hopefully someone else who knows what they’re doing”). You will however need some plugins to do this, I can’t remember if any of these came out of the box but they’re not difficult to install:

Build number drop down:

So… step one: get a list of available builds. For this you’ll need the Dynamic Parameter Plugin, this does what it says (like most plugins) and lets you dynamically generate the options to pass as parameters to the build, it uses groovy which is lucky because that’s the way we’re going to get our list of builds.

If the plugin installed correctly you should be able to tick the “This build is parameterized” check-box at the top of the job configuration page and be able to see “Dynamic Choice Parameter (Scriptler)” in the drop-down. This is where Scriptler comes in. It offeres lots of groovy script management stuff but for our purposes the main thing is code reuse and tidiness. Because in my scenario I have a job for Dev, Test, UAT and Production I don’t really want a copy of my groovy script in each job, so I can save the script in Scriptler and reference it from all of the jobs.

You can find Scriptler in the menu on the left of the Jenkins homepage, it’s fairly self explanatory for this basic stuff so just add a new script: I set the name to be “DynamicChoice_AllBuilds” and used the same for the Id. As for the script itself you’ll need this:

import hudson.model.*

BUILD_JOB_NAME = "Build"

def getJobs() {
    def hi = Hudson.instance
    return hi.getItems(Job)
}

def getBuildJob() {
    def buildJob = null
    def jobs = getJobs()
    (jobs).each { job ->
        if (job.displayName == BUILD_JOB_NAME) {
            buildJob = job
        }
    }
    return buildJob
}

def getAllBuildNumbers(Job job) {
    def buildNumbers = []
    (job.getBuilds()).each { build ->
        buildNumbers.add(build.number)
    }
    return buildNumbers
}

def buildJob = getBuildJob()
return getAllBuildNumbers(buildJob)

Hopefully I’ve written it so that it’s decipherable but the only thing you’ll need to change is the BUILD_JOB_NAME = “Build” line, just set this to the display name of the job that you want the list of builds for, in my case it’s simply “Build”. Save the script and return to the job configuration page. In the dynamic choice parameter section you should now be able to select the new script in the “Script” drop-down.

The last thing we have to configure in this section is the “Name” attribute which has two functions: 1) It’s the label that is displayed next to the drop-down when you actually run the job. 2) It’s the name of the variable that we reference to use the build number. Therefore if you change it in this section remember to change it where it is referenced in the sections below. I chose “BUILD_NUMBER” just to keep it simple and so the dynamic parameter section looks like this:

Screen Shot 2013-01-17 at 14.02.24

If you save the job and start a build you should hopefully see something like this:

Screen Shot 2013-01-28 at 11.57.40

Doing something with it:

Ok, so we have a dynamic drop-down with all the available builds, but it doesn’t actually do anything, so now to Step 2: actually doing something useful with it!

In my setup I’m using the Copy Artifact plugin to (surprise surprise) copy all of the artifacts and archived stuff from my Build job into the workspace of my deployment job so that I can prepare it all for deployment (unzip files, rename things, flatten direcotries, etc etc) which in my case is copying a directory up to the Puppet Master.

This plugin has a lovely feature where you can specify the name of the job you want to copy from (the same name as BUILD_JOB_NAME is the grovvy script above) and also the name of a build parameter specifying which build to copy. So you would think that you just dump “BUILD_NUMBER” in the text box click save and you’re good to go! Well it turns out that this input expects a blob of XML and not just the number of the build! To get round this I used the EnvInject plugin to set another variable that contains the chosen build number wrapped in the appropriate XML (which I found from some debug output somewhere). I called my variable BUILD_NUMBER_XML so this is the variable value and what the top of my build section looks like :

BUILD_NUMBER_XML=<SpecificBuildSelector plugin="copyartifact@1.23">  <buildNumber>${BUILD_NUMBER}</buildNumber></SpecificBuildSelector>

Screen Shot 2013-01-28 at 12.01.33

And that’s it for the basic setup, you should now be able to create a Jenkins job with a dynamic build number drop-down!!

Optional:

The only plugin I haven’t mentioned is the Build Name Setter plugin. This is useful when you’re deploying builds from another job whether you’re using a drop-down or not, because you can set the name of the deployment run to include the number of the build you’re deploying, just tick the “Set Build Name” box and use something like:

Deploy Build #${ENV,var="BUILD_NUMBER"}

Screen Shot 2013-01-28 at 16.12.50

Advertisements

2 comments

  1. Hi,

    I liked the selection of build number based on “if the promotion is done e.g. ‘isKeepLog’ true ” I am keen to understand how Can I extend the logic to make it work got the filter meaning if one has promoted the code to level 3 then it should be possible to install it in any environment that has value less than or equal to 3 but not above , so that the filterting takes place based on the selected level

    can you please guide me, I am unable to access the promotion level from the build info

  2. Shorter version:

    import hudson.model.*;

    return Hudson.instance.getItemByFullName(“THE_BUILD_NAME”,Job).builds
    .findAll{b->b.result==Result.SUCCESS}.collect{b -> b.parent.name +” #” + b.number};

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s