从私有代码库自动部署Hexo站到GitHub Pages

之前我们谈到如何 从私有代码库自动部署Hugo站到GitHub Pages 。以为将之前的workflow yaml修改为Hexo的版本非常容易,亲自试了下发现打脸了。原因在于Hexo的依赖很多,因此环境配置比Hugo就复杂很多,同时还兼有各种包和库的兼容性问题。相比之下,Hugo就显得非常干净,使用GitHub Action容易不少。

花了好多时间并且尝试不了下20次,才将Hexo的action workflow最终调通 :-) ,记录下踩过的坑和解决文案。

与Hugo的workflow相比,需要解决如下几个问题:

  • 主题目录的submodule配置
  • 使用PAT同时拉取两个私有库(主库及主题submodule)的代码
  • Pandoc在GitHub Action中的安装(可选)

开始吧!

准备工作,需要有三个repo(可以属于不同账户),但不失一般性,假设它们三个都属于同一账户:

  • 私有库(private): 存放网站的源码
  • 主题库(private): 存放被修改过的主题的源码
  • 目标库(public): GitHub Pages (xxx.github.io)

需要做的是在目标库创建一个Personal Access Token (PAT),并将其配置在私有库的secret中,再创建一个工作流的yaml,大功告成。

在私有库中创建Action Workflow Yaml

为方便理解,在这个tutorial里使用自上而下的组织方式。先来看看最终的workflow yaml,然后后面小节用来填空和解决问题:

name: Hexo Build & Deploy - Private to Public

on:
  push:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v3.0.0
      with:
        token: ${{ secrets.MYPAT }}
        submodules: 'true'
        persist-credentials: false

    - name: Prepare Node env
      uses: actions/setup-node@v3
      with:
        node-version: 16

    - name: Install pandoc
      run: |
        cd /tmp
        wget -c https://github.com/jgm/pandoc/releases/download/2.14.0.3/pandoc-2.14.0.3-1-amd64.deb
        sudo dpkg -i pandoc-2.14.0.3-1-amd64.deb

    - name: Hexo
      run: |
        pandoc --version
        npm i -g hexo-cli
        npm i
        hexo clean && hexo g

    - name: Deploy
      uses: JamesIves/github-pages-deploy-action@v4.3.3
      with:
        ssh-key: ${{ secrets.DEPLOY_KEY }}
        repository-name: finisky/finisky.github.io
        branch: master # The branch the action should deploy to.
        folder: public # The folder the action should deploy.
        single-commit: true
        commit-message: "Deploy by source"

此workflow yaml包括如下几个部分:

  • Checkout: 拉取源码及主题submodule的源码
  • Setup Node Env: 安装配置node环境
  • Install pandoc for mathjax (可选): 使用pandoc和mathjax渲染公式的话,需要此部分
  • Setup and Run Hexo: 安装hexo-cli并且构建网站
  • Deploy: 用 # GitHub Pages Deploy Action 将网站发布到目标库

此workflow是基于 # Using GitHub Actions to Publish Hugo Site From Private to Public Repo 。在私有库如下路径创建 .github/workflows/main.yml

下面要做的几件事:

  • 配置主题Submodule

给上面的yaml填空:

  • token: ${{ secrets.MYPAT }}: 创建PAT MYPAT
  • ssh-key: ${{ secrets.DEPLOY_KEY }}: 创建 DEPLOY_KEY 从私有库发布到目标库
  • repository-name: xxx/xxx.github.io: 目标库的地址,即GitHub Page库的地址

配置主题Submodule

官方推荐的Hexo主题管理方法是用git submodule,同时将配置尽量写在主库中。具体要选用什么方案,有几个要考虑的因素:

  • 主题的配置文件需要保存,修改过的主题文件也需要保存
  • 主题的更新是个大坑,NexT主题更新频繁,且有很多breaking change,merge和解决冲突挺麻烦

最简单的方式就是直接不用submodule,将主题目录的.git删除,并把整个文件夹也checkin到主库中。但问题在于将来的更新很难处理。

我们最终选择将theme/next fork到自己的github账户中,创建另一个私有主题库mythemenext。同时用两个分支来解决主题的升级问题:master 分支与官方库保持一致,可以fast-forward。v8.5分支存放修改之后的主题文件与配置。如需更新,则在v8.5分支mergerebase master

增加submodule的命令长这样,它的意思是创建一个submodule并且track它的master分支。这个被track的分支可以按需修改。

git submodule add -b master <git@github.com:MYSUBMODULE.git> <path/to/MYSUBMODULE>

我们可以在私有库创建主题库了:

git remote add mythemenext git@github.com:finisky/mythemenext
git submodule add -b v8.5 https://github.com/finisky/mythemenext themes/next/

如果遇到这个错误: 'themes/next' already exists in the index . 在 git submodule add 命令中加入 --force 选项即可.

本节参考了文章:

利用 Github Action 部署 Hexo How to Setup Blog with Hexo and NexT on GitHub Pages

创建Personal Access Token

Personal access tokens (PATs) are an alternative to using passwords for authentication to GitHub Enterprise Server when using the GitHub API or the command line.

创建PAT的主要目的是给私有库访问目标库的权限,可以让私有库的actions推送构建好的代码到目标库中去。

参照 这里 来生成PAT:

Profile Photo -> Settings -> Developer settings -> Personal access tokens -> Generate new token

记得要勾选下面两个scope: workflow and write:packages.

PAT生成好之后,复制下来,妥善保管留待后用,为方便指代,不妨设它为TOKENXXX

注意PAT是一个账户级的token,而且是代开发者使用的,更好的方式是使用deploy key,它是代码库级的token。本文这里只能使用PAT,原因在于我们需要用账户级的token来同时拉取私有库和submodule的代码,后文有详解。

在私有库中设置Secret

在私有库中: > Settings -> Secrets -> Actions -> New repository secret

粘贴刚才生成的PAT TOKENXXX 到value框中,并命名这个secret为MYPAT

创建Deploy Key

这里的Deploy Key用来将生成好的HTML文件从私有库上传到目标库中。而之前的PAT是用于拉取私有库和submodule的代码。实际上,PAT也可以用来完成Deploy Key的功能。

Tips: 如果你选择使用PAT进行部署,本节可以略去,只要将yaml中 ssh-key: ${{ secrets.DEPLOY_KEY }} 替换为 token: ${{ secrets.MYPAT }} 即可。但建议使用Deploy Key。

参考 这篇这篇文章 创建 deploy key:

ssh-keygen -t ed25519 -C "your_email@example.com"

参考 这篇 将生成的deploy key添加到私有库:

Once you've generated the key pair you must add the contents of the public key within your repository's deploy keys menu. You can find this option by going to Settings > Deploy Keys, you can name the public key whatever you want, but you do need to give it write access. Afterwards, add the contents of the private key to the Settings > Secrets menu as DEPLOY_KEY.

安装Pandoc(可选)

运行GitHub Actions时可能遇到错误:

Error: R][hexo-renderer-pandoc] pandoc exited with code null.

如果你用pandoc和mathjax来渲染公式,下面这部分就必不可少;否则,可以略过此步,并删除下面代码及下面那步的pandoc --version

- name: Install pandoc
  run: |
    cd /tmp
    wget -c https://github.com/jgm/pandoc/releases/download/2.14.0.3/pandoc-2.14.0.3-1-amd64.deb
    sudo dpkg -i pandoc-2.14.0.3-1-amd64.deb

如果遇到如下错误

Error: R][hexo-renderer-pandoc] pandoc exited with code 64: YAML parse exception at line 4, column 0, while scanning a simple key: could not find expected ':'

是pandoc的兼容性问题,可以通过修改上面wget pandoc的版本解决,使用与你本地编译的版本一模一样的版本号为妙。参考: # pandoc exited with code 64 Solution


使用dpkg来安装pandoc的原因在于官方文档使用docker image的方案 # Using pandoc with GitHub Actions 不适用于我们的情况:

steps:
  - uses: docker://pandoc/core:2.9
    with:
      args: "--help" # gets appended to pandoc command

在Action的下一步 Setup and Run Hexo to build the Static Site 会使用全局的 pandoc 命令进行页面渲染。因此参考了 Hexo之问题集合 方案,并加以修改,使用wgetdpkg来安装pandoc。

GitHub Actions中拉取Submodule

如果在构建网站时发现如下警告:

WARN No layout: tags/index.html WARN No layout: nlpadapters/index.html WARN No layout: deployhugofromprivaterepo/index.html

大概率是主题库submodule没有拉取成功。默认的checkout是不拉取submodule的,需要在checkout部分添加 submodules: 'true'

尝试使用 # Access private submodules in GitHub Actions 的方案来拉取submodule代码。但后来发现有另一个错误:

Run actions/checkout@v2.3.4 Syncing repository: finisky/finiskyblogsource ... Fetching the repository Removing auth Error: The process '/usr/bin/git' failed with exit code 128

看起来是主库的代码 finisky/finiskyblogsource 都拉不下来了。因为 actions/checkout 需要使用同一个 deploy key 来拉取主库和submodule的代码。也尝试在主库添加一样的deploy key,但github提示这个key已被使用,看起来它不允许在同一个账户中使用同一个deploy key读写不同的repo。

所以,我们要使用账户级的PAT来同时拉取私有库和主题库的代码,将Checkout部分的代码稍加修改:

# Checkout
- name: Checkout
  uses: actions/checkout@v3.0.0
  with:
    token: ${{ secrets.MYPAT }}
    submodules: 'true'
    persist-credentials: false

Hexo网站的两种发布方式

看下这两步:

- name: Hexo
  run: |
    pandoc --version
    npm i -g hexo-cli
    npm i
    hexo clean && hexo g

- name: Deploy
  uses: JamesIves/github-pages-deploy-action@v4.3.3
  ...

显然,我们有两种方式可以发布Hexo站:

  • Setup and Run Hexo to build the Static Site中使用hexo deploy
  • github-pages-deploy-action

我们选用了后者来让这个脚本与Hugo的部署脚本保持一致。所以在 Hexo 步骤中,只使用了 hexo clean && hexo generate

总结

恭喜你!

将此yaml checkin,然后,就可以实现向私有库push完之后触发自动构建及部署了:

Hexo Deployment Action