2

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

  1. Define a multi-branch pipeline build for each project so that each branch does not require its own daily/nightly build job.
  2. 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.

Mike G
  • 1,956
  • 1
  • 30
  • 62

1 Answers1

0

I think you are creating a classical infinite event loop. But the problem is as follows.

I am maybe wrong, but you are using git both as source control and as artifacts repository, i.e. you're adding probably Python packages you've built and pushing it to the same repository.

This means you at least have to push to a special branch you are ignoring will your trigger.

I think the flow though shall be: 1. After the specific build has been tested, you should use tags to mark the commit. 2. Separate job would react on regex matching tags added and build a package. Another step would push the package into a kosher pypi index, if you need to learn how, the internet is full of them

The problem thus is in my humble opinion the way you're using Gerrit + CI,

I initially feared you really need to do those git push operations, but you don't.

So action item on your end is one:

Decide whether you want

  • patchy temp solution (separate branch)

  • real solution: put your packages into pypi compatible server

In either case you'd have several groovy files for that.

mvk_il
  • 940
  • 8
  • 11
  • No python here :) The idea is that I'm trying to build a package similar to a NodeJS module or bower.io package. I'll edit the above question to clarify what I'm trying to achieve. – Mike G Jul 16 '17 at 15:42