For some time I’ve been wanting to put together some easy to use git auto deployment scripts that I can use with GitHub and BitBucket. Despite hearing anecdotes to the contrary, I kept thinking to myself “It can’t be that hard to auto deploy a git repo from these services”. Now I’ve finally spent some time digging into it and have come to the conclusion that while it is not super simple, it is not impossible either. And now with code in hand, it should be much easier to get going!
Git Post Deploy Hooks
This entire approach makes use of the POST deploy hooks that are offered by GitHub and BitBucket. Both services allow you to POST a payload of information about incoming commits to a specific URL whenever new code is pushed to the repo. The Deploy script makes use of this POST data to see if it’s a recognized repo and branch, and if so, automatically pulls in the new changes for you. Setting up a service hook is slightly different between GitHub and BitBucket, but both services offer decent help articles on the subject.
Getting from POST data to Git Auto Deploy
If you are in a hurry to set up your Auto Deploy, you’ll probably get there faster going straight to the GitHub repo: https://github.com/lkwdwrd/git-deploy
OK, great, so we know we can set up GitHub and BitBucket to ping a URL with some commit payload information, but how do we leverage this into a git auto deploy script? I decided my preferred approach was to create an endpoint to ping for each supported service. Also, because we basically want to auto
git pull changes, most of the code to create an endpoint is exactly the same. In other words, most of it can be shared code. After some thought I decided I wanted a class structure where the main script is in an abstract class that is extended for each service so that new endpoints can easily be created for future services that offer similar POST data service hooks.
After getting the abstract parent class and two child classes set up for both GitHub and BitBucket, I abstracted out the registration array into a config file meant to be user editable. I feel this makes it slightly more user friendly because at the end of the day you can simply put your repo information in the configuration file, set up your POST hooks to ping the correct end point and BAM: Git Auto Deployment!
Well, almost… Let’s get everything set up!
Setup and Configuration
The first step to set up your auto deployment is to clone the deploy repo into wherever you would like the endpoints to be located. On WP Copilot I cloned the repo into
deploy/. This means my deployment endpoints are
https://lkwdwrd.com/deploy/bitbucket.php. These can be located wherever you wish on your site.
Once you’ve got the deploy script cloned into your desired location, you need to set up a repo to auto deploy. As an example I’ve written a WordPress plugin stored on GitHub that makes use of the excellent Prism JS code highlighter. I SSHed into my server and navigated to my
wp-content/plugins folder. Once there I simply ran
git clone https://github.com/lkwdwrd/prism-code-highlighting. I then entered the now present
prism-code-highlighting/ directory and ran
pwd, which gave me the full path to the repo. You’ll want to copy the file path down.
Going back to the
deploy/ directory I updated my
deploy-config.php file to register the Prism repository for auto deployment. I needed the name, the branch I wanted to deploy, and the path (the one I got by running
pwd earlier). Note you can also specify a remote name if it is something other than ‘origin’, and you can specify a ‘post_deploy’ callback function if your code needs to perform additional functions after the code is pulled.
You can register as many repos as you want with the deploy script by adding a new element to the
Once you have the repo information saved in the
deploy-config.php file, set up a POST hook (see links above) to ping the appropriate endpoint. When you commit to the deploy branch you specified, GitHub or BitBucket will ping your endpoint, the script will recognize new code is available, and perform a
git pull automatically for you.
Congratulations! You’re auto deploying your code!
One of the reason I like to have BitBucket available as an endpoint is the fact that they have unlimited private repositories for free. Something GitHub doesn’t have. You can work with private repos just like you do public ones, but you will need to set up an SSH deploy key for each private repo you want to deploy. It’s easy, but it took me a while to wrap my head around how this multiple SSH key thing works.
On your sever you can create an SSH key by running
ssh-keygen -t rsa. With private repos you can only use one key with one repo. BitBucket wont let you use the same key to deploy multiple repos for security reasons. At first I was unhappy about it, but have come to terms with the fact that it is a decent security measure. Setting up multiple keys isn’t too hard, it just takes some understanding.
SSH into your server and then navigate to
~/.ssh/. Once there, run
ls to see if you have a
config file present. If you do not, create one. In that file you will want to use this pattern to give each repo it’s own SSH deploy key:
Host <alias> HostName bitbucket.org IdentityFile ~/.ssh/<filename>
You can put as many of these entries in the
config file as you want. The
<filename> is whatever filename you choose when running
ssh-keygen -t rsa. I usually make it the same as the alias I choose. The
<alias> can be whatever you want. This is an alias for the server you put in the
HostName declaration. When you use the alias in url paths, your server will see it and replace the alias with the specified
HostName and use the SSH key you specified in the
Yeah, confusing. So for example, if I’ve got the following in my
Host wp-copilot-theme HostName bitbucket.org IdentityFile ~/.ssh/wp-copilot-theme
I will generate an ssh key
ssh-keygen -t rsa -f ~/.ssh/wp-copilot-theme. Then I’ll run
cat ~/.ssh/wp-copilot-theme.pub and copy the public key. I’ll enter this public key as the deploy key in my BitBucket repo (instructions). When that is set up I’ll use the
<alias> I defined when I actually run
git clone. GIT will then go to the .ssh config file and see “Oh, Replace this
<alias> with this
HostName, and use the SSH key in
IdentityFile.” Or at least that is how it works in my head..
In our example I would run
git clone git@wp-copilot-theme:wpcopilot/wcp-theme.git when I clone my private repo and it will resolve to
git clone firstname.lastname@example.org:wpcopilot/wcp-theme.git and use the wp-copilot-theme ssh key. This will then be accepted by bitbucket because we’ve given them the .pub version of this key as our deploy key. The rest of the setup works just like it would if it was a public repo.
And you now officially have auto deployment from GitHub or BitBucket, or heck, why not both? You can set up as many deploys as you want. Enjoy, and pull requests welcome!