Sunday 15 March 2015

Automatically triggering a Jenkins build on Git commit

In this series:

 

Following on from my previous post, Getting started with Jenkins, Git and MSBuild, the next step is to get Jenkins to build whenever I commit changes to a local Git repository.

Option1 – Polling the repository

Now, it is possible to setup a Build Trigger to get Jenkins to poll for changes in a Git repository. You do this using the Poll SCM option on the project configuration page in Jenkins.

jenkins009

By enabling Poll SCM and entering a cron expression * * * * * in the Schedule text box we can get Jenkins to poll the repository for changes every minute. You can enter whatever cron expression you like but this serves as a simple example.

Polling the repository is a bit ugly and inefficient. Wouldn’t it be better to get Git to notify Jenkins of a commit and to trigger a build that way? Well you can do just that using ‘Git hooks’.

Option 2 – Triggering a build using Git hooks

Inside every Git repository there’s a hidden .git folder. Inside the .git folder is a hooks subfolder. This folder can hold scripts that are executed by Git when it performs certain operations. This feature is well documented (see Customizing Git - Git Hooks in the Git documentation).

jenkins010

I’m not going to delve into Git hooks here but will just show the steps I took to get Git to trigger a Jenkins build on a Git commit to a local repository by using the post-commit hook.

However, before we get into the details of the post-commit Git hook we need a few other pieces to be in place.

The Git Plugin notifyCommit endpoint

When you install the Git Plugin for Jenkins you get an HTTP endpoint that can be used to trigger Jenkins to check a Git repository for changes and to schedule a build if it finds any. You can test this by hitting the URL directly. Here’s an example that works on my setup (you would need to change the url to match a repository you have access to):

http://localhost:8080/git/notifyCommit?url=file://c:/Source/Andy.French.Configuration.Service

This feature is described in the ‘Push notification from repository’ section of the Git Plugin documentation. The documentation describes what happens when you hit the endpoint:

“This will scan all the jobs that are configured to check out the specified URL and the optional branches.  If they are also configured with polling, polling will be immediately triggered (and if that finds a change worthy of a build, a build will in turn be triggered). We require the polling configuration on the job so that we only trigger jobs that are supposed to be triggered from changes in the source tree.”

NB: There’s a gotcha here! Make sure you have enabled Poll SCM in your Jenkins build configuration. Don’t specify a schedule, just enable the polling. If you don’t, nothing will happen.

If you see an error like the following check you’ve enabled Poll SCM:

No Git consumers using SCM API plugin for: file:///c:/Source/Andy.French.Configuration.Service

If you hit the notifyCommit endpoint and there are changes in the repository a build will be triggered. If there are no changes nothing will happen but you can still see that the repository was checked in the Git Polling Log.

jenkins011

Curl

When you installed Git you got curl – a utility for automating HTTP jobs - for free. It’s an exe that lives in the Git bin directory. You can use it to submit requests to an HTTP endpoint like the notifyCommit one we have been looking at and we can do this from a script.

The post-commit Git hook

What we need is for Git to use curl to call the notifyCommit endpoint after a commit takes place. We can do that by using the post-commit Git hook. To get this working add a file called post-commit (no file extension) to the .git\hooks folder in your repository and open it in a text editor. Add the following to the file:

#!/bin/sh
curl http://localhost:8080/git/notifyCommit?url=file://c:/Source/Andy.French.Configuration.Service

You will want to change the URL to one that points to the repository you want to build.

NB: There’s another gotcha here! The first line of the script is essential. This is a bash script and it won’t be executed if that line is missing.

Wrap-up

After putting the post-commit Git hook in place I was able to trigger Jenkins builds whenever I committed changes to the repository. Result! The next step is to run unit tests as part of the build.