バックエンド(Spring Boot)にAzure Application Insightsを入れてリクエストを計測してみた

Spring Bootって何?

もう書かなくてもいいんじゃないかな?? (誰に言われたわけでもないけど)

https://projects.spring.io/spring-boot/projects.spring.io

導入方法

前回同様、GitHubにあったSpring Frameworkのサンプルアプリpetclinicを使い、Azure Application Insights を使用した Java Web アプリの分析 | Microsoft Docs を見ながら導入した。 最初の一歩を開発元が用意してくれてるのありがたい。

petclinicはSpring Framework定番のサンプルアプリっぽい。コミュニティで色んな派生アプリを作っている模様。

github.com

コード

GitHubに置いてみた。

https://github.com/nobiinu-and/spring-petclinic-rest/tree/monitoring-request

変更点はここで確認できる。

https://github.com/spring-petclinic/spring-petclinic-rest/compare/master...nobiinu-and:monitoring-request

試行錯誤したところ

  • Application Insightsのログを出せるようにした
  • Application InsightsのInstrumentation Keyを外出しした

Application Insightsのログを出せるようにした

Application Insightsの設定ファイルに以下を加えれば良い。

    <SDKLogger>
        <Type>CONSOLE</Type>
    </SDKLogger>

思いつきだったのに、探すの結構苦労した...orz

Application InsightsのInstrumentation Keyを外出しした

環境変数 "APPLICATION_INSIGHTS_IKEY" で指定すれば、勝手に読み込んでくれるので、修正点はなし。

Application Insights SDK は、次の順序でキーを探します。
システムのプロパティ: -DAPPLICATION_INSIGHTS_IKEY=your_ikey
環境変数: APPLICATION_INSIGHTS_IKEY
構成ファイル: ApplicationInsights.xml

見えるようになったもの

ガイドにあるようなデータが取れてる。

f:id:couger:20171126133739p:plain

f:id:couger:20171126133744p:plain

残ってる課題

SQLとかの実行時間知りたい

Azure Application Insights における依存関係の追跡 | Microsoft Docsを見ると、SQLの実行時間なども分析してるんだけども...。追加の設定が必要なのかな?

Performance monitoring for Java web apps in Azure Application Insights | Microsoft Docs この辺が参考になりそう。Agentを別立てする必要がありそうなので、今回はパス。

出力しているログも分析したい

Azure Application Insights を使用した Java トレース ログの探索 | Microsoft Docsに書いてあった。 logbackの設定を変更すればいいらしい。

参考にしたページ

フロントエンド(Angular)にAzure Application Insightsを入れてページビューを計測してみた

Angularって何?

Angular Docs

Angularは、Googleオープンソースコミュニティで開発されているJavaScriptフレームワークです。 AngularJSと呼ばれていたバージョン1(AngularJS 1)から、バージョン2で大きく変更されて、以降はAngularと呼ばれています。 バージョン2時点では「Angular 2」と呼ばれることもありましたが、現在はAngularが正式名称です。
JavaScriptフレームワーク「Angular」新バージョン4の変更点と今後の展望 (1/3):CodeZine(コードジン) より引用。

会社のとあるチームの人たちが使ってるんだけど、最近モニタリングに取り組み始めて、Applicaiton Insightsを使ってる。
個人的にもやらないとなーと思いつつ、手がつけられてなかったので、ちょうどいい機会だからのっかった感じ。

導入方法

手頃なアプリがなかったので、GitHubにあったSpring Frameworkのサンプルアプリpetclinicを使い、Add Application Insights to an Angular SPA – Premier Developer を見ながら導入した。

petclinicはSpring Framework定番のサンプルアプリっぽい。コミュニティで色んな派生アプリを作っている模様。

github.com

マイクロサービス版もある!! Kubernetes + Istioの練習するときに使ってみよう :D

コード

GitHubに置いてみた。

github.com

変更点はここで確認できる。

Comparing spring-petclinic:master...nobiinu-and:monitoring-owner-list · spring-petclinic/spring-petclinic-angular · GitHub

試行錯誤したところ

  • webpackをインストールした
  • logPageViewの引数を指定した
  • Application InsightsのInstrumentation Keyを外出しした

webpackをインストールした

基本、インストールはREADMEの手順に沿って行う。
最後の ng serve でエラーが起きた(メモ忘れたので詳細がわからん)ので、npm install --save-dev webpack をして、webpackをインストールして解決。

logPageViewの引数を指定した

logPageViewはtrackPageViewをラッパーしたもの。
引数を指定しない場合、Application Insightsはページ名にWindowのタイトルを利用する。
サンプルアプリはページごとにWindowのタイトルが変わらないので、コンポーネントの名前を入れてみることにした。
コンポーネント(クラス)の名前は this.constructor.name で指定できる。

Application InsightsのInstrumentation Keyを外出しした

KeyをGitHubで晒すのもなぁと思った(というか、晒してたので慌てて削除した)ので、 Angular 4 で Connection String や Secret を Environment Variables から取得する - Qiitaを参考に外出し。

残ってる課題

全ての画面を対象にする

Add Application Insights to an Angular SPA – Premier Developer にも書かれてるけど、記載されている方法だとコンポーネントごとにコードを記述する必要がある。
コンポーネントの基底クラスを作って、そっちで処理しろって書いてあるんだけど、なんか面倒。

以下のような感じで、ルーティングの NavigationStart イベントを使っても処理できるかもしれない?
(画面名がコンポーネント名の代わりにURLになっちゃうんだけども)

export class AppComponent {

  constructor(router: Router, private myMonitoringService: MyMonitoringService) {
    router.events
    .filter((event) => event instanceof NavigationStart)
    .subscribe((event: NavigationStart) => {
      this.myMonitoringService.logPageView(event.url);
    });
  }
}

一応実装してみた。動いてはいる模様。

Comparing monitoring-owner-list...monitoring-using-router-events · nobiinu-and/spring-petclinic-angular · GitHub

ただ、この方法だとルートガードでキャンセルされた場合(実際に画面遷移しなくても)計測してしまう。
キャンセルされた場合の話を考えるといろいろ難しくなりそうなので、これで置いとくことにする。(別途、キャンセルしたことを通知すればいい気も)

Durationで計測されているのはどの処理なのか?

画面の切り替えは1秒以内で行われているんだけど、Durationで計測されてる時間は2秒以上かかってた。
ちなみに、バックエンドからデータを取ってくる時間は含まれていない(バックエンドの処理に細工して、5秒sleepさせたけど、その時間は含まれなかった)。
処理時間は参考程度にしておくって手もあるんだけど、なんかモニャモニャする。

参考にしたページ

Azure Application Insightsを入れてページビューを計測してみた

Application Insightsって何?

Azure Application Insights とは何か | Microsoft Docsを引用してみる。

Application Insights は、複数のプラットフォームで使用できるWeb 開発者向けの拡張可能なアプリケーション パフォーマンス管理 (APM) サービスです。 このサービスを使用して、実行中の Web アプリケーションを監視することができます。 パフォーマンスに異常があると、自動的に検出されます。 組み込まれている強力な分析ツールを使えば、問題を診断し、ユーザーがアプリを使用して実行している操作を把握できます。

AWSで言うと"CloudWatch"に当たるらしく、主にメトリクスの採取に使うらしい。
ページビューを計測するために適当なのかはよくわかんないけど、まぁいいんですよ!

AWSとAzureのサービス名対比表 | Ryuzee.com

導入方法

何が取れるか、どう取ればいいのかわからなかったので(マニュアルを読もう)、まずは計測したいページだけに入れてみて、取れたデータを眺めることにした。

Application InsightsをBasicプランで作成し、あとはGitHub - Microsoft/ApplicationInsights-JS: Microsoft Application Insights SDK for JavaScriptを見ながらページにJavaScriptを仕込めば良い。

ちょっと試行錯誤して、最終的に入れ込んだスクリプトは以下。

<script src="ai.0.js"></script>
<script type="text/javascript">
    var snippet = {
        config: {
            instrumentationKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
        }
    };
    var init = new Microsoft.ApplicationInsights.Initialization(snippet);
    var appInsights = init.loadAppInsights();
    appInsights.setAuthenticatedUserContext("ユーザID");
    appInsights.trackPageView("ページ名");
</script>

以下、試行錯誤したところ。

Include AI JS SDK script and initialize statically を使ってApplication Insightsを入れた

Use JS snippet and initialize dynamically (download full Application Insights script from CDN) の方がお手軽なんだけど、 以下のAuthenticatedUserIdを指定する方法がわからなかったので、こちらに。

ファイルは npm install applicationinsights-js を実行、node_modules/applicationinsights-js/dist にできる ai.0.js を使った。
ai.0.js はminifyしたヤツ。minifyしてないのは ai.js になる。

setAuthenticatedUserContextを使ってユーザIDを指定した

Facebookで以下のことを教えてもらったので、ユーザIDを指定することにした。
ありがとう! ボッチエンジニアの人!!!

ai.js とかが発行するuserIdはCookieに保存されてるので、その生存期間が過ぎたり、異なるブラウザからアクセスすると、同一ユーザーであってもApplication Insights 上では別ユーザー扱いになっちゃうんです。 なので、認証を終えたら、authenticated user id を付けてあげると、そういった問題が解決できるそうです。

trackPageViewの引数を指定した

引数を指定しない場合、Application Insightsはページ名にWindowのタイトルを利用する。
サイトのタイトルが長くて、結果画面が見づらかったので、カスタマイズすることにした。
最初から作るサイトであれば、こういうところも考慮に入れてタイトルどうするか考えた方がいいのかな?

見えるようになったもの

こんなのが見えるようになった。

f:id:couger:20171125105757p:plain

f:id:couger:20171125105944p:plain

個人的にはほったらかしてたエラーが分析されるようになって、「直さなきゃ」ってモチベーションが生まれた。

f:id:couger:20171125112345p:plain

気になる料金

価格—Application Insights | Microsoft Azure によると、今回適用したBasicプランでは、

  • 1GB/月までは無料
  • それ以降は234.6円/GB
  • データは90日間保持される。蓄積したデータをエクスポートしたい場合は51円/GB。

ということなので、まぁほぼお金かからない。助かる。

参考にしたページ

github.com

まずはここ。
APIリファレンスは同じサイトのApplicationInsights-JS/API-reference.md at master · Microsoft/ApplicationInsights-JS · GitHubにある。

Mob Programming の体験ができる/事例発表があるイベント

気が向いたら更新。

これから

体験できる

事例発表など

終わったもの

体験できる

事例発表など

Mob Programming のエントリまとめ (リンクだけ)

いちいち探すの面倒なので、まとめておこう。 ひとまずリンクだけ。

インタビュー

考察とか

動画

やってみた

やってみた @ Agile Japan 2017

やってみた @ DevLove関西

やってみたじゃないイベント

ツール

【デンパ】 人間の業を肯定し、得体のしれないモチベーションを使ってアジャイルと付き合う

Joy,Inc.の強烈でまっすぐな「たーのしー!!」と、インフルエンザウィルス、けものフレンズに脳みそがやられた結果、貯めに貯め込んだ色んなものがスパークしまくって、いろいろつながったらしく、ずーっと追いかけてた答えみたいなものが出てきたので、忘れないために書いておく。

超個人的なものなので、適用範囲は狭い。というか、オレ専用。 傍流 of 傍流。光と闇のはざま。フツーの人は来ちゃいけないところのハズ。

後、いくつかの少ない経験と所詮本質の掴めないニワカが集めた情報から導き出された理屈なので、これでいいのか良く分かんない。 ついでに、ここに書いてるストーリ通りに物事が動いたかというと、かなり怪しい。自分の理屈のために事実を捻じ曲げてることは十分にありえる。記憶の改ざんなんてラクショーだもんね。

まぁ、こんなこと考える必要があるのはオレだけだし、すがるものも他に見つからないから、これを使って実験することにする。

スッキリしたこと

大きく2つ。これを続ければ、オレはうまくアジャイルと付き合える(ハズだ)。

  • 良く分かんないモチベーションを大事にする
  • 人間の業を肯定し、それを使って、人の役に立つロールを見つける

良く分かんないモチベーションを大事にする

続けるためにはモチベーションが必要だ。

ただ、オレには使命感みたいなのがない。会社が、組織が、お客様が。とか、そういうのがない。 危機感もない。かなりのんびりしている。あとで大事になって慌てるタイプだ。できないやつの典型。

どっちもない人はどうすればいいんだろう? オレは、良く分かんないモチベーションを使うことにした。なんかわかんないけど、夢中でやっちゃうやつ。 自分の中の理屈はわからないんけど、感じてることは分かる「たのしー」「すげー」「さすがー」

  • パイプライン作るのたのしー!!
  • ツール使ったら、こんなに簡単になるんだ、すげー!!
  • 達人ってこんな本読んでるんだ、さすがー!!

そういうの。(ちょっと強引?)

実は最後のは説明できる。達人に憧れるけど、近づけないので、せめて同じものに触れようとしてるのだ。涙ぐましい。 それやる時間があるなら、スキルを身に着ける訓練して、達人に近づけばいいんだけど、なにせ、オレなので、そんなことはしない。 しても続かない。ここに業がある。

業の話は置いといて、まぁそういう原初的な感情を使ってモチベーションを上げて、続けることにした。 これにはアップダウンが起きるという副作用があるんだけど、そこは人間だし仕方ないよねーってことにしてフタをする。 とあるマンガによれば、たゆまぬ鍛錬により「エンドルフィンどばどば」を常態化させることができるらしいので、そっちに行くのもありかもしれない。

人間の業を肯定し、それを使って、人の役に立てるロールを見つける

アジャイルは達人のノウハウが凝縮されている。これでもかってくらいギトギトに。 奴らは、マネジメント、エンジニアリング、マインドセット全方向で攻めてくる。さすが達人だ。逃げ場は用意されてない。

一方、オレは弱い人間だ。「気が散りやすい」「自分を中心に考える」「思慮が浅い」「苦手なことは後回し」「続けるの苦手」「危機感知能力が低い」辺りは標準装備。 売上? KPI? 何それ? 自分がやってることすら、意図を説明するのに一苦労、っていうより、上手く説明ができない。 説明できないから企画も立てられない、なので、必然的に予算も取れない。いつもスカンピンだ。(まぁそれで訓練されるものもあるんだけど)

こういう人間がアジャイラーを目指すと、間違いなく挫折する。能力を獲得するために必要な鍛錬ができないからだ。やってるうちに飽きちゃうし。

最初は真面目にアジャイルなエンジニアになろうともがいてたんだけど、苦しいばっかで旨みがない。 それでも何かになりたくて、あっちこっちうろついてたんだけど、まぁ、訓練できない人は何にもなれない。 ひたすら情報だけが貯まっていくだけの日々。しかし、なれない人には使う機会もない。

バッドエンドまっしぐらだったんだけど、45歳になってとある教育を受けたとき、このまま情報ため込んで爆死はちと寂しいと考えるようになり、 長期間に渡り情シスさんのDevOpsの取り組みを手伝い、また、自分でも色んな助けを借りながら社内勉強会を長く続けてきたこと、 さらに会社でも共創というキーワードが流行り始め、アジャイルに興味がある人が増えてきたのもあって、オレのポジションがなんとなーく分かってきた。

自分自身がアジャイラーになることは一旦諦めて、そっちに向かう人に、自分が持ってる情報をパスする役 になればいいのである。

ロール「情報を渡す人」として自分を見れば、

  • 「気が散りやすい」は、「いろんなところに足を運び、情報を取って来る」
  • 「自分を中心に考える」は、「いろんなものを自分のこととして考えられるので、情報にオレなりの解釈を1つ加えて出すことができる (つっても無駄なのも多いんだろうけど)」
  • 「思慮が浅い」は、「ざっくり合えばいいやくらいで、情報をライトに送れる」
    • 相手にとって迷惑かどうかはオレにはわからんないのだ。マジ。当たらないと思ったことが当たったりするし、その逆もあるしで。

と、弱みがプラスに変わるのだ。 強引? だって、そう思い込まなきゃ、この先やってらんないだもん。 オレが動ければいいんだから、自分の脳みそをある程度の騙せる理屈と体験さえあればいいのだ。(この辺が自分中心)

そうそう。体験は大事。 社内でオレの雑な情報の渡し方でも喜んでくれる、返事を返してくれる人と出会えたのは、非常にありがたかった。

隣の人は聞き上手で、さらに、水どうと、デイリーポータルZが好きという、オレにとってヒジョーに話しやすい人だったのである。そーとー話聞いてもらった。マジ感謝。

コミュニティはチャットで会話をするようになったのがデカい。オレの思考の垂れ流しをスルーしてくれる人たちで助かった。(もちろん返事もしてもらった。沢山)

そういう人たちに情報を何回も渡すことで、こっちもだんだん情報の渡し方に慣れていくことができた。 感謝。感謝。感謝のメッセージ1万本とか言ったら怒られそうだし、オレもそんなに出せない。

情シスさんとは2年という、オレにとっては非常に長い期間お付き合いをさせていただいている。 長いから、たまに、前に出した情報が、時間が経った後にヒットするなんてことがある。 そういう経験を通じて、以前より待つこともできるようになった。犬でも「待て」ができるのに、なぜオレにはできなかったのか。犬以下。

まとめ

そんなこんなで、色んな意味で弱い人間のオレが、その業を克服することなく、なんとかアジャイルと付き合う方法は、

  • 良く分かんないモチベーションを大事にする
    • 「使命感、危機感」を感じないのを負い目にせず、「たのしー」「すげー」「さすがー」で動く
  • 人間の業を肯定し、それを使って、人の役に立つロールを見つける
    • オレのダラシない部分を「情報を渡す人」に必要な要素に変換して、少しでもいいので人の役に立つことをする

この辺らしい。

ただ、この先、このロールだけで生きていけるのか? というとちと疑問がある。 作る人には未練もあるし、何かしら方法を探したいなー。なー。なー。 言うだけならタダだし、言うとなれるっていう話もあるから、言うだけ言っておこうっと。

でも、みうらじゅんまで長じれば…あるいは…。でもあの人のスキルセットって、サブカルの中でもかなりレアらしいからなぁ。

構築に役立ったと思うもの

考え方やスタイル?

芯を外してるものも多い気がするけども。角さん、牛尾さん、川口さんにはいつも感謝しておりますです!!!

追いかけすぎて、ストーカーと化しているんじゃないか…と心配になるレベル…。ばれてるかなぁ。ばれてるだろうなぁ。

後、ここ最近の良く分からんデンパなツィートに反応していただいた皆様ありがとうございました。

練習

練習嫌いなので、知らず知らずのうちに練習させられてたんだと思う。

  • 分ける
    • 全部でまるっとまとめない
      • できてるところ、できてないところ
      • 合意できるところ、できないところ
      • イイところ、悪いところ
    • 褒めるのに使うし、アジャイルやる人探すのにもいるし、とにかくこれないと辛い
  • 捨てる
    • 全部自分でやりたい
      • 昼の勉強会を長く続けるためには、人の力を借りる必要があったので、自分でやりたいは捨てないとアカン
      • 捨てたおかげで、何が大事なんだっけ、オレ? を考えられるようになった
  • 説明する
    • 全部説明しなくていい
      • ポインタさえ示しておけば、ピンときたとこ抜き出すくらいのライトさでもヒットする人はいる
      • 逆にヒットしない人に、オレは上手に説明できないだろうから、そこはご縁がなかったことにして一旦忘れる
    • ピンと来たところを引用する via 川口 恭伸さん
      • オレが作った変な要約を渡すよりよっぽど良い
  • 待つ
    • 情報を渡した後、しばらくたってから様子を見にいく (今もせっかちなとこあるけど)
      • 情報渡してすぐ反応がないからといってダメだーって言ってると、せっかく出てきた芽が見のがしてしまう
      • しばらくたって芽が出ることもたまにあるから、渡した後忘れてしまうくらいでいい

オレを勘違いしてくれた皆様

最重要。オレという人間を勘違いして、色んなところで使おうとしてくれた/してくれてる人がいる。 名前出すと怒られそうなので、こういう感じでお茶を濁しておくけど、感謝しとりますー!!!

…って、実は仕掛けられてて、今も観察の対象だったりする??

Visual Studio Team Services と Rocket.Chat の連携 (プルリクエストだけ)

平間ソンでできたこと1つ目。

背景

  • 開発チームはVSTSを使っている
  • ちょっとした連絡にはRocket.Chatを使っている
  • VSTSでプルリクエストを作った後、いちいち手動でRocket.Chatに連絡しているので、面倒
  • Rocket.Chatのサーバは 社内イントラ にある

やりたいこと

  • VSTSでプルリクエストを作ったら、自動でRocket.Chatにメッセージを投げるようにしたい

実現案

a. VSTSのRoom使う (Service Hooks)

多分一番素直なやり方。今回は使えないけど。

連携方法

Roomを開いて、Manage Events -> Pull requestsを選択。 出てくるダイアログで、プロジェクトとリポジトリ、変更した人(チャットメンバーまたは誰でも)を選べば通知ができる。(チェックボックスをONにするのを忘れずに)

詳しくは https://msdn.microsoft.com/en-us/library/vs/alm/work/productivity/collaborate-in-a-team-room あたりを見ればわかる。

対応しているイベント

作成と、ステータス変更。タイトルなどの修正は対応してない。

連携イメージ

f:id:couger:20160503152620p:plain

b. Service Hooksを使う

Service Hooksについて

Service Hooksを使うと、外部ツールと連携ができる。 https://www.visualstudio.com/en-us/get-started/integrate/service-hooks/webhooks-and-vso-vs

連携可能なツール

一覧がどこにあるのかわからなかった。 https://www.visualstudio.com/en-us/integrate/explore/explore-vso-vsi.aspx で紹介されているアイコンでなんとなくわかるのでよし。

Rocket.Chatとの連携

Rocket.ChatのIncomming WebHookはSlackと互換性があるので、Service Hooksの設定で連携先にSlackを選択、URLにRocket.ChatのIncomming WebHookのURLを設定すれば良い。 ただし、https必須。

Rocket.Chatをhttps

独自ドメインも証明書も持ってないので、AzureのWeb Appsでも使おうかと思ったけど、はまりそうだったので、Herokuを利用。Herokuだと本家リポジトリにあるリンクから一発でデプロイできる。

https://github.com/RocketChat/Rocket.Chat

でも、ここまでするなら素直にSlack使ったほうがいいよなぁ...と思ったことは内緒にしておく。

連携方法

Rocket.Chat

管理 -> サービス連携 -> 新しいサービス連携 -> Incomming WebHookで作成。 作成したら、Webhook URLに表示されているURLをメモしておく。

VSTS

プロジェクトの設定 -> Service Hooks -> "+"ボタンでHookを追加する。

  • Serivice: Slack
  • Trigger: Pull request created
  • Action:
    • Slack Webhook URL: (Rocket.Chatで作成したWebhookのURLを設定)

Trigger "Pull request updated" についても同じようにHookを作る。

f:id:couger:20160503152221p:plain

対応しているイベント

Roomと同じ。 作成と、ステータス変更。タイトルなどの修正は対応してない。

連携イメージ

f:id:couger:20160503152822p:plain

URLのリンクがうまくいってないのは、SlackとRocket.Chatで書式が違うから。(だと思う)
Incommig WebHookの設定にScriptという項目があるので、そこでごにょごにょすれば直るかもしれない?

c. REST APIを使う

背景の Rocket.Chatのサーバは社内イントラにある のおかげで、a,b案は使えない。 ので、結局ここに落ち着くはず。

HubotでVSTSREST APIを叩き、拾ってきた情報をRocket.Chatに流す。

HubotとRocket.Chatの連携

Rocket.ChatもRocket.Chat連携用のHubotもコンテナが用意されてるのでそれを使うと楽。 RocketChat/hubot-rocketchat: Rocket.Chat Hubot adapter

VSTSREST API

Pull Requestに関しては以下のページを参照。 Git Pull Requests | REST API Reference for Visual Studio Team Services and Team Foundation Server

APIに必要な認証

Basicのみ対応。
GitHubにあるRailsアプリをVSTSでビルドして、Azureにデプロイする with Docker - cougerの日記 を見て、Alternate authentication credentials を有効にする。
Personal Access Tokenに対応しているので、そちらを使おう。ScopeはCode(Read)のみでOKっぽい。
指定する場合はこんな感じになる。ユーザ名はなんでもOK、パスワードにPersonal Access Tokenを指定すれば良いようだ。

http://[なんでもOK]:[Personal Access Token]@hogefuga.visualstudio.com/....

Personal Access Tokenの有効期間は180日なのでご注意をば。設定で1年間にすることも可能。

Personal Access Token、有効期間について @kkamegawa さんにアドバイスもらいました。ありがとーございます。

できたもの

だんだん疲れてきたので、できたものをペタペタ。

最初はActiveなものを全部出して、その後は、新規作成したものだけ表示。
vsts show pr [Active|Completed|Abandoned] のコマンドをhubotに投げると指定したステータスのプルリクを全部表示。
あと、チャーハン。

ごちゃごちゃしているのはなんとかならないものかなぁ。

Hubotスクリプト

Personal Access Tokenを使うように変更。

# Description:
#   VSTSのPull Requestが作成されたらメッセージを投下します
#
# Configuration
#   vsts... の変数を適宜変更してください
#
# Commands:
#   hubot vsts show pr [Active|Completed|Abandoned] - 指定したステータスのPull Requestを全部表示
#   hubot チャーハン - チャーハン作ります

cronJob = require('cron').CronJob
startDate = new Date

vstsAccount = "[VSTSアカウント名]"
vstsProject = "[VSTSプロジェクト名]"
vstsRepository = "[VSTSリポジトリ名]"
vstsPersonalAccessToken = "[VSTS Personal Access Token]"
vstsRemoteUrlBase4PR = "https://#{vstsAccount}.visualstudio.com/DefaultCollection/#{vstsProject}/_git/#{vstsRepository}/pullrequest"
vstsRestApiUrlBase4PR = "https://hubotvstsnotifier:#{vstsPersonalAccessToken}@#{vstsAccount}.visualstudio.com/defaultcollection/#{vstsProject}/_apis/git/repositories/#{vstsRepository}/pullrequests\?api-version\=1.0"

module.exports = (robot) ->
  createRestApiUrl4PR = (status, top) ->
    url = vstsRestApiUrlBase4PR
    if status?
      url = "#{url}\&status\=#{status}"
    if top?
      url = "#{url}\&$top=#{top}"
    url

  searchPullRequests = (status, top, callBack) ->
    url = createRestApiUrl4PR status, top
    robot.http(url)
      .get() (err, res, body) ->
        responseJson = JSON.parse body
        callBack responseJson.value

  createPRMessage = (pullReq) ->
    prUrl = "#{vstsRemoteUrlBase4PR}/#{pullReq.pullRequestId}"
    "[#{pullReq.pullRequestId}](#{prUrl}) #{pullReq.title} (#{pullReq.sourceRefName} -> #{pullReq.targetRefName})"

  showPullRequests = (status, top) ->
    callBack = (pullReqs) ->
      prMsgs = for pullReq in pullReqs
        createPRMessage pullReq
      if prMsgs.length is 0
        msg = "@all: プルリクエストはなかったよ"
      else
        msg = "@all: プルリクエストが#{prMsgs.length}個あるよ\n#{prMsgs.join('\n')}"
      robot.send {room: 'general'}, msg
    searchPullRequests status, top, callBack

  showRecentPullRequests = (status, top) ->
    callBack = (pullReqs) ->
      prMsgs = for pullReq in pullReqs
        creationDate = new Date pullReq.creationDate
        continue if startDate > creationDate
        createPRMessage pullReq
      startDate = new Date
      if prMsgs.length is 0
        return
      msg = "@all: 新しいプルリクエストが#{prMsgs.length}個あるよ\n#{prMsgs.join('\n')}"
      robot.send {room: 'general'}, msg
    searchPullRequests status, top, callBack

  robot.respond /vsts show pr (.*)/i, (msg) ->
    showPullRequests msg.match[1], null
    
  robot.respond /チャーハン/, (msg) ->
    msg.send """
```` <- 本当は3個
チャーハン作るよ!!
  ∧_∧
 (`・ω・)  。・゚・⌒)
 /  o━ヽニニフ))
 しーJ
```` <- 本当は3個
"""

  # 初回のみActiveなものを全部出す
  showPullRequests "Active"

  # 以降は新しいもののみ出す
  new cronJob('*/30 * * * * *', () ->
    showRecentPullRequests "Active"
  ).start()

実行環境

カレントディレクトリにscriptsフォルダを作成して、上記のCoffee Scriptを配置したあと docker-compose up -d でRocket.ChatとHubotが立ち上がり、VSTSの連携が始まります。

フォルダ構成

+ root
   + bot
       + Dockerfile
   + scrpts
      + hubot-vsts-notifier.coffee
   + docker-compose.yml

docker-compose.yml

chat:
  image: rocketchat/rocket.chat
  environment:
    - MONGO_URL=mongodb://db/rocketchat
  ports:
    - "3000:3000"
  links:
    - db

db:
  image: mongo
  ports:
    - 27017

bot:
  build: ./bot
  links:
    - chat
  environment:
    ROCKETCHAT_URL: http://chat:3000
    ROCKETCHAT_ROOM: ''
    LISTEN_ON_ALL_PUBLIC: true
    ROCKETCHAT_USER: [RocketChat認証ユーザ名]
    ROCKETCHAT_PASSWORD: [RocketChat認証パスワード]
    ROCKETCHAT_AUTH: password
    BOT_NAME: bot
  volumes:
    - ./scripts:/home/hubot/scripts

Dockerfile

FROM rocketchat/hubot-rocketchat

RUN npm install cron time

連携イメージ

f:id:couger:20160503182847p:plain