TFS 2017 Release Management: How to display parent

2020-03-08 06:04发布

问题:

Is there any way to show the parent PBI for a Task Work item under Release in the list under TFS2017?

The screenshot below shows two tasks associated with Release-3. Here I wish to be able to display the parent PBI for each of them. Either by expanding them or just by displaying an additional column with link to the parent PBI

I appreciate your help

Edit: I know that that there is a possibility to create a query on TFS. The problem is that I need to display the information on the parent Work item that are related to a specific Release so the user can use them for reporting. I tried to to create a query for this purpose but I couldn't find a filtering option based on Release so I thought it might be possible to enable some additional columns or there might be an extension for that but I couldn't figure out how to do it..

回答1:

The steps to achieve that with extension:

  1. Get specify release to get build id
  2. Get work items of that build per build id
  3. Get related work items

There is simple code of extension to get work items of specific release that you can refer to:

HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Custom widget</title>
    <meta charset="utf-8" />
    <script src="node_modules/vss-web-extension-sdk/lib/VSS.SDK.js"></script>
    <script type="text/javascript">
        VSS.init({
            explicitNotifyLoaded: true,
            usePlatformStyles:true
        });
        VSS.require(["TFS/Dashboards/WidgetHelpers", "TFS/TestManagement/RestClient", "TFS/WorkItemTracking/RestClient", "TFS/Build/RestClient", "VSS/Service", "VSS/Identities/Contracts", "VSS/Identities/RestClient", "VSS/Authentication/Services"], function (WidgetHelpers, TFS_Test_WebApi, TFS_Work_WebApi, TFS_Build_Client, VSS_Service, idContracts, idRest, VSS_Auth_Service) {
            WidgetHelpers.IncludeWidgetStyles();
            VSS.register("WidgetStarain", function () {

                 var authHeader = "none";
                var vstsAccount = "none";
                var projectName = "none";
                var releaseRestAPIPrex = "none"
                var getReleaseWorkItems= function (widgetSettings) {
                    var c = VSS.getWebContext();
                    vstsAccount = c.account.name;
                    projectName = c.project.name;
                    releaseRestAPIPrex="https://" + vstsAccount + ".vsrm.visualstudio.com/DefaultCollection/" + projectName + "/_apis/release"
                    VSS.getAccessToken().then(function (token) {

                        authHeader = VSS_Auth_Service.authTokenManager.getAuthorizationHeader(token);

                        $.ajax({
                            type: 'GET',
                            url: releaseRestAPIPrex+'/definitions?api-version=3.0-preview.1',
                            cache: false,
                            dataType: 'json',
                            beforeSend: function (xhr) {
                                xhr.setRequestHeader("Authorization", authHeader);
                            },
                        }).done(function (data) {
                            var v = data.value;
                            $("#releaseDefList").empty();
                            $("#releaseDefList").append('<option value="select">select</option>');
                            $.each(v, function (index, value) {
                                $("#releaseDefList").append('<option value="' + value.id + '">' + value.name + '</option>');
                            });
                        }).error(function (e) {
                            var s = "ss";
                        });

                    });

                };
                $("#releaseDefList").change(function () {
                    var str = "";
                    $("#releaseList").empty();
                    $("#releaseList").append('<option value="select">select</option>');
                    $("#releaseDefList option:selected").each(function () {

                        var releaseDefId = $(this).val();
                        if (releaseDefId != "select") {
                            $.ajax({
                                type: 'GET',
                                url: releaseRestAPIPrex+'/releases?definitionId=' + releaseDefId + '&api-version=3.0-preview.2',
                                cache: false,
                                dataType: 'json',
                                beforeSend: function (xhr) {
                                    xhr.setRequestHeader("Authorization", authHeader);
                                },
                            }).done(function (data) {
                                var v = data.value;

                                $.each(v, function (index, value) {
                                    $("#releaseList").append('<option value="' + value.id + '">' + value.name + '</option>');
                                });
                            }).error(function (e) {
                                var s = "ss";
                            });
                        }

                    });


                });
                $("#releaseList").change(function () {
                    var str = "";

                    $("#releaseList option:selected").each(function () {

                        var releaseId = $(this).val();
                        if (releaseId != "select") {
                            $.ajax({
                                type: 'GET',
                                url: releaseRestAPIPrex+'/release/releases/' + releaseId + '?api-version=3.0-preview.2',                                
                               cache: false,
                                dataType: 'json',
                                beforeSend: function (xhr) {
                                    xhr.setRequestHeader("Authorization", authHeader);
                                },
                            }).done(function (data) {
                                var artifacts = data.artifacts;
                                $.each(artifacts, function (index, value) {
                                    var buildId = value.definitionReference.version.id;

                                    TFS_Build_Client.getClient().getBuildWorkItemsRefs(projectName, buildId).then(function (workitemRefs) {
                                        var workItemIds = new Array();
                                        $.each(workitemRefs, function (index, value) {
                                            workItemIds.push(value.id);
                                        });
                                        var workitemString = "";
                                        TFS_Work_WebApi.getClient().getWorkItems(workItemIds,null,null,"All").then(function (workitems) {
                                            $.each(workitems, function (index, value) {
                                                workitemString += "ID: " + value.id + "; Title: " + value.fields["System.Title"];
                                            });
                                            $("#workitems").text(workitemString);
                                        });

                                    });
                                });

                            }).error(function (e) {
                                var s = "ss";
                            });
                        }

                    });


                });
                 return {
                    load: function (widgetSettings) {
                       getReleaseWorkItems(widgetSettings);
                        return WidgetHelpers.WidgetStatusHelper.Success();
                    }
                }
            });
            VSS.notifyLoadSucceeded();
        });
    </script>
</head>
<body>
    <div class="widget">
        <h2 class="title">widgets starain</h2>  
        <div class="token">none</div>

        <select id="releaseDefList">
            <option id="select">select</option>
        </select>
        <select id="releaseList">
            <option id="select">select</option>
        </select>
        <div id="workitems">
            none workitem
        </div>


    </div>
</body>
</html>

vss-extension.json:

{
  "manifestVersion": 1,
  "id": "sample-extension",
  "version": "0.5.34",
  "name": "My test extension",
  "description": "my test extension description",
  "publisher": "Starain",
  "targets": [
    {
      "id": "Microsoft.VisualStudio.Services"
    }
  ],
  "icons": {
    "default": "Images/logo.png"
  },
  "scopes": [
    "vso.work",
    "vso.build",
    "vso.build_execute",
    "vso.test",
    "vso.test_write",
    "vso.release"
  ],
  "contributions": [
        {
      "id": "WidgetStarain",
      "type": "ms.vss-dashboards-web.widget",
      "targets": [ "ms.vss-dashboards-web.widget-catalog", "Starain.sample-extension.WidgetStarainConfiguration" ],
      "properties": {
        "name": "widget starain",
        "description": "custom widget",
        "catelogIconUrl": "Images/iconProperty.png",
        "previewImageUrl": "Images/iconProperty.png",
        "uri": "WidgetStarain.html",
        "supportedSizes": [
          {
            "rowSpan": 1,
            "columnSpan": 2
          }
        ],
        "supportedScopes": [ "project_team" ]
      }
    } 
  ],
  "files": [
    {
      "path": "node_modules/vss-web-extension-sdk/lib",
      "addressable": true
    },
    {
      "path": "Images",
      "addressable": true
    },
    {
      "path": "Scripts",
      "addressable": true
    },
    {
      "path": "WidgetStarain.html",
      "addressable": true

    }
   ]
}