ProbotでGitHubのBotを作成してGlitchにデプロイしてみる

ProbotはGitHub Appsを作成するためのフレームワークです。 主な機能として、「GitHubのWebHookから送信された各イベントに対する処理」、「GitHubのAPI実行」を簡潔に記載することができます。
2018.05.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

GitHubを使う上で、チームによってローカルルールがある場合があると思います。これをみんなで守るためには、例えば啓蒙活動やレビューで頑張ることも一つの方法ですが、本質的には「そもそもルールを破れない状況を作る」ことが一番大切であるように思えます。

GitHubではBotを作成することができるので、ある程度GitHubの使い方に関するローカルルールをBotによって強制的に守らせることが可能です。

本記事では、「Issueを閉じる際にはラベルとマイルストーンが設定されていなければいけない」といったルールを守らせるためのBotをProbotで作成し、Glitchにデプロイしてみました。

本記事で行うこと

  • ProbotによるGitHubのBot作成
    • Issueをクローズした際にマイルストーンもしくはラベルが未指定の場合、Issueに注意コメントをつけた上で再度オープンする
  • ローカルでProbotによるアプリケーションを起動してテスト
  • Glitchにデプロイ

前提条件

  • ローカルでNode.jsが動作すること
    • 本記事ではv8.11.2で動作確認をしました

各要素の簡単な説明

Probot

ProbotはGitHub Appsを作成するためのフレームワークです。

主な機能として、

  • GitHubのWebHookから送信された各イベントに対する処理
  • GitHubのAPI実行

を簡潔に記載することができます。

Glitch

Glitchが本質的になんなのかについてはまだいまいち掴めていませんが、本記事ではGitHubと連携可能なエディタ兼Node.jsのPaaSとして使用しています。

ざっと見た感じではGitHubとPaaSの中間のようなサービスに見えますが、詳しくは公式をご覧ください。

参考:Glitch - The community where you'll build the app of your dreams

やってみる

Probot

プロジェクトの作成

以下のコマンドを実行し、Botの準備のための質問にいくつか答えるとProbotによるBotのためのテンプレートが作成されます。

test-inabaの部分には作成したいBotの名前を指定します。

$ npx create-probot-app test-inaba
npx: 226個のパッケージを10.752秒でインストールしました。

Let's create a Probot app!
? **App name:** test-inaba
? **Description of app:** A Probot app
? **Author's full name:** inabajunmr
? **Author's email address:** inabajun.for.regi@gmail.com
? **Homepage:**
? **GitHub user or org name:** inabajunmr
? **Repository name:** test-inaba

〜略〜
added 993 packages in 26.38s

Done! Enjoy building your Probot app!

完了すると指定した名前のディレクトリ配下にテンプレートが作成されます。

$ ls -la test-inaba
total 672
drwxr-xr-x 15 inabajunmr  staff 480  5 28 02:44 .
drwxr-xr-x 31 inabajunmr  staff 992  5 28 02:44 ..
-rw-r--r--  1 inabajunmr  staff 236  5 28 02:44 .env.example
-rw-r--r--  1 inabajunmr  staff  56  5 28 02:44 .gitignore
-rw-r--r--  1 inabajunmr  staff  81  5 28 02:44 .travis.yml
-rw-r--r--  1 inabajunmr  staff  3224  5 28 02:44 CODE_OF_CONDUCT.md
-rw-r--r--  1 inabajunmr  staff  1790  5 28 02:44 CONTRIBUTING.md
-rw-r--r--  1 inabajunmr  staff 772  5 28 02:44 LICENSE
-rw-r--r--  1 inabajunmr  staff 170  5 28 02:44 README.md
drwxr-xr-x  2 inabajunmr  staff  64  5 28 02:44 etc
-rw-r--r--  1 inabajunmr  staff 282  5 28 02:44 index.js
drwxr-xr-x  674 inabajunmr  staff 21568  5 28 02:44 node_modules
-rw-r--r--  1 inabajunmr  staff  304624  5 28 02:44 package-lock.json
-rw-r--r--  1 inabajunmr  staff 722  5 28 02:44 package.json
drwxr-xr-x  3 inabajunmr  staff  96  5 28 02:44 test

Botの設定

テストのためにsmee.ioを利用します。smee.ioで割り当てられたURLをGitHubのWebHookに指定することで、smee.io経由でローカルで起動したアプリケーションでリクエストを受け取ることができます。

Start a new channelをクリックするとWebhook Proxy URLが割り当てられるので、これをメモしておきます。

Register new GitHub Appから新規登録をします。

Webhook URLにsmee.ioで取得したWebhook Proxy URLを指定し、Webhook secretにdevelopmentを指定します。 PermissionsにはIssuesのRead&Writeを、Subscribe to eventsにはIssuesを指定します。

前者はBotからGitHubへのアクセス権限で、後者はWebHookを発火させるEventの指定となります。 作成後のページにIDが表示されるので、こちらもメモしておきます。

最後に、Generate a private keyから秘密鍵を生成し、プロジェクトのディレクトリ直下に配置します。

作成したらnpx create-probot-appで作成したディレクトリの.env.example.envにコピーし、編集します。

APP_IDにGitHubで取得したIDを、WEBHOOK_PROXY_URLにはsmee.ioで取得したURLを指定します。

$ cp .env.example .env
$ vi .env
$ cat .env
APP_ID=12729
WEBHOOK_SECRET=development
LOG_LEVEL=debug
WEBHOOK_PROXY_URL=https://smee.io/XXXXXXXX

Botの動作を編集します。index.jsを以下に修正します。

module.exports = (robot) => {
    // WebHookによって発火するイベントを定義(IssueのClose時に動作)
    robot.on('issues.closed', async context => {
        const exist_label = context.payload.issue.labels.length != 0;
        const exist_milestone = context.payload.issue.milestone != '';
        if (exist_label && exist_milestone) {
          // ラベルとマイルストーンが設定されていれば何もしない
          return;
        }
        const comment = context.issue({body: 'You must add milestone and label!'})
        // Issueにコメントを追加
        context.github.issues.createComment(comment)
        // Issueをオープンする
        const open = context.issue({state: 'open'})
        context.github.issues.edit(open)
    })
}

コメントの通りですが、構造的には「GitHubに対して何をすると、何が起きるか」です。 上記ではIssueが閉じたタイミングでスクリプトを実行し、ラベルとマイルストーンが設定されていなければIssueに「You must add milestone and label!」とコメントし、IssueをOpenします。

「何をすると」の部分、つまりWebHookの定義についてはこちらを参照してください。 例えばIssueそのものに対するイベントであればこちらが、Issueのコメントに対するイベントであればこちらとなります。

また、「何が起きるか」については単純にスクリプトを書いていけばいいのですが、GitHubのAPIについては@octokit/restによる操作が可能です。

詳細な定義はこちらを参照してください。 context.githubがoctokitのインスタンスとなります。

GitHubのリポジトリに作成したBotをインストールする

https://github.com/settings/apps/${xxxxx}/installations から作成したBotをインストールできます。${xxxxx}には作成したアプリ名を指定してください。

Installをクリックし、Botの適用範囲を指定します。

インストールできました。

起動する

以下でローカルにBotを起動できます。

$ npm run dev

起動した状態で、指定したリポジトリのIssueをラベル未指定のまま閉じてみます。

BotによるIssueへのコメントとIssueのオープンが確認できました。

Glitchにデプロイする

ProbotのチュートリアルではGlitch、Heroku、Nowへのデプロイがそれぞれ紹介されていますが、ここではGlitchへデプロイしてみます。

BotをGitHubのリポジトリに追加する

Glitchでデプロイする際にGitHub経由でアプリケーションを送るため、作成したBotをGitHubのリポジトリに追加します。

$ git remote add inabajunmr https://github.com/inabajunmr/test-inaba
$ git add .
$ git commit -m "initial"
$ git push --set-upstream inabajunmr master

Glitchの設定

こちらからGlitchのプロジェクトを作成します。GitHubアカウントでのサインインが可能です。

Advanced OptionsからGitHubへのアクセス権限を追加し、Import from GitHubでBotのリポジトリをインポートします。

リポジトリを指定します。

インポートできました。

プロジェクトの名前を変更します。

.envファイルを編集します。

APP_ID=12729
WEBHOOK_SECRET=XXXX
PRIVATE_KEY_PATH=.data/private-key.pem
NODE_ENV=production

APP_IDはローカルで指定した.envの内容と同様です。 WEBHOOK_SECRETは以下のコマンドで生成した値を指定しました。

$ openssl rand -base64 32

.data/private-key.pemを作成します。ファイルに先ほどダウンロードした秘密鍵をコピペします。

Showをクリックすると、デプロイされたアプリケーションにアクセスできます。

GitHub Appsの再設定

以下のURLからBotの設定画面を再度開きます。${xxxxx}には作成したアプリ名を指定してください。 https://github.com/settings/apps/${xxxxx}

先ほどdevelopmentと指定したWebhook secretに、新しく生成した値を指定し直します。

また、Webhook URLにGlitchのURLを指定します。今回の場合、https://test-inaba.glitch.meとなります。ShowからアクセスできるアプリケーションのURLから、/probotを無くしたものがWebhook URLとなります。

設定が完了したので、再度GitHubにてテストしたところ正常に動作することが確認できました。

まとめ

ProbotはGitHub Appsを作成するためのフレームワークです。

主な機能として、

  • GitHubのWebHookから送信された各イベントに対する処理
  • GitHubのAPI実行

を簡潔に記載することができます。

ProbotでGitHubのBotを作成し、Glitchでデプロイしてみました。 Probotの設定および実装は非常にシンプルにできており、Botの実装が簡単に行えそうです。

私からは以上です。

参考