GitHub has an awesome feature that allows us to build on the potential merge result of a pull request.
This allows us to run unit and UI tests against the result of a merge, so we know with certainty that it works, before we merge the code.
To get this working with TeamCity is a pain in the ass though.
Lets look at a basic workflow with this:
First we will look at two active pull request, and we are about to merge
Pull request 2 advertises the /head (actual branch) and /merge (result “if we merged”)
TeamCity say you should tie your builds to the /merge for CI, this will build the merge result, and I agree.
However lets look at what happens in GitHub when we merge in Feature 1.
The new code goes into master, which will recalculate the merge result on Pull request 2. TeamCity correctly builds the merge reference and validates that the Pull Request will succeed.
However if we look in GitHub we will see the below
It now blocks you and prompts you to updates your branch.
After you click this, the /head and /merge refs will update, as it adds a commit to your branch and recalculates the merge result again, then you need wait for another build to validate the new commit on your branch.
This now triggers a second build.And when it completes you can merge.
The issues here is we are double building. There is two solutions as I see it,
- GitHub should allow you top merge without updating your branch
- TeamCity should allow you to trigger from one ref and build on a different one
I was able to implement the second result using a build configuration that calls the TeamCity API to trigger a build. However my preference would be number 1 as this is more automated.
Inside it looks like this
Below is example powershell that is used in the trigger build, we had an issue with the SSL cert (even though it wasn’t self signed) so had to disable the check for it to work.
add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy $buildBranch ="%teamcity.build.branch%" Write-Host $buildBranch $buildBranch = $buildBranch.Replace("/head","/merge") $postbody = "<build branchName='$buildBranch'> <buildType id='%TargetBuildType%'/> </build>" Write-Host $postbody $user = '%TeamCityUser%' $pass = '%TeamCityPassword%' $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd) Invoke-RestMethod https://teamcity/httpAuth/app/rest/buildQueue -Method POST -Body $postbody -Credential $credential -Headers @{"accept"="application/xml";"Content-Type"="application/xml"}
You will see that we replace the branch name head with merge, so we trigger after someone clicks the update branch button only.
Also don’t forget to add a VCS trigger for file changes “+:.”, so that it will only run builds when there are changes.
We are running with this solution this week and I am going to put a request into GitHub support about option 1.
This is a really big issues for us as we have 30-40 open pull requests on our repo, so double building creates a LOT of traffic.
If anyone has a better solution please leave some comments.