Custom GitHub Checks With Jenkins Pipeline
At Natural Intelligence, we are bringing massive complex pipelines into production and want to support multiple teams and their orchestration needs in a manner that is simple and easy to operate.
Using pipelines to run complex workflows is simple and easy to get started with. Our team builds pipelines which get triggered from Github and run on Jenkins. We have hundreds of repositories and sometimes we need to configure dependencies between them inside a single pipeline.
In this post, I will share the approach we have taken to bring complex pipelines in a trustable manner to production and the new groovy pipeline code I have written to make it possible.
The desire is to test the pull request in Github as good enough to merge into master. The default Jenkins behavior is to send the check only at the end of the pipeline. If the pipeline succeeds, the pull request in Github will be marked as mergeable, otherwise — merging will be blocked.
Our main purpose of the updated pipeline is to bring deep code visibility and transparency to the software development process. Each stage in the pipeline is Bulletproofed to determine the stage status and to reflect it on the pull request in Github.
To demonstrate how the whole setup works end to end, I think it is best to walk through the pipeline and dive into the functions.
This is a simple example of how to use the buildGithubCheck in your pipeline:
As shown below, you can see in Github the stage name of each pipeline stage in Jenkins.
Introducing GitHub Webhook
Our deployment is triggered by a GitHub Webhook: Organization Folder which defines the Github hooks and also marks commit status on PR (pull request) using the GitHub check runs API.
The “check runs API” enables you to build GitHub Apps that run powerful checks against code changes in a repository. You can create apps that perform continuous integration, code linting, or code scanning services and provide detailed feedback on commits.
This is how you create a custom check run in your Jenkins Pipeline flow:
- Step 1 — Configure the GitHub APP in order to integrate with Jenkins
- Step 2 — Send the GitHub checks from Jenkins pipeline
Step 1: GitHub APP Configuration
- Create a GitHub App and select the permissions it needs to access such as: checks, contents, etc.
- Generate a private key from Github for the GitHub App and store it as a Jenkins credentials.
- Add a repository access for the Installed GitHub Apps
Once the application is registered, remember to write down your App ID and Installation ID, as they will be needed later.
- App ID can be found here:
- Installation ID can be found here:
Step 2: Send a GitHub check from Jenkins pipeline
Each GitHub check run will be used in the following function:
These are the function parameters:
Repository: The project name.
CommitID: The last commit id that occurred on the PR.
PrivateKey: The stored private key in Jenkins credentials.
Status: Tag the check run as: success, failure, neutral, and etc.
CheckName: The name of the check run.
Function Implementation details
- Sending an HTTP request from Jenkins Pipeline
- Generating a JsonWebToken
- Validating the JsonWebToken
- Getting an access token
- Getting a previous check name run ID
- Creating/Updating a check run
Sending a HTTP request from Jenkins Pipeline
There is a Jenkins plugin which allows sending an HTTP request but we did not want to be dependent on another plugin so that’s why we use pure Java class.
But there is a catch!
HttpsURLConnectionImpl.setRequestMethod() does not support PATCH requestMethod needed to update existing GitHub check. Therefore, we had to write our own function for setting the request method:
In order to authenticate API calls with GitHub App you need to use a jsonWebToken. The following steps describe how it is done.
Generate jsonWebToken signed with the private key:
The function getRSAPrivateKey will use the private key that we created earlier in order to read the RSA private key through groovy code and will create a JSON Web Token (JWT) and encode it using the
The function accessTime returns an object with two fields:
- iat (issued at)— set to current time
- expirationTime — current time + 50 seconds
Validate the jsonWebToken:
GitHub checks that the request is authenticated by verifying the jsonWebToken with the app’s stored public key.
Send the jsonWebToken to the access_tokens API in order to get an access token:
Lists check runs for a commit ref
A previous pipeline execution could have already marked the PR, therefore we need to know if to update it or create a new one.
Let’s check if a check run already exists:
If it exists we will use its ID and set the requestMethod to PATCH, otherwise we will set the requestMethod to POST in order to create a new check run.
Create\Update a check run
Creates\Update a new check run for a specific commit in a repository. Use the requestMethod and the check run ID (if exists) from the previous function:
You can create your own GitHub check runs in Jenkins using pure groovy pipeline code and to confirm unit tests, typos, linting error and whatever your business might require.
The gist of the full code can be found here: buildGithubCheckScript