Up & Running With Hugo, Part 2: Setting up GitHub & Forestry (CI & CD)

Up & Running With Hugo, Part 2: Setting up GitHub & Forestry (CI & CD)

For this week on Frontend Friday, we have a follow up to Up & Running With Hugo, Part 1: Building Your First Site. This week, we cover integrating your repository with GitHub, and setting up continuous integration and continuous deployment with Forestry.io and some other handy tools.

Table of Contents

  1. Introduction
  2. Setting up Git
  3. Setting up Continuous Integration
  4. Setting up Continuous Deployment with Forestry
  5. Next Steps

1) Introduction

Before we continue, you might be asking What is CI & CD..? Let me explain:

Continuous Integration (CI)

Continuous Integration (CI) is a development practice where developers check-in code to a version control tool multiple times per day. Each time code is checked-in, an automated build can be performed, allowing developers to identify problems with code quickly.

Continuous Delivery (CD)

Continuous Deployment (CD) is a development practice where any change to software is automatically deployed to a production or staging environment. This allows for real-world testing and enables more rapid delivery.

More on CI & CD in our Frequently Asked Questions.

Why are these important?

CI & CD allows you to automate the tedious parts of building websites – making sure they are built right, and deploying those changes to production or staging environments for your team to review.

Version control also maintains a complete history of all changes that are checked into version control.

This enables developers to quickly roll back changes that don’t have the outcome that was desired. (I.e, when a hasty change breaks your whole site! :P)

2) Setting up Git

Git is our version control system, which will enable CI & CD through tools like Forestry.

If you’re new to Git and don’t have Git installed, head over to Git download page to download an installer for your OS.

Next, open your terminal once more and ensure your working path is the Boilerplate project (or any project you would like to connect with git). If not, run:

cd /PATH/TO/hugo-boilerplate

Then we’ll create a local repository:

git init

Next, we’ll add all of the files in the project to the local repository:

git add .

To see the status of the repository, run:

git status

Finally, we’ll commit these changes to the local repository’s version history:

git commit -am "Init"

Pushing to the Remote

Up to this point you’ve just been working on your local repository. If anything were to happen to your computer, all would be lost!

That’s why we set up a remote repository on services like GitHub, BitBucket, or GitLab. That way, our changes are stored in the Cloud and can be shared with your entire team.

Head over to your favorite Git provider and create a new repository.

If prompted, ensure you don’t initialize the repository with a README, license, or a .gitignore file. That will just make things more complicated.

If you’re new to Git, we recommend you create a GitHub account and then create a GitHub repository.

Next, grab the Remote URL for your repository, and we’ll add it to your local repository. (Instructions for finding this can be found for GitHub & BitBucket.)

git remote add origin YOUR_REMOTE_URL
git branch --set-upstream-to origin master

Verify the URL is correct:

git remote -v

Finally, push your local repositories history to the remote repository’s master branch:

git push origin master

Congrats! You now have your Hugo site set up with version control so that you can easily set up continuous integration and continuous deployment.

Head over to your repository in GitHub, GitLab, or BitBucket to see the updated code.

3) Setting Up Continuous Integration

Now, we’ll set up continuous integration for your site. This will allow your developers to ensure that the quality of the code is up to par before pushing it to the remote.

We’ll do this using the Node package Husky, which allows you to run tests and other commands based on Git hooks.

In this case, we’re going to use the pre-push hook, to run tests on our CSS and JS, and confirm that our production build checks out before pushing our changes to the remote repository.

To get started, run:

npm install husky --save-dev

Next, we’re going to setup our pre-push test commands. Open up package.json in your favorite text editor, and find the scripts section.

In the Hugo Boilerplate, it will look something like this:

"scripts": {
    "start": "gulp server",
    "preview": "cross-env NODE_ENV=production HUGO_ARGS=preview gulp server",

At the bottom of the scripts, add the following:

"prepush": "npm run eslint && npm run stylelint && npm run build"

The final package.json should look like:

  "scripts": {
    "start": "gulp server",
    "preview": "cross-env NODE_ENV=production HUGO_ARGS=preview gulp server",
    "build": "cross-env NODE_ENV=production gulp build",
    "clean": "gulp clean",
    "hugo": "node_modules/.bin/hugo --source hugo/",
    "eslint": "./node_modules/eslint/bin/eslint.js src/js/ --ext .js",
    "eslint:fix": "./node_modules/eslint/bin/eslint.js src/js/ --ext .js --fix",
    "stylelint": "npm run stylelint:css && npm run stylelint:scss",
    "stylelint:fix": "npm run stylelint:css --fix && npm run stylelint:scss --fix",
    "stylelint:css": "./node_modules/stylelint/bin/stylelint.js src/css/**/*.css",
    "stylelint:scss": "./node_modules/stylelint/bin/stylelint.js src/scss/**/*.scss",
    "prepush": "npm run eslint && npm run stylelint"

Now, lets commit our changes and try pushing them to the remote repository:

git commit -am "Added Husky for Continuous Integration"
git push

You’ll see console output from Husky, running our Eslint and Stylelint tasks.

  6:1  warning  Unexpected console statement  no-console
  7:1  warning  Unexpected console statement  no-console

Our tests had warnings because our Javascript has console.logs in it, but didn’t fail because it didn’t break any of our rules. Pretty handy!

Both Eslint (Javascript) and Stylelint (CSS) can be configured from .eslintrc.yml and .stylelintrc.yml in the root of the boilerplate.

Testing doesn’t end here! The sky is the limit. Write your own tests, or try out other common static hosting test suites like HTML Proofer or Jest.

4) Setting up Continuous Deployment with Forestry

Your final step is to set up continuous deployment with Forestry, so that each time a commit is pushed to your remote repository, your site is automatically rebuilt and deployed to your hosting provider!

If you haven’t already set up your site in Forestry, follow our comprehensive quick start guide for importing and setting up a site with Forestry CMS.

Head over to the Dashboard, and select your site.

Once inside the CMS, select Settings from the sidebar, and then scroll down to Deployment.


In the Deployment section, we’re going to enable to Deploy on Git Push feature, which watches for changes to your repository and automatically publishes your site when one occurs.

Note: the Deploy on Git Push feature only works when Forestry is handling deploying of your site. To learn how to set up deployment with Forestry, see our hosting docs.

Next Steps

Now that you’ve completed the Up & Running With Hugo guide, you’re all set to make your dive into the world of the JAMStack.

We recommend you head over to the Forestry docs to learn how Forestry can help make managing your static site easier.

Up next

This concludes our Hugo + Git + Forestry.io Introduction. Next week DJ is diving deeper into Continuous Integration and Continuous Delivery using CircleCI - a technology we at Forestry.io are using every day.

Join us every Friday 📅

Frontend Friday is a weekly series where we write in-depth posts about modern web development.

Next week: We'll look into Continuous Integration and Continuous Delivery: Automate Your Static Site Deployment with CircleCI

Last week: Up & Running With Hugo Part I: Building Your First Site.

Have something to add?

Discuss on Hacker News