2020-07-14
This website is written using Hugo, a static site generator similar to Jekyll and others.
I keep the source for the website in a private repo. The source consists of markdown files and HTML templates.
I serve the website from a public GitHub Pages repo.
When Hugo builds the site, it populates a /public
directory in the private
repo with the final assets that are ready to be served to site visitors.
Up until now, I’ve performed a manual step to bridge the gap between the two. This involves copying the assets from the private repo to the public repo, committing, then pushing the change live.
This blog post explains how I automated this process using GitHub Actions.
First I created a GitHub Personal Access Token. This is needed later for pushing to the public GitHub Pages repo. GitHub provides some decent documentation for how to do this. It’s all done through the GitHub website. Since it’s a one off step, there isn’t much point automating it.
Then I added the newly created Personal Access Token as a secret for the private website source repo. GitHub also provides some documentation for how to do this. Adding the secret to the repo will allow us to use use the secret in its GitHub Actions workflows. Again, this is done as a manual step via the GitHub website.
Finally, we can add the GitHub Actions workflow. The workflow is defined as a
YAML file, stored in .github/worflows/deploy.yaml
. It has a few interesting
aspects.
name: build
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: deploy
shell: bash
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
set -exo pipefail
git config --global user.email "ci@ci"
git config --global user.name "CI"
commit_msg="$(git log --pretty='%h %s' -n1)"
git clone https://$GH_TOKEN@github.com/peterstace/peterstace.github.io.git
cd peterstace.github.io
rm -r *
echo petsta.net > CNAME
cp -r ../site/public/* .
git add -A
git status
git commit -m "$commit_msg"
git push
It only executes when changes are pushed to the master branch. This is controlled by:
on:
push:
branches:
- master
When it runs, it first checks out the source repo. This uses a predefined step (provided by GitHub):
- uses: actions/checkout@v2
Then it runs a custom bash script step. This step needs to use the secret,
which is imported as an environment variable named GH_TOKEN
from a secret
also named GH_TOKEN
:
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
The actual bash script clones the public GitHub Pages repo
(peterstace.github.io
), deletes its content, then adds the /public
directory from the source repo. It makes the assumption that Hugo has already
been run on the markdown and HTML templates and the result committed to the
private repo. This is a reasonable workflow, since Hugo is run as part of the
regular development cycle anyway (as part of creating a new blog post or
tweaking a template).
set -exo pipefail
git config --global user.email "ci@ci"
git config --global user.name "CI"
commit_msg="$(git log --pretty='%h %s' -n1)"
git clone https://$GH_TOKEN@github.com/peterstace/peterstace.github.io.git
cd peterstace.github.io
rm -r *
echo petsta.net > CNAME
cp -r ../site/public/* .
git add -A
git status
git commit -m "$commit_msg"
git push