DEV Community

Cover image for Automate deployment using GitHub hooks
Alexandre Plennevaux for BeCode

Posted on • Edited on

Automate deployment using GitHub hooks

The first time I witnessed the cleverness of the deployment using git strategy was with GitHub Pages: simply git push to the master branch of your repository and your static web page is updated. As simple as that.

I wanted to be able to deploy with the same elegance on my own servers and for more complex applications. I thought I understood how it worked but not how to automate it. So I would manually ssh into the server, cd my way into the project folder, then git pull. Every. time. Not really convenient.

When I discovered Trellis I learned to use ansible to be able to deploy by using a oneliner: ./deploy.sh production domain.com)...

But then Ansible is a power tool, which does a lot of other things than just deploy. And I learned the hard way that I should not update my local Ansible version otherwise... All hell break loose.
Also, I would still have to git push to the remote prior to launching the deployment.

One line to rule them all

Working at BeCode is cool because you get to meet dozen of fellow developers, craving to learn and explore. One of our learners pointed me in the direction of using a GitHub Post-Receive hook, thanks to which deployment is a simple : git push production master. The hook launches a local script that git checkout the master branch on the production server, then runs any other custom operations you want (such as composer update for example).

Let's see how to set it up.

1. Setup a bare Git repository on production server

First, create a "bare" repository – one that does not contain the working copy files. It basically is the content of the .git repository folder in a normal working copy. Name it whatever you like (you could also omit the .git part from project.git but I find it best to keep it):

cd /path/to/project/folder/
mkdir project-name.git
cd project-name.git
git init --bare

2. Configure the GitHub hook

Create a post-receive hook at /path/to/project/folder/project-name.git/hooks/post-receive

touch hooks/post-receive

Fill it with your version of the following code (use your specific folder paths) :

#!/bin/sh
NOW=$(date +'%d-%m-%Y_%T')
# check out master branch
GIT_WORK_TREE=/path/to/destination/folder/htdocs git checkout -f master

# custom steps for deployment
# For example, let's execute composer to refresh our dependencies : 
cd /path/to/destination/folder/htdocs
composer update
# backup current version, in case we need to do a rollback
cp -R /path/to/destination/folder/htdocs/. /backups/project-name/$NOW/

Make sure it is executable:

chmod +x post-receive

3. Add the remote-repository to your local system

Let's now add a reference to this bare repository to our local system, as a remote location. Let's call this remote "production". (It could also be called "staging" or "live" or "test"... should you want to deploy to a different system or to multiple systems.)

cd ~/path/to/working-copy/
$ git remote add production ssh://username@myserver.com:22/path/to/project/folder/project-name.git

Check that your new remote is now available, and all the existing ones:

git remote -v

And... that's it!

You can now deploy using this beautiful one liner :

git push production master

Going beyond ? TDD !!

With this, I have the raw basis of a deployment pipeline. The next step would be to add code testing to make sure code updates do not introduce bugs or break anything (regression testing). I assume I should look at how to use Ansible for that.

Since I don't know how to do that yet, I'll leave you to google dev.to/search your way around that one !

Top comments (1)

Collapse
 
robrecord profile image
Record

That's fantastic - I used to use a post-receive hook to do this. But since starting using Trellis, I feel I'd be missing out on a lot of Ansible goodness by bypassing trellis in this way. Have you found a way to combine the two: git push to trigger an ansible deploy? I feel one would need a separate server for this though.