使用 GitLab CI 自动部署 Ghost 主题

715 字
4 分钟
...阅读
...评论
使用 GitLab CI 自动部署 Ghost 主题

居家隔离的第 N 天

今天收到了 Ghost 5.0 发布的邮件,第一时间更新了下,发现主题里有些功能已经不兼容了,于是准备对主题做下更新。在看 Ghost Integrations 的时候发现有个 GitHub 的插件特别好用,支持通过 GitHub Actions 自动部署你的主题。但是我自己的项目用的都是 GitLab,找了一圈,没有官方的插件。于是尝试自己通过 GitLab CI 来实现。

大致看了下基于 GitHub Actions 自动部署的实现方式,通过官方提供的一个 TryGhost/action-deploy-theme 的步骤,代码很简单,总共 40 行,我们来看下它做了什么:

const path = require('node:path')
const core = require('@actions/core')
const exec = require('@actions/exec')
const GhostAdminApi = require('@tryghost/admin-api');

(async function main() {
  try {
    const url = core.getInput('api-url')
    const api = new GhostAdminApi({
      url,
      key: core.getInput('api-key'),
      version: 'canary'
    })

    const basePath = process.env.GITHUB_WORKSPACE
    const pkgPath = path.join(process.env.GITHUB_WORKSPACE, 'package.json')

    let zipPath = core.getInput('file')

    // Zip file was not provided - zip everything up!
    if (!zipPath) {
      const themeName = core.getInput('theme-name') || require(pkgPath).name
      const themeZip = `${themeName}.zip`
      const exclude = core.getInput('exclude') || ''
      zipPath = themeZip

      // Create a zip
      await exec.exec(`zip -r ${themeZip} ${core.getInput('working-directory') || '.'} -x *.git* *.zip yarn* npm* node_modules* *routes.yaml *redirects.yaml *redirects.json ${exclude}`, [], { cwd: basePath })
    }

    zipPath = path.join(basePath, zipPath)

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

把主题打包成 zip 包,然后提供 Ghost 上创建的 Admin API KeyAPI URL,通过 API 去上传,那么我们应该也可以自己去实现。

首先,我们也需要去 Ghost 后台创建一个自定义的 Integration,比如取名叫 GitLab CI,目的是为了获得 Admin API keyAPI URL,后面在 GitLab CI 中需要用到。

iShot_2022-05-24_11.17.16

下一步,去 GitLab CI 中,把这两个内容配置成变量,取名 GHOST_ADMIN_API_KEYGHOST_API_URL 以便在 CI 脚本中使用。

iShot_2022-05-24_16.50.45

在项目中添加 Ghost Admin API 库:

yarn add @tryghost/admin-api --dev

gulpfile.js 中插入部署的任务:

const { series, src, dest } = require('gulp')
const pump = require('pump')
const less = require('gulp-less')
const zip = require('gulp-zip')
const GhostAdminApi = require('@tryghost/admin-api')

const handleError = (done) => {
  return function (err) {
    if (err) {
      console.error(err)
    }
    return done(err)
  }
}

function css(done) {
  pump(
    [
      src('./assets/css/*.less', { sourcemaps: true }),
      less({}),
      dest('assets/css', { sourcemaps: './' }),
    ],
    handleError(done)
  )
}

function zipper(done) {
  const targetDir = 'dist/'
  const themeName = require('./package.json').name
  const filename = `${themeName}.zip`

  pump(
    [
      src(['**', '!node_modules', '!node_modules/**', '!dist', '!dist/**']),
      zip(filename),
      dest(targetDir),
    ],
    handleError(done)
  )
}

async function deploy(done) {
  try {
    const zipFile = `dist/${require('./package.json').name}.zip`
    const api = new GhostAdminApi({
      url: process.env.GHOST_API_URL,
      key: process.env.GHOST_ADMIN_API_KEY,
      version: `v${require('./package.json').version}`,
    })

    await api.themes.upload({ file: zipFile })
    console.log(`${zipFile} successfully uploaded.`)
    done()
  }
  catch (err) {
    console.error(err)
    done(err)
  }
}

const build = series(css)

exports.build = build
exports.zip = series(build, zipper)
exports.deploy = deploy
exports.default = build

package.json 中插入脚本:

{
  /* ... */
  "scripts": {
    "build": "gulp build",
    "zip": "gulp zip",
    "deploy": "gulp deploy"
  }
  /* ... */
}

添加 .gitlab-ci.yml 文件:

image: node:14-slim # 注意:不要用 alpine 的镜像,上传至 https 站点会有问题

stages:
  - deploy

deploy:
  stage: deploy
  script:
    - yarn install
    - yarn zip
    - yarn deploy
  only:
    - tags
  cache:
    paths:
      - node_modules/

注意,为了避免每次提交代码都部署,deploy 任务限制了只有打了 tagcommit 才会触发。

好了,更新代码,打个 tag 就会自动打包上传至 Ghost 后台了!

评论区
Copyright © Bean Deng