チャットデプロイしたい2018

タイトルの通り、チャットデプロイしたい。

  • 開発環境 masterブランチ
  • QA環境 deployment/qaブランチ
  • 本番環境 deployment/production ブランチ

自分のところは、上記みたいに環境とブランチがマッチングしていて、そのブランチにコミットなりマージするとCircleCIのほうでデプロイしてくれる。

例えば、開発環境でおおかた確認してQA環境に反映したいときはmasterからdeployment/qaにPRを作成しマージして、デプロイしてた。それめんどいので、そこをボットでやらせたいと思った。要はこうゆう感じ。

  1. slack上から任意の言葉でbotにデプロイを指示する
  2. slackのbotがGitHub APIでプルリクエスト作成・マージを実行する
  3. CircleCIがGAEにデプロイする

3.はもう出来てるので、1.2.を見てみよう。

1. Slack Bot

SlackのBotってどうやって作るんだっけなー、Hubotってあったよなーと思いつつ、今はBotkitが安定して開発されているっぽいからそれを使う。

Custom Integrations > Botsからボットを登録して、API Tokenを取得しておく。

あとは、レポジトリのexamplesディレクトリのなかにあるslack_bot.jsに先程のトークンを渡して起動させればおk。

controller.hears(['hello'], 'direct_mention', (bot, message) => {
    bot.reply(message, 'Hello!');
    // ここからGitHubのAPIを叩く
});

controller.hearsでなんか受け取って、それで反応してあげれば良いのが分かる。

2. GitHub Apps

まぁGitHubでゴニョゴニョしたいので、GitHub API v3を叩く。

Node.jsのAPIクライアントはoctokitがよさそうってことで使ったのだが、Authenticationがむずい、ドハマリした。

まず、いろいろ認証の仕方が多い。どれを選べばいいんだ!一番簡単なのはPersonal access tokensだったけど、これだと僕のアカウントでプルリクエストが作成され、マージされてしまう。やはりBotとして実行してもらいたいので、だめ。

これを読む限り、GitHub Appsがいちばんオサレそうなので、この方法でやってみる。 GitHub Appsとして認証するためには、まずJSON Web Tokenを作らないといけないらしい。

GitHubのドキュメント見ると、Rubyコードの例が書いてあるけど、Node.jsでやるにはどーしたらいいんだー!と悩んだあげく、こんな感じに書いた。

const fs = require("fs");
const jwt = require("jsonwebtoken");
const key = fs.readFileSync(`${__dirname}/private-key.pem`);
const opts = { algorithm: "RS256" };
const payload = {
  iat: Math.floor(Date.now() / 1000) - 30,
  exp: Math.floor(Date.now() / 1000) + 60 * 10,
  iss: YOUR_ISSUE_NUMBER
};
const jwtToken = jwt.sign(payload, key, opts);

まずはGitHubのWebからGitHubAppsを登録する。パーミッションの設定も忘れなく。

んでprivate-key.pemを生成しとく。それと、アプリの発行IDもその設定画面にあるのでメモっとく。あとは、jsonwebtokenというnpmを使って、トークンを生成する。

const octokit = require("@octokit/rest")({
  headers: {
    accept: "application/vnd.github.machine-man-preview+json",
    authorization: `Bearer ${jwtToken}`
  }
});
const installationToken = await octokit.apps.createInstallationToken({
  installation_id: YOUR_INSTALLATION_ID
});

んで、octokitを初期化するときに、headersに先程のJWTトークンをBearerのあとにひっつける。installation_idがなんぞやってことだけど、Appの設定のAdvancedでなんかアクセスがあるっぽいので、そこから知る。

octokit.authenticate({
  type: "integration",
  token: installationToken
});

んで、このinstallationTokenoctokit.authenticateに渡してようやくAPIが叩けるようになる。PR作成したかったらoctokit.pullRequests.create(opts)とか叩けばよい。すごく長かった。。。

Google Compute Engine

あとは、Botのメッセージをattachmentsを使うとボットっぽくてよい。成功失敗とかバーの色変えられるのでよい。

bot.reply(message, {
  attachments: [
    {
      fallback: "Success",
      color: "good",
      title: `#${result.number} ${result.title}`,
      title_link: result.html_url,
      text: "プルリクできたのだー:smirk_cat:"
    }
  ]
});

んで、いつもBotとかホストするのにherokuにホストしてたけど、最近GCPまわり触ってるからせっかくなので、GCEにホストした。

すごく簡単だった。

token=your_token nohup node slack_bot.js &

あとバックグラウンドでもプロセスを活かすためには、nohup [command] &と打てばよいと教えてもらった。ありがとう。