使用 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 Key
和 API URL
,通过 API 去上传,那么我们应该也可以自己去实现。
首先,我们也需要去 Ghost 后台创建一个自定义的 Integration,比如取名叫 GitLab CI,目的是为了获得 Admin API key
和 API URL
,后面在 GitLab CI 中需要用到。
下一步,去 GitLab CI 中,把这两个内容配置成变量,取名 GHOST_ADMIN_API_KEY
和 GHOST_API_URL
以便在 CI 脚本中使用。
在项目中添加 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
任务限制了只有打了 tag
的 commit
才会触发。
好了,更新代码,打个 tag 就会自动打包上传至 Ghost 后台了!
评论区