Contents

Deploying Hugo to Azure Static Web Apps with Azure DevOps

Earlier this year I decided I wanted to get back into blogging, and nothing screams getting back into blogging then changing the platform you’re using! I had been a long time user of Wordpress and blogged regularly from 2013 to 2016 and figured adopting a new platform is exactly what I need to do to get back into the swing of things.

Side note: changing tech is not the answer, I spent waaaaay too long working through various issues related to Hugo, I got there in the end but I should have just stuck with Wordpress and spent the time writing posts instead of tweaking toml files 😱

One of the main reasons I moved away from Wordpress was that I was using the free service, which served me fine over the years but I wanted to start serving up my blog using my own domain name and get rid of those pesky ads. Also, I wanted more control over how content was saved and so moving to a static generated site seemed like a good idea.

The tech stack

I had also been hearing at the time about the launch of Azure Static Web Apps, which have since gone GA.

Hugo is a static website generator, as the author you write all your content in markdown and check it into source control. Then using the Hugo command line all the markdown files are turned into HTML pages. So all content of my blog is now written in markdown and checked into an Azure DevOps repository.

The final bit of tech is my deployment pipeline, since I’ve been a long time user of Azure DevOps I thought it would be interesting to see if I could deploy to Azure Static Web Apps from a DevOps pipeline. There was already plenty of information about how to do it with GitHub Actions (and already a template available).

It turns out the pipeline itself wasn’t actually all that complicated, but there were two gotchas that I had to figure out along the way.

Deploying with Azure DevOps Pipelines

The pipeline which does the deployment is actually very simple and only contains a few steps:

 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

trigger:
- main

stages:
  - stage: 'GenerateHugo'
    displayName: 'Generate hugo website'
    jobs:
      - job:
        pool:
          vmImage: ubuntu-latest
        workspace:
          clean: all
        steps:
        - checkout: self
          displayName: 'Checkout repository including submodules'
          submodules: true  # true so Hugo theme submodule is checked out
        - script: wget https://github.com/gohugoio/hugo/releases/download/v0.83.1/hugo_0.83.1_Linux-64bit.deb -O '$(Pipeline.Workspace)/hugo_0.83.1_Linux-64bit.deb'
          displayName: Download Hugo v0.83.1 Linux x64
        # 2. Installs Hugo executable
        - script: sudo dpkg -i $(Pipeline.Workspace)/hugo*.deb
          displayName: Install Hugo
        - task: [email protected]
          condition: eq(variables['Build.SourceBranch'], 'refs/heads/main')
          inputs:
            app_location: '/'
            app_build_command: 'hugo -D'
            output_location: '/public'
            azure_static_web_apps_api_token: '$(TOKEN)'
        
        - task: [email protected]
          condition: ne(variables['Build.SourceBranch'], 'refs/heads/main')
          inputs:
            app_location: '/'
            app_build_command: 'hugo -D'
            output_location: '/public'
            azure_static_web_apps_api_token: '$(STAGING_TOKEN)'

Breaking down the pipeline, there is a single stage and a few different tasks.

First of all, the pipeline downloads the Hugo package from GitHub, and then installs it. This is done in two separate script tasks but could obviously be combined into a single task.

🚧 The first gotcha is that the vmImage must be linux based - in this case I’m using the ubuntu-latest - otherwise the AzureStaticWebApp task won’t work

The last two steps determine where the generated site is going to be deployed.

🚧 The second gotcha is that Azure DevOps Pipelines can make use of Static Web Apps pre-production environments

So to get around this limitation I have two different tasks. The first one is executed if the branch that triggered the build is main this deploys the content to my live site, the second is executed if the branch isn’t main and deploys to my staging site (which is a completely different Azure Static Web App).

So my publishing flow is, create a new branch and commit the new post and any assets (images, attachments etc), push to my DevOps repository and open a PR going into main. This will trigger the pipeline to run (using a Build Validation Policy) I can then check that everything looks good on my staging site. Once I’m happy with how everything looks I can complete the PR which will merge into main and run the Pipeline again this time publishing to my live site.

The only other thing that needs to be configured are the pipeline variables.

/deploying-hugo-to-azure-swa-with-devops/images/pipeline-variable.png

Why you should probably stick with GitHub Actions

On of the nice features of Azure Static Web Apps is pre-production environments, these are basically a staged environment of your site you which you can use to review your changes before they go into the production environment.

In the context of blogging it means you can write a draft post, push to branch, open a PR and have it deployed into a pre-production environment where you or someone else can review it. Then when you’re happy with the content it can be merged into main and deployed to your live site.

Unfortunately this feature is only officially supported via GitHub Actions ☹

For this reason if you’re looking to get started blogging with Hugo and Azure Static Web Apps and have the option then choose GitHub.

🍪 I use Disqus for comments

Because Disqus requires cookies this site doesn't automatically load comments.

I don't mind about cookies - Show me the comments from now on (and set a cookie to remember my preference)