之前在看云上专门搞了个电子书来归档和协作一些文章,支持 webhook(钩子),但是一直没用上,今天放假,早上就突然醒了,突发奇想,不如弄个自动同步,把看云的同步到 github
,把 github
同步到看云,经过一个早上的努力总算是搞定了。
网上的资料 只支持单向的同步,我稍微做了一下改动,下面是整个过程。
同步原理
kancloud+webhook+serverless+travis-ci+github
大致流程如下:
- 在看云上编写文章
- 配置看云仓库的
Webhook
通知,当更新文章时通知给 Serverless
- 使用腾讯云提供的
Serverless
,编写云函数接收 Webhook
通知,然后通过 API
的方式触发 TravisCI
构建 - 在
Github
新建仓库,编写相关的仓库更新合并脚本进行同步,此脚本会对比两个仓库哪个更新来判断同步方向 -
Github
更新时自动触发 TravisCI
构建
同步目的:
- 看云文档
github
备份分享 - 看云文档分发到其他博客系统或导入到
gitbook
- 实现基于分支仓库(github.io)的
hexo
静态博客自动发布 - 多人协作共同完善文章库
github 配置
首先登陆github创建一个仓库,名称自定义,用来同步看云某一本书(git 仓库)。
在仓库根目录创建 2 个文件 .travis.yml
和 .travis-push.sh
.travis.yml
script:
+ sh .travis-push.sh
.travis-push.sh
#!/bin/sh
#看云版本库地址:
KY_REPO=https:///coding3min/coding3min.git
#github仓库地址:
GH_REPO=https:///pzqu/coding3min-book.git
KY_REPO_URL=https://${KANCLOUD_USER}:${KANCLOUD_PASS}@$(echo $KY_REPO | awk -F'//' '{print $2}')
GH_REPO_URL=https://${GITHUB_TOKEN}@$(echo $GH_REPO | awk -F'//' '{print $2}')
KY_REPO_NAME=$(echo $KY_REPO | awk -F'/' '{print $NF}' | awk -F '.' '{print $1}')
DEST_REPO_URL=$GH_REPO_URL
SRC_REPO_URL=$KY_REPO_URL
setup_git() {
git show -s --format=%ct
git config --global "pzqu@"
git config --global "pzqu"
rm -rf *
git clone --depth=50 --branch=master $SRC_REPO_URL
repo_dir=$(ls) && cp -rf $repo_dir/* ./ && rm -rf $repo_dir
}
commit_country_json_files() {
git status
git checkout master
# Current month and year, e.g: Apr 2018
dateAndMonth= `date "+%b %Y"`
# Stage the modified files in dist/output
git add -A
# Create a new commit with a custom build message
# with "[skip ci]" to avoid a build loop
# and Travis build number for reference
git commit -m "Travis update: $dateAndMonth (Build $TRAVIS_BUILD_NUMBER)" -m "[skip ci]"
}
upload_files() {
# Remove existing "origin"
git remote rm origin
# Add new "origin" with access token in the git URL for authentication
git remote add origin $DEST_REPO_URL > /dev/null 2>&1
git push origin master --quiet
}
compare_new() {
github_last_commit_time=$(git show -s --format=%ct)
git clone $KY_REPO_URL && cd $KY_REPO_NAME
ky_last_commit_time=$(git show -s --format=%ct)
if [ $github_last_commit_time -gt $ky_last_commit_time ];then
SRC_REPO_URL=$GH_REPO_URL
DEST_REPO_URL=$KY_REPO_URL
else
cd ..
fi
echo "sync $SRC_REPO_URL to $DEST_REPO_URL"
}
compare_new
setup_git
commit_country_json_files
# Attempt to commit to git only if "git commit" succeeded
if [ $? -eq 0 ]; then
echo "A new commit with changed country JSON files exists. Uploading to GitHub"
upload_files
else
echo "No changes in country JSON files. Nothing to do"
fi
代码过长,参考代码位置 github
脚本说明
这个脚本实现了仓库更新时间对比,同步推送代码的功能。
脚本中只需修改看云版本库地址以及 github
地址即可,另外脚本中定义了 3 个变量,是从 ci
平台里取的,用于免密执行 git clone
,为了安全不放在代码库里。
KY_REPO #看云版本库地址
GH_REPO #github仓库地址
$KANCLOUD_USER #看云账号
$KANCLOUD_PASS #看云密码
$GITHUB_TOKEN #github token
注意这 3 个参数可以配置在 travis-ci web
界面中,脚本能够自行调用该参数,不要以明文配置在脚本中。
travis-ci 配置
开启 github 仓库追踪
访问traivs 官网,以 github
账户登录:
点击右上角用户头像 settings
开启刚才新建的 github 仓库跟踪
定义脚本变量
点击 dashboard
,选择对应仓库,点击右侧 More options--Settings
配置 Environment Variales
:
- 注意 TOKEN 和密码不要以明文显示。
- 注意!!这 4 个参数如果用户名或密码中包含
@
符号,需要替换为 %40
,比如密码为 admin@123
需要写为 admin%40123
-
github token
需要访问 github 官网进行创建,点击右上角头像, Settings--Developer settings--Personal access tokens
生成一个新 token
,权限只需要 repo
就行,设置复制到 travis-ci
即可。
腾讯云 serverless
阿里云和腾讯云都提供免费的 serverless 服务,免费服务每个月有流量限制,不过完全够用,这里以腾讯云为例。
无服务器云函数地址:https:///product/scf
选择产品–基础–无服务器云函数–立即使用–函数服务–新建。
选择空白函数,运行环境选择 PHP
下一步,复制以下函数
<?php
function main_handler($event, $context) {
// 解析看云post的数据
$update_title = '';
if($event->body){
$kanyun_data= json_decode($event->body);
$update_title .= $kanyun_data->data->title;
}
// default params
$repos = 'xxxxxxxx'; // 你的仓库id 或 slug扩展名
$token = 'xxxxxxxxxxxxxxx'; // 你的登录token
$message = date("Y/m/d").':kanyun update:'.$update_title;
$branch = 'master';
// post params
$queryString = $event->queryString;
$q_token = $queryString->token ? $queryString->token : $token;
$q_repos = $queryString->repos ? $queryString->repos : $repos;
$q_message = $queryString->message ? $queryString->message : $message;
$q_branch = $queryString->branch ? $queryString->branch : 'master';
echo($q_token);
echo('===');
echo ($q_repos);
echo ('===');
echo ($q_message);
echo ('===');
echo ($q_branch);
echo ('===');
//request travis ci
$res_info = triggerTravisCI($q_repos, $q_token, $q_message, $q_branch);
$res_code = 0;
$res_message = '未知';
if($res_info['http_code']){
$res_code = $res_info['http_code'];
switch($res_info['http_code']){
case 200:
case 202:
$res_message = 'success';
break;
default:
$res_message = 'faild';
break;
}
}
$res = array(
'status'=>$res_code,
'message'=>$res_message
);
return $res;
}
/*
* @description travis api , trigger a build
* @param $repos string 仓库ID、slug
* @param $token string 登录验证token
* @param $message string 触发信息
* @param $branch string 分支
* @return $info array 回包信息
*/
function triggerTravisCI ($repos, $token, $message='kanyun update', $branch='master') {
//初始化
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, 'https:///repo/'.$repos.'/requests');
//设置获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//设置post方式提交
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
//设置post数据
$post_data = json_encode(array(
"request"=> array(
"message"=>$message,
"branch"=>$branch
)
));
$header = array(
'Content-Type: application/json',
'Travis-API-Version: 3',
'Authorization:token '.$token,
'Content-Length:' . strlen($post_data)
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
//执行命令
$data = curl_exec($curl);
$info = curl_getinfo($curl);
//关闭URL请求
curl_close($curl);
return $info;
}
?>
函数说明:
serverless
函数中参数的设置:
该函数只需修改以下两项:
$repos = 'xxx'; // 你的github仓库id 或 slug扩展名
$token = 'xxx'; // 你的travis-ci登录token
获取 travis-ci token
在 travis-ci
官网上点击右上角 Settings--Settings
,复制 token
仓库 ID 获取方法
方法 1,使用 curl 命令,注意需要 travis-ci token
以及 github
用户名称
curl -X GET \
https:///owner/替换成你的github用户名/repos \
-H 'apiexplore: 替换成你的token' \
-H 'cache-control: no-cache' \
-H 'travis-api-version: 3' \
-H 'user-agent: API Explorer'
方法 2,使用 postman
下载地址:https:///downloads/
用 postman
发个 GET
请求,填写 url
和 headers
参数
完成后添加触发方式,选择 API 网关触发器,其他默认,保存。
然后复制访问路径
看云配置
找一本想要实时同步到 github
的书,在文档钩子中添加 serverless
访问路径( webhook
地址) ,保存即可。
开始写书,提交到版本库,查看腾讯云 serverless
日志,提示调用成功:
查看 travis-ci
触发成功构建
查看 github
仓库,内容已经更新
小结
这篇文章中的 serverless
是云行业非常火的一个概念,不再需要服务器,不再需要写应用,只需要专注于函数就可以处理一些问题,大大的节约了成本,支持很多语言,可以自己下来研究下。
webhook
是非常棒的一种架构模式,不仅仅是可以用在代码仓库的同步中,也可以设计到你写的程序里,只要制定好规范,你的程序就可以通过配置调用/被调用,变得更像插件,其他系统对接的时候就更容易。
涉及资源
- 代码仓库 github
- 看云 [编程伐木累的技术小册
- travis-ci
- 腾讯云函数
引用
看云实时同步到 github
QA
Q:如果两端同时编辑,那怎么自动解决冲突合并问题,还是通过邮件通知开发人员去解决?
A:我也考虑过这个问题,如果同时对一个文件进行编辑,只有当同时提交的时候才会发生这个问题,首先是构建速度快,一般1分钟内就会同步完成,这个时候冲突会发生在提交成功前。
要是恰好在这 1 分钟内的,我是先pull
,再覆盖代码再push
,不会发生冲突,但是上一次提交记录会被覆盖掉。