At the end of 2019 I discovered Hugo Framework, I started refactoring my personal websites and writing some posts about some solutions I had to implement to accomplish features I was wondering for. You can find more details in post How to add Iubenda prior blocking of cookie scripts to Hugo Disqus shortcode.

My website is deployed on an Italian Hosting server, so every time I decide to make a change or add a post, I needed to manually re-compile website and upload files via FTP.

This was very annoing.

To resolve this issue I decided to implement some continous integration using Github Actions.

My job to deploy Hugo via FTP is compsed by following steps:

This job must be triggered everytime I commit a change to git.

Let’s see how to implement it.

Please note: in following description I’ll assume you know how to use Github, Hugo and FTP hosting.

Step 1: Checkout git project code

First step consists in download project code from github. In my case, I also need to download hugo theme as submodule. Code needed to do this, is following:

1
2
3
    - uses: actions/checkout@v1
      with:
        submodules: true

Step 2: Build static website with Hugo

Second step is about Hugo build. To do this, let’s use a custom action found in Github Actions Marketplace: Hugo setup.

1
2
3
4
5
6
7
    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: '0.62.0'

    - name: Build
      run: hugo -D

Step 3: Deploy static website to FTP

As third step, we simply have to move generated static website to a remote FTP folder. The action I choosed to do this is FTP Deploy.

1
2
3
4
5
6
7
8
9
    - name: Deploy
      uses: SamKirkland/FTP-Deploy-Action@2.0.0
      env:
        FTP_SERVER: ftp.myhosting.com
        FTP_USERNAME: myusername
        FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
        LOCAL_DIR: ./public/
        REMOTE_DIR:  /path/to/site/root/on/my/hosting/
        ARGS: --delete # will delete files on the server if you've deleted them in git

FTP password value must be stored in Github secrets panel for security reasons like in in following image:

Github secrets settings panel

Trigger job

With following rows, we can specify to Github to run action at push event on master branch:

1
2
3
4
5
6
name: Publish

on:
  push:
    branches:
    - master

Put all together

To make it work, let’s put all code together in file .github/workflows/main.yml of your Github project:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
name: Publish

on:
  push:
    branches:
    - master
  schedule:
    - cron:  '0 8 * * *'

jobs:
  Deploy:
    runs-on: ubuntu-latest
    steps:

    - uses: actions/checkout@v1
      with:
        submodules: true

    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: '0.62.0'

    - name: Build
      run: hugo -D

    - name: Deploy
      uses: SamKirkland/FTP-Deploy-Action@2.0.0
      env:
        FTP_SERVER: ftp.myhosing.com
        FTP_USERNAME: myusername
        FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
        LOCAL_DIR: ./public/
        REMOTE_DIR:  /path/to/site/root/on/my/hosting/
        ARGS: --delete # will delete files on the server if you've deleted them in git

BOUNS: automatically publish scheduled posts

A post written in Hugo with date in future is not builded in static version of the website. On the other hand, Github action can be scheduled to run periodically with a cron-like mechanism.

Using this two behaviours, you can commit posts using date field to schedule it.

You simply have to configure job execution like following (line 7-8) and commit posts with datetime in which you want schedule them.

In this way, Github will periodically rebuild you site until posts will appear at defined time.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
name: Publish

on:
  push:
    branches:
    - master
  schedule:
    - cron:  '0 8 * * *'

jobs:
  Deploy:
    runs-on: ubuntu-latest
    steps:

    - uses: actions/checkout@v1
      with:
        submodules: true

    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: '0.62.0'

    - name: Build
      run: hugo -D

    - name: Deploy
      uses: SamKirkland/FTP-Deploy-Action@2.0.0
      env:
        FTP_SERVER: ftp.myhosting.com
        FTP_USERNAME: myusername
        FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
        LOCAL_DIR: ./public/
        REMOTE_DIR:  /path/to/site/root/on/my/hosting/
        ARGS: --delete # will delete files on the server if you've deleted them in git