语雀自动同步HEXO机器人——搭建细节

Challenge Accepted!

前言

语雀作为专业云端知识库,并且提供了优秀的富文本编辑器,支持在线编辑与版本控制等功能,对于个人来讲适合记录笔记以及写文章。本文的目的在于提供简单的从语雀到个人博客(HEXO)的同步机器人流程搭建细节,使得快速实现语雀作为文本编辑载体,同步个人博客至HEXO的功能

流程介绍

与网上一些经验类似,搭建完成后的同步机器人分成图中四个步骤执行,在语雀更新后个人博客主页全自动同步。
接下来将倒着从最后往前逐一介绍。

HEXO

Hexo是一个博客框架,支持专注于.md格式的内容编辑后快速生成静态博客页面。
github提供托管生成的静态页面的功能,所以一个快速搭建的博客只需要进行接下来的几个步骤。

  1. 安装hexo脚手架初始化项目

    1
    2
    3
    npm install hexo-cli -g
    cd ~/your/blog/dir
    hexo init
  2. 本地编辑博客

    1
    2
    hexo n <title> # 创建名为title的.md,可进行编辑
    hexo s # 本地启动服务查看最终页面
  3. 部署博客(无git配置下只生成静态文件)

    1
    hexo d # 部署博客
  4. 部署博客到github

只需要配置项目根目录的 _config.yml 最后几行,格式如下

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: git@github.com:JoashZhao/blog.git # 你的git项目地址,也支持https
branch: gh-pages

注意到branch这里我填写 gh-pages ,github支持几种托管的方式(详见Repository的Setting),另一种方案可以新建 <nickname>.github.io 的Repository并填写master分支。放在gh-pages分支我是为了把该hexo项目和最后生成的博客静态文件放在一个Repository中。配置完成之后,步骤3的 hexo d 命令将会生成静态文件并push到配好的Repository的分支中。
例如我这里放在blog的gh-pages分支,可以访问https://joashzhao.github.io/blog/访问我的博客主页(若不想在/blog/下访问可以用上述的另一种方法)。

Travis

Travis是一个提供github项目的CI持续集成的免费平台。github项目关联Travis后有两种食用方式,一是新的commit会触发Travis的CI,进行项目的编译部署等(如本文中的博客文件生成和部署),二是可以通过developer api的方式触发Travis的CI流程。

在Travis关联github的项目之后,无论那种方式想要触发CI,项目都需要有一个根目录的配置文件 .travis.yml ,新的commit或者developer api都会让Travis按照这个 .yml配置进行持续集成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
language: node_js
node_js:
- 12.6.0
branches:
only:
- master
cache:
directories:
- node_modules
before_install:
- openssl enc -aes-256-cbc -k "$super_secret_password" -md sha512 -salt -in ./.travis/id_rsa_travis.enc -out ~/.ssh/id_rsa_travis -d
- chmod 600 ~/.ssh/id_rsa_travis
- eval $(ssh-agent)
- ssh-add ~/.ssh/id_rsa_travis
- cp ./.travis/ssh_config ~/.ssh/config
- git config --global user.name JoashZhao
- git config --global user.email 1143768516@qq.com
install:
- npm install hexo-cli -g
- npm install
script:
- hexo d
  • 1-6行是持续集成的nodejs环境,选择适合的版本和项目触发构建的分支。
  • 7-9行是缓存node_modules加快安装模块速度。
  • 10-17是部署之前的秘钥设置,因为Travis对github项目的部署得有写的权限,事先生成一对公私秘钥,公钥放在github项目的 Setting/Deploy Keys 中,私钥放在CI的运行环境中,这样CI才能对github的项目执行deploy的写操作。以防私钥泄露,通过11行的openssl解密的方式把预先加密过的私钥 ./.travis/id_rsa_travis.enc 解密成 ~/.ssh/id_rsa_travis ,CI在部署的时候用解密之后的文件对github项目进行写操作。其中 $super_secret_password 为一个环境变量,可以在Travis的setting页面设置,如下图。( $yuque_token 下节会用到)

Screenshot from 2019-07-16 20-36-00.png

  • 而预先加密的命令类似 openssl enc -aes-256-cbc -k <your_super_secret_password> -md sha512 -salt -in ./.travis/id_rsa_travis -out ~/.ssh/id_rsa_travis.enc ,注意不要把私钥id_rsa_travis直接commit进项目中即可防止泄露。
  • 18-20行安装对应的模块。
  • 22行通过hexo d部署。

至此,通过该yml文件,Travis可以生成和部署博客内容,我们只需要commit到master分支即可。

Yuque-Hexo

yuque-hexo是一个同步语雀的文章到hexo的项目,能抓取账号下的语雀文章内容并且类似类似hexo脚手架的方式部署,主要分为三个步骤。

  1. 添加对应模块和脚本package.json
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
{
"dependencies": {
"cross-env": "^5.2.0",
"yuque-hexo": "^1.6.1"
},
"yuqueConfig": {
"postPath": "source/_posts/yuque",
"cachePath": "yuque.json",
"mdNameFormat": "title",
"adapter": "hexo",
"concurrency": 5,
"baseUrl": "https://www.yuque.com/api/v2/",
"login": "joashzhao",
"repo": "blog",
"onlyPublished": false
},
"scripts": {
"clean": "hexo clean",
"clean:yuque": "yuque-hexo clean",
"deploy": "yuque-hexo sync && hexo deploy",
"publish": "npm run clean && npm run deploy",
"dev": "hexo s",
"sync": "yuque-hexo sync",
"reset": "npm run clean:yuque && npm run sync"
}
}

其中yuqueConfig为语雀的文章同步至HEXO的配置,scripts添加的为yuque-hexo的命令行工具,主要用到deploy命令。

  1. 设置Token

yuque-hexo在v1.6.0更新后,需要设置对应的Token才能获取到语雀的文章。
首先在https://www.yuque.com/settings/tokens新建一个token,然后添加到Travis的环境变量中(如前所述),注入构建的脚本,把CI的最后一步改为 :

1
2
script:
- cross-env YUQUE_TOKEN=$yuque_token npm run deploy

其中 cross-env 是为了兼容不同系统设置环境变量。到此,执行 npm run deploy 脚本就可以同步语雀的文章并部署了。
目前为止,有了一个半自动的部署流程,在语雀发表文章,手动进入Travis触发构建即可,如果需要全自动的流程,则可以通过下面的方式进行。

语雀Web Hook

语雀的Web Hook可以在文档更新之后触发一个http的post请求,前面提到Travis可以通过api的方式触发构建过程,但是这两步骤无法直接连接使用,所以可以启一个代理的服务,Web Hook的请求发送至该服务后,该服务去触发Travis的CI构建。

  1. 使用阿里云的函数计算服务,配置以下的handler
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
'use strict';

const https = require('https');

function checkQueries(queries) {
if (typeof queries !== 'object') {
return false;
}
const { branch, token, repos } = queries || {};
if (!branch || !token || !repos) {
return false;
}
return true;
}

module.exports.handler = function(req, resp) {
const validQueries = checkQueries(req.queries);
if (!validQueries) {
resp.setStatusCode(400);
return resp.send('{"success": false}');
}
const { branch, message = 'yuque update', token, repos } = req.queries;

const payload = JSON.stringify({
message,
branch
});
const headers = {
'Content-Type': 'application/json',
'Travis-API-Version': '3',
Authorization: `token ${token}`,
'Conent-Length': Buffer.byteLength(payload)
};
const options = {
hostname: 'api.travis-ci.com',
port: 443,
path: `/repo/${encodeURIComponent(repos)}/requests`,
method: 'POST',
headers
};

let result = '';
const request = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
result += chunk;
});
res.on('end', function() {
resp.setStatusCode(200);
resp.setHeader('content-type', 'application/json');
resp.send(result);
});
});
request.on('error', function() {
resp.setStatusCode(500);
resp.send('{"success": false}');
});
request.write(payload);
request.end();
};
  • 其中22行的branch, message, token, repos为语雀的Web Hook请求可携带的参数,解析出来后,在请求 api.travis-ci.com 的时候注入进去。
  • 28-40行为满足Travis developer api的触发build条件,token可以在Travis这里找到。
  1. 配置语雀Web Hook

在语雀的Web Hook配置页面填入类似${our_server_url}?branch=master&token=${your_travis_token}&repos=${repo_name}即可。该链接需要与上述的定义的服务匹配。其中 <repo_name> 可以在通过请求对应api找到。




后记

至此,语雀同步到HEXO的机器人搭建细节全部结束,当在语雀更新文章后,个人的HEXO博客内容也可以自动更新。同时一些没有在语雀的发布内容也可以通过commit到github的方式触发Travis构建部署。我们只需要专注于内容本身,极大地缩短了构建部署这样繁琐的过程的时间: )