Question

I'm trying to build a report to show the relative efficiency of my various build agents and having trouble getting the info I need out of the tool.

What I'd like to have is a simple grid with the following columns:

  • Build Number
  • Build Definition
  • Build Agent
  • Build Status
  • Build Start Time
  • Build Duration

Which would let me do something like chart the duration of successful builds of a given build definition on agent1 against the same build definition on agent2 through agentN.

How would I go about this?

Was it helpful?

Solution

My initial intention was to point you to TFS OLAP Cube & describe how you could retrieve what you were after. Then I realized that the cube does not provide with the info which Agent built what Build.

Then I thought it would be simple to write a small TFS-console app that print the infos you 're after:

using System;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;

namespace BuildDetails
{
    class Program
    {
        static void Main()
        {
            TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFS:8080/tfs/CoLLeCtIoNNaMe"));
            var buildService = (IBuildServer)teamProjectCollection.GetService(typeof(IBuildServer));

            IBuildDefinition buildDefinition = buildService.GetBuildDefinition("TeamProjectName", "BuildDefinitionName");
            IBuildDetail[] buildDetails = buildService.QueryBuilds(buildDefinition);

            foreach (var buildDetail in buildDetails)
            {
                Console.Write(buildDetail.BuildNumber+"\t");
                Console.Write(buildDefinition.Name+"\t");
                Console.Write(buildDetail.BuildAgent.Name+"\t");
                Console.Write(buildDetail.Status+"\t");
                Console.Write(buildDetail.StartTime+"\t");
                Console.WriteLine((buildDetail.FinishTime - buildDetail.StartTime).Minutes);                
            }           
        }
    }
}

This won't compile, since
enter image description here

Eventually I dove into the IBuildInformationNode[] and got the build agent as follows:

IBuildInformation buildInformation = buildDetail.Information;
IBuildInformationNode[] buildInformationNodes = buildInformation.Nodes;
string agentName;
try
{
  agentName = buildInformationNodes[0].Children.Nodes[3].Fields["ReservedAgentName"];
}
catch
{
  agentName = "Couldn't determine BuildAgent";
}
Console.Write(agentName + "\t");

The try-catch is necessary, so you can deal with builds that failed/stopped before agent-selection.

If you use this latter part as a substitute to the failing Console.Write(buildDetail.BuildAgent.Name+"\t"); you should end up with a console app, whose output can be piped into a *.CSV file & then imported to Excel.

OTHER TIPS

The following code should help in getting the Build Agent Name for the given build detail.

private string GetBuildAgentName(IBuildDetail build)
    {
        var buildInformationNodes = build.Information.GetNodesByType("AgentScopeActivityTracking", true);
        if (buildInformationNodes != null)
        {
            var node = buildInformationNodes.Find(s => s.Fields.ContainsKey(InformationFields.ReservedAgentName));
            return node != null ? node.Fields[InformationFields.ReservedAgentName] : string.Empty;
        }

        return string.Empty;
    }

Make sure that you have refresh the build information in the build details object.You can do so by the either calling the following code on your build Details object before getting the build agents

string[] refreshAllDetails = {"*"};
build.Refresh(refreshAllDetails, QueryOptions.Agents);

Hope it helps :)

The build agent information isn't always in the same place.

I found it for a build I was looking at in buildInformationNodes[1].Children.Nodes[2].Fields["ReservedAgentName"]. The following seems to work for me (so far).

private static string GetAgentName(IBuildDetail buildDetail)
{
   string agentName = "Unknown";
   bool fAgentFound = false;

   try
   {
      foreach (IBuildInformationNode node in buildDetail.Information.Nodes)
      {
         foreach (IBuildInformationNode childNode in node.Children.Nodes)
         {
            if (childNode.Fields.ContainsKey("ReservedAgentName"))
            {
               agentName = childNode.Fields["ReservedAgentName"];
               break;
            }
         }
         if (fAgentFound) break;
      }

   }
   catch (Exception ex)
   {
      // change to your own routine as needed
      DumpException(ex);
   }
   return agentName;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top