Continuous Deployment of Ghost Themes

Wed, Jan 27, 2021 3-minute read

When I restarted my blog (this is at least blog v3) using Ghost I wanted to get up and running as quickly as possible so I purchased the Horace theme and followed the installation instructions - which basically came down to:

  1. Extract the theme’s .zip file to a directory.
  2. Make any modifications you need.
  3. Create a new .zip file.
  4. Upload the .zip file in Ghost Admin.

This process was fine once, maybe twice, but as I made more tweaks it was mind-numbing. This is where GitHub Actions saved the day (DISCLAIMER: I work at GitHub but not on GitHub Actions).

The first thing I did was create a new GitHub repository (blog-theme) and I added the contents of the theme’s .zip file to that repository. I kept this as a private repository because the Horace theme is commercially license so I can’t legally share it.

Once I had the theme’s contents in a repository I looked to see if Ghost has an API for uploading themes - it turned out it did. I knew it wouldn’t be hard to write a GitHub action that used the API to upload a theme but on the off-chance someone had already written it I searched the GitHub Marketplace - lo and behold there was. Not only that, it was an official GitHub action from Ghost!

With that knowledge in hand I set to creating an extremely simple GitHub Actions workflow which I saved to .github/workflows/CD.yaml in the repository:

name: CD
on:
  push:
    branches: [ main ]
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Deploy Ghost Theme
        uses: TryGhost/action-deploy-theme@v1.4.1
        with:
          api-url: https://willbar.com
          api-key: ${{ secrets.GHOST_ADMIN_API_KEY }}

This workflow would trigger whenever there was a push to the main branch and I also added workflow_dispatch which allows me to manually trigger the workflow from the GitHub Actions user interface.

The job then simply calls a GitHub Action (actions/checkout) to clone the repository and then calls the GitHub Action from Ghost to deploy the theme (TryGhost/action-deploy-theme). To give me control over upgrades to the GitHub actions I pinned them both to specific tags (if I was being extra paranoid I could have pinned them to specific commits).

The TryGhost/action-deploy-theme action assumes the theme’s content is in the default directory that actions/checkout clones to so I didn’t have to configure any paths, I simply had to provide the base URL for the API (my blog https://willbar.com in this case) and an API key.

To get an API key you go to Integrations in Ghost Admin and create a custom integration, give it any name you like (I simply called mine GitHub), and then copy the generated Admin API key. Committing secrets to your repository - even if it’s private - should be avoided, so I used GitHub Action’s built-in feature to protect the secret. This was as simple as going to the repository’s Settings, clicking Secrets, and adding a new secret called GHOST_ADMIN_API_KEY (this name has to match the one in the workflow) and pasting the Admin API key generated earlier.

Now whenever I push a new commit to the repository my blog’s theme is automatically updated.