第4回までで、
定期実行で定時ミーティングの時間を通知する
デイリースクラムの時間を通知すると言った定期的な処理をHubotに行わせたい場合、
cronモジュールの導入
cronモジュールのようなnpmのモジュールを使用するには、package.
ファイルのdependencies
にモジュールの情報を追加します。
通常、dependencies
の項目は次のようになっています。
"dependencies": {
"hubot": ">= 2.6.0 < 3.0.0",
"hubot-scripts": ">= 2.5.0 < 3.0.0"
},
ここにcronモジュールを追加することでスクリプトからcron
モジュールを使用できるようになります。
"dependencies": {
"hubot": ">= 2.6.0 < 3.0.0",
"hubot-scripts": ">= 2.5.0 < 3.0.0",
"cron": ">= 1.0.4"
},
サンプルスクリプト
cronモジュールを使って月曜日から金曜日の午前11時にミーティングの開催を呼びかけるスクリプトの例を示します。
cronJob = require('cron').CronJob
module.exports = (robot) ->
cronjob = new cronJob('0 0 11 * * 1-5', () =>
envelope = room: "#chatroom"
robot.send envelope, "デイリースクラムを始めましょう @all"
)
cronjob.start()
![図1 cronを使ったサンプルスクリプトの実行例 図1 cronを使ったサンプルスクリプトの実行例](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_001.png)
見てのとおり、
注意点として、hear
やrespond
を使った発言方法ではmsg
オブジェクトのsend
メソッドなどを使いますが、robot
オブジェクトのsend
メソッドを直接使ってチャットルームに発言することになります。
send
メソッドの第一引数envelope
は発言先のチャットルームや発言対象のユーザの情報を格納したオブジェクトです。この例ではhubot-ircを使ってIRCの#chatroomチャンネルに発言することを想定しています。どのようなenvelope
が必要かは、Adapter
よって異なるため注意が必要です。
cronモジュールの詳しい使い方はリファレンスを参照してください。
永続化機能で投票結果を保存する
Hubotに何かを記憶させようとしたとき、brain
というインターフェースを通じて様々なストレージに情報を永続化できます。
本節では、
redis-brainによるRedis永続化機能の追加
Redisを使った永続化を行うには、
HubotとRedisを接続するには、redis-brain.
を有効化するためには、hubot-scripts.
でredis-brain.
を読み込み、
["redis-brain.coffee"]
#!/bin/bash
# redis://<host>:<port>[/<brain_prefix>]
export REDIS_URL=redis://127.0.0.1:6379/hubot
bin/hubot
このように設定すると、brain
から保存したデータを127.
サンプルスクリプト
brain
を使った永続化のサンプルとして、
module.exports = (robot) ->
KEY_SCORE = 'key_score'
getScores = () ->
return robot.brain.get(KEY_SCORE) or {}
changeScore = (name, diff) ->
source = getScores()
score = source[name] or 0
new_score = score + diff
source[name] = new_score
robot.brain.set KEY_SCORE, source
return new_score
robot.respond /list/i, (msg) ->
source = getScores()
console.log source
for name, score of source
msg.send "#{name}: #{score}"
robot.hear /^(.+)\+\+$/i, (msg) ->
name = msg.match[1]
new_score = changeScore(name, 1)
msg.send "#{name}: #{new_score}"
robot.hear /^(.+)--$/i, (msg) ->
name = msg.match[1]
new_score = changeScore(name, -1)
msg.send "#{name}: #{new_score}"
![図2 永続化機能を使ったサンプルスクリプトの実行例 図2 永続化機能を使ったサンプルスクリプトの実行例](/assets/images/dev/serial/01/hubot/0005/002.png)
brain
の詳細については、
HTTPリクエストを送ってURLからコンテンツを取得する
本節では、
scoped-http-clientの使用方法
Hubotには、Robot
クラスのオブジェクトとResponse
クラスのオブジェクトにscoped-http-clientのオブジェクトがセットされているため、GET
やPOST
でHTTPリクエストを送って結果を取得するだけなら新たなモジュールを追加する必要はありません。
URLを受け取って取得したHTML文字列をチャットに発言するサンプルを次に示します。
module.exports = (robot) ->
robot.respond /get (.*)/i, (msg) ->
url = msg.match[1]
msg.http(url).get() (err, res, body) ->
msg.send body
![図3 HTTPリクエストを送信するサンプルスクリプトの実行例 図3 HTTPリクエストを送信するサンプルスクリプトの実行例](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_003.png)
msg.ScopedClient
オブジェクトです。
scoped-http-clientの詳しい使い方は公式リファレンスを参照してください。
サンプルスクリプト
ここでは、
Node.
でスクレイピングするときには、
"cheerio": ">= 0.17.0"
cheerio = require 'cheerio'
module.exports = (robot) ->
robot.hear /(https?:\/\/.*)/i, (msg) ->
url = msg.match[1]
msg.http(url).get() (err, res, body) ->
$ = cheerio.load(body)
title = $('title').text()
msg.send title
![図4 titleタグを抽出するサンプルスクリプトの実行例 図4 titleタグを抽出するサンプルスクリプトの実行例](/assets/images/dev/serial/01/hubot/0005/004.png)
このように、
本節で紹介したscoped-http-clientはモジュールを追加しなくても使えるため手軽ではありますが、
Webサーバ機能を使って外部からのリクエストを待ち受ける
HubotはデフォルトでexpressによるWebサーバが立ち上がるようになっており、
注意点として、
本節では、
Webサーバ機能について
Hubotを起動すると、
hubot --create
したときに最初から使用可能になっているhttpd./hubot/
, /hubot/
, /hubot/
, /hubot/
, /hubot/
のルートが登録されます。
Hubotを起動した状態で、
$ curl --dump-header - http://127.0.0.1:8080/hubot/version HTTP/1.1 200 OK X-Powered-By: hubot/hubot Date: Thu, 03 Jul 2014 15:38:08 GMT Connection: keep-alive Transfer-Encoding: chunked 2.7.5
Hubotがデフォルトで待ち受ける8080番ポートが既に使用されている場合は、PORT
オプションを環境変数で指定することで待ち受けるポート番号を変更することができます。
では、/hubot/
へのリクエストを受け付けるコードを抜粋します。
robot.router.get "/hubot/version", (req, res) ->
res.end robot.version
robot.
がexpressのオブジェクトです。つまり、
express = require 'express'
app = express()
app.get "/hubot/version", (req, res) ->
res.end 'version string'
app.listen(8080)
httpd.
expressの具体的な使い方は、
GitHubのリポジトリに対するpushを通知するサンプルコード
実用的な例として、
GitHubには、
サンプルコードを次に示します。
module.exports = (robot) ->
say = (message) ->
envelope = room: "#chatroom"
robot.send envelope, message
ping = (payload) ->
say "GitHubからのpingを受信しました"
push = (payload) ->
repository = payload.repository
say "新しい差分がpushされました: #{repository['name']}"
for commit in payload.commits
say "commit: #{commit['message']}"
robot.router.post "/github/hook", (req, res) ->
# どのような種類のイベントかがリクエストヘッダにセットされています
event = req.headers['x-github-event']
# イベントの中身はリクエストボディにJSONで格納されています
payload = req.body
switch event
when "ping" then ping payload
when "push" then push payload
res.send 200
GitHubがイベントごとにどのようなデータを送ってくるかはリファレンスで一覧できます。サンプルでは、
今回のスクリプトは、
リポジトリの設定画面から
![図5 Webhook 図5 Webhook](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_005.png)
ここで、
![図6 Webhooksの設定例 図6 Webhooksの設定例](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_006.png)
簡単に試すだけなら、
では、
![図7 GitHubのリポジトリに対するpushを通知するサンプルコードの実行例 図7 GitHubのリポジトリに対するpushを通知するサンプルコードの実行例](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_007.png)
実際に使用する場合は、
Jenkinsのビルドの実行結果を通知するサンプルコード
もう1つの例として、
Jenkinsは、
GitHubのWebhooksと同様に、
module.exports = (robot) ->
say = (message) ->
envelope = room: "#chatroom"
robot.send envelope, message
robot.router.post "/jenkins/hook", (req, res) ->
headers = req.headers
payload = req.body
name = payload['name']
status = payload['build']['status']
say "[Jenkins] #{name} : #{status}"
res.send 200
動作を試すには、
![図8 Jenkinsの設定例 図8 Jenkinsの設定例](/assets/images/dev/serial/01/hubot/0005/thumb/TH800_008.png)
設定が反映されると、
![図9 Jenkinsのビルドの実行結果を通知するサンプルコードの実行例 図9 Jenkinsのビルドの実行結果を通知するサンプルコードの実行例](/assets/images/dev/serial/01/hubot/0005/009.png)
まとめ
本連載の最終回となる今回は、
本連載では、
本連載はこれにて終了しますが、