0

I am trying to pull work item information from Team Foundation Server. I have a working program that pulls all WorkItems. I am attempting to only pull WorkItems that belong to a specific iteration (IterationId).

One way to do this that I have tried... is to produce a list of all the WorkItems and then filter out lines that have an IterationID that matches the user given iteration. The problem with this is that it takes a very long time to pull all changes. Most of my iterations only contain 5-10 WorkItems.

My program that pulls all changes:

Uri tfsUri = new Uri(projectCollection.Uri.ToString());
        VersionControlServer controlServer = projectCollection.GetService<VersionControlServer>();
        var hHistory = controlServer.QueryHistory("$/MyPath/",
                                                    VersionSpec.Latest,
                                                    0,
                                                    RecursionType.Full,
                                                    String.Empty,
                                                    null,
                                                    VersionSpec.Latest,
                                                    int.MaxValue,
                                                    false,
                                                    false,
                                                    true);
foreach (Changeset change in hHistory)
{
    cfChangedFiles = change.Changes;
    foreach (WorkItem wi in change.WorkItems)
    {
        strInput = Encoding.GetEncoding(1252).GetString(GetStreamAsByteArray(cfChangedFiles[i].Item.DownloadFile()));
        Console.WriteLine("Iteration ID: " + wi.IterationId.ToString());
        Console.WriteLine("Title: " + wi.Title.ToString());
        Console.WriteLine("ChangesetID: " + change.ChangesetId.ToString());
        Console.WriteLine("SourceText:\t\t" + strInput); //EDIT NEW
        //...Print Other Things...
    }
}

I have also tried pulling the information using WorkItemStore.Query:

WorkItemStore workItemStore = (WorkItemStore)projectCollection.GetService(typeof(WorkItemStore));
// Run a query.
WorkItemCollection queryResults = workItemStore.Query(
    "Select [State], [Title] " +
    "From WorkItems Where [System.IterationId] ='73'");
foreach(WorkItem wi in queryResults)
{
    Console.WriteLine("Iteration ID: " + wi.IterationId.ToString());
    /*...Print Other Things...
}

The problem with the above code is that I cannot pull certain things (like the Source Text).


Similar Question: TFS API - slow foreach changeset iteration - This question is similar in that the OP's program loads very slowly. However, the answer given is already implemented in my program. This also still pulls all changes.

Community
  • 1
  • 1
Kyle Williamson
  • 2,251
  • 6
  • 43
  • 75

2 Answers2

1

I'd probably go with option 2, run a query for all Work Items in that iteration path and then find any associated changesets. I assume it would be faster.

In your foreach loop wi.Links should allow you to get the ChangesetId.

From: How can I query work items and their linked changesets in TFS?

foreach (WorkItem workItem in workItemCollection)
{
    Console.WriteLine("WI: {0}, Title: {1}", workItem.Id, workItem.Title);
    foreach (var changeset in
        workItem.Links
            .OfType<ExternalLink>()
            .Select(link => artifactProvider
                .GetChangeset(new Uri(link.LinkedArtifactUri))))
    {
        Console.WriteLine(
            "CS: {0}, Comment: {1}",
            changeset.ChangesetId,
            changeset.Comment);
    }
}
Community
  • 1
  • 1
rerwinX
  • 2,025
  • 8
  • 9
  • Hi thank you for the response. I have made an edit to my original question. I also need things like text of the changeset's downloaded file. The second option has no way to download the change (from what I can tell). I still appreciate the answer! – Kyle Williamson Feb 10 '16 at 15:04
  • 1
    No problem. What about using "foreach (var change in changeset.Changes)" and then you can use "change.Item.ServerItem" to get the server path or "change.Item.DownloadFile()" to grab the file? – rerwinX Feb 10 '16 at 15:32
  • I am actually doing something very similar where I use `change.Item.ServerItem` and `.DownloadFile()`. The issue is that it is still being called for all changes. Which is causing the working program to take 12~ minutes to run. I am really trying to find a way to download the file using my second attempt/your answer. If not using `workItemCollection` (which runs very quickly), find a way to only pull certain changes from the first block of code. Currently it pulls all changes. – Kyle Williamson Feb 10 '16 at 21:34
0

I found a solution to my question. The 6th and 7th parameters of QueryHistory are the starting ChangesetID and ending ChangesetID.

Uri tfsUri = new Uri(projectCollection.Uri.ToString());
    VersionControlServer controlServer = projectCollection.GetService<VersionControlServer>();
    var hHistory = controlServer.QueryHistory("$/MyPath/",
                                                VersionSpec.Latest,
                                                0,
                                                RecursionType.Full,
                                                String.Empty,
                                                VersionSpec.ParseSingleSpec(changeset.ChangesetId.ToString(), null),
                                                VersionSpec.ParseSingleSpec(changeset.ChangesetId.ToString(), null),
                                                int.MaxValue,
                                                false,
                                                false,
                                                true);

I used WIQL to select all ChangesetIDs that correspond to a given IterationID. Then, I looped through the above code for each ChangesetID. This allowed my application to only load the changes for my given ChangesetID.

Kyle Williamson
  • 2,251
  • 6
  • 43
  • 75