JavaScript
Node.js
GitHub

Node.jsサーバーでGitHubhook受け取ってpushだけで簡単にページ反映させる

前提条件

  • Node.js 多分v6以上かつ、
  • GitHubhookを受け取れるサーバーがある
  • npm initはもうしてる場所
  • GithubのDeployKeyはもちろん通してある

本文

PHPとかはいっぱいあるのにNode.jsのサンプルあんまない!:sweat:
github-webhook-handlerを使うとちょー簡単です!! ただ、Buffer.fromを内部で使ってるので4系とか古いNode.jsでは動かない。。。です多分。。。:sleeping:

ということでぱぱっとインストール

$ npm install github-webhook-handler -S

サンプルコード

とりあえずログまで取るようにしてる適当なサンプルコードです。
github-webhook-handlerのerr.messageはJsonなので、それに習ってlogは全部Jsonに揃えとくと綺麗かも。
execでコールバックが山なりになってますが、exec-thenとか使うともっと綺麗になるかもですね〜〜:blush:

github-webhook-handler.js
'use strict';

const logFilePath = './github-webhook.log';
const PORT = '7777';
const SECRET = process.env.WEBHOOK_SECRET || 'secret'; // ソース上にsecretがあるのはあれなので環境変数にしておくと良いかもっていう
const REPOSITORY_NAME = 'hoge'; // よしなに変えて
const errorMessages = {
    noMatch: 'not match repository or branch'
};

const fs = require('fs');
const http = require('http');
const exec = require('child_process').exec;
const createHandler = require('github-webhook-handler');
const handler = createHandler({
    path: '/webhook',
    secret: SECRET
});

const writeLog = (data) => {
    fs.appendFileSync(logFilePath, data+"\n", (err) => {
        if (err) {
            writeLog(JSON.stringify({error: err})+"\n");
            throw err;
        }
    });
}

http.createServer((req, res) => {
    handler(req, res, function (err) {
      res.statusCode = 404;
      res.end('no such location');
    })
  }).listen(PORT);

handler.on('error', (err) => {
    writeLog(err.message);
});

handler.on('push', (e) => {
    const payload = e.payload;
    const repoName = payload.repository.name;
    const branch = payload.ref.split("/").pop();
    let log = {
        pull: {
            error: '',
            stdout: ''
        },
        restart: {
            error: '',
            stdout: ''
        }
    };

    // リポジトリの確認とmasterが更新されたらっていう判断
    if (repoName !== REPOSITORY_NAME && branch !== 'master') {
        writeLog(JSON.stringify({ error: errorMessages.noMatch }));
        return;
    }

    // んで最後に反映する処理をよしなに書いておく...
    exec('git pull origin master', (err, stdout, stderr) => {
        if (err) { log.pull.error = err }
        log.pull.stdout = stdout;
        writeLog(JSON.stringify(log));

        exec('npm install', (err, stdout, stderr) => {
            if (err) { log.pull.error = err }
            log.pull.stdout = stdout;
            writeLog(JSON.stringify(log));

            exec('forever restart app.js', (err, stdout, stderr) => {
                if (err) { log.restart.error = err }
                log.restart.stdout = stdout;
                writeLog(JSON.stringify(log));
            });
        });
    });
});

これでGitHubhookのpushでhostname:7777/webhookを叩くようにしておけばページが反映されそうですね。
んでとりあえず死ぬと困ると思うのでデーモン化して起動しとこうかな...:innocent:

$ npm install -g forever
$ WEBHOOK_SECRET=hogehoge forever start github-webhook-handler.js

オチ

やっぱCIツール使いましょう:smiley: