自从GitHub action可以免费使用后,我就开始想利用它解决博客的构建和部署的问题。直到今天,终于实现了自己比较满意的GitHub action。
Hexo博客在使用时,存在几点不方便的地方:
Hexo的初始化需要安装各种依赖库,这点本文暂时也没能实现开箱即用。 当更换电脑后,又需要重新配置一遍本地的Hexo环境 Hexo deploy命令在实际使用中并不方便 我想要的是,配置一次,之后就无需关心hexo的问题,可以让我专注于写文章。而GitHub action就提供了这样功能,我们可以把hexo的配置放在GitHub仓库里,然后每次更新文章(Markdown文件)后,GitHub action就自动根据仓库里的hexo配置去构建博客并且发布到相应的博客仓库。
我的总体思路就是,仓库A有两个分支,分别是master
和hexo-settings
。master
放的是Markdown文件,也就是hexo博客中的source/_posts
里的文件,hexo-settings
放的是hexo的配置信息,也就是,hexo博客源码中,除了node_modules
和source
之外的所有文件。同时,master
分支作为hexo-settings
的一个submodule,路径就是source/_posts
,主题也作为hexo-settings
的一个submodule,路径当然就是themes/theme_name
了。这样,当git clone hexo-settings
后,只需要同时拉取submodules,就可以获得完整的hexo博客源码了。Github action就是这样,先拉取完整的源码,然后再根据packages.json
安装相关依赖(node_modules),就可以生成html文件了。
生成html文件之后,还需要部署到博客仓库里(name.github.io)。这里,我采用的是在本地新建一个空的git仓库,把生成的文件(public文件夹里的文件)都放进去,然后强制把这个本地仓库push到博客仓库,覆盖原有的内容。这样的好处是,博客仓库永远都只有一个commit,别人没办法获得我的博客的历史版本。
经过一番折腾,最后的成品在本文文末。下面是对该action代码的解释,如果只想要结果,可以直接拉到文末获取代码。
第一块代码是on
。表示action被触发的条件,我写了两个,一个是push事件发生时,一个是watch。watch这个是抄来的,我在网上看到有人说加这个watch代码就可以实现监控star事件,也就是当我点击项目的star按钮时,action就会执行,是个很有趣的功能。
第二块是job
,是action的任务内容。env
是环境变量,这里的HEXO_BRANCH
表示的是hexo配置信息所在的分支,MD_BRANCH
是Markdown文件所在分支(即该分支内容就是_posts
文件夹的内容)。需要根据实际分支名进行修改。接下来steps
里是任务的步骤。
步骤Get repo name and username
是从GitHub提供的环境变量$GITHUB_REPOSITORY
中获取当前的仓库A的名字和用户名作为环境变量,用于后续步骤。其中,用户名是用来拼接出最后要部署到的仓库名USER_NAME/user_name.github.io
。步骤Init Env
也是设置环境变量。其中,HEXO_ENV_PATH
是hexo配置的绝对路径,BLOG_PATH
是本地新建的空的git仓库的绝对路径。
步骤Cache pandoc and npm
实现了npm
和pandoc
安装包的缓存,GitHub就会帮我们保存这些内容,这样下一次执行该action时,就可以从GitHub的服务器获取保存的内容,无需花时间去网络上下载。这里我缓存的是~/.npm
目录,然后我发现似乎只能有一个缓存,所以我把pandoc的安装包也放在这个目录里,一起保存了。如果缓存不命中,那就只能重新下载pandoc安装包了。
步骤Prepare hexo
和Update content
分别是安装博客的依赖和构建博客,并且把生成的文件都移动到上面说的空的git仓库。注意这里用的是npm run build
,这个命令会执行packages.json
中scripts
下的build
命令。因为我的build
命令比较复杂,所以都写在那里了。如果只想要hexo generate
,那可以直接把npm run build
替换成hexo generate
。
最后,步骤Add all to the empty git
就是把新的仓库里的所有文件commit了。再用github-push-action
把这个新的仓库强制push到博客仓库。这里的变量secrets.ADMIN
也是要根据实际进行修改。需要在GitHub上的博客仓库的设置里新建一个personal access token,然后把这个token放到仓库A的secrets里,也就是仓库A设置里的Secrets选项。Secrets选项设置的就是一个键值对,我设置的键就叫做ADMIN
,值就是前面那个token。详细的token设置可以参考GitHub官方文档 。
至此,我的GitHub博客基本已经不需要去打理hexo部分的内容,只需要专心写md文件,写完push上去,就会自动发布到博客里。我也尝试过把这个action代码只放在hexo-settings
分支里,这样master
分支就没有action代码了,所以当有文章更新时,并不会马上发布,而是需要我点击star按钮才会发布,可以理解为:star按钮就是“发布”按钮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 name: update on: push: branches: - master - hexo-settings watch: type: [started ] jobs: build: runs-on: ubuntu-latest env: HEXO_BRANCH: hexo-settings MD_BRANCH: master HEXO_FOLDER: _hexo_env BLOG_FOLDER: _blog steps: - name: Get repo name and username run: | echo "USER_NAME=$(echo $GITHUB_REPOSITORY | awk -F / '{print $1}')" >> $GITHUB_ENV echo "REPO_NAME=$(echo $GITHUB_REPOSITORY | awk -F / '{print $2}')" >> $GITHUB_ENV - name: Init Env run: | echo "MD_PATH=$(dirname $GITHUB_WORKSPACE)/$REPO_NAME" >> $GITHUB_ENV echo "HEXO_ENV_PATH=$(dirname $GITHUB_WORKSPACE)/${{ env.REPO_NAME }}/$HEXO_FOLDER" >> $GITHUB_ENV echo "BLOG_PATH=$(dirname $GITHUB_WORKSPACE)/${{ env.REPO_NAME }}/$BLOG_FOLDER" >> $GITHUB_ENV echo "BLOG_REPO_NAME=${{ env.USER_NAME }}/$(echo ${{ env.USER_NAME }} | awk '{print tolower($0)}').github.io" >> $GITHUB_ENV - uses: actions/checkout@v2 with: persist-credentials: false fetch-depth: 0 path: ${{ env.MD_PATH }} ref: ${{ env.MD_BRANCH }} - uses: actions/checkout@v2 with: persist-credentials: false fetch-depth: 0 path: ${{ env.HEXO_ENV_PATH }} ref: ${{ env.HEXO_BRANCH }} - uses: actions/setup-node@v2 with: node-version: '14' - name: Init an empty git for blog deploying run: | mkdir $BLOG_PATH cd $BLOG_PATH git init - name: Cache pandoc and npm id: cache-pn uses: actions/cache@v1 env: cache-name: cache-pandoc-npm with: path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }} restore-keys: ${{ runner.os }}-build-${{ env.cache-name }} - name: Download pandoc if: steps.cache-pn.outputs.cache-hit != 'true' run: | cd ~ mkdir -p .npm cd .npm sudo apt install -y wget wget -O pandoc.deb https://github.com/jgm/pandoc/releases/download/2.9.2/pandoc-2.9.2-1-amd64.deb - name: Install pandoc run: sudo dpkg -i ~/.npm/pandoc.deb - name: Prepare hexo run: | cd $HEXO_ENV_PATH npm install -g hexo-cli npm install git clone https://github.com/next-theme/hexo-theme-next themes/next cat ./package.json npm --version hexo version - name: Update content run: | cd $MD_PATH shopt -s extglob mkdir -p $HEXO_ENV_PATH/source/_posts cp -r !(.gitignore|.git|.github|.|..|$HEXO_FOLDER|$BLOG_FOLDER) -t $HEXO_ENV_PATH/source/_posts cd $HEXO_ENV_PATH npm run build cp -r public/* -t $BLOG_PATH - name: Add all to the empty git run: | cd $BLOG_PATH git status git config --local user.email "blog-bot@bot.bot" git config --local user.name "blog-bot" git add . git commit -m "Update blog" - name: Deploy uses: ad-m/github-push-action@master with: github_token: ${{ secrets.ADMIN }} directory: ${{ env.BLOG_PATH }} repository: ${{ env.BLOG_REPO_NAME }} force: true