前言
对于一些 GitHub 上的仓库,我们希望当代码进入 master 或者其它特定分支时网站能够自动部署。此时,就需要用到 Github Webhooks 功能。本文以静态网站的自动化部署为例,介绍如何配置 GitHub webhook、如何写自动化脚本以及如何开启监听服务等,非静态网站原理也是类似。
整体流程
Happy Path
Github Webhooks
按照以上的序列图,在启动监听服务之前,我们先配置一下 GitHub webhooks。在对应项目的 Github 仓库最右边有一个 Settings 标签(需要管理员权限),找到 Webhooks -> Add webhook,如下图:
Secret 字段,是我们自己定义的,最好稍微复杂一点。
最会发送一个带有X-Hub-Signature
的 POST
请求。通过它可以验证和我们服务器进行通信的合法性,为了方便我们直接用第三方的库 github-webhook-handler 来接收参数并做监听事件的处理等工作。
Server
自动化 shell 脚本
自动化当然离不开一些脚本的支持,在服务器上选定一个合适的目录,创建 auto_build.sh
,它主要是做 fetch 最新代码、build 等相关工作。
以下是一个简单的 Demo 实现:
#! /bin/bash
SITE_PATH='/home/docsite'
if [ ! -d ${SITE_PATH} ]; then
cd /home
git clone git@github.com:tmf-map/docsite.git
fi
cd ${SITE_PATH}
git fetch --all
git reset --hard origin/master
yarn install --prod
yarn build
rm -rf /home/www/*
cp -rf ${SITE_PATH}/build/* /home/www
这里也可以使用 git pull
, 但不同的项目有可能 build 的时候会导致服务器端的仓库出现文件改动,保险起见建议使用 fetch
+ reset
的方式。
不要直接把网站的静态目录和项目 dist 或者 build 目录当作同一个目录。
否则在 build 的过程中,会删除之前打包好的文件,导致服务器短暂不能访问。当然以上脚本的内容只是一个示例,大家可以根据实际的需求灵活配置。
启动监听服务器
在之前的 GitHub webhook 部分,我们设置了服务器请求路径和 Secret,这些都是为了和 server 端配合使用的,此时我们需要创建一个 node server 监听服务器。
我们可以在 auto_build.sh
脚本的同级目录下面执行下面命令初始化一个 package.json
:
npm init -f
然后执行下面命令安装上面提到的第三方库:
npm i github-webhook-handler
接下来创建服务的主入口文件 index.js
:
vi index.js
紧接着参考 github-webhook-handler 的 demo 编辑我们的 index.js
:
var http = require('http');
var spawn = require('child_process').spawn;
var createHandler = require('github-webhook-handler');
var handler = createHandler({path: '/auto_build', secret: 'your secret...'});
http
.createServer(function (req, res) {
handler(req, res, function (err) {
res.statusCode = 404;
res.end('no such location');
});
})
.listen(6666);
handler.on('error', function (err) {
console.error('Error:', err.message);
});
handler.on('push', function (event) {
console.log(
'Received a push event for %s to %s',
event.payload.repository.name,
event.payload.ref
);
if (event.payload.ref === 'refs/heads/master') {
runCommand('sh', ['./auto_build.sh'], function (msg) {
console.log(msg);
});
}
});
function runCommand(cmd, args, callback) {
var child = spawn(cmd, args);
var response = '';
child.stdout.on('data', function (buffer) {
response += buffer.toString();
});
child.stdout.on('end', function () {
callback(response);
});
}
然后利用 pm2 将 node 服务跑起来:
pm2 start index.js --name=github-webhook-handler
到这一步服务已经跑起来了,但是对外网并不能直接访问到,所以还需要配置一下 Nginx 做一下反向代理:
server {
listen 80;
server_name www.example.com;
···
location /auto_build {
proxy_pass http://127.0.0.1:6666;
}
···
}
到这里整个服务已经搭建完成,在服务器端会产生如下截图所示的目录结构:
docsite
即 Server Repo
, 另外auto_build.sh
在这里是放在 github-webhook-server
中,具体放在哪个位置可自行决定。后面我们测试一下即可,在此不再详述。
Issues
有时候 GitHub webhooks 调用并不会成功,需要 Redeliver 才行。
不是很稳定,具体原因有待分析。