getting associated changesets for work items

During some of our internal processes, we port sets of approved bugs over from one branch to another.  Since we're dogfooding Team Foundation, the bugs are Team Foundation work item id's and we need the changesets associated with those.  You can easily open the work items inside VS, but if it's a dozen or more work items, that takes a bit of time just to get the associated changeset id's.

This is a beta3 sample (we're thinking about some ways of making this a little cleaner for RTM, but that's work in progress) that will take a list of work item id's and list out the associated changesets (if any) for those work items.

You may need to make your browser window wider if this code doesn't look right for you.  Note that for simplicity it doesn't include error checking you would normally do (for instance, if you ask for a work item id that doesn't exist or you don't have access to, you'll get an exception, but this doesn't currently catch it) but it should get the point across.  One of the things to take away from this is that we have a couple of concepts that are important here:

  1. we have the concepts of artifacts (some of which are work items and changesets) inside Team Foundation.  This is extensible as third parties can add their own artifacts.
  2. we have a linking mechanism that holds associations (links) between artifacts.

I'll update this code once RTM is close if the API changes any.

Update: The linking support moved from the Microsoft.TeamFoundation.Server namespace in the Microsoft.TeamFoundation.dll library to Microsoft.TeamFoundation namespace in the Microsoft.TeamFoundation.Common.dll library - updates below (one using statement change), and a solution attached to make it easier for people to get this working for them.

Here's an example usage:

D:\task1_binaries.x86dbg\bin\i386>ChangesetsFromWorkItems.exe dogfood 48066 bogus 40866 foobar 48490
WorkItem 48066 has associated changeset(s): 9527
ignoring unparseable argument bogus
WorkItem 40866 has associated changeset(s):
ignoring unparseable argument foobar
WorkItem 48490 has associated changeset(s): 9067, 9259

using System;

using System.Collections.Generic;

 

using Microsoft.TeamFoundation.Client;

using Microsoft.TeamFoundation.WorkItemTracking.Client;

using Microsoft.TeamFoundation;

class ChangesetsFromWorkItems

{

    static void Main(string[] args)

    {

        if (args.Length < 2)

        {

            Console.Error.Write("Usage: ChangesetsFromWorkItems <server> <workitemid> [workitemid...]");

   Environment.Exit(1);

        }

        TeamFoundationServer server = TeamFoundationServerFactory.GetServer(args[0]);

        WorkItemStore wiStore = (WorkItemStore)server.GetService(typeof(WorkItemStore));

        int workItemId;

        for (int i = 1; i < args.Length; i++)

        {

            if (!int.TryParse(args[i], out workItemId))

            {

                Console.Error.WriteLine("ignoring unparseable argument {0}", args[i]);

                continue;

            }

            WorkItem workItem = wiStore.GetWorkItem(workItemId);

            List<string> associatedChangesets = new List<string>();

            foreach (Link link in workItem.Links)

            {

                ExternalLink extLink = link as ExternalLink;

          if (extLink != null)

                {

                    ArtifactId artifact = LinkingUtilities.DecodeUri(extLink.LinkedArtifactUri);

                    if (String.Equals(artifact.ArtifactType, "Changeset", StringComparison.Ordinal))

                    {

                        associatedChangesets.Add(artifact.ToolSpecificId);

                    }

                }

            }

            string changesets = String.Join(", ", associatedChangesets.ToArray());

            Console.WriteLine("WorkItem {0} has associated changeset(s): {1}", workItemId, changesets);

        }

    }

}

 

ChangesetsFromWorkItems.zip