序章

複数の開発者がいるプロジェクトで作業している場合、ある人がリポジトリにプッシュしてから、別の人が古いバージョンのコードに変更を加え始めると、イライラする可能性があります。 このような間違いには時間がかかるため、リポジトリの同期を維持するためのスクリプトを設定する価値があります。 この方法を実稼働環境に適用して、修正プログラムやその他の変更をすばやくプッシュすることもできます。

この特定のタスクを完了するための他のソリューションが存在しますが、独自のスクリプトを作成することは、将来のカスタマイズの余地を残す柔軟なオプションです。

GitHub を使用すると、リポジトリの webhooks を構成できます。これは、イベントが発生したときにHTTPリクエストを送信するイベントです。 たとえば、Webhookを使用して、誰かがプルリクエストを作成したり、新しいコードをプッシュしたりしたときに通知を受け取ることができます。

このガイドでは、あなたまたは他の誰かがコードをGitHubにプッシュするたびに、GitHubWebhook通知をリッスンするNode.jsサーバーを開発します。 このスクリプトは、リモートサーバー上のリポジトリを最新バージョンのコードで自動的に更新し、新しいコミットをプルするためにサーバーにログインする必要をなくします。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • Ubuntu 16.04初期サーバーセットアップガイドに従ってセットアップされた1つのUbuntu16.04サーバー。これには、sudo特権を持つ非rootユーザーとファイアウォールが含まれます。
  • Gitがローカルマシンにインストールされています。 チュートリアルオープンソースへの貢献:Git入門に従って、コンピューターにGitをインストールしてセットアップすることができます。
  • Ubuntu 16.04 にNode.jsをインストールする方法で説明されているように、公式PPAを使用してリモートサーバーにインストールされたNode.jsとnpm。 ディストリビューション安定バージョンをインストールするだけで、追加の構成なしで推奨バージョンが提供されます。
  • プロジェクトコードを含むGithub上のリポジトリ。 プロジェクトを考えていない場合は、チュートリアルの残りの部分で使用するこの例フォークしてください。

ステップ1—Webhookを設定する

まず、リポジトリのWebhookを構成します。 この手順がないと、Githubは、問題が発生したときに送信するイベントや、それらを送信する場所を認識できないため、重要です。 最初にWebhookを作成してから、その要求に応答するサーバーを作成します。

GitHubアカウントにサインインし、監視するリポジトリに移動します。 リポジトリのページの上部メニューバーにある設定タブをクリックしてから、左側のナビゲーションメニューのWebhookをクリックします。 右隅にあるWebhookの追加をクリックし、プロンプトが表示されたらアカウントのパスワードを入力します。 次のようなページが表示されます。

Webhooks Page

  • ペイロードURLフィールドに、http://your_server_ip:8080と入力します。 これは、まもなく作成するNode.jsサーバーのアドレスとポートです。
  • コンテンツタイプapplication/jsonに変更します。 作成するスクリプトはJSONデータを想定しており、他のデータ型を理解することはできません。
  • シークレットには、このWebhookのシークレットパスワードを入力します。 Node.jsサーバーでこのシークレットを使用してリクエストを検証し、リクエストがGitHubからのものであることを確認します。
  • このWebhookをトリガーするイベントの場合は、プッシュイベントのみを選択します。 プッシュイベントのみが必要です。これは、コードが更新され、サーバーと同期する必要があるためです。
  • アクティブチェックボックスを選択します。
  • フィールドを確認し、Webhookの追加をクリックして作成します。

pingは最初は失敗しますが、Webhookが構成されているので安心してください。 それでは、リポジトリをサーバーに複製してみましょう。

ステップ2—リポジトリをサーバーに複製する

スクリプトはリポジトリを更新できますが、最初にリポジトリの設定を処理できないため、ここで更新します。 サーバーにログインします。

  1. ssh sammy@your_server_ip

ホームディレクトリにいることを確認してください。 次に、Gitを使用してリポジトリのクローンを作成します。 sammyをGitHubユーザー名に、hello_hapiをGithubプロジェクトの名前に置き換えてください。

  1. cd
  2. git clone https://github.com/sammy/hello_hapi.git

これにより、プロジェクトを含む新しいディレクトリが作成されます。 次のステップでこのディレクトリを使用します。

プロジェクトのクローンを作成したら、Webhookスクリプトを作成できます。

ステップ3—Webhookスクリプトを作成する

GitHubからのWebhookリクエストをリッスンするサーバーを作成しましょう。 ポート8080でWebサーバーを起動するNode.jsスクリプトを記述します。 サーバーはWebhookからのリクエストをリッスンし、指定したシークレットを確認して、GitHubから最新バージョンのコードをプルします。

ホームディレクトリに移動します。

  1. cd ~

NodeWebhooksという名前のWebhookスクリプト用の新しいディレクトリを作成します。

  1. mkdir ~/NodeWebhooks

次に、新しいディレクトリに移動します。

  1. cd ~/NodeWebhooks

NodeWebhooksディレクトリ内にwebhook.jsという名前の新しいファイルを作成します。

  1. nano webhook.js

次の2行をスクリプトに追加します。

webhook.js
var secret = "your_secret_here";
var repo = "/home/sammy/hello_hapi";

最初の行は、ステップ1で作成したシークレットを保持する変数を定義し、リクエストがGitHubからのものであることを確認します。 2行目は、ローカルディスクで更新するリポジトリへのフルパスを保持する変数を定義します。 これは、ステップ2でチェックアウトしたリポジトリを指しているはずです。

次に、httpおよびcryptoライブラリをスクリプトにインポートするこれらの行を追加します。 これらを使用してWebサーバーを作成し、シークレットをハッシュして、GitHubから受け取ったものと比較できるようにします。

webhook.js
let http = require('http');
let crypto = require('crypto');

次に、child_processライブラリを含めて、スクリプトからシェルコマンドを実行できるようにします。

webhook.js
const exec = require('child_process').exec;

次に、このコードを追加して、GitHub Webhookリクエストを処理し、本物のリクエストの場合はコードの新しいバージョンをプルダウンする新しいウェブサーバーを定義します。

webhook.js
http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

http.createServer()関数は、Githubからの着信リクエストをリッスンするポート8080でWebサーバーを起動します。 セキュリティ上の理由から、リクエストに含まれているシークレットが、手順1でWebhookを作成したときに指定したシークレットと一致することを検証します。 シークレットはx-hub-signatureヘッダーでSHA1ハッシュ文字列として渡されるため、シークレットをハッシュして、GitHubから送信されたものと比較します。

リクエストが本物の場合、シェルコマンドを実行して、git pullを使用してローカルリポジトリを更新します。

完成したスクリプトは次のようになります。

webhook.js
const secret = "your_secret_here";
const repo = "~/your_repo_path_here/";

const http = require('http');
const crypto = require('crypto');
const exec = require('child_process').exec;

http.createServer(function (req, res) {
    req.on('data', function(chunk) {
        let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex');

        if (req.headers['x-hub-signature'] == sig) {
            exec('cd ' + repo + ' && git pull');
        }
    });

    res.end();
}).listen(8080);

サーバーの初期設定ガイドに従った場合は、ポート8080でトラフィックを許可することにより、このWebサーバーが外部Webと通信できるようにする必要があります。

  1. sudo ufw allow 8080/tcp

スクリプトが配置されたので、正しく機能していることを確認しましょう。

ステップ4-Webhookをテストする

nodeを使用してWebhookをテストし、コマンドラインで実行できます。 スクリプトを開始し、ターミナルでプロセスを開いたままにします。

  1. cd ~/NodeWebhooks
  2. nodejs webhook.js

Github.comのプロジェクトのページに戻ります。 リポジトリのページの上部メニューバーにある設定タブをクリックしてから、左側のナビゲーションメニューのWebhookをクリックします。 手順1で設定したWebhookの横にある編集をクリックします。 次の画像に示すように、最近の配信セクションが表示されるまで下にスクロールします。

Edit Webhook

右端の3つのドットを押すと、再配信ボタンが表示されます。 ノードサーバーが稼働している状態で、再配信をクリックしてリクエストを再送信します。 リクエストを送信することを確認すると、正常な応答が表示されます。 これは、pingを再配信した後の200 OK応答コードによって示されます。

これで、スクリプトがバックグラウンドで実行され、起動時に開始されることを確認できます。 CTRL+Cを使用すると、ノードのWebhookサーバーが停止します。

ステップ5—SystemdサービスとしてのWebhookのインストール

systemd は、Ubuntuがサービスを制御するために使用するタスクマネージャーです。 起動時にWebhookスクリプトを開始し、systemdコマンドを使用して他のサービスと同じように管理できるようにするサービスをセットアップします。

新しいサービスファイルを作成することから始めます。

  1. sudo nano /etc/systemd/system/webhook.service

次の構成をサービスファイルに追加して、systemdにスクリプトの実行方法を指示します。 これにより、Systemdにノードスクリプトの場所を通知し、サービスについて説明します。

必ずsammyを自分のユーザー名に置き換えてください。

/etc/systemd/system/webhook.service
[Unit]
Description=Github webhook
After=network.target

[Service]
Environment=NODE_PORT=8080
Type=simple
User=sammy
ExecStart=/usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

新しいサービスを有効にして、システムの起動時に開始されるようにします。

  1. sudo systemctl enable webhook.service

次に、サービスを開始します。

  1. sudo systemctl start webhook

サービスが開始されていることを確認します。

  1. sudo systemctl status webhook

サービスがアクティブであることを示す次の出力が表示されます。

Output
● webhook.service - Github webhook Loaded: loaded (/etc/systemd/system/webhook.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2018-08-17 19:28:41 UTC; 6s ago Main PID: 9912 (nodejs) Tasks: 6 Memory: 7.6M CPU: 95ms CGroup: /system.slice/webhook.service └─9912 /usr/bin/nodejs /home/sammy/NodeWebhooks/webhook.js

これで、新しいコミットをリポジトリにプッシュして、サーバー上の変更を確認できるようになりました。

デスクトップマシンから、リポジトリのクローンを作成します。

  1. git clone https://github.com/sammy/hello_hapi.git

リポジトリ内のファイルの1つに変更を加えます。 次に、ファイルをコミットして、コードをGitHubにプッシュします。

  1. git add index.js
  2. git commit -m "Update index file"
  3. git push origin master

Webhookが起動し、変更がサーバーに表示されます。

結論

新しいコミットをリモートリポジトリに自動的にデプロイするNode.jsスクリプトを設定しました。 このプロセスを使用して、監視する追加のリポジトリーをセットアップできます。 リポジトリをプッシュするときに、Webサイトまたはアプリケーションを本番環境にデプロイするように構成することもできます。