Gatsby Build Automation

December 1, 2018

What I wanted to simplify for myself is the following process:

  • write a blog post on Sublime Text on my laptop
  • push it to the repository's master branch
  • push it to the production server
  • Gatsby builds all the static files and deploys it

Thanks to DigitalOcean's guide on automating with Git hooks, I was able to set everything up the way I want it.

Several locations need to be established.

  • My local machine:

    • /home/localuser/git/blog/
  • My remote production server:

    • /home/remoteuser/blog
    • /var/www/blog/prod

Nginx setup

On my remote machine, Nginx is installed and is statically serving my blog domain, blog.jyntran.ca.

If it's not already, you may need to go through the installation process:

sudo apt-get update
sudo apt-get install nginx

Inside a new file called /etc/nginx/sites-available/blog:

server {
        listen 80;
        listen [::]:80;

        server_name blog.jyntran.ca;
        root /var/www/blog/prod/public;
        index index.html;
        ...

Notice how the root is going to the subdirectory public? It's the place where the static files, including index.html will reside after a build.

Now make a symlink to sites-enabled, check that your Nginx configurations are ok, then restart Nginx. Note: you may need sudo for these commands.

ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/blog
nginx -t
service nginx reload

Production directory

I set up a space for the production blog at /var/www/blog.

Inside it I set up a directory where the push happens.

cd /var/www/blog
mkdir prod
cd prod

Make sure the user has proper privileges to write to the folder:

sudo chown -R `whoami`:`id -gn` /var/www/blog/prod

Git hook

Now go to the home directory, and create a directory for the blog's Git hooks will be.

cd ~/blog
git init --bare

With the --bare argument, this creates a Git instance with no working directory. Since my working directory is on my local machine, this is fine with me.

Now, for the creation of the hook itself:

vim hooks/post-receive

And the contents, mostly ripped from the guide above:

#!/bin/bash

while read oldrev newrev ref
  do
    # ref = refs/head/master
    if [[ $ref =~ .*/master$ ]]; then
      echo "Master ref received. Deploying master branch to production..."
      git --work-tree=/var/www/blog/prod --git-dir=/home/remoteuser/blog checkout -f
      cd /var/www/blog/prod
      yarn install && gatsby build
    elseh
      echo "Ref $ref successfully received. Doing nothing: only the master branch may be deployed on this server."
    fi
  done

What's happening here? Read in the received data: if the ref is referring to the master branch, checkout the repo in the production folder, and once in there, use Yarn to install any packages that's changed, and use Gatsby to build.

Local setup

Now to set up the client side, that is, my local machine.

I have my remote origin set up to my GitHub repository. We need to do the same for the production repository.

Let's go to the working directory:

cd /home/localuser/git/blog

Before running these commands, make sure you replace some of these values: remoteuser and server_domain_or_IP, and blog if your home subfolder is named something else.

For pushing to both GitHub and to production:

git remote set-url --add --push origin git@github.com:jyntran/gatsby-blog.git
git remote set-url --add --push origin remoteuser@server_domain_or_IP:blog

Check them with the flag verbose:

git remote -v

And the result:

origin  git@github.com:jyntran/gatsby-blog.git (fetch)
origin  git@github.com:jyntran/gatsby-blog.git (push)
origin  remoteuser@server_domain_or_IP:blog (push)

The final product

Now to test the push!

git push origin master

You might be prompted for the password of your production server if SSH keys are not set up. If you read the message that returns, you will now see the client message from the post-receive hook, as well as output from yarn install and gatsby build:

Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 3.01 KiB | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To git@github.com:jyntran/gatsby-blog.git
 + a0c5a49...08aa6cb master -> master
remoteuser@server's password: 
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 3.01 KiB | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Master ref received. Deploying master branch to production...
remote: yarn install v1.12.3
remote: success Already up-to-date.
remote: Done in 1.59s.
remote: Running gatsby build...
remote: success open and validate gatsby-configs — 0.013 s
remote: success load plugins — 0.377 s
remote: success onPreInit — 0.375 s
remote: success delete html and css files from previous builds — 0.076 s
remote: success initialize cache — 0.010 s
remote: success copy gatsby files — 0.085 s
remote: success onPreBootstrap — 0.021 s
remote: success source and transform nodes — 0.218 s
remote: success building schema — 0.656 s
remote: success createPages — 0.113 s
remote: success createPagesStatefully — 0.046 s
remote: success onPreExtractQueries — 0.000 s
remote: success update schema — 0.243 s
remote: success extract queries from components — 0.093 s
remote: success run graphql queries — 0.194 s — 6/6 31.22 queries/second
remote: success write out page data — 0.006 s
remote: success write out redirect data — 0.001 s
remote: success onPostBootstrap — 0.001 s
remote: 
remote: info bootstrap finished - 5.049 s
remote: 
remote: success Building production JavaScript and CSS bundles — 13.028 s
remote: success Building static HTML for pages — 2.542 s — 32/32 49.69 pages/second
remote: info Done building in 20.632 sec
To remoteuser@server:blog
 + a0c5a49...08aa6cb master -> master

Now that Gatsby has finished the build, the /var/www/blog/prod/public directory is populated with the static files for Nginx to find.

Finally, it's all set - an automated Gatsby build process for the production server. Hurray!