So you want to roll your own custom build of Jenkins

Written by: Stephen Connolly
4 min read

Every so often we have a customer that cannot risk the big jump of moving to a newer Jenkins, but they are currently in need of some specific patch or other.

As a rule, CloudBees do not provide custom builds of Jenkins to customers (Note: we do support customers who wish to run their own custom builds of Jenkins, e.g. see the support terms for such customers)

But suppose you are under the clock… your Jenkins instance is suffering from a critical issue… the issue is fixed in a newer version of Jenkins… but you are on the final sprint before your next release goes GA and there is no time to upgrade Jenkins but the critical issue means that Jenkins is not working for you .

The only answer is to create a custom build of Jenkins with the fix cherry-picked onto the version you were running.

Here is Stephen's cheat-sheet for creating just such a build:


  • You will need a machine to compile Jenkins on. It can be Mac OS-X, Linux or Windows (but build speed on Windows is significantly impaired due to anti-virus software... also GIT on windows is not as nice as on other operating systems)

  • You will need to install a recent Java JDK (6 or 7)

  • You will need to install Apache Maven (3.0.5 or 3.0.4 are recommended at present and certainly for building any Jenkins version prior to 1.520ish as 3.1.0 was only recently released and any plugin compatibility issues with Maven 3.1.0 and the Maven plugins used in Jenkins' pom.xml files may not have been resolved prior to the release of Maven 3.1.0)

  • You will need to install GIT

  • Check that everything needed is on the path

    $ java -version
    $ mvn -version
    $ git --version  

    On my machine I get the following

    $ java -version
    java version "1.7.0_25" Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
    Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
    $ mvn -version
    Apache Maven 3.0.5 (r01de14724cdef164cd33c7c8c2fe155faf9602da; 2013-02-19 13:51:28+0000)
    Maven home: /usr/share/java/maven-3.0.5
    Java version: 1.7.0_25, vendor: Oracle Corporation
    Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre
    Default locale: en_US, platform encoding: UTF-8
    OS name: "mac os x", version: "10.8.4", arch: "x86_64", family: "mac"
    $ git --version
    git version  

Building Jenkins

  1. Checkout Jenkins

    $ git clone  
  2. Switch to the tag you want to base off

    $ cd jenkins $ git checkout jenkins-1.480.3  
  3. Verify that you have Maven and the Java JDK set up correctly (i.e. just do a quick build)

    $ mvn package -DskipTests  
  4. Cherry pick the commits you want

    $ git cherry-pick _________  
  5. Give it a version number to indicate that it is your build

    $ mvn versions:set versions:commit -DnewVersion=1.480.3-yourcompany-01-SNAPSHOT  

    Use a version number that ends in -SNAPSHOT until you are happy that you have the build you will put into production. For builds that you will put into production, remove the-SNAPSHOT . Once you have built a version number without a -SNAPSHOT use a higher version number for all subsequent builds.

  6. Build Jenkins with your commits

    $ mvn clean package -DskipTests  

    Note: Ideally you would not skip the tests, but getting the test suite to work the first time building Jenkins can be tricky

  7. The results of the build are ./war/target/jenkins.war

Extra Brownie Points

If this is something you expect to be doing on a regular basis, you will likely want to do the following

  • Fork the Jenkins repository on GitHub into your own GitHub account

  • Change the origin of your GIT checkout to be your fork

  • Push your patch-set to a named branch, e.g. jenkins-1.480.3-patchset

  • When you want to move the baseline of your patchset to a new version of jenkins, you would then rebase the patchset onto the newer version of Jenkins, e.g.

    $ git checkout jenkins-1.480.3-patchset
    $ git rebase jenkins-1.509.2
    $ git checkout -b jenkins-1.509.2-patchset
    $ git push -u origin jenkins-1.509.2-patchset  
  • If you intend on including fixes that you wrote yourself and which are not cherry-picks from upstream, ensure that your patchset has all the cherry-picks first before the custom patches. That will make rebasing the patchset onto a newer version of Jenkins easiest.

  • Do not add the version number changes (i.e. from the mvn versions:set command) to your patchset , e.g. your release process would probably be something like this

    $ git checkout jenkins-1.480.3-patchset -b jenkins-1.480.3-yourcompany
    $ mvn clean versions:set versions:commit -DnewVersion=1.480.3-yourcompany-01
    $ git commit -a -m "Update version to 1.480.3-yourcompany-01"
    $ git tag jenkins-1.480.3-yourcompany-01
    $ git checkout jenkins-1.480.3-yourcompany-01
    $ git branch -d jenkins-1.480.3-yourcompany
    $ mvn package -DskipTests  

    That will keep the version number changes out of your patch set but also keep a tag of what you built.

    Note: power GIT users will probably cringe at my creation and destruction of the jenkins-1.480.3-yourcompany branch, but they should know the “correct” way to do it and the commands to use also. The above is aimed for novice GIT users and will work for them

In conclusion

I hope you found this useful. And I also hope that if you have to travel this road, you find the cherry-picks easy to merge. Merging cherry-picks from a very new Jenkins (anything within the last month) onto a very old Jenkins (anything more than a year old) can be painful/fun…

—Stephen Connolly

Stephen Connolly has over 20 years experience in software development. He is involved in a number of open source projects, including Jenkins . Stephen was one of the first non-Sun committers to the Jenkins project and developed the weather icons. Stephen lives in Dublin, Ireland - where the weather icons are particularly useful. Follow Stephen on Twitter and on his blog .

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.