銀の光と碧い空

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

VSTS 拡張を作ってみる (5) : GridViewの拡張 その②

今日はGridをもう少し拡張してみます。

Gridに表示するデータはプロパティを指定していましたが、関数を実行した結果を表示することもできます*1。ビルド定義一覧を表示した前回のGridに最新のビルドジョブの実行結果を表示するようにしましょう。ビルドジョブの実行結果はgetBuildsAPIで取得することができます。対象のビルド定義のIDを指定しないといけないのですが、複数指定できるのでビルド定義一覧に対してまとめて1回で取得できます。前回のコードのgetDefinitionsを呼び出している場所を次のように修正します。

var regex = /^[^-_]+[-_]+([^-_]+)([-_]+|$)/;
buildClient.getDefinitions(webContext.project.name).then(function(buildDefinitions) {
    buildClient.getBuilds(webContext.project.name, buildDefinitions.map(function(x){return x.id;})).then(function(builds){
      //grouping
      var groups = new Map();
      buildDefinitions.forEach(function(b){
        var m = regex.exec(b.name);
        var n = m == null ? "" : m[1];
        var group = groups.get(n);
        if (group == null){
          group = [];
          groups.set(n, group);
        }
        group.push(b);
      });
      var output = [];
      groups.forEach(function(value, key, m){
        var item = {};
        item.groupName = key;
        item.children = value;
        output.push(item);
      });
      Controls.create(Grids.Grid, container, {
        height: "1000px", // Explicit height is required for a Grid control
        columns: [
            { text: "group", index: "groupName", width: 100, indent: true },
            { text: "ID", index: "id", width: 50 },
            { text: "Name", index: "name", width: 200 },
            { text: "Last Status", width: 50, getColumnValue: function(dataIndex){
              var id = this.getRowData(dataIndex).id;
              //buildNumberRevisionの最新1件を取得。OrderByDescending(b => b.buildNumberRevision).FirstOrDefault()
              var filtered = builds.filter(function(e, i, array) {
                return e.definition.id == id;
              }).sort(function(a,b) { 
                if (a.buildNumberRevision < b.buildNumberRevision)
                  return 1;
                if (a.buildNumberRevision > b.buildNumberRevision)
                  return -1;
                return 0;
              });
              if (filtered == null || filtered.length == 0)
                return "";
              if (filtered[0].result != 2)
                return "NG";
              return "OK";
            }}
        ],
        // This data source is rendered into the Grid columns defined above
        source: new Grids.GridHierarchySource(output),
        gutter: {
          contextMenu: true
        },
        contextMenu: {
          items: getContextMenuItems(),
          executeAction: menuItemClick,
          arguments: function(contextInfo)  {
                  return { item: contextInfo.item };
          }
        }
      });
    });            
});

buildDefinitions.map(function(x){return x.id;})でビルド定義一覧のIDを配列で取得します*2。ビルド定義をグルーピング化している場所は前回と同じですが、"Last Statusというカラムを追加しています。getColumnValue プロパティに関数を指定することで、関数の結果をカラムに表示します。ビルド結果はビルド定義ごとに複数存在するため、ビルドナンバーの一番大きなもの(最新の結果)を1件取得しています。LINQでいうOrderByDescending(b => b.buildNumberRevision).FirstOrDefault()をやっています*3

あとは、ビルド結果の成功か失敗かによって表示する文字列を返していますが、resultプロパティが数値なので!= 2とかで比較しています。TypeScript側の定義を見るとこうなっているようです。

export enum BuildResult {
    /**
     * No result
     */
    None = 0,
    /**
     * The build completed successfully.
     */
    Succeeded = 2,
    /**
     * The build completed compilation successfully but had other errors.
     */
    PartiallySucceeded = 4,
    /**
     * The build completed unsuccessfully.
     */
    Failed = 8,
    /**
     * The build was canceled before starting.
     */
    Canceled = 32,
}

vss-sdk/tfs.d.ts at 0.92.0 · Microsoft/vss-sdk · GitHub

という感じで最新のビルド結果を表示することができました。

f:id:tanaka733:20151222215959j:plain

*1:ハイパーリンクとかアイコンとか装飾をつけたいんですが、現状できなさそうな予感

*2:これがJavaScriptで一般的な書き方なのかは不明

*3:これもJavaScriptで一般的なのかは(略