Jenkins – Branches
We have an application that to fully test it with different
phases we would need about 15 jobs (see the following post for simplification
of jobs: http://javaandroidandrest.blogspot.com/2014/03/jenkins-multijob-plugin.html). The problem with this is that once you branch
your trunk version you do not want to duplicate all jobs.
One solution for this problem is to use the “Job Generator
Plugin” (https://wiki.jenkins-ci.org/display/JENKINS/Job+Generator+Plugin).
With this plugin you create a template job, and every time you run it, it will
create a new job for you and based on the template values and insert the
relevant parameters. This is a nice plugin to save the duplicate job and then
update with all parameters, but in the end you have all jobs duplicated, and if
you find a bug in the job, you need to update it for all duplications.
I decided to go in a different direction. I created my base
of jobs that will work with any version of my application (trunk or branches).
The only difference between jobs of different branches is the location in the
SCM and the location on the disk of the build machine (we need to have separate
workspaces for each branch). There are sometimes other parameters like which
version of java to compile with, but as you will see all of this is not an
issue.
The first plugin that we need to add is “EnvInject Plugin” (https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin).
This plugin will allow us to inject values to parameters in the job based on a
properties file.
I create a properties file per version and per OS (I run
some of the jobs on different OS’s for validation).
The value of my property file can be something like (trunk.windows.properties):
#March 26 2014
JAVA_HOME=D:\ins\java\jdk1.7.0_40
PERFORCE_MAP=//depot/Foundation/dev
MY_VERSION=trunk
APP_VERSION=current-SNAPSHOT
BASE_DIR=D:\Perforce_WS\
and for
linux (trunk.linux.properties):
#March 26 2014
JAVA_HOME=/usr/java/jdk1.7.0_40/
PERFORCE_MAP=//depot/Foundation/dev
MY_VERSION=trunk
APP_VERSION=current-SNAPSHOT
BASE_DIR=/fnduser3/fnd/dev/
What is nice
about this plugin is that the property files all need to sit only on the master
machine, and Jenkins will copy the file to each slave and inject the properties
at the beginning of the job. So in the end I have two files per branch (one for
each OS) and in the file I put the different values of the parameters. You need
to remember to parameterize the workspace per version, so that you can run the
same job in parallel for different versions, and for easy debugging of the
workspace.
So now all
my jobs are version agnostic. What I need is to pass into the job is the
version that I need (I have a job per OS since there might be different
settings in the job per OS [the parameter file is per version]). To pass the
parameter I add a parameter to the build (https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Build), my default is trunk since this is
the most used value.
The only
part of the job that cannot be parameterized is the SCM since we need to poll
the SCM for changes. So what we need to do is create a watcher job per branch.
If you have different builds based on SCM path then you will need a watcher per
path.
Each watcher
will poll the SCM and when it detects a change it will then trigger the generic
job, and pass into the job the parameter for the version of the build. The
generic job will then inject all parameters based on the property file and run
the job.
To summarize:
we have a watcher job per version (polls SCM), which then triggers the version
agnostic jobs and injects the current version running. The job then injects all
parameters relevant to the version from the properties file.
But now we
have the issue of debugging. All works fine and the one of the version agnostic
jobs fails. Yes I can have a look in the log and find the version according to
the injected properties file:
But this is
not nice. So we will need another plugin – “Build Name Setter” (https://wiki.jenkins-ci.org/display/JENKINS/Build+Name+Setter+Plugin).
This plugin will allow us to change the name of the run once it starts running.
So we can configure all the version agnostics jobs:
What this will
do is to rename the current job and add the version to the name of the job.
This way in the history of each version agnostic job you can easily see which
versions have run and passed and which have failed:
Once all
jobs are running fine we sometimes want to have the compiled artifacts in a
link of the job. This works fine in our case, but it is not very nice, since
you need to go to the history of the version agnostic job to find the right
version and then get the artifact. To overcome this issue we will use the “Copy
Artifact Plugin” (https://wiki.jenkins-ci.org/display/JENKINS/Copy+Artifact+Plugin).
This will allow us to copy artifacts from one job to another. So on your
watcher jobs, you can copy all artifacts from the other jobs, put them all in an
archive folder and then share them in the watcher job.