Code review time: getting a list of C# files to review from TFS

The last couple of weeks I have been bussy with a lot of code reviews at our Professional Development Center at info support. We are in the finalizing stage of our next release of our software factory Endeavour. During this release colleagues made several changes to an existing code base for bug fixes and additional features. As you might know by now we use Team Foundation Server since August last year for managing our sources and work items. So for my code review work, I wanted a list of C# files that have changed since the last release. (This matches the date we started using TFS, so I can just query Version Control for all changes since we started using TFS)


 


So I started of with using tf.exe to get me the list I wanted. While tf.exe can deliver you a lot of information, this specific question: Which C# files got changed since the day we added all sources to our repository, does not work completely.


I used queries like :tf history “c:mylocalworkspaceFolder”  /recursive /format:detailed /no prompt /version:D08/01/2005


 


This results in a pretty lengthy list, with all information on all changes on all files made since the 1st of august 2005.


 


So you can get a list, but this list contains all information on all change sets in all detail, and that was just too much. I could have used it and then use Excel to tweak the list to my needs, but hey I am a programmer and know I can get exactly what I need using the object model of version control. (Excel is just way to complex for meJ)


 


Just to show you how powerful the object model is, you can see the code below on what is required to get a list of C# files that got modified since a specific version.


 


using System;


using System.Collections.Generic;


using Microsoft.TeamFoundation.Client;


using Microsoft.TeamFoundation.VersionControl.Client;


 


namespace GetReviewList


{


 class Program


 {


  static void Main(string[] args)


  {


&nbsp;&nbsp; if ((args.Length < 2) || (args.Length > 3))


&nbsp;&nbsp; {


&nbsp;&nbsp;&nbsp; Console.WriteLine(“expected input args: [serverUri]”);


&nbsp;&nbsp; &nbsp;Console.WriteLine(“Sample for server TFSB3 local working folder c:temp and all changes of C# files after date 12 april 2005”);


&nbsp;&nbsp;&nbsp; Console.WriteLine(“GetReviewList “c:temp*.cs” “D04/12/2005” “http://TFSB3:8080″”);


&nbsp;&nbsp;&nbsp; Console.WriteLine(“for alternative version specs, see tfs documentation on version specs for Changesets, Labels, etc.”);


&nbsp;&nbsp;&nbsp; return;


&nbsp;&nbsp; }


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


&nbsp;&nbsp; string localPath = args[0];


&nbsp;&nbsp; string versionFromString = args[1];


&nbsp;&nbsp; TeamFoundationServer tfs = null;


&nbsp;&nbsp; if (args.Length == 3)


&nbsp;&nbsp; {


&nbsp;&nbsp;&nbsp;&nbsp; tfs = TeamFoundationServerFactory.GetServer( args[2]);


&nbsp;&nbsp; }


&nbsp;&nbsp; else


&nbsp;&nbsp; {


&nbsp;&nbsp; &nbsp;&nbsp; // asume single unique server


&nbsp;&nbsp; &nbsp;&nbsp; tfs = TeamFoundationServerFactory.GetUniqueServer();


&nbsp;&nbsp; }


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


&nbsp;&nbsp; List<string> changedFiles = new List<string>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


&nbsp;&nbsp; VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));


&nbsp;&nbsp; try


&nbsp;&nbsp; {


&nbsp;&nbsp;&nbsp; foreach (Changeset item in&nbsp;vcs.QueryHistory(localPath,VersionSpec.ParseSingleSpec(versionFromString,null), 0,RecursionType.Full, null,VersionSpec.ParseSingleSpec(versionFromString,&nbsp;null), null, Int32.MaxValue, true, false))


&nbsp;&nbsp;&nbsp; {


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;// now get the server items involved


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;DateTime checkInDate = item.CreationDate;


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;string user = item.Committer;


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;foreach (Change changedItem in item.Changes)


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;{


&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; //filter all other files then c# files, those need


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//to be reviewed


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//[


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // update: removed check on .cs files, based on the feedback of James. When using a file mask in the


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// itempec you can query for any type of file. e.g. itemspec: c:temp*.cs would result in all c# files


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Thank you James


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //]


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string filename = changedItem.Item.ServerItem.Substring(changedItem.Item.ServerItem.LastIndexOf(‘/’) + 1);


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filename = (string.Format(“{0}”, filename));


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //if you need more info on the changes per file you can also use the string below that shows


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //not only the files changed, but also who, when and what was done at checkin.


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //filename = (string.Format(“[{0}]t[{1}]t[{2}]t {3}”, user,


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;checkInDate.ToString(“dd-MM-yyyy”),changedItem.ChangeType.ToString(), filename));


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!changedFiles.Contains(filename))


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;changedFiles.Add(filename);


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;//now print the list of items


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;foreach (string file in changedFiles)


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(file);


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;}


&nbsp;&nbsp;&nbsp;&nbsp; }


&nbsp;&nbsp;&nbsp; &nbsp;catch (Exception e)


&nbsp;&nbsp;&nbsp;&nbsp; {Console.WriteLine(e.Message);}


&nbsp;&nbsp;&nbsp;&nbsp; }


&nbsp;&nbsp; }


&nbsp; }


&nbsp;


&nbsp;If you would use the program to get your review list, notice you can use also different specifications for the history by specifying not a date but e.g. a change set from which moment on you want to know the changes. The way you would do this is exactly the same as on the tf.exe command line. There is the notion of a version specification that can have the following formats:


&nbsp;


Date/time :&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D10/20/2005


[Update: you can find great info on the date formats you can use at James Mannings blog at the following location]


Changeset number: &nbsp;&nbsp;&nbsp; C1256


Label&nbsp;: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Lmylabel


Latest version&nbsp;:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; T


Workspace: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WWorkspaceName[;WorkspaceOwner]


&nbsp;


&nbsp;