Automate deployment with Github Web Hooks

Automate deployment with Github Web Hooks

I was working on my portfolio website recently and I had to make a lot of DevOps stuff on my **Digital Ocean** machine. I played around with reverse proxies with **nginx** to run my node application. While doing so, I had to search around for nginx configurations and I came across someone talking about these things called Github Web hooks. It sounded fancy so I went to the official Github Web hooks page to have a look. At first, it confused me. I had heard about Web hooks but I couldn’t come up with a reason as to why someone would use this. As I read on, I gradually realised that I can use it in my portfolio website to automate my deployment. How is that even possible? What does automate deployment with Web Hooks even mean? Is it a new Javascript framework?

Automate Deployment

Simply put, when you make a commit to the master branch of your repo, your website server pulls the master branch automatically, shuts down the server and restarts it with your new commit. This means that after making a commit to the master branch, you don’t have to manually SSH into your server and run shell commands. This is an over simplified version of Automation. All companies use it in their production builds to run tests, versions, A/B testing before their deployment. Basically everything is automated these days. If you are looking to get started doing this in your own project, read on.

Web Hooks

When you push a commit from your local machine to an online repository ( Github, BitBucket etc ), you are essentially sending your files to a Github Managed Server. Folks over at Github can offer you a pipe/peak into their server when you make a push. So you can think of Bob at the Github office whose only job in life is to be alerted when a push is made in your repository. Github lets you talk to Bob and make a deal with him that whenever a push is made, he will send a request to your endpoint with the data of the push. So all you need to do now is to create a simple endpoint that accepts a post request. You can then give that endpoint to Bob. *Thats all what a web hook is. Its *Bob.

Create your endpoint

var express = require("express");
var app = express();
app.post("/webhooks/github", function (req, res) {

})

If you are familiar with Node and Express, this will be very simple to you. Just create an endpoint in whatever language you use and you will be fine.

Tell Bob about it

  1. Go to the settings of your repo

Repository SettingsRepository Settings

  1. Click on the Webhooks tab

Webhooks TabWebhooks Tab

And then add a webhook.

You will be asked the following:

  1. Payload URL

  2. Content Type

  3. Which events would you like to trigger this webhook?

For the Payload URL, just add the url of your website followed by your endpoint. So in my case, I used subhannaeem.com/webhooks/github as my payload URL.

localhost will not work here. Github needs a unique URL.

For the Content Type, select what works for you. I use Node so I chose JSON.

For the last question, I choose the option : **Just the push event. **I don’t want to be notified if someone makes a pull request or some other action on my repo. I just want know if a push is made to the master branch of my repo. We will get to that in a moment.

Press save and you are good to go!

Setup a Deploy Script

Now that we have our Endpoint and WebHook set up, we need to do something with the data Github sends us. Let’s recap for a second here. We make a push to our repo. Bob at Github receives our push and sends a request to our endpoint. We then check if the request contains the correct data. If it does, then we restart the server and tell bob everything is fine by sending him a 200 response. If the data is not valid we send him a 500 response.

How do you restart the server? Lets create a deployment script. It will live somewhere on our server. It will be responsible for pulling our branch and restarting our web application. We will execute this script from our web application code.

cd portfolio-website

echo "Pulling from Master" 

git pull origin master

echo "Pulled successfully from master"

echo "Restarting server..."

pm2 start bin/www

echo "Server restarted Successfully"

I put this deploy script in my /home directory. I make sure that it has the sufficient permissions to execute. If you receive an error when executing this file, use chmod to give it permissions. My web application lives in the /home/portfolio-website directory.

This script is just a set of shell commands and should be very familiar to you. We go into the */home/portfolio-website *directory. We pull from the master branch. And then we use the **pm2** module to run a daemon process in the background to run our node server. If you use node then you must be familiar with **pm2**. If not, then just use the command that you use to spin up your server.

Now we need to call this script from our web application code. In NodeJs there is something called a** Child Process**. Your Node code can spin up a virtual terminal window and then run commands in it. Ofcourse this a simplified way to think about it. Actually there are a lot of features that the Child process offers. If you wanna know more about Child process then read this article. If you just want to run some commands for now, then read on.

var express = require("express");
var app = express();
var childProcess = require('child_process');
var githubUsername = 'Donald'


app.post("/webhooks/github", function (req, res) {
    var sender = req.body.sender;
    var branch = req.body.ref;

    if(branch.indexOf('master') > -1 && sender.login === githubUsername){
        deploy(res);
    }
})

function deploy(res){
    childProcess.exec('cd /home && ./deploy.sh', function(err, stdout, stderr){
        if (err) {
         console.error(err);
         return res.send(500);
        }
        res.send(200);
      });
}

So here we first check the sender and the branch. If the sender of the push is indeed *Donald *( use your Github username here ), and if the branch is Master, then run the deploy() funciton. The deploy() function spins up a child process and executes a command. This command goes to the /home directory and executes the deploy script. Upon execution, if I receive some sort of an error, I send a 500. Otherwise I send a 200.

Now whenever you make a commit to the master branch of your repo, You will run your deploy script which in turn will pull the master branch on your server and restart the web application. So from now on, if you want to make a change on your website, all you have to do is to push to the master branch.

That’s it. Pretty cool huh? You can extend this to your needs easily. No more SSH and no more mistakes while executing shell commands. Cheers!

2019-05-07