Hugo - GitHub Action Improvements

very much a lessons learned post and some automation! šŸ¤¦ā€ā™‚ļø

The Lesson!

Never, assume a demo, no matter how simple it is. Will always work!

September, Come Cloud With Us - The pre story to this post.

So in September, I had the opportunity to present my “Getting Started with Blogging” Talk at the Come Cloud with Us User Group. THe summary of the talk is a whistle stop tour of a slide deck, explaining why you should get into blogging and then a live demo of deploy Hugo to an Azure Static Web App. Nice and easy. nothing super crazy demo wise… So I thought (The BIGGEST Mistake Ever!). The its demo is pretty easy, install hugo, make a GitHub Repository, Static Web App and push šŸ„³.

But no. this was not the case, As you can see in the video below. The GitHub action would not build. It failed every time and I even tried two different themes, that Ive had working in the past. Still nothing. - So I changed the end of the talk as you can see in the video, showing my Actual blog and a working action to show “What should happen”.

Post user group talk, I’ve spent some time trying to find the cause of said issue, Apart from the fact that I didn’t check the demo before hand.

Skip to 33:45 to see the Action error.

The issues during session

The post mortem begins, When you create a Static Web App and connect to a GitHub Repository, you get a GitHub Action to compile the Hugo site and upload. On investigation currently (October 2024) the GitHub action uses this action: Azure/static-web-apps-deploy@v1. During the deployment process, I noticed that the Oryx builder used a very specific version of Hugo 0.112.5-48e33e10af2feb2a0e1c32d04880ed016619f2d8+extended and here is the problem.

Since the release of 0.128.0 Hugo has made a configuration change from using IsSite.Server to Hugo.IsServer. When looking a the theme I used during the User Group Demo Bilberry. I noticed there was an update on the 18th August.

alt text

Ok, So there is clearly an issue with the Azure/static-web-apps-deploy@v1 action. So how do we fix it? Having done some google-fu I found a github issue which looked interesting and showed a possibility that this might be possible. Git Issue #332. I guess I can also thank Chris Reddington for the inspiration here. In short this simple GitHub Action gave me the idea and hope that we might be able to work around this issue.

 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
36
name: Azure Static Web Apps CD

on:
  push:
    branches:
      - main

jobs:
  build_and_deploy_job:
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true

      - name: Installing Hugo 0.91.2
        run: |
          wget https://github.com/gohugoio/hugo/releases/download/v0.91.2/hugo_extended_0.91.2_Linux-64bit.deb
          sudo dpkg -i hugo_extended_0.91.2_Linux-64bit.deb
          hugo version          

      - name: Building site
        run: |
          cd ./src
          hugo --minify          

      - name: Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_GRAY_FOREST_040213F00 }}
          action: "upload"
          # For more info: https://aka.ms/swaworkflowconfig
          app_location: "/src/public" # output directory after the hugo build
          skip_app_build: true

So how do we improve?

Github Action Improvements

First thing first, we need to be able to download and install Hugo into a GitHub hosted runner. Sounds pretty easy right. to save some time for you all, I’ve already spent the hours working out the cli magic to sort this and you can have two favours.

Download Hugo Extended (Linux)

 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
name: Hugo Check and Install (Linux)

on:
  push:
    branches:
      - main
  workflow_dispatch:
  # Uncomment the following lines if you want to add pull request triggers
  # pull_request:
  #   types: [opened, synchronize, reopened, closed]
  #   branches:
  #     - main

jobs: 
  check-and-install:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Check Operating System
        run: |
          echo "Operating System: Linux"
          cat /etc/os-release
                    
      - name: Get latest Hugo version
        id: get_latest_version
        run: |
          latest_version=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r .tag_name)
          echo "Latest Hugo version is $latest_version"
          echo "version=$latest_version" >> $GITHUB_ENV
                    
      - name: Download Hugo
        run: |
          HUGO_VERSION="${{ env.version }}"
          DOWNLOAD_URL="https://github.com/gohugoio/hugo/releases/download/${HUGO_VERSION}/hugo_extended_${HUGO_VERSION#v}_Linux-64bit.tar.gz"
          
          echo "Downloading Hugo from $DOWNLOAD_URL"
          curl -LO "$DOWNLOAD_URL"
          
          echo "" # Verbose Spacing
          echo "Checking Local Directory [$PWD]"
          ls # Display the contents of the current directory          

      - name: Install Hugo
        run: |
          HUGO_VERSION="${{ env.version }}"
                    
          echo ""
          echo "Using Hugo version ${HUGO_VERSION}"
          echo "Extracting Hugo for Linux"
          tar -zxf "hugo_extended_${HUGO_VERSION#v}_Linux-64bit.tar.gz"
          chmod +x hugo
          
          echo "" # Verbose Spacing
          echo "Hugo installed for Linux"
          sudo mv hugo /usr/local/bin/
                    
      - name: Check Hugo version
        run: hugo version

Download Hugo Extended (Windows)

 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
name: Hugo Check and Install (Windows)

on:
  push:
    branches:
    - main
  workflow_dispatch:
  # Uncomment the following lines if you want to add pull request triggers
  # pull_request:
  #   types: [opened, synchronize, reopened, closed]
  #   branches:
  #     - main

jobs:
  check-and-install:
    runs-on: windows-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Check Operating System
      run: |
        Write-Host "Operating System: Windows"
        systeminfo | Select-String -Pattern "OS Name|OS Version"        

    - name: Get latest Hugo version
      id: get_latest_version
      run: |
        $latest_version = (Invoke-RestMethod -Uri "https://api.github.com/repos/gohugoio/hugo/releases/latest").tag_name
        Write-Host "Latest Hugo version is $latest_version"
        echo "version=$latest_version" >> $env:GITHUB_ENV        

    - name: Download Hugo
      run: |
        $HUGO_VERSION = $env:version
        Write-Host "HUGO_VERSION is $HUGO_VERSION"

        # Trim the 'v' character if it exists
        $trimmed_version = if ($HUGO_VERSION.StartsWith('v')) { $HUGO_VERSION.Substring(1) } else { $HUGO_VERSION }
        $DOWNLOAD_URL = "https://github.com/gohugoio/hugo/releases/download/$($HUGO_VERSION)/hugo_extended_${trimmed_version}_windows-amd64.zip"

        Write-Host "Downloading Hugo from $DOWNLOAD_URL"
        Invoke-WebRequest -Uri $DOWNLOAD_URL -OutFile "hugo_extended_${trimmed_version}_windows-amd64.zip"

        Write-Host "Checking Local Directory [$PWD]"
        Get-ChildItem        

    - name: Install Hugo
      run: |
        $HUGO_VERSION = "${{ env.version }}"
        $trimmed_version = if ($HUGO_VERSION.StartsWith('v')) { $HUGO_VERSION.Substring(1) } else { $HUGO_VERSION }

        Write-Host "Using Hugo version $HUGO_VERSION"
        Write-Host "Extracting Hugo for Windows"
        Expand-Archive -Path "hugo_extended_${trimmed_version}_windows-amd64.zip" -DestinationPath '.' -Force
        Write-Host "Hugo installed for Windows"

        Move-Item -Path "hugo.exe" -Destination "C:\ProgramData\chocolatey\bin\"        

    - name: Check Hugo version
      run: hugo version

Once I had this working, I started on “upgrading” the actual build-and-upload GitHUb action. Below is the finalised working version of the updated script.

Useful Tips and Information

Under the Build and Deploy Job stage the following things have been changed.

> skip_app_build
This disabled the Orynx builder, and means we need to use the hugo --minify step to build the source files for the web app.

> app_location
Now that we are manually building the source files, I’ve created a dedicated directory for this build process action-hugo-swa-builder this means that anyone can take this action, replace with their secrets and get back to blogging!

> hugo –minify
What I learnt about this step was that when running this (which is required and happens behind the scenes in the Oryx builder) is it creates a new folder public which is the actual files used for the web app.

GitHub CI/CD Action

 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
name: Azure Static Web Apps CI/CD
# Ref for initial Fix: https://github.com/Azure/static-web-apps/issues/322

on:
  push:
    branches:
    - prod
  workflow_dispatch:
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - prod

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest

    steps:
    - name: Download and Install Hugo
      run: |

        # Get Latest Release of Hugo
        latest_version=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r .tag_name)
        echo "Latest Hugo version is $latest_version"
        echo "version=$latest_version" >> $GITHUB_ENV

        # Set HUGO_VERSION from the environment variable
        HUGO_VERSION="$latest_version"

        # Construct the download URL
        DOWNLOAD_URL="https://github.com/gohugoio/hugo/releases/download/${HUGO_VERSION}/hugo_extended_${HUGO_VERSION#v}_Linux-64bit.tar.gz"
        echo "Downloading Hugo from $DOWNLOAD_URL"
        curl -LO "$DOWNLOAD_URL"

        echo " " # Verbose Spacing
        echo "Checking Local Directory [$PWD]"
        ls # Display the contents of the current directory

        # Extract Hugo
        echo "Extracting Hugo Tar File"
        tar -zxf "hugo_extended_${HUGO_VERSION#v}_Linux-64bit.tar.gz"
        chmod +x hugo

        # Install Hugo
        echo "" # Verbose Spacing
        sudo mv hugo /usr/local/bin/
        echo "Hugo: $HUGO_VERSION Installed!"

    - name: Check Hugo version
      run: hugo version

    - name: Checkout repository
      uses: actions/checkout@v4.2.0
      with:
        submodules: true
        path: ./action-hugo-swa-builder

    - name: Build Hugo Site
      run: |
        echo "Building Hugo Site, Directory [./action-hugo-swa-builder]"
        cd ./action-hugo-swa-builder
        hugo --minify        

    - name: Build and Deploy Job
      id: builddeploy
      uses: Azure/static-web-apps-deploy@v1
      with:
        azure_static_web_apps_api_token: ${{ secrets."REPLACE_WITH_YOUR_SECRET"> }} # Replace "REPLACE_WITH_YOUR_SECRET" with Your GitHub Secret
        repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
        action: "upload"
        ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
        # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig

        # Skip Oryx Build, Current (October 2024) - Uses Hugo v0.112.5, No Longer works due to .Site.IsServer depreciation
        skip_app_build: true
        #app_location: "/" # [DEFAULT] App source code path

        # Updated Application Path, Based on Hugo Minify Build Path
        # $PWD is the working directory for the GitHub Action,
        # public, Is the build folder from 'hugo --minify'
        app_location: "./action-hugo-swa-builder/public"
        api_location: "" # Api source code path - optional
        output_location: "public" # Built app content directory - optional
        ###### End of Repository/Build Configurations ######

  close_pull_request_job:
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    steps:
    - name: Close Pull Request
      id: closepullrequest
      uses: Azure/static-web-apps-deploy@v1
      with:
        azure_static_web_apps_api_token: ${{ secrets."REPLACE_WITH_YOUR_SECRET"> }} # Replace "REPLACE_WITH_YOUR_SECRET" with Your GitHub Secret
        action: "close"

Summary

Well here we are, at the end of a blog post. So I guess there are a couple of things I’ve learnt from this one.
1 - Don’t assume the worlds simplest demo will always work (Unless you butcher an action to fix the dependencies issue šŸ˜‰)
2 - Updates happen we know this. Just as of posting this in October, I’ve not seen any response on the Static Web App Issues repository. GitHub Issue #1547
3 - I’ve learn’t a lot more about Hugo and building a static web app

So I hope this post was useful and that others, Should they run into the same decencies issues I did with the IsSite.Server problem, have a workaround until Microsoft releases an official update to the Github Action.