Thursday, December 15, 2022

Pulling data from TFS

This has nothing to do with WPF, but it was excessively difficult to find any useful information on the subject. I get the impression Microsoft has gone to great lengths to make you not want to do this.

Lets jump right in and write a console app that finds the most recent check in and lists it, together with the files that were modified.

Start a new project in Visual Studio. Chose  C# console .Net Framework and call the project TFS.

Browse to Tools -> NuGet Package manager -> Manage NuGet packages for solution

Click the Browse tab and install Microsoft.TeamFoundationServer.ExtendedClient.

Add these usings to Program.cs

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.VisualStudio.Services.Common;
using System;

Now we need to figure out our server URL and path. Add two declarations to Main(). Yours will contain your server name and the path to your project or solution. My declarations look like this. If your tfs server uses https it would look more like https://tfs-back:443/...


string server = "http://tfs-back:8080/tfs/DefaultCollection";
string path = "$/Financial/Dev/";

I can use my default credentials to connect to tfs. You may need to create and pass custom credentials. 

TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(server), new VssCredentials(true));
VersionControlServer vcs = tpc.GetService<VersionControlServer>();

Now we come to the meat of the code. The Query. It has a lot of parameters. Try playing with them. This example returns the most recent changeset that targets the latest version of the solution. It doesn't care who created the changeset.

foreach (object obj in vcs.QueryHistory(path,
                                        VersionSpec.Latest,
                                        deletionId: 0,
                                        RecursionType.Full,
                                        user: null,
                                        new ChangesetVersionSpec(1),
                                        VersionSpec.Latest,
                                        maxCount: 1,
                                        includeChanges: true,
                                        slotMode: true))

In the body of the foreach we print selected information from the changeset and the changed files.

{
    Changeset changeSet = (Changeset)obj;
    Console.WriteLine($"Changeset {changeSet.ChangesetId} {changeSet.CreationDate} {changeSet.CommitterDisplayName} {changeSet.Comment}");
    foreach (Change change in changeSet.Changes)
        Console.WriteLine($"    {change.Item.ServerItem}");
}

So the whole process is quite simple, but then most things are once you know how to do them. This is what the output might look like.

Changeset 1225 12/15/2022 11:48:53 AM JOHN SMITH Settings Roll should set APYVariance Edit, Level Codes, and Objects
    $/Financial/Dev/Scripts/F2000Master_Database.sql
    $/Financial/Dev/F2K.Net/Core/Database/Config/DistrictConfig.cs

Here's the code in its entirety.

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
 
namespace TFS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string server = "http://tfs-back:8080/tfs/DefaultCollection";
            string path = "$/Financial/Dev/";
 
            TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(server), new VssCredentials(true));
            VersionControlServer vcs = tpc.GetService<VersionControlServer>();
 
            foreach (object obj in vcs.QueryHistory(path,
                                                    VersionSpec.Latest,
                                                    deletionId: 0,
                                                    RecursionType.Full,
                                                    user: null,
                                                    new ChangesetVersionSpec(1),
                                                    VersionSpec.Latest,
                                                    maxCount: 1,
                                                    includeChanges: true,
                                                    slotMode: true))
            {
                Changeset changeSet = (Changeset)obj;
                Console.WriteLine($"Changeset {changeSet.ChangesetId} {changeSet.CreationDate} {changeSet.CommitterDisplayName} {changeSet.Comment}");
                foreach (Change change in changeSet.Changes)
                {
                    Console.WriteLine($"    {change.Item.ServerItem}");
                }
            }
 
            Console.ReadLine();
        }
    }
 
}