Tfs ';创建工作项的副本';通过Azure DevOps的REST API?

Tfs ';创建工作项的副本';通过Azure DevOps的REST API?,tfs,azure-devops,azure-devops-rest-api,Tfs,Azure Devops,Azure Devops Rest Api,我想“创建工作项的副本”,这可以通过UI获得,最好是通过API。 我知道如何创建新的工作项,但是UI中连接所有当前父链接/相关链接以及所有其他详细信息的功能非常有用 通过此API创建的内容如下: 任何帮助都将不胜感激。我们不能只复制工作项,因为它包含我们应该跳过的系统字段。此外,您的流程可能有一些规则,这些规则可能会阻止创建步骤中的某些字段。下面是一个通过REST API克隆工作项的小示例: 类程序 { 静态字符串[]systemFields={“System.IterationId”、“Sys

我想“创建工作项的副本”,这可以通过UI获得,最好是通过API。 我知道如何创建新的工作项,但是UI中连接所有当前父链接/相关链接以及所有其他详细信息的功能非常有用

通过此API创建的内容如下:


任何帮助都将不胜感激。

我们不能只复制工作项,因为它包含我们应该跳过的系统字段。此外,您的流程可能有一些规则,这些规则可能会阻止创建步骤中的某些字段。下面是一个通过REST API克隆工作项的小示例:

类程序
{
静态字符串[]systemFields={“System.IterationId”、“System.ExternalLinkCount”、“System.HyperLinkCount”、“System.AttachedFileCount”、“System.NodeName”,
“System.ReviedDate”、“System.ChangedDate”、“System.Id”、“System.AreaId”、“System.AuthorizedAs”、“System.State”、“System.AuthorizedDate”、“System.Watermark”,
“System.Rev”、“System.ChangedBy”、“System.Reason”、“System.WorkItemType”、“System.CreatedDate”、“System.CreatedBy”、“System.History”、“System.RelatedLinkCount”,
“System.BoardColumn”、“System.BoardColumnDone”、“System.BoardLane”、“System.CommentCount”、“System.TeamProject”};//要跳过的系统字段
静态字符串[]customFields={“Microsoft.VSTS.Common.ActivateDate”、“Microsoft.VSTS.Common.ActivatedBy”、“Microsoft.VSTS.Common.ResolvedDate”,
“Microsoft.VSTS.Common.ResolvedBy”、“Microsoft.VSTS.Common.ResolvedReason”、“Microsoft.VSTS.Common.ClosedDate”、“Microsoft.VSTS.Common.ClosedBy”,
“Microsoft.VSTS.Common.StateChangeDate”};//跳过不需要的字段
const string ChildRefStr=“System.LinkTypes.Hierarchy Forward”;//应仅为一个父级
静态void Main(字符串[]参数)
{
字符串pat=“”//https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate
字符串orgUrl=”https://dev.azure.com/";
字符串newProjectName=“”;
int wiIdToClone=0;
VssConnection connection=newVSSConnection(新Uri(orgUrl)、新VssBasicCredential(string.Empty,pat));
var witClient=connection.GetClient();
CloneWorkItem(witClient、wiIdToClone、newProjectName、true);
}
私有静态void CloneWorkItem(WorkItemTrackingHttpClient witClient,int wiIdToClone,字符串NewTeamProject=“”,bool CopyLink=false)
{
WorkItem wiToClone=(CopyLink)?witClient.GetWorkItemAsync(wiIdToClone,展开:WorkItemExpand.Relations)。结果
:witClient.GetWorkItemAsync(wiIdToClone).Result;
字符串teamProjectName=(NewTeamProject!=“”)?NewTeamProject:wiToClone.Fields[“System.TeamProject”].ToString();
字符串wiType=wiToClone.Fields[“System.WorkItemType”].ToString();
JsonPatchDocument patchDocument=新的JsonPatchDocument();
foreach(wiToClone.Fields.Keys中的var键)//复制字段
如果(!systemFields.Contains(键)和&!customFields.Contains(键))
如果(NewTeamProject==“”||
(NewTeamProject!=“&&key!=“System.AreaPath”&&key!=“System.IterationPath”)//不要将区域和迭代复制到另一个项目中
patchDocument.Add(新的JsonPatchOperation()
{
操作=操作。添加,
Path=“/fields/”+键,
Value=wiToClone.Fields[键]
});
if(CopyLink)//复制链接
foreach(wiToClone.Relations中的var链接)
{
如果(link.Rel!=ChildRefStr)
{
patchDocument.Add(新的JsonPatchOperation()
{
操作=操作。添加,
Path=“/relations/-”,
值=新
{
rel=link.rel,
url=link.url
}
});
}
}
WorkItem clonedWi=witClient.CreateWorkItemAsync(patchDocument,teamProjectName,wiType).Result;
Console.WriteLine(“新工作项:+clonedWi.Id”);
}
}
链接到完整项目:

class Program
{
    static string[] systemFields = { "System.IterationId", "System.ExternalLinkCount", "System.HyperLinkCount", "System.AttachedFileCount", "System.NodeName",
    "System.RevisedDate", "System.ChangedDate", "System.Id", "System.AreaId", "System.AuthorizedAs", "System.State", "System.AuthorizedDate", "System.Watermark",
        "System.Rev", "System.ChangedBy", "System.Reason", "System.WorkItemType", "System.CreatedDate", "System.CreatedBy", "System.History", "System.RelatedLinkCount",
    "System.BoardColumn", "System.BoardColumnDone", "System.BoardLane", "System.CommentCount", "System.TeamProject"}; //system fields to skip

    static string[] customFields = { "Microsoft.VSTS.Common.ActivatedDate", "Microsoft.VSTS.Common.ActivatedBy", "Microsoft.VSTS.Common.ResolvedDate", 
        "Microsoft.VSTS.Common.ResolvedBy", "Microsoft.VSTS.Common.ResolvedReason", "Microsoft.VSTS.Common.ClosedDate", "Microsoft.VSTS.Common.ClosedBy",
    "Microsoft.VSTS.Common.StateChangeDate"}; //unneeded fields to skip

    const string ChildRefStr = "System.LinkTypes.Hierarchy-Forward"; //should be only one parent


    static void Main(string[] args)
    {
        string pat = "<pat>"; //https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate
        string orgUrl = "https://dev.azure.com/<org>";
        string newProjectName = "";
        int wiIdToClone = 0; 


        VssConnection connection = new VssConnection(new Uri(orgUrl), new VssBasicCredential(string.Empty, pat));
        var witClient = connection.GetClient<WorkItemTrackingHttpClient>();

        CloneWorkItem(witClient, wiIdToClone, newProjectName, true);            
    }

    private static void CloneWorkItem(WorkItemTrackingHttpClient witClient, int wiIdToClone, string NewTeamProject = "", bool CopyLink = false)
    {
        WorkItem wiToClone = (CopyLink) ? witClient.GetWorkItemAsync(wiIdToClone, expand: WorkItemExpand.Relations).Result
            : witClient.GetWorkItemAsync(wiIdToClone).Result;

        string teamProjectName = (NewTeamProject != "") ? NewTeamProject : wiToClone.Fields["System.TeamProject"].ToString();
        string wiType = wiToClone.Fields["System.WorkItemType"].ToString();

        JsonPatchDocument patchDocument = new JsonPatchDocument();

        foreach (var key in wiToClone.Fields.Keys) //copy fields
            if (!systemFields.Contains(key) && !customFields.Contains(key))
                if (NewTeamProject == "" ||
                    (NewTeamProject != "" && key != "System.AreaPath" && key != "System.IterationPath")) //do not copy area and iteration into another project
                    patchDocument.Add(new JsonPatchOperation()
                    {
                        Operation = Operation.Add,
                        Path = "/fields/" + key,
                        Value = wiToClone.Fields[key]
                    });

        if (CopyLink) //copy links
            foreach (var link in wiToClone.Relations)
            {
                if (link.Rel != ChildRefStr)
                {
                    patchDocument.Add(new JsonPatchOperation()
                    {
                        Operation = Operation.Add,
                        Path = "/relations/-",
                        Value = new
                        {
                            rel = link.Rel,
                            url = link.Url
                        }
                    });
                }
            }

        WorkItem clonedWi = witClient.CreateWorkItemAsync(patchDocument, teamProjectName, wiType).Result;

        Console.WriteLine("New work item: " + clonedWi.Id);
    }
}