利用 github 的 webhooks 自動(dòng)部署博客

原文發(fā)布于自己的博客平臺(tái)【http://www.jetchen.cn/github-webhooks/


背景

博客原是 WordPress 搭建的,由于某些個(gè)人無(wú)法接受的原因,準(zhǔn)備轉(zhuǎn)成靜態(tài)博客,之前轉(zhuǎn)過(guò),使用的是 HEXO,基本成功了,但是是部署在 github pages 上面的,如今準(zhǔn)備部署在國(guó)內(nèi)的阿里云服務(wù)器上。

問(wèn)題

使用 HEXO 搭建的博客平臺(tái),進(jìn)行寫博客的流程是:

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

所以此處需要改造的點(diǎn)其實(shí)很簡(jiǎn)單,就是把 github 倉(cāng)庫(kù)中的 html 文件全部下載至服務(wù)器上,然后利用 web 服務(wù)器做個(gè)反向代理即可,比如 nginx。

后續(xù)的部署流程:

1、本地寫完博客,編譯完成后上傳至 github 倉(cāng)庫(kù)
2、登陸到服務(wù)器上面進(jìn)行 git update 操作

問(wèn)題就此暴露出來(lái)了,每次寫完博客都要登陸下服務(wù)器去更新下 html 文件,我的天,這誰(shuí)頂?shù)米 ?/p>

解決

于是自然而然想到了 git 倉(cāng)庫(kù)的 web 鉤子,即當(dāng) git 倉(cāng)庫(kù)收到 push 或者其他命令時(shí),會(huì)自動(dòng)調(diào)我們的鉤子程序(其實(shí)就是向我們指定的地址發(fā)送一個(gè) post 請(qǐng)求),而我們只需要讓我們的這個(gè)程序去跟新下服務(wù)器上面的代碼(html 文件)即可。

流程示例圖見(jiàn)下圖:

流程示例圖

從上面可以出,我們只剩 2 件事需要做,一是配置下 github 的 webhook,二是在我們的服務(wù)器上寫一個(gè) web 程序來(lái)處理 github 發(fā)送過(guò)來(lái)的請(qǐng)求。

1、webhook 配置

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


webhook 配置

請(qǐng)求的數(shù)據(jù),每個(gè)平臺(tái)都不一樣,在此以 github 為例,數(shù)據(jù)內(nèi)容見(jiàn)下圖:
注:請(qǐng)求頭中有一個(gè)很重要的簽名參數(shù),該參數(shù)前部分為加密方式,后部分為的簽名,而明文就是我們?cè)?webhook 中配置的秘鑰。這點(diǎn)很重要哦。

webhook 請(qǐng)求示例圖

2、程序編寫

寫一個(gè)簡(jiǎn)單是 web 程序。

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

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

pip install flask
pip install gitpython

代碼比較簡(jiǎn)單,不多贅述,主要就是兩點(diǎn):

1、簽名校驗(yàn)
2、git update

詳細(xì)代碼如下:


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 '你沒(méi)有權(quán)限訪問(wèn)!'
        
    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倉(cāng)庫(kù)
        # repo = Repo('D:\project\mixed\\blog.github.io\\') # 獲取本地git倉(cāng)庫(kù)
        # origin = repo.remotes.origin # 獲取遠(yuǎn)程庫(kù) & 遠(yuǎn)程分支
        # 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 '簽名校驗(yàn)失??!'
        
    return jsonify({}), 200
    
if __name__ == "__main__":
    app.run(port=8001)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容