Visutal Studio Team Services(VSTS)でビルド結果を通知するにはService Hooksを使います*1。Integrated されているサービスもあるのですが、これ以外のサービスと連携するには自前でWeb Hookを作る必要があります。
Integrate with service hooks | Visual Studio Team Services
Web Hookを作るライブラリやサービスは多数ありますが、今回は ASP.NET Web Hooksを使うことにしました。Web Hooksの概要はこちらのブログがわかりやすいです。
Microsoftが出しているライブラリなんだから、MicrosoftのDevOpsのサービスの切り札でもあるVSTSのWebHookのIntegrationが存在しないはずはない!!!11といいたいところなんですが、ないです。しょうがないのでCustomで作成することにします。ASP.NET WebHooks はWebHookを送信する側と受信する側の両方に対応したライブラリとツールがあるんですが、今回は受信側だけを使います。受信側はReceiver
と言い、Microsoft.AspNet.WebHooks.Receivers.Custom
がカスタム用のレシーバーライブラリです。また、プロジェクトテンプレートですが、ASP.NET 5 Web API
を使うのが楽でした。余計なものが追加されるので、それを避けたい場合はEmpty
がいいでしょう。
まず、Nugetからライブラリを追加します。
PM> Install-Package -IncludePrerelease Microsoft.AspNet.WebHooks.Receivers.Custom
次にStartUpメソッドにCustomWebHooksの初期化処理を追加します。
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); GlobalConfiguration.Configuration.InitializeReceiveCustomWebHooks(); // この1行を追加 } }
そして、VSTSからのWebHookを受け取るVSTSWebHookReceiver
クラスを作成します、IWebHookReceiver
インターフェースを実装すればいいのですが、便利メソッドがあるので、WebHookReceiver
クラスを継承しておくのがいいでしょう。Nameプロパティをオーバーライドして、そのプロジェクトで一意な名前を付けます。これはWebHooksを受け取るURLにも使われます。実際に受け取る処理はReceiveAsync
をオーバーライドします。実際にこのクラスで受け取るWebHookのURLは
https://<ホスト名>/api/webhooks/incoming/vsts/id?key=value
といったURLになります。idの部分はReceiveAsync
の第一引数に渡されますが空でも問題ありません、クエリ文字列も任意です。
さて、このようなURLのクエリパラメーターも取得して、Bodyで送信されてきたJSONをパースする処理はこんな風に書けます。
public class VSTSWebHookReceiver : WebHookReceiver { public override string Name => "vsts"; public override async Task<HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request) { var query = request.GetQueryNameValuePairs().FirstOrDefault(e => e.Key == "flg"); var json = await ReadAsJsonAsync(request); var message = json["detailedMessage"]["text"]; return new HttpResponseMessage(HttpStatusCode.Accepted); } }
あとは、このプロジェクトをAzure Web Appsなどにデプロイすれば完了です。
実際にVSTSから送信してみましょう。Service Hooksの画面からWeb Hooksを選択します。
Build Completedを選びビルド完了後のメッセージを選択します。
ActionのURLにReceiverで受け取るURLを指定します*2。
入力したらTestボタンを押してテストでWeb Hookを送ってみます。リモートデバッグしてみると実際に送信されてきていることが確認できます*3。
さて、このままだとインターネット上に裸のまま公開されているので、もしこのURLが見つかるとWebHooksに投げられまくりの状態になります。そこで簡易的な認証などを行いたいわけですが、CustomWebHookReceiver
というクラスを継承すると、送信データの正当性検証などを行うコードが書かれています。これをうまく使えばいいのですが、VSTSについては送信側でこれに対応することができません*4。ですので今回は割愛しますが、必要な場合はコードを見てみると参考になると思います。なお、これに関するドキュメントは今のところ見つけられていないので、「コード見ろ」状態です。
*1:Service Hooksはビルド結果以外のイベントでも送信可能
*2:このURL欄、なぜか https://example.com/hoge/?k=v みたいな/の直後に?が来るURLだとフォームの入力値検証はOKなのにFinishで保存しようとすると不正なURLで保存できなくなります
*3:WebHookは基本的にはインターネット上にアプリを公開しないと本番データを受信できないですが、Azure Web Appsだとリモートデバッグで手元で確認できるのが便利です
*4:最初に書いた通り、送信するデータのBody部分は編集できないし、Headerに指定できるのは固定文字列のみであるため