Wednesday, May 9, 2012

TFS Queries: Searching in all files of the source control

For an intro on LinqPad and the TFS API please read this post
For the list of all the posts in this series please read this one

Context


Searching in all files of a solution inside Visual Studio is very useful. In TFS you can search for files of a collection but there is no built in functionality to search for text inside those files. Using the TFS API we can do this kind of thing.

Required references


Microsoft.TeamFoundation.Client.dll
Microsoft.TeamFoundation.Framework.Client.dll
Microsoft.TeamFoundation.VersionControl.Client.dll

Query (C# Program)

string[] textPatterns = new[] { "Main(string", "(this " };
string[] filePatterns = new[] { "*.cs", "*.xml", "*.config" };

void Main()
{
 var tfs = TfsTeamProjectCollectionFactory
  .GetTeamProjectCollection(new Uri("http://localhost:8088/tfs"));

 var versionControl = tfs.GetService<VersionControlServer>();
 
 var teamBranches = versionControl.QueryRootBranchObjects(RecursionType.Full)
  .Where (s => !s.Properties.RootItem.IsDeleted)
  .Select(s => s.Properties.RootItem.Item)
  .ToList()
  .Dump("Searching in the following branches");
 
 filePatterns.Dump("File patterns");
 textPatterns.Dump("Text patterns");

 foreach (var teamBranch in teamBranches)
  foreach (var filePattern in filePatterns)
   foreach (var item in versionControl.GetItems(teamBranch + "/" 
    + filePattern, RecursionType.Full).Items)
    SearchInFile(item);
}

// Define other methods and classes here
private void SearchInFile(Item file)
{
 var result = new List<string>();
 var stream = new StreamReader(file.DownloadFile(), Encoding.Default);
 
 var line = stream.ReadLine();
 var lineIndex = 0;
 
 while (!stream.EndOfStream)
 {
  if (textPatterns.Any(p => line.IndexOf(p, StringComparison.OrdinalIgnoreCase) >= 0))
   result.Add("Line " + lineIndex + ": " + line.Trim());
 
  line = stream.ReadLine();
  lineIndex++;
 }
 
 if (result.Count > 0) result.Dump(file.ServerItem);
}

Result


You will get all the lines and line numbers matching the text search patterns for all files matching the file search patterns. This may take a lot of time (30 minutes on some occurrence so be careful!). You might want to add more restrictions, especially the the branches to query around line 12.



4 comments:

TrayKarn said...

Hello, I am very happy to see this. Although I think that this is for tfs2010. Is there any way you could show what changes are required to perform this sort of querying in tfs2008??? I would find it very helpful.

Unknown said...

Hi TrayKarn,

You are right, I'm targeting TFS2010 and even TFS2012 for some of the latest queries. Unfortunately, I know that the API changed a bit since previous versions. Looking at the MSDN documentation I can only find information on TFS2005 http://msdn.microsoft.com/en-us/library/bb130334(v=vs.80) and I can see a lot of changes. I know that VersionControlServer doesn't have QueryRootBranchObjects on it and that you can't use TfsTeamProjectCollectionFactory but something else. The rest of the query should not change much but as I don't have access to a TFS2008 server I cannot test the changes required.

Sorry about that.

TrayKarn said...

No worries thanks for the reply.

Pinnacle Web Solutions said...

Thanks a lot , it worked like a charm...

Just need to add following Nuget (Microsoft.TeamFoundationServer.ExtendedClient) to get the referenced Assemblies