Ghost With Gitlab CI/CD

Discover how to integrate GitLab with Ghost CMS for auto-deploying themes, a feature commonly associated with Github. This post serves as a comprehensive guide for those using a self-hosted GitLab instance and struggling to find resources on this integration.

Ghost With Gitlab CI/CD

As you might have noticed, this website uses Ghost CMS. Ghost officially supports Github as integration which allows users to auto-deploy themes. However for my use case, I use a self-hosted Gitlab instance for my code repository and after searching on how to integrate Gitlab with Ghost, I did not find anything. Hence this post will show how to integrate Gitlab with Ghost.

Setup

First we need to create an integration in order to create an admin api key. Integrations -> Custom.

After copying the Admin Api key we navigate to the our Gitlab instance.

Settings -> CI/CD -> Variables

The GHOST_ADMIN_API_KEY contains the Admin Api key we copied from the Ghost instance. The GHOST_URL contains the url to the ghost instance e.g. https://example.com

Gitlab CI/CD

After creating our project in Gitlab, create a new file .gitlab-ci.yaml with the following contents

image: node:latest

stages:
  - test
  - deploy

cache:
  key: $CI_PROJECT_NAME
  paths:
    - node_modules/

test_theme_with_gscan:
  stage: test
  script:
    - npm install
    - npm install -g gscan
    - npx gscan .

deploy_to_ghost:
  stage: deploy
  rules:
    - if: $CI_COMMIT_TAG
  script:
    - apt update
    - apt install -y zip jq
    - npm install @tryghost/admin-api
    - npm version --no-git-tag-version ${CI_COMMIT_TAG} #Change the version in package.json to the tag version
    - zip -r $(jq -r '.name' package.json).zip . -x *.git* *.zip yarn* npm* node_modules/\* *routes.yaml *redirects.yaml *redirects.json deploy.js .gitlab-ci.yml .idea/\*
    - node deploy.js

This file has two stages, test and deploy, in the test stage it will install the dependencies and run gscan. This will verify that the theme is compatible with the latest version of ghost.

Once the test stage successfully runs, then comes the deploy stage. This stage will only run if there is a tag. The version of the theme is update with the tag version and the deploy.js script is ran.

In the project folder add a new file deploy.js with the following content

const path = require('path');
const process = require('process');
const {exec} = require('child_process');
// The admin API client is the easiest way to use the API
const GhostAdminAPI = require('@tryghost/admin-api');



(async function main() {
    try {
        // Configure the client
        const api = new GhostAdminAPI({
            url: process.env.GHOST_URL,
            key: process.env.GHOST_ADMIN_API_KEY,
            version: 'v5.0'
        });
        const basePath = path.join("/builds",process.env.CI_PROJECT_PATH);

        const pkgPath = path.join(basePath, "package.json");
        const themeName = require(pkgPath).name;
        const themeZip= `${themeName}.zip`;

        let zipPath = path.join(basePath, themeZip);

        // Deploy it to the configured site
        await api.themes.upload({file: zipPath});
        console.log(`${zipPath} successfully uploaded.`); // eslint-disable-line no-console
    } catch (err) {
        console.error(err); // eslint-disable-line no-console
        process.exit(1);
    }
}());

The main purpose of this file is to deploy the theme to the ghost site.

Now whenever a push is performed the test stage will run and when a tag is pushed both the test and deploy stage will run.

Below is a POC to generate a JWT from the admin api key.