Stream of Consciousness

Mark Eschbach's random writings on various topics.

Hugo - Deploying to multiple environments

Categories: tech

Tags: hugo continuous-delivery

Well, now that I have an official production location thanks to the module I published this morning I need to figure out how to manage multiple deployment locations.

My ideal delivery pipeline is:

stateDiagram-v2
  direction LR
  [*] --> action_deploy_integ: on push
  action_deploy_integ --> validate_integ
  validate_integ --> deploy_prod: passes
  validate_integ --> [*]: failed
  deploy_prod --> [*]

Experimenting

Where validate_integ is run on the Gitea Actions afterwards. For now I need to figure out how to deploy with minimal changes to /hugo.toml. Specifically the baseURL property needs to be overridden per environment as the URLs change.

The following did not work. I was testing this by reviewing index.xml for the absolute URLs generated. Could also be checked via /index.html xpath /html/head/link[@rel="canonical"] value.

  • Having baseURL per deployment target in /hugo.toml.
  • Setting HUGO_ENVIRONMENT={target} as the generation step is what actually gets deployed. Should probably be set to production when actually deploying.

Solution

I was able to get this to work

  • Exporting the changed configuration option via HUGO_BASEURL environment variable to the desired target URL.
  • Regenerating for a production build: hugo --logLevel info --ignoreCache --cleanDestinationDir --enableGitInfo --gc --minify
  • Running a deploy for the target: hugo deploy --target=integ --logLevel info

Application to Gitea Actions

Resulting stanzas for deployment look like the following. I have omitted the actions required to install the tools and caching for clarity.

name: Build and Deploy site to integ
run-name: Build for and deploy to integ
on:
  push:
    branches:
      - main
  workflow_dispatch:

defaults:
  run:
    shell: bash
jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build for integ
        env:
          # For maximum backward compatibility with Hugo modules
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production
          HUGO_BASEURL: "https://soc.example.com"
        run: |
          hugo --logLevel info --ignoreCache --cleanDestinationDir --enableGitInfo --gc --minify          
      - name: "Deploy to integ"
        env:
          AWS_ACCESS_KEY_ID: ${{secrets.INTEG_AWS_ACCESS_KEY_ID}}
          AWS_SECRET_ACCESS_KEY: ${{secrets.INTEG_AWS_SECRET_ACCESS_KEY}}
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production
        run: |
          hugo deploy --target=integ --logLevel info          
      - name: Build for prod
        env:
          # For maximum backward compatibility with Hugo modules
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production
          HUGO_BASEURL: "https://soc.meschbach.com"
        run: |
          hugo --logLevel info --ignoreCache --cleanDestinationDir --enableGitInfo --gc --minify          
      - name: "Deploy to integ"
        env:
          AWS_ACCESS_KEY_ID: ${{secrets.PROD_AWS_ACCESS_KEY_ID}}
          AWS_SECRET_ACCESS_KEY: ${{secrets.PROD_AWS_SECRET_ACCESS_KEY}}
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production
        run: |
          hugo deploy --target=prod --logLevel info          

Works as expected! I am glad I now have my phased deploy.