Automating GIT merges with Powershell and Visual Studio Team Services (VSTS)
Background
The other day I went to open a pull request against a feature branch and I noticed a whole lot of changes I didn’t push myself in the diff. I instantly realised I was working on a newer version of master than what my feature branch was based on.
I had a few options, I could:
- Tell the reviewer of the pull request to only look at the commits authored by me in the past day.
- Checkout the upstream branch, pull master, open a separate pull request and self merge that in.
- Create some automation to sync my feature branch with master.
I decided this was a good chance to brush up my scripting skills and automate something.
Discovery
One thing I’ve learnt about building anything is buy-in is key. Before I went any further I described the problem I was having to a few of my colleagues. Turns out they all faced the same hassle.
One of them noted that merge conflicts are a sticking point and you can’t automate that. I needed a way to report merge conflicts out and automatically merge anything else. For this we decided posting to Slack was appropriate.
Step 1. Writing the script
To get this up and running locally all you’ll need is
- Powershell v3 or later
- Git
- A Target Repository with read/write access
Cloning the repo
This fragment of code checks out a target folder, if the folder hasn’t been cloned already it runs git clone.
You’ll notice I pipe the output of git clone
to write-host
. This little workaround is needed because when Powershell invokes git the output is recorded as stderror
which when using Powershell ISE or VSTS build agents handle as an error.
List, Iterate, Checkout, Pull, Push
This snippet contains the bulk of the heavy lifting.
- Firstly we list all the branches in the target repo using
git for-each-ref
which returns a list of branch names likeorigin/master
- Next we iterate over the branch names, chop of the first 7 characters and compare them to the pattern we expect with PowerShell
-like
git checkout
is run and thengit pull
which ensures the local version is up to date.- Then we pull in master using
git pull origin $defaultBranch
which is where the merge commit will be created if successful. - To see if the pull succeeded we use
git status --porcelain
this command returns the files in the working directory. - If there’s none then we can run
git push
if there are files we not the failure and clean the working directory & reset the head. - The final step in the loop checks out master again and deletes the branch we were working on so if you re-run this you get a fresh copy.
Reporting the changes
To keep the script relatively simple I opted to use a PowerShell Module to call Slack found here.
This block is all about formatting the Slack messages.
- We go grab the commit details from git about the latest commit in master
- Group the result list by value, these are emoji’s for success and failed
- Loop through the list appending the status to the message
- Post the message to Slack.
Here’s an example message from the snippet above.
The final product
All these code snippets combine to make one big script, which will clone the repo, list all the branches, checkout each, pull master, push successful merges (if that’s enabled) and report the results to Slack.
If you’re like me you’d look at this and say we’re pretty much done, and for the most part we are. That being said we still don’t have it running anywhere except locally, which ain’t ideal.
Configuring VSTS
For this step you’re gonna need to be able to create build definitions in VSTS and be able to change user permissions with VSTS source control.
1. Firstly create yourself a build definition in VSTS. Give it a creative name, I called mine ‘The Great Merger’.
2. Configure the ‘Get sources’ step which will clone your chosen repo, I opted to clean the sources and output directory each build, to keep the build server fresh.
3. Now create an Agent phase. Important note, remember to check Allow scripts to access OAuth token
which allows the build agent to communicate with git using it’s built-in Authentication provider.
4. Inside the newly created Agent phase create an inline PowerShell step and paste in the script.
5. Next head to the Variables tab and decide which variables you want to sub-in. Here’s mine:
And that should just about do it. Lastly if you’re using ‘VSTS Git’ you’ll want to check the permissions of the ‘Project Collection Build Service’ user and check it has Contributor permissions.
After fixing that up all that’s left is to run the build and see what happens. Happy merging!