利用 github 的 webhooks 自動部署博客

可以搜索微信公眾號【Jet 與編程】查看更多精彩文章


一、背景

博客原是 WordPress 搭建的,由於某些個人無法接受的原因,準備轉成靜態博客,之前轉過,使用的是 HEXO,基本成功了,但是是部署在 github pages 上面的,如今準備部署在國內的阿里雲服務器上。

二、問題

使用 HEXO 搭建的博客平臺,進行寫博客的流程是:

1、本地使用 Markdown 編寫博客,2、本地編譯成 html 文件,3、將 html 文件上傳至服務器,一般免費的有 github page,gitee 等

所以此處需要改造的點其實很簡單,就是把 github 倉庫中的 html 文件全部下載至服務器上,然後利用 web 服務器做個反向代理即可,比如 nginx。

後續的部署流程:

1、本地寫完博客,編譯完成後上傳至 github 倉庫2、登陸到服務器上面進行 git update 操作

問題就此暴露出來了,每次寫完博客都要登陸下服務器去更新下 html 文件,我的天,這誰頂得住。

三、解決

於是自然而然想到了 git 倉庫的 web 鉤子,即當 git 倉庫收到 push 或者其他命令時,會自動調我們的鉤子程序(其實就是向我們指定的地址發送一個 post 請求),而我們只需要讓我們的這個程序去跟新下服務器上面的代碼(html 文件)即可。

流程示例圖見下圖:

利用 github 的 webhooks 自動部署博客

從上面可以出,我們只剩 2 件事需要做,一是配置下 github 的 webhook,二是在我們的服務器上寫一個 web 程序來處理 github 發送過來的請求。

1、webhook 配置

配置比較簡單,需要注意的是,秘鑰雖然是非必填的,但是最好還是加上,為了安全。

利用 github 的 webhooks 自動部署博客

請求的數據,每個平臺都不一樣,在此以 github 為例,數據內容見下圖:
注:請求頭中有一個很重要的簽名參數,該參數前部分為加密方式,後部分為的簽名,而明文就是我們在 webhook 中配置的秘鑰。這點很重要哦。

利用 github 的 webhooks 自動部署博客

2、程序編寫

寫一個簡單是 web 程序。

本人主要是編寫 java 代碼的,如果要用 java 來寫的話,比較麻煩,所以考慮選擇一款解釋性語言來編寫,其實用啥語言都無所謂啦,畢竟代碼處理邏輯很簡單,選用自己熟悉的就行,例如 Python、PHP、nodejs 等都行。

此處選擇的是使用 Python 來編寫,web 框架是比較輕量的 Flask,操作 git 使用的是 gitPython,所以需要安裝下:

pip install flask


pip install gitpython

代碼比較簡單,不多贅述,主要就是兩點:

1、簽名校驗


2、git update

詳細代碼如下:

from flask import Flask, request, Blueprint, jsonify, current_app
from git import Repo
import hmac

app = Flask(__name__)

@app.route("/api/github_hook", methods=['POST'])
def github_web_hook():

header_signature_origin = request.headers.get('X-Hub-Signature')
if header_signature_origin is None:
return '你沒有權限訪問!'


hash_type, header_signature = header_signature_origin.split('=')
if hash_type != 'sha1':
return '不支持的加密方式!'

secret = str.encode("http://www.jetchen.cn")

hashhex = hmac.new(secret, request.data, digestmod='sha1').hexdigest()
if hmac.compare_digest(hashhex, header_signature):
repo = Repo('/data/blog-test/blog.github.io/') # 獲取本地git倉庫
# repo = Repo('D:\\project\\mixed\\\\blog.github.io\\\\') # 獲取本地git倉庫
# origin = repo.remotes.origin # 獲取遠程庫 & 遠程分支
# origin.pull('--rebase') # 拉代碼
remote = repo.remote()
remote.pull('master')

if 'after' in request.json:
commit = request.json['after'][0:6] # pull 的最新的commit
print('Repository updated with commit {}'.format(commit))

else:
return '簽名校驗失敗!'

return jsonify({}), 200

if __name__ == "__main__":
app.run(port=8001)


分享到:


相關文章: