Rory Primrose

Learn from my mistakes, you don't have time to make them yourself

View project on GitHub

Finding solutions not covered by automated builds

Posted on February 7, 2012

I am slowing building a set of automated tasks in my current role as a TFS administrator to verify the state of TFS. My latest task looks for solutions that are not covered by automated builds.

It’s a fairly straight forward task that enumerates solution files and matches them to build definitions across all projects and collections in a TFS instance.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Xml;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.VersionControl.Client;
    
namespace TFSVerifier
{
    [Export(typeof(ITask))]
    public class FindSolutionsWithoutBuildsTask : ITask
    {
        private Uri TfsAddress = new Uri("http://[TfsAddressHere]:8080/tfs", UriKind.Absolute);
    
        public string Name
        {
            get { return GetType().Name; }
        }
    
        public void Execute()
        {
            TfsTeamProjectCollection server = new TfsTeamProjectCollection(TfsAddress);
    
            server.EnsureAuthenticated();
    
            TfsConfigurationServer configurationServer = server.ConfigurationServer;
    
            ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren(
                new[] { CatalogResourceTypes.ProjectCollection },
                false, CatalogQueryOptions.None);
    
            collectionNodes.ToList().ForEach(x => ProcessCollection(server, x));
        }
    
        private void ProcessCollection(TfsTeamProjectCollection server, CatalogNode collectionNode)
        {
            Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
            TfsTeamProjectCollection teamProjectCollection = server.ConfigurationServer.GetTeamProjectCollection(collectionId);
    
            ReadOnlyCollection<CatalogNode> projectNodes = collectionNode.QueryChildren(
                new[] { CatalogResourceTypes.TeamProject },
                false, CatalogQueryOptions.None);
    
            projectNodes.ToList().ForEach(x => ProcessProject(server, collectionNode, x));
        }
    
        private void ProcessProject(TfsTeamProjectCollection server, CatalogNode collectionNode, CatalogNode projectNode)
        {
            String projectName = projectNode.Resource.DisplayName;
                
            VersionControlServer versionControl = server.GetService<VersionControlServer>();
            ItemSpec spec = new ItemSpec("$/" + projectName + "/*.sln", RecursionType.Full);
            ItemSet set = versionControl.GetItems(spec, VersionSpec.Latest, DeletedState.NonDeleted, ItemType.File, false);
    
            if (set.Items.Any() == false)
            {
                return;
            }
    
            IEnumerable<String> solutionsInProject = from x in set.Items
                                                        select x.ServerItem;
    
            IBuildServer buildServer = server.GetService<IBuildServer>();
            IBuildDefinition[] definitions = buildServer.QueryBuildDefinitions(projectNode.Resource.DisplayName, QueryOptions.Definitions);
            IEnumerable<String> projectsBeingBuild = ProjectsBuiltInProject(definitions);
            IEnumerable<String> projectsNotBeingBuild = solutionsInProject.Except(projectsBeingBuild);
    
            if (projectsNotBeingBuild.Any())
            {
                Console.WriteLine(collectionNode.Resource.DisplayName + ": " + projectName);
    
                Console.ForegroundColor = ConsoleColor.Yellow;
    
                projectsNotBeingBuild.ToList().ForEach(x => Console.WriteLine(x));
    
                Console.ForegroundColor = ConsoleColor.Gray;
            }
        }
    
        private IEnumerable<String> ProjectsBuiltInProject(IBuildDefinition[] definitions)
        {
            foreach (IBuildDefinition definition in definitions)
            {
                IEnumerable<String> projectsToBuild = ProjectsToBuild(definition);
    
                foreach (String projectToBuild in projectsToBuild)
                {
                    yield return projectToBuild;
                }
            }
        }
    
        private IEnumerable<String> ProjectsToBuild(IBuildDefinition definition)
        {
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);
    
            manager.AddNamespace("y", "clr-namespace:System.Collections.Generic;assembly=mscorlib");
            manager.AddNamespace("x", "clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow");
    
            doc.LoadXml(definition.ProcessParameters);
    
            XmlNode node = doc.SelectSingleNode("//y:Dictionary/x:BuildSettings/@ProjectsToBuild", manager);
    
            if (node == null)
            {
                return new List<String>();
            }
    
            String projectsToBuild = node.Value;
            String[] projects = projectsToBuild.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    
            return projects;
        }
    }
}

Enjoy