Guide or Assistance On Setting Up CI/CD With GitHub Actions To My Linode

I am looking for either a guide/how-to or some assitance in setting up CI/CD to my Linode with GitHub Actions.

I have a NodeJS project on GitHub that I would like to have updated on my Linode any time I push updates to my main branch without me having to SSH into the machine and manually running a git pull on the production branch. The CI/CD needs to pull down the updated code, update/install any added/updated NodeJS packages, build the production code, and then restart it via PM2.

Thanks for any information that can be provided for me!

2 Replies

Hey Demonicpagan,

That's a solid workload which you've outlined here, and it's really pleasant to be able to automate things to this extent. I don't know anything really about GitHub's Actions product, but I have a hunch that you might be able to get away without building a full CI/CD pipeline. Please read on to find my recommendation of how you might just create a git remote and a webhook. I hope this does the trick for you :]

Here is the outline:

  • initialize a new bare repository on the server
  • create a webhook to checkout, update, build, deploy, and restart
  • add the new remote URL
  1. On the Linode you'll want to create a new bare repository.
$ mkdir node-project.git && cd node-project.git
$ git init --bare
Initialized empty Git repository in /home/Demonicpagan/node-project.git/

You also need to create a GIT_WORK_TREE directory, and a deployment directory. Feel free to modify the content of these examples as needed, of course.

$ mkdir /opt/node-project-work-tree/
$ mkdir /opt/node-project/


2 . Next we are dealing with 43 lines of bash which take care of your 5 tasks. I've modified a file listed in the references to include some bug fixes and comments. You can put this file in /home/Demonicpagan/node-project.git/hooks/post-receive. Touch it and set it as executable with chmod +x.

$ touch hooks/post-receive
$ chmod +x hooks/post-receive

Here are its contents. Be sure to change the values at the top of the file to correspond to your actual stuff.

#!/bin/bash
PROJECT=node-project
TARGET=/opt/node-project-work-tree/
DEPLOY=/opt/node-project/
GIT_DIR=/home/Demonicpagan/node-project.git/
BRANCH="main"

while read -r _ newrev ref
do
    # only pulling the updated code on the main branch
    if [ "$ref" = "refs/heads/$BRANCH" ];
    then
        # get the file list to check for packages
        filelist=$(git diff-tree --no-commit-id --name-only -r "$newrev")

        # check out the files to the working tree
        echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
        git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
        cd $TARGET || exit 1

        # if the package files have been changed
        # then we are reinstalling 
        if [[ $filelist == *"package.json"* || $filelist == *"package-lock.json"* ]]; 
        then
            echo "Changes detected in Package files..."
            echo "Reinstalling dependencies..."
            npm i --only=prod
        fi

        # we are building and deploying in any case
        echo "Building UI..."
        npm run build
        echo "Redeploying UI..."
        rm -rf ${DEPLOY:?}/*
        cp -r $TARGET/build/* $DEPLOY/

        # restart with PM2
        pm2 restart $PROJECT

    else
        echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
    fi
done

3 . Lastly on your home machine you add the remote that you have created on the Linode platform, and push your project.

$ git remote add linode [email protected]:node-project.git/
$ git push linode +main:refs/heads/main

From then on, deployment from your home machine would consist of one command.

$ git push linode

…and that's that! I hope this outline for a git remote serves your needs.


References:

Thank you for this. I'm looking at what you have provided and seeing what I can make of it to use it. There are a few changes I needed to make for the shell script as I use yarn and not npm and building places what things in a dist folder that I will be running the project from.

I have been trying to figure out why my post-recieve hook is not firing. Here is the contents of that file. I don't know where the error is, but it is never entering the while loop.

My repo since I want to not push directly to my Linode and host my repo on GitHub, I did a checkout and the repo lives in /home/demonicpagan/DexcomMongoBackup. I have a webhook written in NodeJS that should run the post-receive hook, but at the moment is a moot point since the hook isn't firing.

#!/bin/bash

# for debugging
set -ex

PROJECT=DexcomBackup
TARGET="/home/demonicpagan/DexcomMongoBackup"
GIT_DIR="/home/demonicpagan/DexcomMongoBackup/.git"
BRANCH="main"

while read -r _ newrev ref
do
    echo "I ENTERED DO WHILE LOOP"
    # only pulling the updated code on the main branch
    if [ "$ref" = "refs/heads/$BRANCH" ]; then
        echo "REF: $ref"
        # get the file list to check for packages
        filelist=$(git diff-tree --no-commit-id --name-only -r "$newrev")

        # check out the files to the working tree
        echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
        git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
        cd $TARGET || exit 1

        # if the package files have been changed
        # then we are reinstalling
        if [[ $filelist == *"package.json"* || $filelist == *"yarn.lock"* ]]; then
            echo "Changes detected in Package files..."
            echo "Reinstalling dependencies..."
            yarn --production=true
        fi

        # we are building and deploying in any case
        echo "Rebuilding Bot..."
        yarn clean
        yarn build
        echo "Redeploying Bot..."

        # restart with PM2
        pm2 restart $PROJECT

    else
        echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
    fi
done

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct