Querying a Team Foundation Server for Changesets Using F#

I blogged a little while ago about how useful I’ve found writing code which can be used to accelerate mundane tasks. One task that comes up frequently is having to search through a list of things. I’ve previously covered line by line searches. This post deals with Team Foundation Server 2010 changesets, but the techniques used can be applied to just about anything you can get into an F# seq or .NET IEnumerable.

Although you can certainly search source control history using Team Explorer or other tools, nothing quite offers the versatility of pure code. The Seq module in F# offers plenty of methods which can be combined gracefully in order to query sequences of objects, and is perfect for a requirement like this (as is System.Linq for those who wish to implement this in C#). A major benefit of choosing F# is the rapid edit/compile/run cycle that can be achieved using F# interactive.

To access the Team System services, you’ll need to reference some of the assemblies installed to the GAC along with Team Explorer. The ones we’re interested in are:

  1. #r "Microsoft.TeamFoundation.Client"
  2. #r "Microsoft.TeamFoundation.VersionControl.Client"
  3.  
  4. open Microsoft.TeamFoundation.Client
  5. open Microsoft.TeamFoundation.VersionControl.Client

To get access to our changesets, we need to create a new TfsTeamProjectCollection object using an appropriate URI for the server, and some appropriate NetworkCredentials. We can then get a VersionControlServer which can be used to access the changesets for the project collection.

  1. let uri = Uri("https://tfs.codeplex.com/tfs/sometfsserver")
  2. let creds = NetworkCredential(@"user", "password", "domain")
  3. let tfs = new TfsTeamProjectCollection(uri, creds)
  4. let server = tfs.GetService<VersionControlServer>()

Now we just need to use VersionControlServer’s QueryHistory method to grab the changesets we want. They’re returned as a non-generic IEnumerable containing Changeset objects. To make accessing the items a little easier, we can use Linq’s Cast extension method to get a strongly typed sequence we can use with F#’s Seq module.

QueryHistory has a lengthy parameter list that I’m not going to explain here, because the most up to date documentation on VersionControlServer.QueryHistory can be found on MSDN.

The complete sample below combines everything together and includes a couple of functions which are used to help output our results.

  1. #r "Microsoft.TeamFoundation.Client"
  2. #r "Microsoft.TeamFoundation.VersionControl.Client"
  3.  
  4. open System
  5. open System.Collections
  6. open System.Diagnostics
  7. open System.Linq
  8. open System.Net
  9. open Microsoft.TeamFoundation.Client
  10. open Microsoft.TeamFoundation.VersionControl.Client
  11.  
  12. let shortenString (len:int) (s:string) =
  13.     if len < 3 then failwith "len must be greater than or equal to 3" else
  14.     match s with
  15.     | null -> s
  16.     | s when s.Length > len -> s.Remove(len 3) + "…"
  17.     | _ -> s
  18.  
  19. let printChangeset (c:Changeset) =
  20.     printfn "%5i    %O    %-40s    %s"
  21.             c.ChangesetId
  22.             c.CreationDate
  23.             (shortenString 40 c.Comment)
  24.             c.Owner
  25.  
  26. let uri = Uri("https://tfs.codeplex.com/tfs/sometfsserver")
  27. let creds = NetworkCredential(@"user", "password", "domain")
  28. let localSourcePath = @"D:\_codeplex\nunitresultsexplorer"
  29. let tfs = new TfsTeamProjectCollection(uri, creds)
  30. let server = tfs.GetService<VersionControlServer>()
  31.  
  32. server.QueryHistory(localSourcePath, ChangesetVersionSpec.Latest, 0,
  33.                     RecursionType.Full, null, null, null, Int32.MaxValue,
  34.                     false, true).Cast<Changeset>()
  35. |> Seq.filter (fun c -> c <> null &&
  36.                         c.Comment <> null &&
  37.                         c.Comment.StartsWith("Work item"))
  38. |> Seq.iter printChangeset
  39.  
  40. printfn "Done."

We simply use Seq.filter to get rid of results we’re not interested in (those that don’t start with “Work item”), and simply print each result using Seq.iter and good old side effects. Shown is some sample output when searching my NUnit Results Explorer project.

  1.  6131    10/11/2010 16:39:06    Work item 413. Updated TreeViewItem I…    domain\user
  2.  3290    03/10/2010 15:31:54    Work item 276. Window for font select…    domain\user
  3.  3226    02/10/2010 17:11:12    Work item 262. Expand/collapse all. R…    domain\user
  4.  3151    01/10/2010 12:41:07    Work item 262. Expand/Collapse all fu…    domain\user
  5.  2581    28/09/2010 12:08:31    Work item 288. Corrected alignment of…    domain\user
  6.  2275    26/09/2010 20:54:47    Work item 262. Some more test cases, …    domain\user
  7.  2061    24/09/2010 21:19:52    Work item 263. Errors and warnings di…    domain\user
  8.  1923    24/09/2010 12:57:40    Work item 263. Initial work for error…    domain\user
  9.  1695    23/09/2010 12:42:10    Work item 254. Allow opening of multi…    domain\user
  10. Done.

The collection based functions included in Linq and F#’s libraries can be extremely useful when writing custom queries. This article has demonstrated that by showing how easily F# and the Team Explorer libraries can be harnessed to query a version control server. However, the techniques can be applied to anything you can turn into a generic IEnumerable or seq.

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • LinkedIn
  • Technorati

One thought on “Querying a Team Foundation Server for Changesets Using F#

  1. Great little post, exactly what I needed to get me started querying for non reviewed changesets in TFS. Cheers matey!

Leave a Reply

Your email address will not be published. Required fields are marked *