[HL-28] How to Test Code in Jenkins with GitHub Pull Requests
This all starts with an idea that I’d like to run unit tests whenever a pull request or a commit to a pull request is created.
I thought a bit to directly write a build server which listens for GitHub webhooks. However, I think it’s better to use an existing tool like Jenkins or AWS CodePipeline for visualizing, monitoring and easy-to-maintain.
I had a look at CodePipeline, but it only listens to changes of a branch instead of commits in a pull request like what TravisCI does. I probably can use API Gateway and Lambda to implement, but Jenkins seems to be a more sophisticated tool to learn.
Honestly, my first impression is that Jenkins’s UI is really Java-style (not looking very nice). I will use one of my previous repo in this demo, https://github.com/HengfengLi/pymapplot.
Workflow
The workflow should be as the following diagram:

- Developers create a pull request and push local branch to GitHub.
- GitHub post a request to Jenkins’s webhook endpoint.
- Jenkins pulls latest code from GitHub to local directory.
- Jenkins builds or tests code.
- Jenkins informs GitHub about building/testing results.
Steps
1. Run Jenkins with docker
Run the following command:
docker run -p 8080:8080 -v {YourHostPath}/jenkins_home:/var/jenkins_home jenkins/jenkins
If you want to persist configurations and plugins, you need to map a volume
from host to container /var/jenkins_home.
You will see a password in console and copy it in somewhere for next step.
2. Setup Jenkins
- Go to
http://localhost:8080 - Input the saved password or you can find the password in
/var/jenkins_home/secrets/initialAdminPassword - Choose
Install suggested plugins - Create a new admin
- Go to
Manage Jenkins - Click
Configure Global Security - Choose
Safe HTMLinMarkup Formatterdropdown menu (HTML will be displayed inBuild Historyinstead of plain text).
3. Install plugins
- Visit
Manage Jenkinsand thenManage Plugins - Find
GitHub Pull Request Builderplugin - Install without restart
4. Configure Jenkins
- Visit
Manage Jenkinsand thenConfigure System - Find
GitHub Pull Request Buildersection - Input Jenkins’s url to
Jenkins URL overridefield. I usengrokto expose my local port for testing, so it is a url likehttps://XXXXXXXXX.ngrok.io - Click
Addbutton next toCredentials, then chooseJenkins - In
Kind, chooseSecret text - Input your GitHub access token (with
repoandadmin:repo_hookpermissions) inSecretfield - Type
jenkins-globalinDescriptionfield (this is an option name). - Click
Add - Update
DescriptioninGitHub Pull Request Buildersection - Add GitHub username into
Admin list - Save the changes
5. Configure GitHub webhooks
Add webhool url in GitHub repository
- Go the repository
- Click
Settings, clickWebhooks, addwebhook - Type
https://XXXXXXXXX.ngrok.io/ghprbhook/inPayload URL - Choose
application/x-www-form-urlencodedinContent type - Choose
Let me select individual events - Choose
Pull requests,Pushes,Issue comments - Click
Add webhook
Enable Jenkins GitHub plugin service
- Go the repository
- Click
Settings, clickIntegrations & services - Click
Add service - Choose
Jenkins GitHub plugin - Type
https://XXXXXXXXX.ngrok.io/github-webhook/inJenkins hook url - Click
Add service
6. Create a project
- Go to Jenkins’s homepage
- Click
New Item - Type
pull-request-demoin name - Choose
Freestyle project - Click
OK
7. Configure the project
General
- Tick
GitHub project - Type your project url like
https://github.com/HengfengLi/pymapplotinProject url
Source Code Management
- Click
Git - Type
https://github.com/HengfengLi/pymapplot.gitinRepository URL - Click
Advanced - Type
origininName - Type
+refs/pull/*:refs/remotes/origin/pr/*inRefspec
Build Triggers
- Tick
GitHub Pull Request Builder - Tick
Use github hooks for build triggering
Build
- Click
Add build step - Choose
Execute shell - Type the testing command
python -m unittest discover tests
8. Build now

- Go to the project homepage
- Click
Build Now - You can see a job has been scheduled (see above figure)
- You can also check the following console log:
Started by user hengfeng
Building in workspace /var/jenkins_home/workspace/pull-request-demo
Cloning the remote Git repository
Cloning repository https://github.com/HengfengLi/pymapplot.git
> git init /var/jenkins_home/workspace/pull-request-demo # timeout=10
Fetching upstream changes from https://github.com/HengfengLi/pymapplot.git
> git --version # timeout=10
> git fetch --tags --progress https://github.com/HengfengLi/pymapplot.git +refs/heads/*:refs/remotes/origin/*
> git config remote.origin.url https://github.com/HengfengLi/pymapplot.git # timeout=10
> git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
> git config remote.origin.url https://github.com/HengfengLi/pymapplot.git # timeout=10
Fetching upstream changes from https://github.com/HengfengLi/pymapplot.git
> git fetch --tags --progress https://github.com/HengfengLi/pymapplot.git +refs/pull/*:refs/remotes/origin/pr/*
> git rev-parse refs/remotes/origin/master^{commit} # timeout=10
> git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 117a9d187255c126ad445ea19b21c63eb8a8c676 (refs/remotes/origin/master)
> git config core.sparsecheckout # timeout=10
> git checkout -f 117a9d187255c126ad445ea19b21c63eb8a8c676
Commit message: "Merge pull request #5 from HengfengLi/feature/update-gitignore"
First time build. Skipping changelog.
[pull-request-demo] $ /bin/sh -xe /tmp/jenkins8196395077623670742.sh
+ python -m unittest discover tests
.
----------------------------------------------------------------------
Ran 1 test in 0.017s
OK
Finished: SUCCESS
9. Test pull requests

- Check out a local branch
- Make some changes
- Push to a remote branch
- Make a pull request
- You will see a new job is scheduled
- You can open the pull request page and see the following changes:

Summary
Yes, so many configurations. There are still many plugins and configurations that can be explored. This is just a “hello world” example.
There are some further questions:
- How to ensure the security?
- I’d like to ensure only corporate network can access the admin portal, but I also want to expose the webhook endpoints.
- How to build docker images inside a Jenkins container?
- How to deploy code to AWS ECS or Beanstalk?
It’s really nice to have such a small feature to check every commit of your pull request, adding lint checking and unit tests. This can really improve codebase’s quality and encourage to write more tests.