TFS11 API: Reading the Team Configuration – Iterations and Areas

Team Configuration

In the previous blog post, I have written about querying for available teams and their members. Today, we are going to talk about retrieving and understanding the team configuration settings. If you have read the previous post, you have surely noticed that the TeamFoundationTeam object, which represents our TFS team, doesn’t contain any properties which tell us which areas or iterations the team is working on. Luckily for us, this is exactly what the TeamConfiguration class is for.

Reading the team iterations

Let’s start by examining which information about a team’s iterations is available using WebAccess:

The iterations dialog

I’d just like to note that the iteration dates are actually not a part of the teams configuration settings. The reason for this is that the iteration schedule is defined on the project level and does not depend on the team. Only the selected iterations will be stored as part of the team configuration.

In order to read the configuration for our team, we need to use the TeamSettingsConfigurationService TFS service. This service currently supports only two methods: GetTeamConfigurationsForUser() and SetTeamSettings().

As you might imagine, the GetTeamConfigurationsForUser() method is the one we need to use to retrieve the team configurations. What’s interesting about this method, is that it does not retrieve configurations for all the teams the currently authorized identity has permissions for. Instead, it only retrieves the configurations for the teams that the current user is a member of. Here’s a code sample:

TfsTeamProjectCollection collection = GetServer("<server_uri>");
string projectUri = GetProject(collection, "<project_name");

var configSvc = collection.GetService<TeamSettingsConfigurationService>();
var configs = configSvc.GetTeamConfigurationsForUser(new[] { projectUri });

foreach (TeamConfiguration config in configs)
{
	// Output some basic team info.
	Console.WriteLine("Team name: {0}", config.TeamName);
	Console.WriteLine("Team ID: {0}", config.TeamId);
	Console.WriteLine("Is default team: {0}", config.IsDefaultTeam);
	
	// Access the actual configuration settings.
	TeamSettings ts = config.TeamSettings;
	
	// Output the information on the teams iterations.
	Console.WriteLine("Product backlog: {0}", ts.BacklogIterationPath);
    Console.WriteLine("Current iteration: {0}", ts.CurrentIterationPath);
	
	Console.WriteLine("Team iteration paths:");

	foreach (string path in settings.IterationPaths)
		Console.WriteLine("  {0}", path);
}

In order to build the code from this blog post, you will need to reference a few TFS 11 assemblies: Microsoft.TeamFoundation.Common.dll, Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.ProjectManagement.dll.

Let me just run through the code quickly. The first thing we need to to is to obtain an instance of the TeamSettingsConfigurationService class and call the GetTeamConfigurationsForUser(), passing in a collection of team project URIs we want to retrieve the configuration information for. Next, we simply iterate over all the configurations and output the various settings.

As you can see, the TeamConfiguration object, much like the TeamFoundationTeam object, doesn’t have a lot of properties. However, the important property here is the TeamSettings property, which is of type Microsoft.TeamFoundation.ProcessConfiguration.Client.TeamSettings. This object holds the information about the team’s iterations and work areas. While the BacklogIterationPath property should be pretty self-explanatory, the CurrentIterationPath property has a bit of a twist to it.

The product backlog view

You see, the current iteration is defined by the iteration schedule. An iteration has a start date and a finish date, although both of these values can also be empty. Since you can set up the iteration dates (if you have permissions to do so, of course) so that multiple iterations overlap, you can actually have several iterations that are currently in progress. But we still have only a single current iteration… How’s it determined, then? Well, any iteration for which the start date is less than or equal to today’s date and the end date is greater than or equal to today is considered a currently active iteration. All of the active iterations are sorted by StartDate (ascending), then by FinishDate (ascending) and finally, by the iteration path. After the sorting, the first iteration in the list is the current iteration. I’m not sure if this makes all the sense in the world, but then again, your team wouldn’t be working on multiple iterations at once, right? It’s just an interesting implementation detail, that’s all.

Reading the team work areas

The final piece of information we can use are the team work area settings. A team administrator can choose one or more work areas for the team and decide whether sub-areas are included:

The areas dialog

This information can be retrieved using the following snippet:

TfsTeamService teamService = collection.GetService<TfsTeamService>();
Guid defaultTeamId = teamService.GetDefaultTeamId(projectInfo.Uri);

var config = configurations.FirstOrDefault(c => c.TeamId == defaultTeamId);
if (config != null)
{
	foreach (TeamFieldValue tfv in config.TeamSettings.TeamFieldValues)
		Consolw.WriteLine("Area path: {0} ({1})", tfv.Value, tfv.IncludeChildren);		
}

The teams work areas are encapsulated in TeamFieldValue objects, which have only two properties: the Name and a IncludeChildren flag. The output for the team whose work area settings are displayed in the above image would be:

Area path: Test\Development\Features (True)
Area path: Test\Development (True)

There are two interesting things I’d like to note here. First, the Features work area has the IncludeChildren flag set, although it does not have any children. Second, there are no special settings for storing the default work area. It seems that the default work area TeamFieldValue object is simply stored as the first element in the array, thus indicating that it is the default value.

Conslusion

And that’s it for today. I’m sure you’ll agree that the API seems simple enough and that there shouldn’t be any problems using it. However, I’ve noticed that there’s no way to retrieve the configuration info for a team I am not a member of, in spite of being the project collection administrator. This is something that you can do from WebAccess, and I’ve spent quite some time using Reflector trying to find a way but have had no luck so far. Got questions or comments about the API or this blog post? Send ‘em in!

Be Sociable, Share!
  • http://blogs.msdn.com/buckh Buck Hodges

    Ivan, we should hopefully have the API added for RTM to allow you to get the config info for a team without being a member of the team.

    Buck

    • Ivan Popek

      Buck, I am really glad to hear it and thanks for letting me know. On a side note, do you know if there are any plans on surfacing the team member capacity/interruptions through the client-side API as well? Once again, thank you for the feedback.

  • Louis-Philippe

    “I’m not sure if this makes all the sense in the world, but then again, your team wouldn’t be working on multiple iterations at once, right? It’s just an interesting implementation detail, that’s all”

    Well, it is a pretty big limitation in the case where you can have multiple teams working on the same project but on different areas / iterations at the same time.

    Features planned in iterations can all be part of the same project, but released at different intervals (in time length) by multiple teams.

    I don’t understand at all how this has made it in the RC since it goes against real world applications. The current iteration is used to filter display of multiple other areas throughout the web interface, most notably, the board.