Search code examples
c#tfsazure-devopsjson-patchazure-devops-rest-api

Using VsConnection WorkItemTrackingHttpClient patch to add parent relation via VSTS client API


I am trying to programmatically add a parent-child relationship between two work items. I am using the Microsoft Team Foundation and Visual Studio Services libraries to export and import TFS 2015 and VSTS backlog objects.

https://learn.microsoft.com/en-us/vsts/integrate/concepts/dotnet-client-libraries

https://www.visualstudio.com/en-us/docs/integrate/api/wit/samples#migrating-work-items

I have worked through obtaining a VssConnection to my servers and getting a WorkItemTrackingHttpClient to execute Wiql queries and create work items. I also have a query to identify the parent of a target work item.

What I cannot figure out is how to add the link between child work items and their parent. I do not know the correct JsonPatchDocument item path to add the parent, or the correct property or method on an existing WorkItem to update it with a parent link. Does anyone have documentation links or specific information on adding a parent relationship to a work item using these libraries?

Here are some code excerpts for context:

using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
// ...
var sourceConnection = new VssConnection(new Uri(_sourceTsUrl), new VssClientCredentials());
var targetConnection = new VssConnection(new Uri(_targetTsUrl), new VssClientCredentials());
var sourceClient = sourceConnection.GetClient<WorkItemTrackingHttpClient>();
var targetClient = targetConnection.GetClient<WorkItemTrackingHttpClient>();
// ...
var queryResults = sourceClient.QueryByWiqlAsync(query).Result;
var ids = queryResults.WorkItems.Select(x => x.Id).ToList();
var items = sourceClient.GetWorkItemsAsync(ids);
foreach (var item in items.Result)
{
    // ...
    var patchItem = new JsonPatchDocument();
    foreach (var fieldName in item.Fields.Keys)
    { patchItem.Add(new JsonPatchOperation() { Path = $"/fields/{fieldName}", Value = item.Fields[fieldName], Operation = Operation.Add }); }
    // TODO - add patch field(?) for parent relationship
    var parentResults = sourceClient.QueryByWiqlAsync(parentQuery).Result;
    // ...
    var task = targetClient.CreateWorkItemAsync(patchItem, targetProject, itemType, validateOnly, bypassRules, suppressNotifications);
    var newItem = task.Result;
    // TODO - alternatively, add parent via the returned newly generated WorkItem
}

Addendum: I've tried adding the following code, but the changes do not get committed to the remote object, it only exists in local memory, and I cannot find a method to push the changes/updates.

if (!string.IsNullOrWhiteSpace(mappedParentUrl))
{
    if (newItem.Relations == null)
    { newItem.Relations = new List<WorkItemRelation>(); }
    newItem.Relations.Add(new WorkItemRelation() { Rel = "Parent", Title = mappedParentTitle, Url = mappedParentUrl });
}

Solution

  • Refer to this code to create task work item with parent link (Update it to meet your requirement):

    var url = new Uri("https://XXX.visualstudio.com"); 
    var connection = new VssConnection(url, new VssClientCredentials());
    var workitemClient = connection.GetClient<WorkItemTrackingHttpClient>();
    string projectName = "[project name]";
    int parentWITId = 771;//parent work item id
    var patchDocument = new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument();
    patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation() {
        Operation=Operation.Add,
        Path= "/fields/System.Title",
        Value="parentandchildWIT"
    });
    
    patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation() {
        Operation = Operation.Add,
        Path = "/relations/-",
        Value = new {
            rel = "System.LinkTypes.Hierarchy-Reverse",
            url = connection.Uri.AbsoluteUri+ projectName+ "/_apis/wit/workItems/"+parentWITId,
            attributes = new {
                comment = "link parent WIT"
            }
        }
    });
    var createResult = workitemClient.CreateWorkItemAsync(patchDocument, projectName, "task").Result;