CoffeeScript
Hubot
Slack
ibmcloud

Hubotを使ったSlackボットをIBM Cloudで動かす

Hubotを使用したSlackボットを作成し、IBM CloudのNode.js上で動かしてみました。Qiita上ではいくつか解説エントリーがあるのですが、環境の変更などの影響で記載されたとおりにやってもうまくいかない箇所がいつくかありましたので、内容的に重複しているものもありますが、私がやった手順をまとめました。

作成したもの

Slack上でRSS連携して購読している情報がUTC(Coordinated Universal Time)表記なのですが、JST(Japan Standard Time)に読み替えないと該非が分からず、毎回9時間加算する脳内変換をするのも面倒でした。そこで、時間(HH:MM)を含むメッセージが該当チャンネルに書き込まれたら、自動的に9時間加算した時間を書き込むようにしました。

スクリーンショット 2018-06-09 16.20.00.png

セットアップ

Node.jsとnpmはインストール済みの前提です。適当な作業ディレクトリ(仮に「hubot_slack」とします)を作り、移動した後に下記のコマンドを実行します。「yo hubot」を実行すると、ウィザードにいくつか質問されます。「Bot adapter」を「slack」と書く以外はおそらくデフォルトのままで、特に指定なしでも問題ないと思います。

Hubotセットアップ
$ mkdir hubot_slack
$ cd hubot_slack
$ npm install yo generator-hubot
$ yo hubot

? Owner John Doe <johndoe@test.com>
? Bot name hubot_slack
? Description A simple helpful robot for your Company
? Bot adapter slack

初期セットアップが終わりました。試しに起動してみます。いくつかメッセージで出力された中に、以下のメッセージが含まれていました。指示に従い「hubot-scripts.json」を削除します。また、今回はHerokuを使用する予定はないので、「HUBOT_HEROKU_KEEPALIVE_URL」を「external-scripts.json」から削除します(設定ファイル上は小文字表記でした)。

Hubotセットアップ
$ ./bin/hubot
Your hubot-scripts.json is empty, so you just need to remove it.
[Sat Jun 09 2018 16:39:55 GMT+0900 (JST)] ERROR hubot-heroku-keepalive included, but missing HUBOT_HEROKU_KEEPALIVE_URL. `heroku config:set HUBOT_HEROKU_KEEPALIVE_URL=$(heroku apps:info -s | grep web.url | cut -d= -f2)`
$ rm hubot-scripts.json 
$ vi external-scripts.json
変更後のexternal-scripts.json
[
  "hubot-diagnostics",
  "hubot-help",
  "hubot-google-images",
  "hubot-google-translate",
  "hubot-pugme",
  "hubot-maps",
  "hubot-redis-brain",
  "hubot-rules",
  "hubot-shipit"
]

UTCをJSTに変換するスクリプトの作成

Hubotではscriptsフォルダ以下のスクリプトを実行することができます。最初から「scripts/example.coffee」という処理例の記載されているスクリプトが存在するので、そのスクリプト下記の処理を追加しました。

「数字2桁」+「:」+「数字2桁」という組み合わせの文字の書き込みがあれば、その数だけfor文の処理を回します。このチャンネルに書き込まれる「HH:MM」表記の時間はUTCに統一されている前提なので、HHの値を単純に9時間加算をします。加算後の数字が24時を越えた場合は、overnightフラグを立てた上で24を減算し、時間は00〜23時に修正します。書き込むメッセージの作成時に、日付が変わっている(overnightフラグが立っている)場合は最後に「(Next Day)」と表記をつけました。

example.coffee
module.exports = (robot) ->
  robot.hear /[0123456789]{2}:[0123456789]{2}/g, (res) ->
    for time in res.match
      hours_and_minutes = time.split(":")
      hour = parseInt(hours_and_minutes[0]) + 9

      if hour >= 24
        overnight = true 
        hour = hour - 24

      if hour < 10
        hour = "0" + hour.toString()
      else
        hour = hour.toString()

      if overnight == true
        message = "[FYI] " + time + " UTC = " + hour + ":" + hours_and_minutes[1] + " JST (Next Day)"
      else
        message = "[FYI] " + time + " UTC = " + hour + ":" + hours_and_minutes[1] + " JST"

      if send_message
        send_message = send_message + "\n" + message
      else
        send_message = message

    res.send send_message

ローカルマシン上で動作テスト

Slack接続のセットアップをします。App Directoryから任意のワークスペースにHubotをインストールします。続いて、「Add Configuration」を実行し、ボットのUsername(仮に「utc2jst」とします)を設定し、「Add Hubot Integration」を実行します。そうするとSetup Instructionsの画面が表示されますので、その画面に表示されるAPI tokenを確認します。

API tokenの値をHUBOT_SLACK_TOKENに環境変数に定義します。Macのターミナルの場合は、exportコマンドで設定が可能です。

HUBOT_SLACK_TOKEN設定コマンド(例)
$ export HUBOT_SLACK_TOKEN=abcd-123456789012-345678901234-AbD5EfGhI67JkLmNOPQRStU

環境変数が設定できたので、Slackボットをローカルマシン上で実行します。

Slackボット実行
$ ./bin/hubot --adapter slack
[Tue Jun 12 2018 23:59:59 GMT+0900 (JST)] INFO Logged in as @utc2jst in workspace HOGE
[Tue Jun 12 2018 23:59:59 GMT+0900 (JST)] INFO Connected to Slack RTM
[Tue Jun 12 2018 23:59:59 GMT+0900 (JST)] INFO hubot-redis-brain: Using default redis on localhost:6379

SlackのAppに存在する「utc2jst」がactiveになっていることを確認し、Direct Messageで「12:34」などと話かけて、正しく変換結果を応答することを確認します。確認が完了したらアプリケーションを停止します。

IBM Cloudへのデプロイ

ローカルマシン上でSlackボットを実行し続けるのもつらいので、クラウド環境で動作させます。IBM Cloudライトアカウントであれば、Node.jsアプリケーションを試しに無料で実行出来ますので、IBM Cloudを使用します。IBM Cloudライトアカウントがない方はアカウントをセットアップしてください。

カタログの中からSDK for Node.jsのアプリケーションを作成します。任意のアプリケーション名(仮に「slack20180612」とします)、任意のホスト名(仮に「slack20180612」とします)を入力します。デプロイする地域・ロケーションの選択はどこでもいいのですが、このエントリーでは「米国南部」とします(ロケーションによってURLが少し変わります)。「組織名」と「スペース」はおそらく初期値のままで変更は必要ないと思いますが、あとでその情報を使用しますので、どのような値が設定されていたかはメモをしておいてください。必要な情報を入力・選択できたら「作成」ボタンを実行し、アプリケーション・ランタイムを作成してください。

IBM CloudのPaaSはCloud Foundryを採用していますので、アプリケーションのPush時にはmanifest.ymlを使用します。アプリケーションが存在するディレクトリにmanifest.ymlを配置します。nameとhostは一つ前のパラグラフの設定で指定したIBM Cloudのアプリケーション名とホスト名を、envのHUBOT_SLACK_TOKENは環境変数に設定したSlackのAPI keyと同じ値に修正してください。

manifest.yml
applications:
- path: ./
  memory: 256M
  instances: 1
  domain: mybluemix.net
  command: ./bin/hubot --adapter slack
  name: slack20180612
  host: slack20180612
  disk_quota: 1024M
  env:
    HUBOT_SLACK_TOKEN: abcd-123456789012-345678901234-AbD5EfGhI67JkLmNOPQRStU

IBM Cloudにローカルのnode_module以下をPushするとアプリケーションが正常起動できませんので、同じディレクトリに「.cfignore」というファイルを作成し、「node_modules」とだけ書いておいてください。このファイルによりIBM CloudへのアプリケーションPush時にnode_modules以下は対象から除外されます。

.cfignore
node_modules

準備ができたのでIBM Cloudにアプリケーションをデプロイします。IBM Cloud CLIの指示に従い、IBM Cloud CLIをインストールし、IBM Cloudにコマンドライン接続します。「bx target -o 組織名 -s スペース名」は先ほどNode.jsのアプリケーション・ランタイムを作成した際に指定した「組織名」と「スペース」を指定してください。「bx cf push(もしくはbx app push)」でmanifest.ymlに指定されたアプリケーション・ランタイムに対してアプリケーションをデプロイします。

アプリケーションのデプロイが完了し、起動が完了したら、Slackでボットに接続し、Direct Messageで動作確認後、チャンネルにボットを招待します。これにより、該当チャンネルに「12:34」と書くと、「[FYI] 12:34 UTC = 21:34 JST」と変換結果を書き込んでくれます。

参考ページ