Hubot+HerokuでSlack用のリマインダーbotを作る


運用系の案件で、毎週公開するものなど、指定の日時に何らかの作業をしなければならないことが決まっていることが多く、そのためのリマインダーとしてGoogleKeepを使っていたりしましたが、せっかくなので自分でリマインダーを作ってみます。

## 0.今回利用するもの(Mac環境)
* yeoman
* Hubot(generator-hubotで生成)
* Heroku(& heroku toolbelt)
* redis

 redisを入れてなければ、`$ brew install redis` でHomebrewを使ってインストールしておく。


## 1.Hubotのインストール
Hubotの[公式サイト](https://hubot.github.com/docs/)を参照し、yeomanジェネレーターを利用して開発をしていく。

yeomanとhubotのyeomanジェネレーターをインストールするには、

~~~
$ npm i -g yo generator-hubot
~~~
を実行する。

インストールが終わったら、開発用ディレクトリに移動し、`$ yo hubot`を実行して、hubotを生成する。
生成時の質問項目の、Bot adapterにはslackを指定しておく。

~~~
? Bot adapter slack
~~~

この状態で、Hubotは使えるようになっています。
試しに、`./bin/hubot -a shell -n`でHubotを起動し、Hubotの機能を使ってみます。

~~~
$ ./bin/hubot -a shell -n

hubot ping
Hubot> PONG
hubot time
Hubot> Server time is: Mon Jan 18 2016 14:17:45 GMT+0900 (JST)
exit
~~~
終了するときは、`exit`を実行します。


## 2.Herokuの準備
Herokuの準備を始める前に、Herokuをコマンドラインから操作するために必要な、[heroku toolbelt](https://toolbelt.heroku.com/)をインストールしておきます。
また、[Heroku](https://www.heroku.com/)に会員登録していない場合は、公式サイトより登録しておきます。


Herokuの操作に必要なものがそろったら、コマンドラインからHerokuにログインします。

~~~
$ heroku login
~~~
登録しているメールアドレス、パスワードをそれぞれ入力するとHerokuにログインできます。
ログインしたら、Heroku上に今回作成するbot用のアプリを作成します。

~~~
$ heroku create [your-hubot-app-name]
~~~

Heroku上にアプリが作成できたら、Hubotの操作に必要なredisのHubot用のadd-onsをインストールする。今回は無料で利用できる[Redis To Go](https://elements.heroku.com/addons/redistogo)を利用する。
add-onsのインストールには、無料のものでもクレジットカード情報の入力が必要となるため、[https://heroku.com/verify](https://heroku.com/verify)より登録しておく。

~~~
$ heroku addons:create redistogo:nano
~~~

## 3.SlackにHubotを連携させる

[http://my.slack.com/services/new/hubot](http://my.slack.com/services/new/hubot) より、連携させるHubotの名前を入力すると、APIトークンが作成されます。

~~~
HUBOT_SLACK_TOKEN=[your hubot slack token]
~~~

このトークンをHerokuのconfigに書き込みます。

~~~
heroku config:set HUBOT_SLACK_TOKEN=[your hubot slack token]
~~~

続いて、デプロイに必要な`HUBOT_HEROKU_KEEPALIVE_URL`にHeroku上のURLを設定します。設定するURLは、

~~~
$ heroku apps:info
~~~
を実行して表示される、`Web URL`の値を指定すれば良い。

~~~
Web URL:       https://[your-bot-name].herokuapp.com/
~~~

## 4. デプロイする
Herokuに対してpushすることでデプロイが行われます。

~~~
$ git push heroku master
~~~

デプロイが完了すると、Slack上でも自分の作成したbotと会話できるようになります。

## 5.独自機能を実装する
Hubotは、`script`ディレクトリ以下にあるjsファイルをすべて実行する仕組みになっているので、`script`ディレクトリ配下にファイルを作成していきます。

まずは、試しに、こちらが入力したメッセージがヒットしたら、botが特定のメッセージを返す機能を実装してみます。

ファイル名はなんでも良いですが、今回は`respond.coffee`とします。
`respond.coffee`を`script`ディレクトリに配置します。

hiと入力したら、botにHiと答えさせるjsは以下のようになります。

~~~lang:respond.coffee
# Description:
#   respond Hi

module.exports = (robot) ->
  robot.respond /hi/i, (msg) ->
    msg.send 'Hi'
~~~

`# Description:`の部分は、記述がないとHubotの起動時にWarningが出るので記述しています。
ソースを見てなんとなく分かると思うのですが、Hubotの`respond`機能を使って、hiという文字が入力されたら、`msg.send`でHiと返しています。

coffeeScriptでなくても実行できます。

~~~lang:respond.js
// Description:
//  respond Hi

module.exports = function(robot) {
  robot.respond(/hi/i, function(msg) {
    msg.send('Hi');
  });
};
~~~

機能を作成したら、`git add .`→`git commit -am 'commit msg'`→`git push heroku master`の流れで、再度デプロイします。

## 6. リマインド機能を実装する
機能の追加方法が分かったので、いよいよ本題であるリマインド機能を実装していきます。
今回は、「毎週木曜日の午前11時」に「何かしらのメッセージ」を通知する機能を作成します。

まずは、リマインド機能に必要な定刻に通知をさせるため、cronをインストールします。

~~~
$ npm i cron --save
~~~

全体のソースは以下のようになります。

~~~lang:remindMeHungry.coffee
# Description:
#   Remind Me "Hungry..." Thursday, at AM11:00

cronJob = require('cron').CronJob # cronJobのの読み込み

module.exports = (robot) ->
  cronJob = new cronJob('00 00 11 * * 4', () ->
    envelope = room: "#general"
    robot.send envelope, "Hungry...!!!"
  )

  cronJob.start() # cronJobの実行
~~~

cronによるjobの設定は、`new cronJob('* * * * * *', function(){})`で行います。引数の`'* * * * * *'`には、左から、jobを実行させたい `秒`、`分`、`時`、`日付`、`月`、`曜日`を指定できます。`秒`、`分`、`時`、`日付`、`月`はそれぞれ2桁の整数を指定し、`曜日`には、0,1,2,3,4,5,6(日,月,火,水,木,金,土)を指定できます。複数指定する場合は、曜日であれば、1-5(月から金まで)や、1,3,5(月または水または金)のように指定ができます。

また、メンションを付ける場合は、メッセージの文字列に`@username: `を付けると個人に対してメッセージを送ることができます。
その他、グループに向けてメンションする場合は、 ＠channel→`<!channel>`、＠here→`<!here>`、＠everyone→`<!everyone>`として変換して使う必要があります。

~~~
module.exports = (robot) ->
  cronJob = new cronJob('00 00 11 * * 4', () ->
    envelope = room: "#general"
    mention = "@username: "
    robot.send envelope, mention + "Hungry...!!!"
  )

  cronJob.start() # cronJobの実行
~~~

ここまでで、機能の実装としてはこれで問題ないですが、Herokuのサーバー時刻が日本時間になっていない場合、意図した時刻にjobが走ってくれないので変更します。

~~~
$ heroku config:add TZ=Asia/Tokyo
~~~

変更できたら、`bash`を使い、heroku環境でコマンドが打てるようにしたら、`date`コマンドで確認できます。

~~~
$ heroku run bash


~ $ date
Thu Jan 21 13:06:41 JST 2016
~~~

これで指定時刻にリマインドが行われるはずです！