Github Webhook

Hexo部落格自動部署 (2)

接續先前關於登入git的文章
在能夠進行pull和deploy之後,接下來就是要如何在有push發生的時候自動deploy。研究了一下Travis和Github的API發現Github有提供Webhook可以使用,下面就來說說怎麼把App跟Github用webhook接起來。

成品: http://hexo.sasdf.cf
因為不用重跑npm install的關係,部署時間短了1分半左右。

Step1: Creating WebHooks

在repo的設定中找到Webhooks,輸入接收訊息的app網址,選擇接收的時候用的格式(json),然後隨機產生一串足夠長的Secret,之後選擇想要接收的event。
addwebhook.png

Step1(Alt): Github API & OAuth

Github也有提供一套完整的API可供使用,不過會需要用OAuth驗證,程式寫起來比較麻煩一些。
參見Github API - Webhooks

Step2: Handling events

設定好Webhook之後就要來實作剛剛輸入接收訊息的那部分。其中Header的X-Hub-Signature是用剛剛輸入的Secret作為鑰匙計算payload的HMAC sha1。這簽名可以用來確認request是從Github傳來的。然後Payload的ref和Header的X-GitHub-Event可以用篩選要處理的事件。

app.post('/webhook', bodyParser.json({
    verify: function(req, res, buf){ // 確認簽名是正確的
        var signatureHeader = req.get('X-Hub-Signature').split('=');
        if(signatureHeader[0] !== 'sha1') console.log('Warning: Unsupported Cipher Algorithm '+signatureHeader[0]);
        var hmac = crypto.createHmac('sha1', webhookSecret);
        hmac.update(buf);
        var sign = hmac.digest('hex').toLowerCase();
        if(signatureHeader[1] !== sign){ // 簽名不符合
            var e = new Error(signatureHeader[1]+' !== '+sign);
            e.name = 'Signature Mismatch';
            e.status = 400;
            e.statusCode = 400;
            throw e;
        }
        req.signature = sign; // 簽名符合,如果post沒有payload的話並不會執行verify函式,值為undefined。
        return true;
    }
}), function(err, req, res, next){ // Error Handler
    console.log(err.toString());
    res.status(400).send('Rejected!');
    return;
}, function(req, res){ // Event Handler
    if(!req.signature){ // 沒有傳送Payload
        res.status(400).send("Invalid Format");
        return;
    }
    var event = req.get('X-GitHub-Event').toLowerCase();
    if( event === "push"){
        if(req.body.ref === "refs/heads/" + devBranch){ // 重新Deploy
            res.status(202).send(event+" OK!");
            Deploy();
            return;
        }
    }
    res.status(202).send(event+" SKIPPED!"); // 預設回傳值
})

參見Github Developer - Webhooks