A Dutch software developer living in Chile
# Thursday, September 17, 2009
Moving TFS Historic builds to a new location

If you have a bunch of TFS builds that get a new home, it is always nice to let TFS know those files have been moved. But sadly, in the documentation there’s not much to find about this, nor is there any UI interface that lets you make this kind of change.

So I asked a question on the build forums, and Hongye Sun of Microsoft told me the best way to go at this, is use the Team Build APIs.

I’ve created a simple MoveBuild command line tool that allows you to move all the known builds from an old drop location to a new one, across all TFS projects.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;

namespace MoveBuild
{
  class Program
  {
    static void Main(string[] args)
    {
      if (args.Length < 3)
      {
        ShowUsage();
        return;
      }

      try
      {
        string tfsServer = args[0];
        string sourceDir = args[1];
        string targetDir = args[2];

        bool commit = args.Length == 4 && String.Equals(args[3], "/Commit", StringComparison.InvariantCultureIgnoreCase);

        TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(tfsServer);
        ICommonStructureService css = (ICommonStructureService)tfs.GetService(typeof(ICommonStructureService));
        foreach (ProjectInfo item in css.ListAllProjects())
        {
          MoveBuilds(tfs, item.Name, sourceDir, targetDir, commit);
        }

      }
      catch (Exception ex)
      {
        if (!Debugger.IsAttached)
          Console.WriteLine(ex.ToString());
        else
          throw;
      }

    }

    private static void MoveBuilds(TeamFoundationServer server, string teamProject, string sourceDir, string targetDir, bool commit)
    {

      int recordCount = 0;
      IBuildServer buildServer = (IBuildServer)server.GetService(typeof(IBuildServer));
      foreach (IBuildDetail item in buildServer.QueryBuilds(teamProject))
      {
        bool isMatch = item.DropLocation.StartsWith(sourceDir, StringComparison.InvariantCultureIgnoreCase);
        if (!isMatch)
          continue;
        recordCount++;
        //Console.ForegroundColor = isMatch ? ConsoleColor.Green: ConsoleColor.Red;
        //if (!isMatch)
        //  Console.Write("SKIPPED: ");
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine(item.BuildNumber);
        
        Console.ForegroundColor = ConsoleColor.Gray;
        StringBuilder newDropLocation = new StringBuilder();
        newDropLocation.Append(targetDir);
        if (item.DropLocation.Length > sourceDir.Length)
          newDropLocation.Append(item.DropLocation.Substring(sourceDir.Length));

        StringBuilder newLogLocation = new StringBuilder();
        newLogLocation.Append(targetDir);
        if (item.LogLocation.Length > sourceDir.Length)
          newLogLocation.Append(item.LogLocation.Substring(sourceDir.Length));

        Console.WriteLine("Old location: {0}", item.DropLocation);
        Console.WriteLine("New Location: {0}", newDropLocation);
        Console.WriteLine("Old log location: {0}", item.LogLocation);
        Console.WriteLine("New log location: {0}", newLogLocation);

        if (commit)
        {
          item.LogLocation = newLogLocation.ToString();
          item.DropLocation = newDropLocation.ToString();
          item.Save();
        }

      }
      Console.ForegroundColor = ConsoleColor.Gray;
    }

    private static void ShowUsage()
    {
      Console.WriteLine("MoveBuild - Usage");
      Console.WriteLine("MoveBuild <TFS URL> <SourceFolderPattern> <DestinationFolder> [/Commit]");
      Console.WriteLine();
      Console.WriteLine(@"Example: MoveBuild http://mytfsserver:port \\OldServer\OldShare \\NewServer\NewShare");
      Console.WriteLine(@"This will move all builds which have a drop location starting with \\OldServer\OldShare to \\NewServer\NewShare");
      Console.WriteLine();
      Console.WriteLine("If you specify /Commit the changes will be made to the database, if not, you only see a list of builds that would have been changed by this program");
    }

  }

}

To get this to build you need to:

  • Add a refference to the following Microsoft.TeamFoundation libraries (which are in %ProgramFiles%\Microsoft Visual Studio 9.0\Common\IDE\PrivateAssemblies
    • Microsoft.TeamFoundation.dll
    • Microsoft.TeamFoundation.Build.dll
    • Microsoft.TeamFoundation.Build.Common.dll
    • Microsoft.TeamFoundation.Build.Client.dll
    • Microsoft.TeamFoundation.Client.dll
    • Microsoft.TeamFoundation.Common.dll
  • Set your project’s properties to build for platform x86 if you’re developing on a x64 platform, otherwise you get a BadImageFormatException when loading these references.

Thursday, September 17, 2009 4:44:49 PM (Pacific SA Standard Time, UTC-04:00)  #    Comments [0]