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

銀の光と碧い空

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

VSTS の APIを使って指定したビルド定義をビルドキューに積む

VSTS C#

VSTSにはAPIがあるので、指定したビルド定義をビルドQueueに積むことができます。

Visual Studio Team Services and Team Foundation Server REST API Reference

ビルド周りについてはこちら。

Builds | REST API Reference for Visual Studio Team Services and Team Foundation Server

これらに対応した.NET のクライアントライブラリもNugetで公開されています。

.NET Client Libraries for Visual Studio Team Services (and TFS)

4つある中で、ビルドの操作ができるのはMicrosoft.TeamFoundationServer.Clientでした。で実際のAPIなんですが、かなり使いづらいです。とりあえずコードを載せます。ユーザーとパスワードは代替パスワードという仕組みがあって、普段ログインに使うパスワードとは別のVSTS専用のパスワードを発行できます。

async Task QueueBuild()
{
    var build = new BuildHttpClient(new Uri("https://<YourDomain>.VisualStudio.com/DefaultCollection/"), new VssBasicCredential("<UserName>", "<Password>"));
    var project = "<Project>";
    var definitionName = "<BuildDefinitionName>";
    
    //定義されているビルド定義一覧を取得
    var definitions = await build.GetDefinitionsAsync(project: project);
    definitions.Dump();
    //名前を指定して選択
    var target = definitions.First(d => d.Name == definitionName);
    target.Dump();
    //ビルド定義で設定されているデフォルトブランチ取得するために詳細な定義を取得する。
    //GetDefinitionsAsyncでは取れない。メソッドの定義されている返り値の型は同じだけど、実際のオブジェクトの型はこちらの方は継承先の詳細情報が入っている型。
    //そのため返り値をキャストしないと取得できない! (or Reflection)
    //しかもId指定しないといけないので直接呼び出すのはつらい
    var targetDetail = await build.GetDefinitionAsync(project, target.Id) as BuildDefinition;
    targetDetail.Dump();
    
    //Buildクラスにはたくさんプロパティがあるけど指定できるのはこれだけ
    //ref: https://www.visualstudio.com/integrate/api/build/builds#queueabuild
    //しかし.NET Client LibraryではProjectを指定しないといけない...
    //挙句ProjectのGuidを設定しないといけないので直接指定するのは無理げー
    var res = await build.QueueBuildAsync(new Build
    {
        Definition = new DefinitionReference
        {
            Id = targetDetail.Id
        },
        SourceBranch = targetDetail.Repository.DefaultBranch,
        Project = target.Project
    });
    //Queueに積まれた時点で返ってくる
    res.Dump();
}

コメントで苦労の後を感じて頂ければ幸いです...

APIに対応するメソッドはQueueBuildAsyncで引数にBuildオブジェクトを指定する必要があります。が、このBuildオブジェクトプロパティがたくさんあるのに、QueueBuildAsyncで何が必要かの情報がありません... REST APIのドキュメントを見ると、Definition.IdSourceBranchを指定すればよいとあるのですが、実際に実行すると、Projectも指定する必要があります。このProjectもプロパティがたくさんあって、特にGuidといった値が必要なので、実質このサンプルコードのように最初にビルド定義一覧をとってきて、その返り値に含まれているProjectを渡す、という処理が必要になりました。

また、SourceBranchは実際にそのビルドで対象とするブランチを指定するわけですが、ビルド定義で指定したデフォルトブランチを使いたい場合ビルド定義から取得する必要があります。が、ビルド定義一覧を取得するGetDefinitionsAsyncではデフォルトブランチ情報は取得できません。ビルド定義のIdを指定して取得できるGetDefinitionAsyncメソッドを使う必要があります。しかも、GetDefinitionAsyncの返り値はDefinitionReferenceクラスで、一覧を取得するGetDefinitionsAsyncの返り値List<DefinitionReference>と一見同じなように見えます。が、GetDefinitionAsyncの方は実はより具象的なBuildDefinitionクラスのオブジェクトが返されるため、キャストするとデフォルトブランチなどの詳細な情報を取得することができます。

ということでドキュメントもないので、いろいろ試行錯誤が必要ですがなんとかできました。ちなみにライセンス的に逆コンパイル禁止になっているのでご注意ください。

www.nuget.org

https://www.microsoft.com/net/dotnet_library_license.htm