DevOps

GitHub and Jenkins pull request checking

In my previous post titled GitHub and Jenkins integration I showed one possible way of integrating GitHub with Jenkins and outlined the idea and flow of pull request checking. In this post I will show you how to configure Jenkins job to achieve that and also how to add a bit of fancy to this whole process.

Jenkins job setup

Picking up where I left, let’s create a simple Jenkins job to demonstrate the whole pull request checking idea. Since there are many things that might appear in Jenkins job definition let’s focus on what is required for this integration and leave out the rest. First thing you need to do is provide link to your GitHub repository in GitHub project field. The URL follows established GitHub convention (and will be used in other places throughout this configuration) https://GITHUB_HOST:GITHUB_PORT/ORGANISATION/REPOSITORY. This field is located near top of the job configuration page.

Next focus on Source Code Management section of the configuration. Once you select Git you can start with Credentials selection and Repository URL specification. If you followed my advice from previous post just enter credentials that belong to the user created specifically for purposes of automation. The URL should point to .git project file and its schema is slightly different from the aforementioned project URL, so don’t get them mixed up git@GITHUB_HOST:GITHUB_PORT/ORGANISATION/REPOSITORY.git.

After clicking on Advanced you will be presented with some additional specs to fill out. This is critical part since it determines what gets checked out during job execution. Name of the branch needs to be set to origin and the refspec expression should be entered as follows +refs/pull/*:refs/remotes/origin/pr/*. Last thing to provide is branch specifier and select your preferred Repository browser. Branch specifier has value provided by GitHub accessible via build parameter ${sha1}.

source-code-management-advanced

The last step of this configuration is to customize the behavior of GitHub Pull Request Builder plugin. Head over to Build Triggers section and make sure the only checked option from the list is GitHub Pull Request Builder. Don’t forget to check Use github hooks for build triggering so that the plugin properly picks up events sent from GitHub.

build-triggers-basic

And that’s it for GitHub and Jenkins integration. At this point you are good to go since the default settings work quite well. In case you are running a local instance of GitHub you can consider checking Build every pull request automatically without asking (Dangerous!) in Advanced section. This option can be dangerous for public version since it allows anyone to run their code. In case you use local instance of GitHub it makes the pull request checks happen instantly making the results available as soon as possible without the need for approvals of admins.

How does it look like when it runs?

Well, that is certainly a fair question, especially after all that configuration work. The way this integration is designed is making GitHub the frontend and Jenkins the backend of the whole solution. Which makes sense given their respective roles and capabilities. Having said this lets focus on GitHubs representation of various states of build job and how it looks like.

The UI and UX of this integration is very minimalist in its nature (and to sound more hip I dare to call it skeuomorphic) and fits the whole GitHub UI and workflow quite nicely. Consider following picture taken from pull request listing:

GPRB-plugin-icon

Based on the status of your build job the icon on the right of the pull request changes. Orange/brownish circle appears next to a pull request once the event is registered and sent out. Based on the status of the build failure or success is displayed next to the name moments later. This view is great to see what is going on in Jenkins (without the need to filter out running and scheduled jobs). After clicking on your pull request and scrolling to the bottom of the page you should see something similar to this:

GPRB-plugin-status

This section not only enhances the merge buttons original box by providing the information about the build job result but also links the build job itself.

One thing to keep in mind: Always make sure that you can automatically merge the code you are pushing when you create a pull request. This process is quite simple and can’t possibly guess how would you like to resolve your merge conflicts. Pulling the latest version of the code and manually resolving conflicts in your code allows you to kick back and be sure that the build job will test your code properly. I am not sure what gets actually built in case of conflicts in merged code and I don’t want to know. It makes sense to make this step part of your workflow regardless of this integration so I won’t elaborate on this further.

Build triggers

When it comes to ways how to trigger this quality assurance mechanism, you have three options:

  • Create a new pull request (via GitHub)
  • Push new changes to an existing pull request (via git)
  • Using manual trigger
    • This is a nice feature allowing you to pick custom phrase (with regexp matching capabilities) you can use to comment on the pull request resulting in a scheduled Jenkins build. This option is present in GitHub PullRequest Builder plugin section of Jenkins system configuration.

Further customization

Once we have a simple build job up and running we can start thinking about further customization of this process. Even though you can do quite a lot in this area I would suggest sticking to simple solutions where possible. However this is not always the case so lets introduce some basic customization options we can make use of in case our CI setup requires more complex solution than a simple build job:

  • Build parametrization
  • Conditional build steps
  • Scripting and APIs

Build parametrization

Whenever something interesting happens in GitHub the plugin-based integration we have set up in previous post will let Jenkins know. One can expect that this integration is handled by GitHubs Web Hook mechanism. One of these interesting events I am talking about is definitely pullrequestevent event. However if you take a look at the payload of said event you will have to scroll for a while to see it in all its glory. Fortunately, the GitHub Pull Request Builder plugin filters many of these properties out to make the information provided by web hooks more accessible and easier to navigate.

Given your GitHub instance registered an event (like creation of a pull request) it fires off a web hook. This web hook gets picked up by Jenkins and Jenkins schedules a build job with all the necessary information injected as a build parameters. As you might have noticed I used one of many available build parameters earlier in the configuration. Build parameters are one of the basic properties of Jenkins’s jobs and pipelines. They allow CI engineers to pass information and data from one job to the other or to customize the behavior of a job based on values provided.

If you are wondering what is at your disposal check the following list showing a sample build parameters:

sha1=origin/pr/378/merge
ghprbActualCommit=3357460473a4ea60d338dd5f03d231294ba79f89
ghprbActualCommitAuthor=jakub
ghprbActualCommitAuthorEmail= jakub@email.com
ghprbTriggerAuthor=Jakub Staš
ghprbTriggerAuthorEmail=jakub@email.com
ghprbPullId=378
ghprbTargetBranch=feature/PROJ-123-Do-something
ghprbSourceBranch=task/PROJ-123-Do-a-part-of-it
ghprbPullAuthorEmail=jakub@email.com
ghprbPullDescription=GitHub pull request #378 of commit 3357460473a4ea60d338dd5f03d231294ba79f89 automatically merged.
ghprbPullTitle=Task/proj 123 do a part of it
ghprbPullLink=https://GITHUB_HOST:GITHUB_PORT/api/v3/repos/ORGANISATION/REPOSITORY/pulls/378
GIT_BRANCH=task/PROJ-123-Do-a-part-of-it

Conditional build steps

One of the great uses of build parametrization is making use of conditional build steps. Typical situation being when you want to apply different test suits based on target branch (build parameter ghprbTargetBranch). After playing with this for a while I ended up using following setup based on what branch is target branch of pull request at hand:

  • feature branch
    • run unit tests and code quality analysis
      • This is the case when you are finished with a sub-task of a given feature. The scope is relatively small and easy to unit test. Since you might be working on a feature with some of your teammates it makes sense to run at least unit tests against it to make sure you haven’t broken anything and also check the code quality (since chances are that you won’t bother with this further down the road).
  • develop branch
    • run unit tests, integration tests and user acceptance tests
      • In this case you are done with the whole feature and it is supposed to be production ready. The scope has changed significantly and the full test run is required. Even though there are more types of test I would suggest running at least these three types to gain some degree of confidence. At this point the code doesn’t require quality checking since it has been done on a previous stage for every single task pushed to the feature branch. I feel like the moment when this check is successfully passed is the right time to submit this pull request for a code review to your peers.
  • master branch
    • run all the checks
      • The last step is to cherry pick the features you want to push to master. This is the proverbial last line of defense for the development team. Since checks on develop branch level are concerned only with how given feature fits into the latest version of develop branch there might be a situation when two separate features pass their individual pull request checks and still manage to clash with each other once both present on develop branch. At this point it makes sense to run all the checks once more to ensure that this situation is detected and resolved before releasing the code. Optionally, this step can be mirrored by a nightly job run against develop branch to make the release process more fluent.

Conditional build step functionality is provided by Conditional BuildStep Plugin.

Scripting and APIs

Last customization option that is definitely worth checking out is GitHubs own API and the ability to call it from Jenkins. Based on my own experience comments and labels are great tools provided by GitHub to support and drive the development process. This becomes useful in situation when your build jobs take long to finish or you want to improve your code review process.

In case of build jobs or pipeline running for a longer period of time it is useful to be able to see roughly what is going on. This is where you can utilize simple shell script that can comment on the pull request itself as the execution progresses. This way the users that are interested in given pull request get notified on what is happening and can act upon it. Your commenting script can be as simple as this (in case you decide to use it replace all the capitalized words with appropriate values):

Script arguments:

  1. ghprbPullId – ID of the pull request
  2. comment to be added
#!/bin/bash

payload+="{\"body\":\""
payload+=$2
payload+="\"}"

curl -k -H "Authorization: token OATH_TOKEN" -H "Content-Type: application/json" -d "$payload" https://GITHUB_HOST:GITHUB_PORT/api/v3/repos/ORGANISATION/REPOSITORY/issues/$1/comments

When it comes to code review process my experience shows that it is more efficient to let Jenkins check to code prior to submission for a code review. This allows the reviewers to focus on business logic since syntax, formatting and style were checked by Jenkins earlier. Since this information needs to be accessible from the pull request listing I would highly recommend using GitHubs labels in this scenario since they provide nice way to categorize stuff and are easily recognizable. Script to assign such a label can be as simple as this:

Script arguments:

  1. ghprbPullId – ID of the pull request
  2. label to be added
#!/bin/bash

payload='["'
payload+=$2
payload+='"]'

curl -k -H "Authorization: token OATH_TOKEN" -H "Content-Type: application/json" -d $payload https://GITHUB_HOST:GITHUB_PORT/api/v3/repos/ORGANISATION/REPOSITORY/issues/$1/labels

These scripts are really simple to use and allow you to provide useful information to your GitHub users. You can go even further and make your comment even more fancy. Add some visuals or link your logs and tests reports. Following is simple example of how it can look like given you are willing to play with it a little:

github-comment

Conclusion

All things considered it was quite fun playing with these systems. Both these systems simplify developers life a lot and this small improvement makes things even more comfortable. When it comes to results of this integration they were pretty visible moments after deployment and launch of the final version of this in my place of work. If you have these tools I encourage you to try something like this and see if it suits your team in the same way. All the best! :)

Reference: GitHub and Jenkins pull request checking from our JCG partner Jakub Stas at the Jakub Stas blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button