A bit of background...
We've been using Gerrit + Jenkins for over a year with great success. Adding in code-review and build verification has made our developers much more accountable for what they submit into source. I setup the integration between the two for my team as our project was starting out.
Now, I want to be able to do multi-branch builds for a library that utilizes Gerrit for code-reviews. Once a CR passes with a verified build and the change makes it to source I would like a distribution build to occur (the Gerrit trigger can listen to this event).
Simple Example
I wrote a detailed and specific example of what I'm trying to do in the next section
For ease of communicating what I'm attempting to do I'll refer to Project A and Library B. Both are in Gerrit for CR and build verification. This gives 2 Gerrit triggered builds plus nightly builds for each branch that we're distributing.
Library B is consumed by Project A (through bower). When a user submits a change to the library project the Gerrit trigger picks this up and Jenkins builds the change. Once the change has been reviewed and submitted the dist build is manually kicked off. This build then updates the dist within the package. This will get picked up on the next build of Project A (or when a user manually updates bower).
A more detailed example
We've created a library which is a consumable set of common styles and JavaScript which can be used across our organization's different web application projects. We attempted to best create the library as many of the bower.io packages with which most people are familiar (ours mimics Bootstrap). The library's git branch layout is designed to mimic gitflow; the develop branch is always the next release, etc.
The library has a src/
folder which contains all the base code, etc. The bower.json
file points to a dist/
folder which contains the compiled, minified, etc. files. It is through this setup that we consume the package in our web applications.
Using Gerrit we review all the submissions from our teams that come in for this project. This is fairly easy. The Jenkins with Gerrit-Trigger gets notified of the new change and builds the patch set. We tell developers to not submit changes in the dist/
folder as it makes a merge nightmare, but files are there so that each consumer of the library does not have to make the compiled output.
At this point hopefully there is a good high-level view of what we're doing. It may be easier now to explain the issue.
When we're doing day-to-day builds for our QA team of our main web application we do bower install
. In our bower.json file we're pointing to the #develop
ref. This means that the web application will use whatever is the latest in the library's dist/
folder. If a commit to the library updating the dist/
folder hasn't been done before the daily QA build for the web application then the library would effectively not be updated in that build.
This makes QA sad. They send the developer an email that closed tickets are not, in fact, ready for testing. This makes me upset because I in turn get an email from the developer asking WTF.
What I Would Like to Have Happen
- Define a multi-branch pipeline build for each project so that each branch does not require its own daily/nightly build job.
- For the library job, in addition to the pipeline being used for nightly builds, it also is kicked off whenever a patchset is submitted to source.
Specifically regarding point 2 and the above detailed example: My desire is to have the dist/
folder updated automatically in a controlled fashion without developer interaction and whenever a lead has submitted an approved patchset to source.
For point 1 and in regards to this question, I am not seeking help with building the pipeline build for project A.
Issue
I created a multi-branch pipeline for the library project. Within it I want to pull the source:
try {
stage('Checkout') {
// Grab the source to build
checkout scm
}
}
catch (err) {
currentBuild.result = "FAILURE"
emailext body: "The Library build has failed. The source for the build was unable to be pulled from Gerrit. Please view the build information here: ${env.BUILD_URL}",
from: 'Jenkins CI Server <jenkins-no-reply@example.com>',
subject: 'Git Pull Issue With foundation-controls',
to: 'Mike@example.com'
throw err;
}
This works! However, it just pulls the latest for the branch. It doesn't define when the build happens. I turned on SCM polling.
After the build completes I have a step that does this:
stage('Publish') {
if (env.BRANCH_NAME == "master" || env.BRANCH_NAME == "develop" || env.BRANCH_NAME.startsWith("release/") || env.BRANCH_NAME.startsWith('hotfix/')) {
sh 'git add dist'
def gitDiffStatusCode = sh script: 'git diff --cached --exit-code', returnStatus: true
if (gitDiffStatusCode != 0) {
sh 'git commit -m "chore(release): Internal release"'
sshagent(['xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx']) {
sh "git push --force-with-lease origin HEAD:${env.BRANCH_NAME}"
}
} else {
echo 'Nothing to commit';
sendEmail = false
}
}
else if (env.BRANCH_NAME.startsWith('feature/')) {
echo "On A feature branch. Not publishing!"
sendEmail = false
}
else {
echo "Skipping publish - This build is not ocurring on a publish-able branch!"
sendEmail = false
}
}
The problem here is that the push causes the polling to trigger and it gets into an infinite loop.
What I would like to do is use the ability of the Gerrit-Trigger to fire off a build whenever a change/patch is merged (submit has taken place). Instead of a freeform job I want it to be a pipeline build so that it utilizes a Jenkins file.
How can I get this to work so that the Gerrit trigger tells when to do the build?
Other Workaround Attempts
I did come up with a way to skip the build. It involves looking at the last commit message when the build runs. I can then skip all the other steps in the pipeline. This just means that there will always be two builds, one with all the pipeline steps and then one with only the "Checkout" stage. Not ideal.