Wednesday, May 16, 2012

TFS Queries: Recent builds of all team projects

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


We can see all the build results of a team project easily inside Team Explorer or with the Web Access but there is no way to see the build results of all team projects at the same time. Using a simple query and a few Linq operators we can get a useful little report in LinqPad.

Required references


Microsoft.TeamFoundation.Build.Client.dll
Microsoft.TeamFoundation.Client.dll
Microsoft.TeamFoundation.Framework.Client.dll

Query (C# Statements)

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

tfs.EnsureAuthenticated();

var buildServer = tfs.GetService<IBuildServer>();

var spec = buildServer.CreateBuildDetailSpec("*");
spec.MinFinishTime = DateTime.Now.Subtract(TimeSpan.FromDays(7));
spec.MaxFinishTime = DateTime.Now;
spec.QueryDeletedOption = QueryDeletedOption.IncludeDeleted;

var builds = buildServer.QueryBuilds(spec).Builds;
var total = builds.Sum(b => b.FinishTime.Subtract(b.StartTime).TotalMinutes);

builds.Select(x => new
{
 Project = x.TeamProject,
 Definition = x.BuildDefinition.Name,
 Version = x.SourceGetVersion,
 Developer = x.RequestedFor,
 Type = x.Reason,
 Start = x.StartTime,
 Duration = x.FinishTime.Subtract(x.StartTime),
 Build = x.CompilationStatus,
 Tests = x.TestStatus,
 Result = x.Status,
 StyleCopViolations = InformationNodeConverters.GetBuildWarnings(x)
  .Count(inc => inc.Message.StartsWith("SA")),
 FxCopViolations = InformationNodeConverters.GetBuildWarnings(x)
  .Count(inc => inc.Message.StartsWith("CA")),
 Warnings = InformationNodeConverters.GetBuildWarnings(x)
  .Select(inc => inc.Message)
  .Where(m => !m.StartsWith("SA") && !m.StartsWith("CA")),
 Errors = InformationNodeConverters.GetBuildErrors(x)
  .Select(inc => inc.Message)
})
.OrderByDescending(b => b.Start)
.Dump("All builds of the week.  Total build duration: " + total);

Result


You will get a list of the build results of all the team projects for the last week. The total build time is at the top of list. Each build result include the build errors, warnings and the number of StyleCop and FxCop violations found (if you have included those static analysis tools in your project template). Also, on line 9 you can change the query to get build results over a longer period of time.

All builds of the week.  Total build duration: 20.666666666666667

IOrderedEnumerable<> (1 item)
Project Definition Version Developer Type Start Duration Build Tests Result StyleCopViolations FxCopViolations Warnings Errors
Project 1 Main 25 Pascal Manual 09/05/2012 9:34:07 PM 00:12:06 Success Success Success 4 1
IEnumerable<String> (0 items)

IEnumerable<String> (0 items)
Project 2 Main 28 Pascal Manual 09/05/2012 11:25:26 PM 00:08:34 Success Success Success 0 0
IEnumerable<String> (0 items)

IEnumerable<String> (0 items)

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.



Wednesday, May 2, 2012

Setup your first TFS LinqPad query

 

Prerequisites

  • LinqPad (of course)
  • Team Explorer (as part of your complete VS2010 installation)

Setup

  • Inside LinqPad create a new empty query and in the Language combo box select C# Statements.

    image
    • Go to the Query Properties page by the Query menu or by pressing F4.
    • You can add assembly references using two ways in the Additional References tab, by browsing or adding them from the GAC

      image

      Adding assembly reference by browsing
      • Press the Browse button
      • The assemblies we want are under C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.

        image

        Adding assembly references by adding from the GAC
        • Press the Add button
          • Check the Show GAC assemblies option
          • Enter TeamFoundation in the textbox

        image

        Usually we need at least:
        • Microsoft.TeamFoundation.Client.dll
        • Microsoft.TeamFoundation.Common.dll
        But we might also want:
        • Microsoft.TeamFoundation.VersionControl.Client.dll
        • Microsoft.TeamFoundation.Build.Client.dll

          image

          Now, in the Additional Namespace Imports add the following lines
          • Microsoft.TeamFoundation.Client
          • Microsoft.TeamFoundation.Framework.Client
          And maybe those too
          • Microsoft.TeamFoundation.VersionControl.Client
          • Microsoft.TeamFoundation.Build.Client
          Finally press Ok
          We are now ready to write our first query

          A first query

          Let’s start with something simple
          var tfs = TfsTeamProjectCollectionFactory
              .GetTeamProjectCollection(new Uri("http://localhost:8088/tfs"));
          
          tfs.Dump();
          

          Now press F5 and you should get a result like below

          image

          That’s it.  You are now ready to start writing useful LinqPad queries against your TFS server.

          What's next


          You should take a look at useful queries I wrote using LinqPad and the TFS API here.