Deploy harp apps using git hooks

As I run a couple of harp based web sites with a manual rollout process I thought it is time to change this. The rollout process itself is pretty straightforward, but it still requires you to log into the remote server, update the git repo, execute harp compile and copy over the data.

Automation always wins, even if it is simple.

There are several approaches to this problem

  • Have a process on the remote system, that regularly pulls for updates. If an update is found, execute harp and copy over the data. The biggest pro is a decoupled process from the push. The biggest con is, that this is a batch job, so updates are not immediately visible. Also you do not get to know, if the rollout has failed. For this sort of task I do not want to setup an emailing job.
  • Push to two repositories. The regular one, and one that is on the remote server and then executes the deployment steps. Pros: Simple, immediate feedback and immediate rollout. Cons: Does not scale, two pushes at the same time might be a problem, only one person gets to see the error. So the cons make it ideal for small scale project and I really like the immediate feedback.

The nice part about this, is that it only takes three minutes to set up.

Create a bare repository on your webserver

The first step is to create another repository on your destination host. The important part is to initialize this repository as a bare one, meaning it will not contain a working copy, but allows us to push into

mkdir /my/repo.git
cd /my/repo.git
git init --bare

Create a post-update hook

After initializing the repo the next step is to create a hook. Hooks allow you to fire custom scripts. Hooks can happen on the client side or the server side. A common client side hook might be running a linter or ensuring that you cannot push untested code. A common server side hook is an action executed after a push, which will be used as well here. You can read more about git hook here.

You can put the following hook into your freshly created bare repository at /my/repo.git/hooks/post-update.

#!/bin/sh

# Make sure that we abort on error
set -xe

unset GIT_DIR
BAREREPO="/my/mydomain.org.git"
WORKREPO="/home/user/mydomain"
WWWDATA="/var/www/www.mydomain.org"

if [ ! -d $WORKREPO ] ; then
  git clone $BAREREPO $WORKREPO
fi

cd $WORKREPO
git checkout -f master
git pull origin master

npm install
./node_modules/harp/bin/harp compile

cp -rv www/* $WWWDATA

You can see, the script is no magic. You have to to unset the GIT_DIR as this is configured to the current repository. Apart from that configuring the bash to abort on errors is important via set -e. The rest is pretty straightforward. After optionally cloning and then updating the repository, you can simply run the needed commands to create your static page content.

Push two both repositories

The most important step is, that whenever you push, you need to push into both repositories. The one for version control (and possibly shared with other developers) and the one on the web server used for rolling out.

git remote add rollout ssh://user@your-remote-server/my/repo.git

As you can see, there is no need to setup a public git server, when you can use SSH and just have a local, non-hosted repository. Now whenever you want to push, simply execute two pushes to both your remotes, one to update the repo and one to trigger the update on your webserver.

git push origin master
git push rollout master

Other options

One other option, which was already mentioned above, is to constantly pull the content and using a read-only deployment key to pull the data from the official git repo. That would more likely be the way to go with bigger setups, especially with a bigger team doing rollouts.

One last option would be to create the content on your local system, which means in this case doing the static compilation locally and then just push the data to the remote system. One thing to ensure in that setup is an atomic update, so you dont get states where you are updating your live data step by step.

I switched to this for all of my static hosted sites to save some SSH hassle. As usual, ping me on twitter or drop me an email for your thoughts.