How to retrieve all work items associated with a release pipeline using Azure DevOps API

Premier Developer


App Dev Manager Mahendar Madhavaram and Premier Field Engineer Eduardo Bottcher explore how to retrieve all work items associated with a release pipeline using Azure DevOps API.

One of the greatest features of using Boards, Repositories and Pipelines in Azure DevOps is the ability to link and associate work items to all sorts of coding and deployment elements such as commits, branches, pull requests, builds and releases. With those associations in place, it is possible to identify, for example, what work items were deployed on a given release or track what lines of code were involved in the last deployment to production. Those are all very valuable and strategic information you can use for auditing purposes or troubleshooting data to help diagnose an incident. Out of the Box, the tool can display those relations in various screens, like the Build Summary page or the Work Item Form but you can also use the Azure DevOps Rest API to pull that information for your specific scenarios. The good news is that Azure DevOps provides multiple endpoints and technologies to connect and query data.

In this article we are going to learn how to retrieve all work items associated with a release pipeline using the Azure DevOps API.

Setting up the Work Items Associations

The goal here is to make sure the build and release pipeline definitions are configured to associate work items during the whole CI/CD process. As code gets committed and built, tasks, user stories, bugs and other work items links should be created to each operation. That is the foundation to be able to report on those links later in this article.

The first step is to make sure every code change is associated with a work item. This will link the work items with commits, branches and Pull requests. You can accomplish that by enabling a build policy to check for linked work items.

  1. Click the Repositories and the Branches Menu in the Azure DevOps Portal . A screenshot of a cell phone Description automatically generated
  2. Locate in the branch list the one you are going to use to build from, typically that should be your master branch, and click the options icon. Select Branch policies. A screenshot of a cell phone Description automatically generated
  3. Check the option ”Check for linked work items”. Click Save changes. A screenshot of a social media post Description automatically generated

The next step is to enable the build definition to create links to all work items linked to associated changes when a build completes successfully.

  1. Select your build pipeline definition and click Edit on the top right corner of the page. A picture containing screenshot Description automatically generated
  2. In the Options Tab, enable the option “Automatically link new work in this build”. Click Save. A picture containing knife Description automatically generated

The last step is to configure the release pipeline to link those work items to the release when a stage is completed.

1 – Select your release pipeline definition and click Edit on the top right corner of the page. A screenshot of a cell phone Description automatically generated

2 – In the Options Tab, select the Integrations Section and enable the option “Report deployment status to Work Stages. You have the flexibility to choose which environments to associate. A screenshot of a cell phone Description automatically generated

To test this process, create a branch, make changes to a file, commit those changes, create a pull request, merge it, build and then deploy it using your release pipeline. If the associations are being created and the work items are being linked properly, you should be able to see that information in the Details tab under the Deployment section on the Work item page, as shown in the image below:

A screenshot of a cell phone Description automatically generated

Also, you can view all work items that were associated to a given release by going to the Summary page of a release run. It should look like this:

A screenshot of a cell phone Description automatically generated

Let’s say, for example, that we need to list all work items associated to code changes that got deployed to production in the past 3 months. Since none of those pages will give you that type of visualization because they display one release run at a time, you will need to retrieve that data programmatically from Azure DevOps. Let’s evaluate some options:


Although you can use some work item links types as part of your query parameters, by design it is not possible to query by commits, builds or releases. The reason is those links are treated internally in the tool as a relation object instead of the conventional link objects such as Parent and Child link types.

Azure DevOps Analytics

Currently, the v3.0-preview of the OData Endpoint doesn’t expose all the release pipeline information we need for this report. However, it is expected that eventually this will be incorporated as part of the data model. For more information, refer the article on Extending Analytics with OData (Preview)

Rest API

The solution is to use the Azure DevOps REST API but there are many ways to invoke it depending on your client application type and authentication method. The link Azure DevOps Services REST API Reference has some useful information to help you decide which client technology to use.

Writing the client application to call the API

For this article, we will build a console application in C# to call the Azure DevOps Rest API using the Client API library. This will greatly simplify our code and avoid long and extensive json parsing and manipulation when compared to using the HttpClient object. You can still make direct calls if you prefer, though.

Here is the code:

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL,

using System;
using System.Linq;
using Microsoft.TeamFoundation.Build.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.ReleaseManagement.WebApi.Clients;
using Microsoft.VisualStudio.Services.WebApi;

namespace GetRelatedWorkItemsAppPoc
    class Program
        internal const string azureDevOpsOrganizationUrl = "{yourorganization}/";
        internal const string pat = "{yourtoken}";
        internal const string projectName = "{yourprojectname}";

        static void Main(string[] args)
            var connection = new VssConnection(new Uri(azureDevOpsOrganizationUrl), new VssBasicCredential(string.Empty, pat));

            var startDate = new DateTime(2019, 9, 5, 18, 0, 0, DateTimeKind.Utc);
            var endDate = new DateTime(2019, 12, 5, 23, 30, 0, DateTimeKind.Utc);

            var releaseClient = connection.GetClient<ReleaseHttpClient>();
            var buildClient = connection.GetClient<BuildHttpClient>();
            var wiclient = connection.GetClient<WorkItemTrackingHttpClient>();
            var releaseList = releaseClient.GetReleasesAsync(project: projectName, minCreatedTime: startDate, maxCreatedTime: endDate).Result;
            Console.WriteLine($"Organization: {azureDevOpsOrganizationUrl}");
            Console.WriteLine($"Project Name: {projectName} \n");
            Console.WriteLine($"Searching for Deployments from {startDate} to {endDate} UTC\n");

            if (releaseList.Count > 0)
                foreach (var releaseItem in releaseList)
                    var release = releaseClient.GetReleaseAsync(project: projectName, releaseId: releaseItem.Id).Result;

                    Console.WriteLine($"Deployment Report for {release.Name}");
                    var deploymentArtifact = release.Artifacts.FirstOrDefault();

                    if (deploymentArtifact != null)
                        var buildRunId = Convert.ToInt32(deploymentArtifact.DefinitionReference["version"].Id);
                        var buildVersion = deploymentArtifact.DefinitionReference["version"].Name;

                        var workItemList = buildClient.GetBuildWorkItemsRefsAsync(project: projectName, buildRunId).Result;
                        Console.WriteLine($"{String.Empty.PadLeft(5)} List of workitems associated to Build {buildVersion} ");

                        foreach (var workitem in workItemList)
                            var wi = wiclient.GetWorkItemAsync(id: Convert.ToInt32(workitem.Id), expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations).Result;
                            Console.WriteLine($"{String.Empty.PadLeft(10)} {wi.Id} - {wi.Fields["System.Title"]} ");
                        Console.WriteLine("Unable to Locate Artifact for this deployment");
                    Console.WriteLine(" ");
                Console.WriteLine("No Deployments found for this period.");

For this sample to work, replace the variable strings with your organization URL, PAT token and project name.

The first thing the program does after the authentication steps is to list all releases that occurred in the past 3 months.

According to the API, the associated work items are not linked directly to a release run. Instead, they are linked through the build that generated the artifact that was used as source for the release pipeline. Therefore, the application had to load the artifact data to identify the build run and then get a list of all work items associated to that build. You could go one level further and even query all the commits associated with the work items to get to the file names.


I hope you got inspired to explore new ways to interact with Azure DevOps and experience how easy and straightforward it is to pull information from the Azure DevOps using REST API.


1 comment

Comments are closed. Login to edit/delete your existing comments

  • Jorge Wong
    Jorge Wong

    Is there any workarounds available to getting this process to work for projects and repos that are following a GitFlow process? (Create a release branch off develop when we are ready to start a release to production)