Automating deployment of a Hugo website to Github Pages using powershell scripts

Overview

The following article describes how this blog is automatically deployed. The technology stack for this blog is:

  • Source content written within the Hugo framework (a static website generator written in the Go language.
  • Hosted by GitHub Pages, directly from this repository which contains the website build (the source code is in a separate repository).
  • Cloudflare for cached content delivery (along with many other things).

If the technology stack for your project is completely different, this article should still provide you with:

  • Inspiration for how you could automate your production workflow, and
  • Some useful Powershell scripting tips.

The Code

Because of the simplicity of this static website, I do not have separate development and production deployments, so after I have written an article or edited the template and previewed it using hugo server, the website is pushed straight into production.

The production automation script comprises three files:

  • config.json: stores secret keys. Remember to add it to .gitignore !
  • publish.ps1: imports secret keys and passes them as parameters when calling the main script.
  • build_commit_push_clear_cache.ps1: builds the website, uploads to server (in this case, via a git commit to GitHub), clears Cloudflare content delivery cache.

config.json

{
   'production_build_directory': 'PATH//TO//PRODUCTION//BUILD//DIRECTORY',
   'CloudflareAdminEmail': 'YOUR_CLOUDFLARE_ADMIN_EMAIL',
   'CloudflareApiKey': 'YOUR_CLOUDFLARE_API_KEY',
   'CloudflareZoneId': 'YOUR_CLOUDFLARE_ZONE_ID'
}

Note the double backslashes \\ in the production_build_directory path. The first backslash is an escape character used by the Powershell ConvertFrom-Json parser.

publish.ps1

# Import configurations and secret keys from config.json

$config = Get-Content -Raw -Path .\scripts\config.json | ConvertFrom-Json

# Pass the configurations and secret keys as arguments into the script that does the actual work:

### **`./scripts/build_commit_push_clear_cache.ps1`**
 -production_build_directory $config.production_build_directory `
 -CloudflareAdminEmail $config.CloudflareAdminEmail `
 -CloudflareApiKey $config.CloudflareApiKey `
 -CloudflareZoneId $config.CloudflareZoneId

Note that the production_build_directory is a separate git repository to the Hugo source code, in order to comply with Github Pages hosting requirements.

The real work is done by build_commit_push_clear_cache.ps1:

build_commit_push_clear_cache.ps1

Param(
    [parameter(Mandatory=$true)]
    [string] $production_build_directory,
    [parameter(Mandatory=$true)]
    [string] $AdminEmail,
    [parameter(Mandatory=$true)]
    [string] $ApiKey,
    [parameter(Mandatory=$true)]
    [string] $ZoneId
);

# Build the website

Read-Host -Prompt ("Initializing production build. This will delete all files in " `
 + $production_build_directory `
 + ". Press any key to continue, or ctrl+c to abort")

hugo --cleanDestinationDir `
 --destination $production_build_directory

# Upload the website

Read-Host -prompt ("Initializing git commit and push for all files in " `
 + $production_build_directory `
 + ". Press any key to continue or ctrl+c to abort")

git -C $production_build_directory add *
git -C $production_build_directory status

$git_commit_message = Read-Host ("Enter a short commit message, or ctrl+c to abort")

git -C $production_build_directory checkout master
git -C $production_build_directory commit -a -m $git_commit_message
git -C $production_build_directory push

# Clear the Cloudflare cache
<# Credit to [Niels Swimberghe]
(https://swimburger.net/blog/powershell/powershell-snippet-clearing-cloudflare-cache-with-cloudflares-api) #>

Read-Host -Prompt "About to clear the Cloudflare cache. Press any key to continue, or ctrl+c to abort"

$PurgeCacheUri = "https://api.cloudflare.com/client/v4/zones/$ZoneId/purge_cache";
$RequestHeader = @{
    'X-Auth-Email' = $AdminEmail
    'X-Auth-Key' = $ApiKey
};
$RequestBody = '{"purge_everything":true}';
Invoke-RestMethod `
    -Uri $PurgeCacheUri `
    -Method Delete `
    -ContentType  "application/json" `
    -Headers $requestHeader `
    -Body $RequestBody

Notes

  • Read-Host -Prompt statements are used to inform the user of impending actions and provide a chance to abort. It is also used to set the Git commit message. Important if there is a chance that a script will be re-used in a setting where {number_of_users} > 1, or if a less-technical client will be using it – UX is not just for front-end design!
  • git -C <path> runs commands as if git was started in the directory instead of the current working directory.
  • Backticks ` are used to split single commands over multiple lines for readability.
  • Credit to Niels Swimberghe for sharing his Powershell script for clearing the Cloudflare cache via the Cloudflare API.