DEV Community

Youssef El Idrissi for #./TECHLAB.MA

Posted on

GitHub Webhook CI/CD: Step-by-step guide

(This Blog post is part of a collaborative work between Me and Mustapha El Idrissi, Consult his devTo page for more information: https://dev.to/appsbymuss)

What is CI/CD

CI/CD, or Continuous Integration and Continuous Delivery/Deployment, is a set of practices and tools that automates the process of software development, testing, and release. It helps developers deliver code changes more frequently, safely, and reliably.

  • Continuous Integration: This is a development practice where developers frequently integrate their code changes into a shared repository.

  • Continuous Delivery: This goes one step further by automating the entire release process. Once code passes all testing stages, it is automatically deployed to the production environment.

There are lot of tools that are used to perform CI and CD such as and not limited to:

  • Jenkins
  • GitHub Actions
  • GitLab CI/CD
  • Travis CI

However these tools are usually followed by resource use restrictions or require monetary contributions to be used efficiently and at the same time beginners struggle to use such tools at the start of their Software Development career.

  • There is however an easier-to-bootstrap and harder-to-efficiently-setup way to achieve CI/CD which is "GitHub Webhooks"

How to setup GitHub Webhook ?

Step 0: Create a repo

  • Ofcourse when we have a new project we have to create a new repository for it to store our code changes (aka commits), but in this case it will also be useful to achieve our CI/CD goal.

Step 1: Create a route for the POST-webhook

  • Assuming that you already have a server with your desired runtime environment/Framework up and running on a specific port.
  • You're gonna have to also make a webhook in order to let Github have a way to reach your server in the case of new change to the main/production branch on your github repo like so:
require('dotenv').config();
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const { exec } = require('child_process');
const app = express();

const updatedAt = new Date();

function verifySignature(req, res, buf, encoding) {
    const signature = req.headers['x-hub-signature-256']; // GitHub sends the signature here

    if (!signature) {
        console.log('No signature found on request');
        return false;
    }

    const hmac = crypto.createHmac('sha256', process.env.REPO_WEBHOOK_SECRET);
    const digest = 'sha256=' + hmac.update(buf).digest('hex');

    if (signature !== digest) {
        console.log('Signature does not match');
        return false;
    }

    console.log('Signature is valid');
    return true;
}

app.use(bodyParser.json());

app.post('/cicd/github-cicd', (req, res) => {
    const buf = JSON.stringify(req.body); // The raw body of the request
    // const isValid = verifySignature(req, res, buf);

    /* if (!isValid) {
            return res.status(401).send('Invalid signature');
    }*/

    const { ref } = req.body;
    if (ref === 'refs/heads/main') {
        // PM2 is my instance manager
        exec('git pull origin main && pm2 restart cicd_app');
    }
    res.sendStatus(200);
});

app.get('/cicd/time', (req, res) => {
    res.send(`<h1>${updatedAt}</h1>`);
});

app.listen(80, () => {
    console.log("Listening on Port 80...");
});
Enter fullscreen mode Exit fullscreen mode

(Full source code)

Step 2: Configure the repo's settings

  • Go to [YourRepo -> Settings -> Webhooks]
    Image description

  • Then
    Image description

  • Then we get to the webhook creation panel

  • [warn] Depending on the SSL state of your website (if it's activated or not), choose the "SSL Verification" option accordingly.

  • [warn] Incase you want Github to include a "secret" token to authenticate itself to your server to ensure it's Github and not a threat actor, then put a secret word, otherwise leave empty. 

Image description

Step 3: Ready !

  • After Setting up your webhook on your webserver and github webhook of your repo, then you're basically good to go.

Macro

Image description

  • First a developer will push their commit (code changes) to GitHub.
  • Secondly GitHub will send a POST Request to our server, and specifically to our webhook route with the body in JSON with information related to that github push that we've done just a moment ago.
  • Thirdly The server will then ofcourse treat said request as a way to know that there are changes on the production branch that must be applied as soon as possible, therefor a git pull will be attempted and then tests and new builds and whatnot are going to be executed.
  • Finally The server will consequently restart with the updated source code.

Top comments (14)

Collapse
 
ttsoares profile image
Thomas TS • Edited

Why this is better (or not) that configure Vercel (or any other) to keep an eye on a repo and if a push did happens Vercel (or any other) take the new code and restart the application with the new version ?

Collapse
 
0xw3ston profile image
Youssef El Idrissi • Edited

Funny thing is that this method is already inspired by How Vercel, Heroku and Cyclic handle this sort of stuff, so it's neither better nor worse, it's actually the same exact method.

I personally still to this day prefer to work with IaaS instead of PaaS in order to learn more stuff especially things that are DevOps or System design focused, and as you know, IaaS does not offer this sort of stuff by default unless you implement it yourself (like the code/guide shown above).

Furthermore this blog just demonstrates how you could achieve the same exact thing Vercel offers but on your own machines/servers.

And as a bonus there could be some other custom logic that you could add to this (or these) webhook handler (unlike PaaS like Vercel where you don't really get much control about what happens when the "new commit" repo webhook gets triggered)

I hope I didn't complicate the explications too much and if you have any more questions let me know :)

Collapse
 
ttsoares profile image
Thomas TS

Agreed.
My personal issue is that I dislike Micro$oft very much since Windows 3.11...
Have been using GNU/Linux since 1992.

Thread Thread
 
0xw3ston profile image
Youssef El Idrissi

It's quite an honor to be speaking to someone that had at the very least ten times the amount of experience I have, and yes I do agree that Linux is much much better if you're in the IT field, it could only pose some limitations if you're mostly a consumer, like the case in video games etc.

I almost always get a head migraine before I setup a server/service on Windows, whereas in Linux things are a lot more straightforward

Not to mention the fact that Open Source projects are far more admired than Closed source ones.

Nowadays Windows is just a collection of bloatware.

Thread Thread
 
ttsoares profile image
Thomas TS

You are welcomed :-)
I'm now far away from the gaming context. Even though have a simple desktop with Win 10 just to run Unreal Tournament III, kind of old school first person shooting.
Nowadays, one can see lots of YouTube videos with some savvy person teaching some IT subject and, most often than not, they use a Apple Mac hardware. As with Micro$oft, IOs is a cesspool of spyware and all sorts of 'big data' gathering.... Second only to my family, I love liberty and privacy. So, Free Software is the best way - not ideal though as there are tales of "infiltration" - like the systemd one.
Recently I migrate to the MX Linux distro that uses sysV init instead systemd...

Collapse
 
manchicken profile image
Mike Stemle

This is a very good post.

Collapse
 
0xw3ston profile image
Youssef El Idrissi

Thank you :)

Collapse
 
doertemithut profile image
DoerteMitHut

Amazing! I spent Sunday doing a very similar thing wondering what would be the advantages and drawbacks of the various ways to tackle this. Great to see there's others who are interested in this.

Collapse
 
0xw3ston profile image
Youssef El Idrissi

Thank you, to be frank I took inspiration from Heroku and Cyclic, they're PaaS services that offer hosting. What made me take interest in this specific method is its simplicity and also the fact that it eats very little resources, so no additional strain is put on the server.

Collapse
 
razielrodrigues profile image
Raziel Rodrigues

I will take a look!

Collapse
 
okayiy profile image
Okon Inyang

Thank you, Youssef.

Collapse
 
0xw3ston profile image
Youssef El Idrissi

You're welcome :)

Collapse
 
mkarthiatgithub profile image
Karthi Mahadevan

nice, we use gitlab and similar way , we use gitlab webhooks and audit events.
Do you have any other scenarios where this will be useful ?
we monitor all user actions with these events.

Collapse
 
ettourach profile image
Ettourach

great presentation!! SO what is the main raison to do this steps