VSoft Technologies Blogs

rss

VSoft Technologies Blogs - posts about our products and software development.

GitHub makes it relatively simple to contribute to open source projects, just fork the repository, make your changes, submit a pull request. Couldn't be simpler. 

Accepting those Pull requests, is dead simple too, most of the time. But what if you want to build and test the pull request first, before accepting the request. Fortunately the nature of GitHub Pull requests (or more to the point, Git itself) makes this possible. 

Git References
 

Git References are a complex topic all on it's own, but lets take a quick look at a typical cloned repository. In the .git folder, open config file in notepad and take a look at the [remote "origin"] section, here's what mine looks like :

[remote "origin"]
url = https://github.com/VSoftTechnologies/playground.git
fetch = +refs/heads/*:refs/remotes/origin/*

The key entry here is the fetch. Quoting from the git documentation :

"The format of the refspec is an optional +, followed by :, where  is the pattern for references on the remote side and  is where those references will be written locally. The + tells Git to update the reference even if it isn’t a fast-forward."

The default fetch refspec will pull any branches from the original repository to our clone. But where are our pull requests?

Anatomy of a pull request
 

When a pull request is submitted, GitHub  make use of Git References to essentially "attach" your pull request to the original repository. But in my local clone, I won't see them because the default fetch refspec doesn't include them. You can see the pull requests by using the git ls-remote command on the origin :

$ git ls-remote origin
$ git ls-remote origin
27dfaaf83f60ac26a6fe465042f2ddb515667ff1        HEAD
654b98d6eb862e247e5c043460e9f9a64b2f0972        refs/heads/Test
27dfaaf83f60ac26a6fe465042f2ddb515667ff1        refs/heads/master
b333438310a56823f1938071af8c697b202bf855        refs/pull/1/head
95cb80af1330e73188ea32659d7744dcfe37ab43        refs/pull/2/head
90ba13b8edaab04505396dbcb1853f6f9bdaed64        refs/pull/2/merge

 

Notice something odd there. There are two pull requests, but pull request 2 has two entries in the list, whilst pull request 1 has only 1 entry.  refs/pull/2/head is a reference to the head commit of your pull request, whilst refs/pull/2/merge is a reference to the result of the automatic merge that GitHub does. On pull request 1, there was a merge conflict, so the the /merge reference was not created, on pull request 2, the merge succeeded. On the pull request page, you would typically see something like this if the merge succeeded : 

 

Getting Continua CI to see the Pull Requests
 

The main reason for building pull requests on your CI server is to see if they build, and to run your unit tests against that build. You can chose to build the original pull request, or the result of the automatic merge, or both. In reality, if the automatic merge failed, then the person who submitted the pull request has some more work to do, so there's really no point building/testing the original pull request. What you really want to know, is "if I accept this request, will it build and the tests pass", so it's generally best to only build the automatic merge version of the pull request. Continua CI makes this quite simple. On the Git Repository settings, check the "Fetch other Remote Refs" option. This will show the Other Refs text area, which already has a default RefSpec that will fetch the pull requests (the merged versions), and create local (to Continua CI) branches with the name pr/#number - so pull request 1 becomes branch pr/1. 

You can modify this to taste, for example if you are fetching both the merge and the head versions of the  pull requests, you might use a refespec like this :

+refs/pull/*/merge:refs/remotes/origin/pr-merge/*
+refs/pull/*/merge:refs/remotes/origin/pr-head/*

 

Building the pull Requests

 

Now we have gotten this far (which is to say, you enabled one option and clicked on save!) we can build the pull requests (it may take a few minutes to fetch the pull requests). If you manually start a build, you can select the pull request from the branch field for the github repository using the intellsense, just start typing pr/ and you will see a list :

 

Now we can add a trigger to build pull requests (we are talking continuous integration after all). Using the Pattern Matched Branch feature on Continua CI Triggers you can make your trigger start builds when a pull request changeset is fetched from Github. The pattern is a regular expression, so ^pr/.* would match our pull request branches (assuming we use the default refspec)

Adding a trigger specific to the pull requests allows you to set variables differently from other branches, and you will then be able to tailor your stages according to whether you are building a pull request or not. For example, you probably don't want to run your deploy stage when building a pull request).

Updating GitHub Pull Request Status

 

One last thing you might like to add, is to update the Pull Request Status. This can be done using the Update GitHub Status Action in Continua CI (In a future update this will done via build event handlers, a new feature currently in development). This is what the pull request might look like after the status is updated by Continua CI :

 

Showing 1 Comment

Avatar
Vincent Parrett 5 years ago

Someone asked on G+ is this works for Git Repositories on Bitbucket, unfortunately the answer is no. Bitbucket doesn't add the pull request references (refs/pull) so there is no way using git alone to detect a bitbucket pull request. There is a bitbucket feature request still open for this on bitbucket - https://bitbucket.org/site/master/issue/5814/reify-pull-requests-by-making-them-a-ref

Feel free to add your support to the feature request.



Comments are closed.