読者です 読者をやめる 読者になる 読者になる

銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

VSTSのAPIを使ってビルドログを取得する

以前紹介したVSTSのService WebHookを受け取る処理の中で、ビルドの詳細を送信したいため、APIを使ってビルドログを取得することにしました。

tech.tanaka733.net

コードはこんな感じです。

var build = new BuildHttpClient(new Uri("https://<yoruaccount>.VisualStudio.com/DefaultCollection/"), new VssBasicCredential("<username>", "<password>"));
JObject json = null; // WebHookで受け取ったJson
var project = new Guid(json["resourceContainers"]["project"]["id"].Value<string>());
var buildId = json["resource"]["id"].Value<int>();

//詳細なビルドログはIdを指定して取得しないといけないのでいったんビルドログの一覧を取得
var logs = await build.GetBuildLogsAsync(project, buildId);
var errorMessageLines = new List<string>();
foreach (var log in logs)
{
    //なぜかこのAPIの返り値はTask<Stream>
    //実態は { "count": <count>, value: [<logarray>]} なJSONなのでJson.NET でパースしてる
    using (var stream = (await build.GetBuildLogAsync(project, buildId, log.Id)))
    using (var sr = new StreamReader(stream))
    using (var jsonTextReader = new JsonTextReader(sr))
    {
        var serializer = new JsonSerializer();
        var logJson = serializer.Deserialize<JObject>(jsonTextReader);
        //ログメッセージから[error]のついたところだけ抽出してみる
        errorMessageLines.AddRange(logJson["value"].Values<string>().Where(s => s.Contains("[error]")));
    }
}
//後はお好きなように
errorMessageLines.Dump();

ビルドをQueueに積むAPIとは違って、プロジェクトとビルドIdを指定する形式になっています。プロジェクトは名前を文字列で指定するオーバーロードも用意されていますが、WebHookで受け取った場合、名前は受け取ったJSONの中に格納されていない*1ので、Guidを使っています。 実際のログを取得するAPIはなぜか返り値がTask<Stream>です。特に仕様とか書いてないのですが、現状コメントに書いてあるような形式のJSONなのでパースしています。あとは適当に文字列解析して送信に使っています。

*1:正確にはメッセージの中に入っているが、そこから取得するのは面倒