Tuesday, April 29, 2014

Jenkins – Branches

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.







SQL Injection

We all know how the classic SQL injection works (http://en.wikipedia.org/wiki/SQL_injection). A new novel way to try the technique can be found in the following picture: