Philip wrote a simple app to list the work items associated with the changesets for a given path, and it’s in some ways an enhanced update of Naren’s post.
Given an URL to a collection and a server path (e.g., $/myproject/coolthing), it will list the work items that are associated with the most recent 25 checkins. This sample shows how to use the linking service to convert the work item artifact URIs that are stored with the changesets to get the core work item fields (ID, assigned to, state, type, and title).
It will produce output like the following.
Id: 352694 Title: Improve performance of queuing servicing jobs on Azure.
You will need to reference the following DLLs to build this, all of which are found on the .NET tab of the Add Reference dialog in Visual Studio 2010.
- Microsoft.TeamFoundation.Client.dll
- Microsoft.TeamFoundation.Common.dll
- Microsoft.TeamFoundation.VersionControl.Client.dll
using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.TeamFoundation; using Microsoft.TeamFoundation.Client; using Microsoft.TeamFoundation.VersionControl.Client; namespace ListWorkItems { class Program { static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: listworkitems <URL for TFS> <server path>"); Environment.Exit(1); } TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(args[0])); VersionControlServer vcs = tpc.GetService<VersionControlServer>(); // Get the changeset artifact URIs for each changeset in the history query List<String> changesetArtifactUris = new List<String>(); foreach (Object obj in vcs.QueryHistory(args[1], // path we care about ($/project/whatever) VersionSpec.Latest, // version of that path 0, // deletion ID (0 = not deleted) RecursionType.Full, // entire tree - full recursion null, // include changesets from all users new ChangesetVersionSpec(1), // start at the beginning of time VersionSpec.Latest, // end at latest 25, // only return this many false, // we don't want the files changed true)) // do history on the path { Changeset c = obj as Changeset; changesetArtifactUris.Add(c.ArtifactUri.AbsoluteUri); } // We'll use the linking service to get information about the associated work items ILinking linkingService = tpc.GetService<ILinking>(); LinkFilter linkFilter = new LinkFilter(); linkFilter.FilterType = FilterType.ToolType; linkFilter.FilterValues = new String[1] { ToolNames.WorkItemTracking }; // we only want work itms // Convert the artifact URIs for the work items into strongly-typed objects holding the properties rather than name/value pairs Artifact[] artifacts = linkingService.GetReferencingArtifacts(changesetArtifactUris.ToArray(), new LinkFilter[1] { linkFilter }); AssociatedWorkItemInfo[] workItemInfos = AssociatedWorkItemInfo.FromArtifacts(artifacts); // Here we'll just print the IDs and titles of the work items foreach (AssociatedWorkItemInfo workItemInfo in workItemInfos) { Console.WriteLine("Id: " + workItemInfo.Id + " Title: " + workItemInfo.Title); } } } internal class AssociatedWorkItemInfo { private AssociatedWorkItemInfo() { } public int Id { get { return m_id; } } public String Title { get { return m_title; } } public String AssignedTo { get { return m_assignedTo; } } public String WorkItemType { get { return m_type; } } public String State { get { return m_state; } } internal static AssociatedWorkItemInfo[] FromArtifacts(IEnumerable<Artifact> artifacts) { if (null == artifacts) { return new AssociatedWorkItemInfo[0]; } List<AssociatedWorkItemInfo> toReturn = new List<AssociatedWorkItemInfo>(); foreach (Artifact artifact in artifacts) { if (artifact == null) { continue; } AssociatedWorkItemInfo awii = new AssociatedWorkItemInfo(); // Convert the name/value pairs into strongly-typed objects containing the work item info foreach (ExtendedAttribute ea in artifact.ExtendedAttributes) { if (String.Equals(ea.Name, "System.Id", StringComparison.OrdinalIgnoreCase)) { int workItemId; if (Int32.TryParse(ea.Value, out workItemId)) { awii.m_id = workItemId; } } else if (String.Equals(ea.Name, "System.Title", StringComparison.OrdinalIgnoreCase)) { awii.m_title = ea.Value; } else if (String.Equals(ea.Name, "System.AssignedTo", StringComparison.OrdinalIgnoreCase)) { awii.m_assignedTo = ea.Value; } else if (String.Equals(ea.Name, "System.State", StringComparison.OrdinalIgnoreCase)) { awii.m_state = ea.Value; } else if (String.Equals(ea.Name, "System.WorkItemType", StringComparison.OrdinalIgnoreCase)) { awii.m_type = ea.Value; } } Debug.Assert(0 != awii.m_id, "Unable to decode artifact into AssociatedWorkItemInfo object."); if (0 != awii.m_id) { toReturn.Add(awii); } } return toReturn.ToArray(); } private int m_id; private String m_title; private String m_assignedTo; private String m_type; private String m_state; } }
0 comments
Be the first to start the discussion.