實現github的自動鈎子
最近在學習go,也寫了一些玩具放到自己的服務器中,但是感覺每次寫完在本地交叉編譯后上傳到服務器略顯麻煩,上傳代碼到服務器中編譯也是略顯麻煩,把編譯文件加入到git管理中會導致git包變大,拉取代碼變慢,特別是神秘之牆的存在會導致拉取github代碼很慢,所以就實現了一下github的自動鈎子,在服務器上自動編譯並完成自動部署,記錄一下實現的過程。
實現服務端
首先,我們需要准備一個供webhook調用的服務端,我這里用go實現了一個demo,更多功能請參考官方文檔
webhook 其實就是每當接受到push的時候,會向我們注冊的url中發送一條post請求,請求中的參數可以參考webhook的文檔。
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os/exec"
"strings"
)
const Secret = "AxkkeqzADO8WjkBT"
const HookShell = "/data/hook.sh"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
//我們這里只接收json的請求體
if contentType := r.Header.Get("content-type"); contentType != "application/json" {
throwError(w, "not json")
return
}
bytes,err := ioutil.ReadAll(r.Body)
if err != nil {
throwError(w, fmt.Sprintln("body err", err))
return
}
//首先應該對secret進行校驗
signature := r.Header.Get("X-Hub-Signature")
if len(signature) <= 0 {
throwError(w, "signature empty")
return
}
hash := hmac.New(sha1.New, []byte(Secret))
hash.Write(bytes)
sign := "sha1=" + hex.EncodeToString(hash.Sum(nil))
if strings.Compare(sign, signature) != 0 {
throwError(w, "signature error")
return
}
var body map[string]interface{}
if err := json.Unmarshal(bytes, &body); err != nil {
throwError(w, fmt.Sprintln("Unmarshal err", err))
return
}
//body里就已經獲取到我們想要的數據了, 在這里我們只拿取push的分支,更多參數參考可以參考文檔
ref, ok := body["ref"].(string)
if !ok {
throwError(w, "!ok")
return
}
//拿到的ref:refs/heads/master,我們只需要把前面截掉,就是我們想要的分支名
branch := strings.TrimLeft(ref, "refs/heads/")
//我們這里只對master分支進行自動部署
if branch != "master" {
w.WriteHeader(200)
_,_ = w.Write([]byte("not update"))
return
}
//我這里的部署是運行一個shell腳本,我們可以在這里寫自動更新和部署的邏輯
if err := exec.Command(HookShell).Run(); err != nil {
w.WriteHeader(500)
_,_ = w.Write([]byte("deploy error"))
}
})
_ = http.ListenAndServe(":49999", nil)
}
func throwError(w http.ResponseWriter, msg string) {
w.WriteHeader(400)
_,_ = w.Write([]byte("bad request. " + msg))
}
配置webhook
部署完成后,我們需要在倉庫中添加一個webhook
在webhooks配置中,需要輸入鈎子的url,content-type這里我選擇application/json,secret這里是你的密鑰,然后我這里只需要對push操作進行響應。