Easily deploy your Hugo site to Github Pages

I had been using a DigitalOcean droplet to host this blog and personal projects for years. But… Do I really need to spend the $6/month? It’s just a static Hugo site, which Github pages can do for free. Game hosting on itch.io is also free, it even gives you a mechanism to embed your web games. Looks like I’d be sorted!

Here’s a simple CD workflow for deploying a Huge site to Github pages.

Setup your production Github pages repo

Create a Github repo with the name <username>.github.io. Make sure it has a README.md so that you can start pushing to it. Anything pushed to this repo will be accessible from http://<username>.github.io. This will be your production repository. If you have a PRO Github account, you can make the repo private. This means users will be able to access the github.io site but not the repo sources.


Create your dev repository

Create a new repo to host your dev Hugo site from which we will deploy to the production repo. Name it something like <username>.github.io-dev. That’s where you will write your Hugo pages in Markdown.


Configure the CD pipeline

Whenever we push to our dev repo, we will build the site and deploy it to the production repo. For that, we will leverage Github Actions. For the dev repo to publish to the production repo, we need them to exchange keys.

Generate a public/private key pair.

ssh-keygen -t rsa -b 4096 -C "<email>" -f publish_key -P ""

Now, go to the production repo Settings, Deploy keys and paste the contents of publish_key.pub here.


Go to the dev repo Settings, Secrets and add a new secret called ACTIONS_DEPLOY_KEY with the contents of the publish_key file.


Create a .github/workflows/deploy.yml file in your dev repo with the following contents:

name: Build and deploy

    - master

    runs-on: ubuntu-latest
    - name: Checkout
      uses: actions/checkout@v1
    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
    - name: Build
      run: hugo
    - name: Deploy
      uses: peaceiris/actions-gh-pages@v2
        EXTERNAL_REPOSITORY: <username>/<username>.github.io
        PUBLISH_BRANCH: master
        PUBLISH_DIR: ./public

After you push this file and every time you push to dev, the Build and Deploy action will be triggered. It will checkout the dev repo, install the latest Hugo binary, build your site and deploy to the master branch of your production repo. Once it’s done, the latest version of your site will be available on https://<username>.github.io.


Even though my blog contains hundreds of posts, images and files, Build and Deploy takes less than 1 minute!

Make your domain point to your Github Pages

Obviously, this step only applies if you have your own domain. Go to your provider’s admin panel and change your domain’s DNS records.

  • Enter 4 A records with @ hosts and the Github Pages IPs:
  • Enter a CNAME record with www and value <username>.github.io.

The screenshot below shows the Namecheap DNS config panel for my account.


Finally, go to your dev repo and create a static/CNAME file with your domain name. For example, mine contains:


Once that is done and deployed to production, you should see the following in your production repository Settings, inside the Github Pages section. Tick the “Enforce HTTPS” to redirect all traffic from http://<domain> to https://<domain>.


Note that this may take up to 24h to work as your new DNS settings propagate, so be patient!


It takes some setup but the result is a pretty convenient workflow, definitely an improvement over the git hook based setup I had before.

Let me know if you have any issues with this!

Run automated tests for your Godot game on CI

Automated testing in gamedev

Nowadays, most people agree that automated testing is absolutely crucial for all software development. Not so much when it comes to games development though. I still believe that the games industry would be able to iterate and ship faster by introducing unit and integration testing in the right places.

Godot and Gut

Butch Wesley appears to be onboard, considering he created Gut, an automated testing framework for the Godot Game Engine. Gut provides you with a collection of utilities to write and run tests for your game. Out of the box you get basic assertions, test doubles and even full node tree simulation. Tests are run either from the Godot Editor or the command line using the godot executable itelf.

However, what good are automated tests if we exclusively rely on developers running them locally? The answer is: not very good at all.

Dead simple Godot CI pipeline

That is why I experimented with running GDScript tests on a Continuous Integration pipeline using the headless Godot runtime. I created a repo godot-ci-example you can copy to use on your own projects. Here is how it works.

Firstly, create a Godot project, install Gut from the Asset Library and enable it. This is the same as what is explained in Gut’s Install and Command Line wiki pages.


Create a trivial test in res://test/unit/test_example.gd.

extends "res://addons/gut/test.gd"

func test_assert_true_with_true():
	assert_true(true, "Should pass, true is true")

You can now run these tests from the command line.

godot -d -s --path ./project addons/gut/gut_cmdln.gd -gdir=res://test -ginclude_subdirs -gexit

Where godot is your Godot binary and project is the folder where your game lives.

Alright, we now have a basic test setup we can run locally. Let’s move onto the meaty part of the article, continuous integration. I’ll be using Travis CI because it’s easy and free for open source projects hosted on Github, but knock yourself out with your CI system of choice.

Travis looks for a .travis.yml file in the root of your repo. This file tells Travis how to build the project and run tests. I recommend you take a quick look at the docs.

The .travis.yml file is trivial.

language: minimal
script: ./run_tests.sh

The run_tests.sh script will download the headless Godot runtime and run the command we showed above. Make sure run_tests.sh has executable permissions.


curl ${GODOT_URL} --output ${GODOT_ZIP}
unzip ${GODOT_ZIP}
chmod +x ${GODOT_BIN}
./${GODOT_BIN} -d -s --path ./project addons/gut/gut_cmdln.gd -gdir=res://test -ginclude_subdirs -gexit

As you can see, it’s also pretty easy to parameterize which Godot version you want to use.

And that’s it! You can get a cool “Build passing” badge for your repo. Here’s what a typical build would look like.

Running Script res://test/unit/test_example.gd
* test_assert_true_with_true
Run Summary
***  Totals  ***
  scripts:          1
  tests:            1
  passing asserts:  1
  failing asserts:  0
  pending:          0
+++ 1 passed 0 failed.  Tests finished in:  0.0 +++

Happy testing!

Load test your backend services with locust.io at Pycon ES 2017

PyCon ES 2017 was an absolute blast!

The talks were very interesting and they’re all freely available on their Youtube channel.

Celebrating PyCon ES 2017 in Caceres, located in southern Spain, was a great choice. Beautiful medieval city center where some scenes in Game of Thrones were filmed, plus cheap and delicious food.

The conference itself was hosted at an old monastery, repurposed for these kind of events. I honestly have never been to a conference with such a cool venue!

My colleague Andy and I gave a presentation titled “Load test your backend services with locust.io”, watch it!

Finally, take a look at some of my favorite talks in the conference, (most of them in Spanish):

Come to PyCon ES 2017!


PyCon ES 2017, which will be running from September 22nd to September 24th in Cáceres, Spain. I’ll be attending alongside some Bloomberg colleagues as we are one of the main sponsors of the event. If you have tickets, definitely come say hi!

I’ll be helping out at a couple of presentations:

For those not coming, I’m pretty sure all the talks will be recorded and made publicly available.

JSConf EU 2017 - Recommended talks


JSConf EU is one of the biggest JS conferences in Europe and I was lucky enough to attend its 2017 edition earlier this month. This year the event took place in Arena Berlin, a place by the river, typically dedicated to concerts in the east side of the German capital.

Overall, it was a pretty awesome weekend and although I wish there were more talks on advanced technical topics, I understand the event is more focused on community and diversity. It was flawlessly organised, special kudos for the attention to disabilities, the timeliness, quality of the food and free beer!

Below are my favorite talks.

Some of the others are still yet to be made available on the JSConf Youtube channel.