Botkitを利用してSlack上の発言からGitHubのIssueを作成するBotを作る

## はじめに
いい加減趣味でも仕事でも、Slack上からGithubのissueを作成できたほうが、エンジニアにとっても、Githubを使わない立場の人達にとっても幸せだなぁ。と思ったので、せっかくなので作ってみることにしました。

## Botkitとは？
Slackが開発した、Node.jsベースのChatbotの開発フレームワークです。
普段は割りと案件の規模感なんかにマッチした技術選定をするのですが、今回は趣味ベースかつただのBotだったので、「どうせ作るならHubotより新しいBotkitで！」とミーハーな理由で選定してみました。

# 要件定義

ひっそりとバイト先のチームなんかでも需要がありそうだったので、聞いてみると以下の要件がベストかなーと感じました。

## 動作要件

今回はテストということもあって、そこまで複雑にする意義もないのでシンプルに以下の仕様で決定。

* Slackで"Create Issue"を含む投稿があれば検知して動作
* 1行目に"Create Issue"と書くと決め打ち、2行目にタイトル、3行目を本文とする
* 現状ユースケースとなる場所がバグ報告需要ばかりなので、ラベルは特に設けない

## 技術要件

こちらもシンプルに以下で決定。

* Botkit
* Node.js(6.xに環境を定めて、ES2015決め打ちでBabeらない)
* GithubのAPIはPersonal Access Tokenを使用
* Herokuで動いてほしい

# 完成品

![https://i.gyazo.com/43834a5afff51e6301393331e86d90d4.gif](https://i.gyazo.com/43834a5afff51e6301393331e86d90d4.gif)

こんな感じでよく動いてくれるBotができました。
コードはGitHub上に上がっているので、気になる人はのぞいてみてください。
https://github.com/potato4d/bk-slack-to-gh-issue

# 開発のポイント

また、今回開発していく中で、基本的なBotkitの使い方をQiitaにあげておくと、あとでやる人が便利そうだなぁと思ったので共有しておきます。

## Botkitの導入方法

まずはBotkitの導入方法から。
といっても、1分もあれば完了します。

![screencaptureslack-com-apps-new-A0F7YS25R-bots-1469649738760.png](https://qiita-image-store.s3.amazonaws.com/0/75633/300d5df4-0ae3-4ed2-16b6-bc33cb4a631b.png)
[https://[your-team-name].slack.com/services/new/bot](https://[your-team-name].slack.com/services/new/bot) (your-team-nameは適宜書き換え)
にアクセスし、使いたいBotのIDを設定するだけで基本的な設定は完了。

![screencaptur-slack-com-services-B1VPE1XGU-1469649757860.png](https://qiita-image-store.s3.amazonaws.com/0/75633/c92194b4-c957-436b-8f40-038e5adb2f59.png)
その後、アクセストークンが発行されるので控えておきます。
(今回は不正利用対策のため、API Tokenのところを消していますが、この部分に本来はトークンが表示されます)

これでもうBotkitを利用する準備が整いました。
次は実際にBotに発言をさせてみます。

## 基本的なBotkitの使い方

まずは基本的なBotkitの使い方から。
[Botkitのリポジトリ](https://github.com/howdyai/botkit)から落としてくる方法も、Coolで素晴らしいのですが、ミニマリストには似合わなかったので最低限の環境を構築しました。

ここまで大仰なことをしなくても、`npm install`だけで導入可能です。

```bash:terminal
$ npm i -S botkit
```

そうして、基本的なEchobotの作成も、以下のような10行程度の簡潔なコードで利用が可能となります。

```javascript:index.js
const Botkit = require("botkit");
const bot = Botkit.slackbot({
	debug: false
});

bot.spawn("直前で取得したアクセストークンを貼り付ける").startRTM();

bot.hears("(.*)",["ambient","mention"], (bot, message) => {
	bot.reply(message, message.text);
});
```

簡単流れを解説すると、Botkitを`require`したあと、`Botkit.slackbot`メソッドでBotkit自体を初期化。
`bot.spawn`メソッドで実際のTeam上で動くようにします。
その後、`bot.hears`メソッドを設定。ここではあらゆる投稿に反応して、`bot.reply`メソッドでオウム返しをするようになっています。

<img width="380" alt="スクリーンショット 2016-07-28 5.07.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/1a71d119-5bc9-3c41-16f9-dd382880dbd3.png">
こんな風に、どんな投稿にも律儀に返事をしてくれます。

## 特定のワードを検知してGitHubにIssueを建てるまで

さて、簡単な説明でしたが、上のコードを少し改変するだけでIssue用のテンプレートが作成できるので、作っていってみます。

ここでしたいのは、具体的に以下となります。

- - -

1. "Create Issue"という文字列が含まれているかを判定したい
2. それを行ごとに区切っていきたい
3. 区切ったデータをGitHubに投げたい

- - -

まずは1.2から解決していってみます。

### 1. "Create Issue"という文字列が含まれているかを検知したい

先程のサンプルを見るとわかるかと思いますが、Botkitのhearsの第一引数には正規表現の利用が可能となっています。

なので、ここでは`"(Create Issue)"`というシンプルなパターンでマッチさせてやると、"Create Issue"が含まれる投稿のみへの返信が可能となります。

ここではソースコードは以下となります。

```javascript:index.js
const Botkit = require("botkit");
const bot = Botkit.slackbot({
	debug: false
});

bot.spawn("直前で取得したアクセストークンを貼り付ける").startRTM();

bot.hears("(Create Issue)",["ambient","mention"], (bot, message) => {
	bot.reply(message, message.text);
});
```

<img width="438" alt="スクリーンショット 2016-07-28 5.14.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/ff980a90-ecdc-389d-6642-60caace97545.png">

これで"Create Issue"が含まれる投稿のみを検知するようになりました。
正規表現については、説明が難解になりがちなので省きますが、`(任意のワード)`と書くことで、任意のワードが含まれる投稿を検知することができるようになります。

### 2. 1.を行ごとに区切っていきたい

こちらも特に難しい処理を必要とせず、検知した投稿文字列が`message.text`に含まれているため、それを改行コード(`\n`)で区切ってやるだけになります。

区切りには`split`関数を用いて、適当な変数に格納。それを調理していくこととします。
試しにここでは、1行目だけを返信するようにしてみます。

```javascript:index.js
const Botkit = require("botkit");
const bot = Botkit.slackbot({
	debug: false
});

bot.spawn("直前で取得したアクセストークンを貼り付ける").startRTM();

bot.hears("(Create Issue)",["ambient","mention"], (bot, message) => {
	bot.reply(message, message.text.split("\n")[0]);
});
```

<img width="393" alt="スクリーンショット 2016-07-28 5.19.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/905e765b-71e4-2449-9a16-74b82678a0d7.png">

OKですね。2行目が省かれています。

### 3. 区切ったデータをGitHubに投げたい

最後です。こちらはソースコードが少々複雑になるため、全て書かれたコードは[GitHubのもの](https://github.com/potato4d/bk-slack-to-gh-issue)を閲覧していただくこととして、ここではおおまかな流れを解説いたします。

#### GitHubのアクセストークンの取得

<img width="999" alt="スクリーンショット 2016-07-28 6.19.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/8137870d-e3a5-db9b-c7c9-17718a8077fd.png">

まずはGitHub側のトークンの取得から。
https://github.com/settings/tokens/new にアクセスし、適当に権限を与えた後、Generateを押します。
生成が完了すると、トークンが出てきますが、一度しかでてこないため、控えておいてください。

#### 実際の流れまで

さて、準備が完了したので、最後の手順を消化していきます。全体の処理の流れとしては、以下のようになります。

1. これまでのコードを利用して"Create Issue"を検知する
2. 検知した時に、`api.github.com`上の、Issue作成のAPIを`POST`で叩く
3. 完了次第、`bot.reply`メソッドで完了もしくは失敗を通知する

1, 3番は既にやっていることなので、2番についてのみ取り扱います。
先ほど取得したトークンでベーシック認証を用いて、下記のURLをHTTP `POST`メソッドで叩きます。
また、ここにはformDataとして、URLの下に記載されているJSONを送信する必要があります。

URL: `http://user@token:api.github.com/repos/:user/:reponame/issues`

```json:formData
{
    "title": "Issueの題名",
    "body" : "IssueのDesciption"
}
```

これらを`request`モジュールを用いて送ることで、Issueの作成が完了いたします。
このようにして、GitHub上にIssueを作成することが出来ました。
これが完了次第、`bot.reply`メソッドを送信してみてください。

```js:request.js
request({
		url:"http://user@token:api.github.com/repos/:user/:reponame/issues"
		method: "POST",
		json: true,
		headers: {
			"Content-Type":"application/json",
			"User-Agent": "UA(必須)"
		},
	}, (err, res)=>{
	if(err){
		console.log(err);
		return false;
	}
	return res;
});
```

#### 完成した場合のサンプル

Qiita上に全てのソースコードを載せるのは不可であったため、GitHub上にあるコードの場合の結果のスクリーンショットとなります。

<img width="462" alt="スクリーンショット 2016-07-28 5.46.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/39d7eff8-89c9-7195-19fb-beddaf842286.png">

<img width="777" alt="スクリーンショット 2016-07-28 5.47.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/75633/040bd801-1b75-b294-18f7-f85c8937bedd.png">

# まとめ

以下は実際やってみたまとめです。

## 所感

Botkitは非常に簡単にSlackを経由するBotが作成できていい感じですね。今回の場合は`Botkit`の名前だけ知っている状態で、かつGitHubのAPIトークンも使ったことがなく、1から作る場合でも1時間程度で済んだので気軽に初められました。
最近はこう大きなサービスを作らなくても、各所から提供されているAPIを利用すれば、普段の生活を少しだけ幸せにしてくれるプログラムは簡単に書くことが出来ます。

こういったツール群は、すぐに大仰なボイラープレートを使おうとして、まずそこの理解から始まったりしますが、本当はそこまでやらなくても、普段のプログラミングレベルだと十分扱えますので、まずは気軽に初めて見ることをおすすめします。

## 技術的まとめ

* Botとしてのユースケースなら、ボイラープレートよりむしろフルスクラッチのほうが楽かも
* GitHub APIは資料があまり多くなく、Qiitaにも閲覧のAPIを叩いているものばかりで、あまり投稿には触れていないため、公式のAPIドキュメントを読みながらやるのがオススメ
* Botkitと聞くと新しそうな反面、中身はI/Oと変わらないので難しい概念は特に無かった