こんにちは。製品事業部の近藤です。みなさんの現場ではHubotを活用されていますか?Hubotはプロジェクトの様々なことを自動的に解決してくれる優秀なロボットです。Hubotがチャットに常駐するだけで、こんなことを実現してくれるでしょう。
- 朝会やふりかえりの時間を教えてくれる
- Jenkinsおじさんにビルドやリリースをお願いしてくれる(ChatOps)
- チャットに流れたチケット番号から、そのタイトルとリンク先を教えてくれる
- GitHub等のチケットの状態をTrelloに反映してくれる
………ん?最後のTrac等のチケットの状態をTrelloに反映してくれる
という話はなんでしょう?そうなんです。Hubotは各サービスのHubとなり、プロジェクトの運営を円滑に進めてくれている存在なのです!今回はHubotが各サービスのHubとなり、ロボットとして大活躍している様子とその仕組みを紹介します。
robot.respond と robot.hear
Hubotに処理をお願いするには、大きく分けて2つのコマンドがあります。それがrobot.respond
とrobot.hear
です。
robot.respond
は、予めコマンドを登録しておき、下記のようにHubotに呼びかけることで処理を実行できるようにするものです。
Hubot> hubot ping
PONG
この例では、予め登録されていたping
コマンドをHubotが受け取り、PONG
とメッセージを返しています。
もう一つのrobot.hear
は、チャットに流れているメッセージを監視し、該当するメッセージがあった時に処理を行ってくれるものです。例えば朝会等でチケット番号だけで話をするメンバーがいて、その番号がなんなのか分からない事が個人的にとても困っておりました。せめてチャットの上ではそのチケット番号がなんのタスクなのか分かるようにしています。
メッセージの最後のTrac #777
にHubotが反応して、そのチケットがなんなのか要約をチャットにつぶやいています。この反応している部分がrobot.hear
です。
robot.hear /trac \#(\d+)(?=[^\w]|$)/ig, fetchTicket
robot.hear
の最初の引数が監視条件の正規表現、2つ目の引数が処理を実装した関数です。(Tracからチケット情報を取り出す処理であるfetchTicket
の解説は割愛します。興味のある方はリンク先のコードを読んでみてください。)
robot.hearを使ってサービス間連携を実現する
さて、見ての通り、Hubotはチャットに流れるメッセージ全てを監視しています。ということは、他のサービスから流れるメッセージを元に、Hubotに処理をさせることもできるはず。ということで、GitHub上のPull Requestのレビューの状態をTrelloに反映させたいなー、という妄想をモデル化し、下記のシーケンス図にしました。
厳密に言えば、IdobataとHubot間のメッセージの流れは複雑になりそうですが、モデル図なのでこれくらいで勘弁してください。GitHub上でPull Requestにラベルを付与するとIdobataに通知する流れは、それぞれのリポジトリでもOrganization全体でもWebHookの追加で対応できますよね。(英語のドキュメント)
idobataはGitHubからラベルの変更を受け取ると、次のようなメッセージを出力しています。
これは下記の意味を持つ文字列です。
ユーザー名 labeled ラベル名 to 対象のPR情報 issueのタイトル
astahチームではPRのタイトルにはrefs #6131 チケットのタイトル
というように、必ず修正したチケット番号とそのタイトルをつけています。(ここで登場するチケット番号はTracのものです。astahチームではいくつものリポジトリを扱うため、全体のバックログはTracで管理しています。この辺りの背景はまた次回以降お話させてください。)
今回の例ではrefs #6131
という部分です。正規表現を使って、このissueの番号を取得することができます。非常に簡略的ですが、/.*\s+labeled (\w+).*#(\d+).*/i
という正規表現で、1番目にマッチするのが対象のPR情報
、2番目がチケット番号
です。Trelloに登録しているカードも、同様にチケット番号 チケットタイトル
とつけています。すると、カードをチケット番号で検索し、つけられたラベルに該当するListに移動させることができるのです!
コードはこんな感じですね。
robot.hear /.*\s+labeled (\w+).*#(\d+).*/i,(msg)->
label = msg.match[1]
ticket_id = msg.match[2]
trello.get_board target_board_name,(err,board)->
if err
throw err
trello.get_list board, label.capitalize(), (err,list)->
if err
throw err
trello.get_cards_on_board board, (err,cards)->
for card in cards
re = /#(\d+).*/i
match = card.name.match(re)
if match
card_id = match[1]
if card_id == ticket_id
trello.move_card card, list, (err)->
if err
throw err
普段Javaをメインに使っているので、coffeescriptを綺麗に書く技術はないです。callbackで数珠つなぎになっているので、Promiseとか使って書いたほうがいいんでしょうか…。むずかしい。
Hubotはこういったサービス間で自動連携させたい時のHubになりうる存在であることがお分かりいただけたでしょうか?次回はastahチームの開発プロセスを紹介します。お楽しみに。
「astahチームの開発を支える技術(プロジェクトの様々なことを自働化するロボット Hubot編)」への2件のフィードバック