Continuous Delivery with Jenkins

For various reasons, I’ve been working lately on projects where Jenkins is the only available build software and yet there’s a requirement to employ the Continuous Delivery model of software build & release.

However, despite its limitations, you can achieve something close to Continuous Delivery using the relatively new Build Flow plugin.

CAVEAT: And when I say “new”, what I really mean is “embryonic”. The Build Flow plugin has been around for over a year, yet is still at version 0.12 and in no fit state for serious use. There are many missing features, bugs, and other oddities and limitations.

Jenkins is basically a task scheduler, suitable for simple Continuous Integration builds. Each build job can trigger one or more downstream build jobs, and can in turn be triggered by the successful completion of an upstream job. What Jenkins cannot do (natively) is launch a job on the successful completion of multiple upstream jobs. Additionally, Jenkins has no concept of build stages, as you would expect in build software designed for Continuous Delivery (such as Bamboo or Go). Finally, the intra-job wiring is configured in each individual job, giving no real flexibility should you wish to re-arrange the order in which they execute.

The Build Flow Plugin solves this problem. This plugin makes available a special Jenkins job (“Build Flow”) which wires any number of jobs together with a very simple Groovy-based syntax. You can execute jobs in all manner of nested parallel configurations, wrap them in guard/rescue blocks (similar to try/finally) and pass results of jobs as input parameters into others. Furthermore, you can surround your build flow tasks with any amount of Groovy.

All the information you need to get started is available on the Build Flow Plugin page, but I have some further useful examples based on real practical use of the plugin:

Set a time-stamped release version to pass into each job as a Jenkins environment variable called $RELEASE_VERSION:

def buildConstants = [:]
def formattedDate = New Date().format(“yyyyMMdd.HHmmss”, TimeZone.getTimeZone(“Europe/London”))
buildConstants.put(“RELEASE_VERSION”, releaseVersion)

def initialBuild = build(buildConstants, “mvn-deploy”)
parallel (
build(buildConstants, “deploy-to-SIT”)
build(buildConstants, “run-functional-tests”)
build(buildConstants, “deploy-to-UAT”)
build(buildConstants, “run-selenium-tests”)
build(buildConstants, “promote-to-release”)

Leave a Reply

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

You are commenting using your 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

%d bloggers like this: