使用 Travis CI 来构建 GitHub Pages 博客

前情提要

上一篇博文 中提到过,

所以这次给博客续命,力求把更新博文的边际成本,以及因 VPS 出故障而导致博客宕掉的可能性降到最低。

工具链

于是此番我选择了使用

  • GitHub 作为博客 markdown 源码托管方
  • GitHub Pages 作为博客静态文件托管方

“只要这两家公司不倒闭我的博客就能一直活下去”这一颓到爆的博客部署方式。

但好像还差了点什么:GitHub pages 可以接纳的工程种类有静态文件,以及 Jekyll 工程。但我显然不希望每一次更新博客都

1
2
3
4
5
6
7
hexo cl
hexo g
cd public
git init
git remote add origin ${GIT_ORIGIN}
git add .
git push --force origin master

Travis CI, and the difficulties in using it

于是便想到了使用持续集成来替我们完成这件事。此番采用的是 Travis CI 作为持续集成工具。是的,Travis CI 有完整的 Node.js 支持,我们可以让 Travis clone 下我们的 repository,安装所有的依赖,然后生成整个网站的静态文件,但最后的部署呢?显然不能把用户名和密码写进去。Travis 提供环境变量这一功能,但我们把用户名密码写进环境变量显然是一个不优雅的方式。

一些其他博客作者的解决方案是,GitHub 的 Personal Access Tokens。但私以为这手段依然不优雅。想要让 Travis 替我们部署就必须给一个 “repo” 等级的读写权限,但这一权限是不分 repo 的:Travis 一旦拥有这个权限,可以向任何(public)仓库写进任何东西。这一权限是危险的,哪天 Travis 替我们把所有 repo 都删掉也不是不可能(尽管这种可能性可以忽略,但赋予这一权限仍不推荐)。

本宫采用的解决方式是 Deploy keys。这一权限是 repo 级别的,Travis 的读写范围仅限于我们配置权限的这一个 repo。接下来的事情就很一马平川了。下面附上我的 .travis.yml 以及部署用的 bash script。有一个略微 tricky 的点在于,部署到 GitHub 时侯使用的 public key,我们需要让 travis 可以接触到,而网络上监视我们的 GitHub repo 是无法接触到。在这里本宫使用了 Travis 提供的一键文件加密功能

The files

No rights reserved.

.travis.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
language: node_js
node_js: stable
install:
- npm install -g hexo-cli
- npm install
- npm install --save hexo-renderer-jade hexo-generator-feed hexo-generator-sitemap hexo-browsersync hexo-generator-archive
script:
- bash ./deploy.sh
branch:
only:
- Hexo # "Hexo" is the branch where I store markdown sources etc.

deploy.sh

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
#!/bin/bash
set -e
# The branches, I'm generating from "hexo" branch and deploying to "master".
SOURCE_BRANCH="hexo"
TARGET_BRANCH="master"
# Check out the sources
git checkout $SOURCE_BRANCH
function doCompile {
hexo cl
hexo g
}
REPO=`git config remote.origin.url`
SSH_REPO=${REPO/https:\/\/github.com\//[email protected]:} # Later in this script we will be pushing with a ssh private key as the credential
SHA=`git rev-parse --verify HEAD` # Used later in commit message
echo "REPO=${REPO}"
echo "SSH_REPO=${SSH_REPO}"
echo "SHA=${SHA}"
doCompile
# decrypt the deploy private key, and add it to ssh agent
openssl aes-256-cbc -K $encrypted_046cd0986819_key -iv $encrypted_046cd0986819_iv -in travis-deploy-key.enc -out travis-deploy-key -d
chmod 600 travis-deploy-key
eval `ssh-agent -s`
ssh-add travis-deploy-key
cd public
touch CNAME && echo "blog.mahoucoder.com" >> CNAME # This line is unnecessary if you don't wish to configure a custom domain name
git init
git remote add origin ${REPO} # Set remote origin.
git config --global user.name "jilulu" # configure username...
git config --global user.email "[email protected]" # and email, so that GitHub commit could show your name
git add . # Add everything
git commit -m "Deploy to GitHub Pages: ${SHA}"
# Since there's absolutely no need (and is unwanted) to keep
# historical records of generated html files, do a forced update
# to the master branch
git push --force $SSH_REPO $TARGET_BRANCH