本文原創首發於 https://coding3min.com/1194.html
之前在看雲上專門搞了個電子書來歸檔和協作一些文章,支持 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://git.kancloud.cn/coding3min/coding3min.git
#github倉庫地址:
GH_REPO=https://github.com/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 user.email "[email protected]"
git config --global user.name "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://cloud.tencent.com/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://api.travis-ci.org/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://api.travis-ci.org/owner/替換成你的github用戶名/repos \
-H 'apiexplore: 替換成你的token' \
-H 'cache-control: no-cache' \
-H 'travis-api-version: 3' \
-H 'user-agent: API Explorer'
方法 2,使用 postman
下載地址:https://www.getpostman.com/downloads/
用 postman
發個 GET
請求,填寫 url
和 headers
參數
完成後添加觸發方式,選擇 API 網關觸發器,其他默認,保存。
然後複製訪問路徑
看雲配置
找一本想要實時同步到 github
的書,在文檔鉤子中添加 serverless
訪問路徑( webhook
地址) ,保存即可。
開始寫書,提交到版本庫,查看騰訊雲 serverless
日誌,提示調用成功:
查看 travis-ci
觸發成功構建
查看 github
倉庫,內容已經更新
小結
這篇文章中的 serverless
是雲行業非常火的一個概念,不再需要服務器,不再需要寫應用,只需要專注於函數就可以處理一些問題,大大的節約了成本,支持很多語言,可以自己下來研究下。
webhook
是非常棒的一種架構模式,不僅僅是可以用在代碼倉庫的同步中,也可以設計到你寫的程序裏,只要制定好規範,你的程序就可以通過配置調用/被調用,變得更像插件,其他系統對接的時候就更容易。
涉及資源
- 代碼倉庫 github
- 看雲 [編程伐木累的技術小冊
](https://www.kancloud.cn/coding3min/coding3min/1748607)
引用
QA
Q:如果兩端同時編輯,那怎麼自動解決衝突合併問題,還是通過郵件通知開發人員去解決?
A:我也考慮過這個問題,如果同時對一個文件進行編輯,只有當同時提交的時候纔會發生這個問題,首先是構建速度快,一般1分鐘內就會同步完成,這個時候衝突會發生在提交成功前。
要是恰好在這 1 分鐘內的,我是先pull
,再覆蓋代碼再push
,不會發生衝突,但是上一次提交記錄會被覆蓋掉。