locked
How to update ProcessParameters without using WorkflowHelpers.DeserializeProcessParameters() RRS feed

  • Question

  • Hi.

    I'm using TFS 2010 and I'm trying to write a program (C#.NET 4.0 console app) that will update the workspace paths and solutions to build in a build definition.  I've seen a few examples on how to update the ProcessParameters but all of them involve using the WorkflowHelpers.DeserializeProcessParameters() method.

    I've run into a problem when running this program that I believe it is tied to my using the DeserializeProcessParameters() method.  The error I sometimes get is:  "Cannot create unknown type '{clr-namespace:BuildTasks.Custom_Types;assembly=BuidTasks}SourceControlBranch".

    I am trying to create a program that can be used on any team project in any collection.  While the app works fine in one team project I am getting variations of the above error when I run the program to update build defs in other collections and other team projects.

    I do not know what's causing this problem and I don't know how to update the ProcessParameters without using the Deserialize method.

    Your help is appreciated.  Thanks.

    Logan



    Wednesday, May 23, 2012 5:01 PM

Answers

  • Sure, it would look something like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.TeamFoundation.Build.Workflow;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.VersionControl.Client;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://localhost:8080/tfs/DefaultCollection"));
                IBuildServer buildServer = tpc.GetService<IBuildServer>();
    
                List<IFailure> failures;
                List<Type> activityTypes, extensionTypes;
                IBuildDefinition definition = buildServer.GetBuildDefinition("My Project", "My Definition");
                s_assemblies = definition.BuildController.LoadCustomActivitiesAndExtensions(definition.BuildController.CustomAssemblyPath,
                                                                                            RecursionType.Full,
                                                                                            HostEnvironmentOption.All,
                                                                                            out activityTypes,
                                                                                            out extensionTypes,
                                                                                            out failures);
    
                AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    
                var allParameters = WorkflowHelpers.DeserializeProcessParameters(definition.ProcessParameters);
            }
    
            static Assembly CurrentDomain_AssemblyResolve(Object sender, ResolveEventArgs args)
            {
                if (s_assemblies == null || s_assemblies.Count == 0)
                {
                    return null;
                }
    
                return s_assemblies.FirstOrDefault(x => x.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase));
            }
    
            static List<Assembly> s_assemblies;
        }
    }
    

    Thursday, May 24, 2012 7:09 PM
  • You are correct, I apologize. Simply set this to a local path, something like Path.GetTempPath(), and try again.

    Patrick

    Friday, May 25, 2012 1:55 PM
  • Hey Patrick.

    I'm running into something I'm not sure how to get around.  When this executes:

    s_assemblies = definition.BuildController.LoadCustomActivitiesAndExtensions(definition.BuildController.CustomAssemblyPath,
                                                                                            RecursionType.Full,
                                                                                            HostEnvironmentOption.All,
                                                                                            out activityTypes,
                                                                                            out extensionTypes,
                                                                                            out failures);

    I'm getting the error below because the argument 'definition.BuildController.CustomAssemblyPath,' is a TFS source control path rather than a local path.

    TF10122: The path 'C:\Sandbox\BuildProcessTemplates\CustomActivitiesProject\ConsoleApplication\bin\Debug\$\MyTeamProject\BuildProcessTempl
    ates\CustomActivitesLibraries' contains a '$' at the beginning of a path component. Remove the '$' and try again.

    It seems that the method is expecting a local path and not a version control path, but I'm not sure what to do from here.

    Again, your help is really appreciated.

    Thanks.

    Logan


    Friday, May 25, 2012 12:09 PM
  • Thanks for the help.  Y'all know I'm not a full fledged programmer (use at your own rise), but nonetheless here is the console application code after it was successfully tested:

    using System;
    using System.Activities;
    using System.Collections.Generic;
    using System.DirectoryServices;
    using System.DirectoryServices.AccountManagement;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using System.Security.Principal;
    using Microsoft.TeamFoundation;
    using Microsoft.TeamFoundation.Build;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.Common;
    using Microsoft.TeamFoundation.Framework.Client;
    using Microsoft.TeamFoundation.Framework.Common;
    using Microsoft.TeamFoundation.Server;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    using Microsoft.TeamFoundation.Build.Workflow;
    using Microsoft.TeamFoundation.Build.Workflow.Activities;
    using Microsoft.TeamFoundation.VersionControl.Client;
    
    namespace ConsoleApplication_Testing
    {
        class Program
        {
            static List <Assembly> assemblies;
            static void Main(string[] args)
            {
                
                Console.WriteLine("");
                Console.WriteLine("This program searches for (arg. 1) and replaces (arg. 2) user specified text in workspace mappings and solutions to build,");
                Console.WriteLine("for each build definition that meets the user specified (arg. 3) criteria.");
                Console.WriteLine("");
                Console.WriteLine("Five arguments must be passed to run this program.");
                Console.WriteLine("");
                Console.WriteLine("Argument 1:  Existing text to replace");
                Console.WriteLine("Argument 2:  New text");
                Console.WriteLine("Argument 3:  Search filter for which build scripts to edit");
                Console.WriteLine("Argument 4:  Team project name");
                Console.WriteLine("Argument 5:  Collection URL");
                Console.WriteLine("");
                Console.WriteLine("Example");
                Console.WriteLine(@"filename.exe ""\Main\"" ""\Release\"" ""DeployApp"" ""MyTeamProject"" ""http://server:8080/tfs/MyTPC"" ");
                Console.WriteLine("");
                Console.WriteLine("");
    
                if (args.Count() != 5)
                {
                    Console.WriteLine("Five arguments must be passed for this program to run.");
                }
                else
                {
                    try
                    {
                        #region Connect to TFS, create and assign args
                        string oldValue = args[0];
                        string newValue = args[1];
                        string scriptFilter = args[2];
                        string tpColl = args[4];
    
                        Uri collectionUri = new Uri(tpColl);
    
                        TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(collectionUri, System.Net.CredentialCache.DefaultNetworkCredentials, new UICredentialsProvider());
                        WorkItemStore workItemStore = tpc.GetService<WorkItemStore>();
                        Project teamProject = workItemStore.Projects[args[3]];
                        IBuildServer buildServer = tpc.GetService(typeof(IBuildServer)) as IBuildServer;
                        IBuildDefinition[] bldDefs = buildServer.QueryBuildDefinitions(teamProject.Name);
    
                        Dictionary<string, object> wsExistingMappings = new Dictionary<string, object>();
                        Dictionary<string, object> wsNewMappings = new Dictionary<string, object>();
                        bool OutputWorkspaceUpdatesMessage = true;
                        bool OutputSolutionUpdatesMessage = true;
                        bool BuildDefsUpdated = false;
                        #endregion
    
                        //get the currently logged in user
                        WindowsIdentity user = WindowsIdentity.GetCurrent();
                        tpc.EnsureAuthenticated();
                        if (tpc.HasAuthenticated)
                        {
                            var buildInfo = tpc.GetService(typeof(IBuildServer)) as IBuildServer;
                            var spec = buildInfo.QueryBuildDefinitions(teamProject.Name);
    
                            #region for each build definition
                            foreach (IBuildDefinition buildDef in buildInfo.QueryBuildDefinitions(teamProject.Name))
                            {
                                if (buildDef.Name.Contains(scriptFilter))
                                {
                                    if (buildDef.Process.TemplateType.ToString() == "Upgrade")
                                    {
                                        Console.WriteLine("This program will not work on build definitions associated with the upgrade build process template.  The {0} will not be updated.", buildDef.Name);
                                        BuildDefsUpdated = false;
                                    }
                                    else
                                    {
                                        Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                                        Console.WriteLine("Replacing all instances of '{0}' with '{1}' in the {2} build definition.", args[0], args[1], buildDef.Name);
                                        Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
    
                                        // Update workspace paths
                                        #region PopulateDictionaries with existing and new workspace paths
                                        // Add the existing workspace mappings into a dictionary to be saved for later
                                        for (int x = 0; x < buildDef.Workspace.Mappings.Count; x++)
                                        {
                                            StringBuilder tmpServer = new StringBuilder();
                                            Object tmpLocal = new StringBuilder();
                                            wsExistingMappings.Add(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString(), buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
    
                                            // look for the args[1] string both the server item and the local item workspace paths
                                            //  if args[1] is found, replace it with args[2] and stick the new value in the new dictionary
                                            //  if args[1] is not found, retain the existing value in the new dictionary to preserve the mapping
                                            if (buildDef.Workspace.Mappings.ElementAt(x).ServerItem.Contains(oldValue))
                                            {
                                                tmpServer = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                                tmpServer.Replace(oldValue, newValue);
                                            }
                                            else
                                            {
                                                if (OutputWorkspaceUpdatesMessage)
                                                {
                                                    Console.WriteLine("");
                                                    Console.WriteLine("Workspace Mapping Updates");
                                                    OutputWorkspaceUpdatesMessage = false;
                                                }
                                                tmpServer = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This workspace mapping will remain unchanged.", oldValue, buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                            }
    
    
                                            if (buildDef.Workspace.Mappings.ElementAt(x).LocalItem.Contains(oldValue))
                                            {
                                                StringBuilder tmp = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
                                                tmp.Replace(oldValue, newValue);
                                                tmpLocal = tmp;
                                            }
                                            else
                                            {
                                                tmpLocal = buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString();
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This workspace mapping will remain unchanged.", oldValue, buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
                                            }
                                            BuildDefsUpdated = true;
                                            wsNewMappings.Add(tmpServer.ToString(), tmpLocal);
                                        }
                                        #endregion
    
                                        #region Delete mappings and create new ones
                                        //  Since the wsNewMappings contain the updates, or the original values if no updates need to be made
                                        //  Delete the existing mappings
                                        int iCount = buildDef.Workspace.Mappings.Count();
                                        for (int x = 0; x < iCount; x++)
                                        {
                                            buildDef.Workspace.Mappings.RemoveAt(0);
                                        }
    
                                        //  And add the new mappings
                                        foreach (KeyValuePair<string, object> kvp in wsNewMappings)
                                        {
                                            buildDef.Workspace.AddMapping(kvp.Key, kvp.Value.ToString(), WorkspaceMappingType.Map);
                                        }
                                        buildDef.Save();
                                        #endregion
                                        #region Verify workspace edits
                                        // verify workspace edits
                                        IBuildDefinition bldDef = buildServer.GetBuildDefinition(teamProject.Name, buildDef.Name);
                                        Console.WriteLine("");
                                        Console.WriteLine("Verifying workspace mapping updates:");
                                        for (int x = 0; x < bldDef.Workspace.Mappings.Count; x++)
                                        {
                                            Console.WriteLine("   {0}", bldDef.Workspace.Mappings.ElementAt(x).ServerItem);
                                            Console.WriteLine("   {0}", bldDef.Workspace.Mappings.ElementAt(x).LocalItem);
                                        }
                                        Console.WriteLine("");
                                        #endregion
    
                                        // Update .sln paths                           
                                        #region Reflection Code
                                        List<IFailure> failures;
                                        List<Type> activityTypes, extensionTypes;
    
                                        // create a temporary directory using the build def name, to avoid the 'access is denied' errors
                                        string tmpPath = String.Format("{0}\\{1}", Path.GetTempPath(), buildDef.Name);
                                        DirectoryInfo di = Directory.CreateDirectory(tmpPath);
    
                                        assemblies = buildDef.BuildController.LoadCustomActivitiesAndExtensions(tmpPath,
                                                                                        RecursionType.Full,
                                                                                        HostEnvironmentOption.All,
                                                                                        out activityTypes,
                                                                                        out extensionTypes,
                                                                                        out failures);
                                        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
                                        #endregion
    
                                        #region Update .sln paths in the dictionary
                                        var process = WorkflowHelpers.DeserializeProcessParameters(buildDef.ProcessParameters);
                                        BuildSettings buildSettings = new BuildSettings();
                                        buildSettings = (Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings)process["BuildSettings"];
                                        string processParameters = buildDef.ProcessParameters;
    
                                        StringList newSolutionlist = new StringList();
                                        StringList currentSolutionlist = new StringList();
                                        currentSolutionlist = buildSettings.ProjectsToBuild;
    
                                        foreach (string list in currentSolutionlist)
                                        {
                                            StringBuilder tmpSLN = new StringBuilder(list.ToString());
                                            if (list.Contains(oldValue))
                                            {
                                                tmpSLN.Replace(oldValue, newValue);
                                                newSolutionlist.Add(tmpSLN.ToString());
                                            }
                                            else
                                            {
                                                if (OutputSolutionUpdatesMessage)
                                                {
                                                    Console.WriteLine("");
                                                    Console.WriteLine("Solutions to Build Updates");
                                                    OutputSolutionUpdatesMessage = false;
                                                }
                                                newSolutionlist.Add(list.ToString());
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This solution to build will remain unchanged.", oldValue, tmpSLN.ToString());
                                            }
                                        }
                                        #endregion
    
                                        #region Update sln paths in the build definition
                                        //remove exiting build settings and add new ones
                                        process.Remove("BuildSettings");
                                        buildSettings.ProjectsToBuild = newSolutionlist;
                                        process.Add("BuildSettings", buildSettings);
                                        buildDef.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);
                                        buildDef.Save();
                                        #endregion
    
                                        #region Verify solutions to build changes
                                        BuildSettings bldSettings = new BuildSettings();
                                        bldSettings = (Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings)process["BuildSettings"];
                                        StringList solutionsToBuild = bldSettings.ProjectsToBuild;
                                        Console.WriteLine("");
                                        Console.WriteLine("Verifying solutions to build updates:");
                                        foreach (string sln in solutionsToBuild)
                                        {
                                            Console.WriteLine("   {0}", sln);
                                        }
                                        Console.WriteLine("");
                                        #endregion
    
                                        assemblies.Clear();
                                        failures.Clear();
                                        activityTypes.Clear();
                                        extensionTypes.Clear();
    
                                        wsExistingMappings.Clear();
                                        wsNewMappings.Clear();
                                        OutputWorkspaceUpdatesMessage = true;
                                        OutputSolutionUpdatesMessage = true;
                                    }
                                }
                            }
                            #endregion
    
                            #region output updates complete message
                            if (BuildDefsUpdated)
                            {
                                Console.WriteLine("");
                                Console.WriteLine("");
                                Console.WriteLine("");
                                Console.WriteLine("***** Build definition updates are complete.");
                                Console.WriteLine("");
                                Console.ReadLine();
                            }
                            else
                            {
                                Console.WriteLine("");
                                Console.WriteLine("No build definitions were updated.");
                            }
                            #endregion
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        Console.ReadLine();
                    }
                }
            }
            static Assembly CurrentDomain_AssemblyResolve(Object sender, ResolveEventArgs args)
            {
                if (assemblies == null || assemblies.Count == 0)
                {
                    return null;
                }
                return assemblies.FirstOrDefault(x => x.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase));
            }
        }
    }
    
    

    Thursday, June 14, 2012 12:07 PM

All replies

  • Are you working with TFS 2010 API to change the build definition through a console application?  

    I think if you ask this on some xaml forum you might get better answer.  I am not sure though.  Can you post code for deserialization?



    • Edited by Mitul Suthar Thursday, May 24, 2012 4:07 PM more info
    Thursday, May 24, 2012 4:03 PM
  • I am using the TFS 2010 API.  The code for the deserialization part is:

        var process = WorkflowHelpers.DeserializeProcessParameters(buildDef.ProcessParameters);

    Thursday, May 24, 2012 5:06 PM
  • You need to ensure the custom assemblies are downloaded and loaded into your application domain. There is a method available on the IBuildController interface, LoadCustomActivities, which will download and reflect on the assemblies to determine which ones at the custom assembly path export types and/or activities. What you should do in your program is hook up an event handler to the AppDomain.CurrentDomain.AssemblyResolve event, and return the assembly we loaded for you if the requested assembly matches one of the assemblies which we downloaded.

    Patrick

    Thursday, May 24, 2012 6:36 PM
  • Thanks Patrick.

    I don't suppose you have any sample code for LoadCustomActivites or AppDomain.CurrentDomain.AssemblyResolve, do you? 

    I'm not really a programmer yet (though I'm learning), and I'm not sure how exactly to use these given the context and purpose of the application.  Any additional help you can provide would be super appreciated.

    If it'd help I can upload my entire program (it isn't that much code).

    Thanks.

    Logan


    Thursday, May 24, 2012 6:52 PM
  • Sure, it would look something like this:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.TeamFoundation.Build.Workflow;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.VersionControl.Client;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://localhost:8080/tfs/DefaultCollection"));
                IBuildServer buildServer = tpc.GetService<IBuildServer>();
    
                List<IFailure> failures;
                List<Type> activityTypes, extensionTypes;
                IBuildDefinition definition = buildServer.GetBuildDefinition("My Project", "My Definition");
                s_assemblies = definition.BuildController.LoadCustomActivitiesAndExtensions(definition.BuildController.CustomAssemblyPath,
                                                                                            RecursionType.Full,
                                                                                            HostEnvironmentOption.All,
                                                                                            out activityTypes,
                                                                                            out extensionTypes,
                                                                                            out failures);
    
                AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    
                var allParameters = WorkflowHelpers.DeserializeProcessParameters(definition.ProcessParameters);
            }
    
            static Assembly CurrentDomain_AssemblyResolve(Object sender, ResolveEventArgs args)
            {
                if (s_assemblies == null || s_assemblies.Count == 0)
                {
                    return null;
                }
    
                return s_assemblies.FirstOrDefault(x => x.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase));
            }
    
            static List<Assembly> s_assemblies;
        }
    }
    

    Thursday, May 24, 2012 7:09 PM
  • Excellent!  I'll give this a try.  Thanks Patrick.

    Thursday, May 24, 2012 7:35 PM
  • Hey Patrick.

    I'm running into something I'm not sure how to get around.  When this executes:

    s_assemblies = definition.BuildController.LoadCustomActivitiesAndExtensions(definition.BuildController.CustomAssemblyPath,
                                                                                            RecursionType.Full,
                                                                                            HostEnvironmentOption.All,
                                                                                            out activityTypes,
                                                                                            out extensionTypes,
                                                                                            out failures);

    I'm getting the error below because the argument 'definition.BuildController.CustomAssemblyPath,' is a TFS source control path rather than a local path.

    TF10122: The path 'C:\Sandbox\BuildProcessTemplates\CustomActivitiesProject\ConsoleApplication\bin\Debug\$\MyTeamProject\BuildProcessTempl
    ates\CustomActivitesLibraries' contains a '$' at the beginning of a path component. Remove the '$' and try again.

    It seems that the method is expecting a local path and not a version control path, but I'm not sure what to do from here.

    Again, your help is really appreciated.

    Thanks.

    Logan


    Friday, May 25, 2012 12:09 PM
  • You are correct, I apologize. Simply set this to a local path, something like Path.GetTempPath(), and try again.

    Patrick

    Friday, May 25, 2012 1:55 PM
  • Thanks for the help.  Y'all know I'm not a full fledged programmer (use at your own rise), but nonetheless here is the console application code after it was successfully tested:

    using System;
    using System.Activities;
    using System.Collections.Generic;
    using System.DirectoryServices;
    using System.DirectoryServices.AccountManagement;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using System.Security.Principal;
    using Microsoft.TeamFoundation;
    using Microsoft.TeamFoundation.Build;
    using Microsoft.TeamFoundation.Build.Client;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.Common;
    using Microsoft.TeamFoundation.Framework.Client;
    using Microsoft.TeamFoundation.Framework.Common;
    using Microsoft.TeamFoundation.Server;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    using Microsoft.TeamFoundation.Build.Workflow;
    using Microsoft.TeamFoundation.Build.Workflow.Activities;
    using Microsoft.TeamFoundation.VersionControl.Client;
    
    namespace ConsoleApplication_Testing
    {
        class Program
        {
            static List <Assembly> assemblies;
            static void Main(string[] args)
            {
                
                Console.WriteLine("");
                Console.WriteLine("This program searches for (arg. 1) and replaces (arg. 2) user specified text in workspace mappings and solutions to build,");
                Console.WriteLine("for each build definition that meets the user specified (arg. 3) criteria.");
                Console.WriteLine("");
                Console.WriteLine("Five arguments must be passed to run this program.");
                Console.WriteLine("");
                Console.WriteLine("Argument 1:  Existing text to replace");
                Console.WriteLine("Argument 2:  New text");
                Console.WriteLine("Argument 3:  Search filter for which build scripts to edit");
                Console.WriteLine("Argument 4:  Team project name");
                Console.WriteLine("Argument 5:  Collection URL");
                Console.WriteLine("");
                Console.WriteLine("Example");
                Console.WriteLine(@"filename.exe ""\Main\"" ""\Release\"" ""DeployApp"" ""MyTeamProject"" ""http://server:8080/tfs/MyTPC"" ");
                Console.WriteLine("");
                Console.WriteLine("");
    
                if (args.Count() != 5)
                {
                    Console.WriteLine("Five arguments must be passed for this program to run.");
                }
                else
                {
                    try
                    {
                        #region Connect to TFS, create and assign args
                        string oldValue = args[0];
                        string newValue = args[1];
                        string scriptFilter = args[2];
                        string tpColl = args[4];
    
                        Uri collectionUri = new Uri(tpColl);
    
                        TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(collectionUri, System.Net.CredentialCache.DefaultNetworkCredentials, new UICredentialsProvider());
                        WorkItemStore workItemStore = tpc.GetService<WorkItemStore>();
                        Project teamProject = workItemStore.Projects[args[3]];
                        IBuildServer buildServer = tpc.GetService(typeof(IBuildServer)) as IBuildServer;
                        IBuildDefinition[] bldDefs = buildServer.QueryBuildDefinitions(teamProject.Name);
    
                        Dictionary<string, object> wsExistingMappings = new Dictionary<string, object>();
                        Dictionary<string, object> wsNewMappings = new Dictionary<string, object>();
                        bool OutputWorkspaceUpdatesMessage = true;
                        bool OutputSolutionUpdatesMessage = true;
                        bool BuildDefsUpdated = false;
                        #endregion
    
                        //get the currently logged in user
                        WindowsIdentity user = WindowsIdentity.GetCurrent();
                        tpc.EnsureAuthenticated();
                        if (tpc.HasAuthenticated)
                        {
                            var buildInfo = tpc.GetService(typeof(IBuildServer)) as IBuildServer;
                            var spec = buildInfo.QueryBuildDefinitions(teamProject.Name);
    
                            #region for each build definition
                            foreach (IBuildDefinition buildDef in buildInfo.QueryBuildDefinitions(teamProject.Name))
                            {
                                if (buildDef.Name.Contains(scriptFilter))
                                {
                                    if (buildDef.Process.TemplateType.ToString() == "Upgrade")
                                    {
                                        Console.WriteLine("This program will not work on build definitions associated with the upgrade build process template.  The {0} will not be updated.", buildDef.Name);
                                        BuildDefsUpdated = false;
                                    }
                                    else
                                    {
                                        Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
                                        Console.WriteLine("Replacing all instances of '{0}' with '{1}' in the {2} build definition.", args[0], args[1], buildDef.Name);
                                        Console.WriteLine("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
    
                                        // Update workspace paths
                                        #region PopulateDictionaries with existing and new workspace paths
                                        // Add the existing workspace mappings into a dictionary to be saved for later
                                        for (int x = 0; x < buildDef.Workspace.Mappings.Count; x++)
                                        {
                                            StringBuilder tmpServer = new StringBuilder();
                                            Object tmpLocal = new StringBuilder();
                                            wsExistingMappings.Add(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString(), buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
    
                                            // look for the args[1] string both the server item and the local item workspace paths
                                            //  if args[1] is found, replace it with args[2] and stick the new value in the new dictionary
                                            //  if args[1] is not found, retain the existing value in the new dictionary to preserve the mapping
                                            if (buildDef.Workspace.Mappings.ElementAt(x).ServerItem.Contains(oldValue))
                                            {
                                                tmpServer = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                                tmpServer.Replace(oldValue, newValue);
                                            }
                                            else
                                            {
                                                if (OutputWorkspaceUpdatesMessage)
                                                {
                                                    Console.WriteLine("");
                                                    Console.WriteLine("Workspace Mapping Updates");
                                                    OutputWorkspaceUpdatesMessage = false;
                                                }
                                                tmpServer = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This workspace mapping will remain unchanged.", oldValue, buildDef.Workspace.Mappings.ElementAt(x).ServerItem.ToString());
                                            }
    
    
                                            if (buildDef.Workspace.Mappings.ElementAt(x).LocalItem.Contains(oldValue))
                                            {
                                                StringBuilder tmp = new StringBuilder(buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
                                                tmp.Replace(oldValue, newValue);
                                                tmpLocal = tmp;
                                            }
                                            else
                                            {
                                                tmpLocal = buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString();
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This workspace mapping will remain unchanged.", oldValue, buildDef.Workspace.Mappings.ElementAt(x).LocalItem.ToString());
                                            }
                                            BuildDefsUpdated = true;
                                            wsNewMappings.Add(tmpServer.ToString(), tmpLocal);
                                        }
                                        #endregion
    
                                        #region Delete mappings and create new ones
                                        //  Since the wsNewMappings contain the updates, or the original values if no updates need to be made
                                        //  Delete the existing mappings
                                        int iCount = buildDef.Workspace.Mappings.Count();
                                        for (int x = 0; x < iCount; x++)
                                        {
                                            buildDef.Workspace.Mappings.RemoveAt(0);
                                        }
    
                                        //  And add the new mappings
                                        foreach (KeyValuePair<string, object> kvp in wsNewMappings)
                                        {
                                            buildDef.Workspace.AddMapping(kvp.Key, kvp.Value.ToString(), WorkspaceMappingType.Map);
                                        }
                                        buildDef.Save();
                                        #endregion
                                        #region Verify workspace edits
                                        // verify workspace edits
                                        IBuildDefinition bldDef = buildServer.GetBuildDefinition(teamProject.Name, buildDef.Name);
                                        Console.WriteLine("");
                                        Console.WriteLine("Verifying workspace mapping updates:");
                                        for (int x = 0; x < bldDef.Workspace.Mappings.Count; x++)
                                        {
                                            Console.WriteLine("   {0}", bldDef.Workspace.Mappings.ElementAt(x).ServerItem);
                                            Console.WriteLine("   {0}", bldDef.Workspace.Mappings.ElementAt(x).LocalItem);
                                        }
                                        Console.WriteLine("");
                                        #endregion
    
                                        // Update .sln paths                           
                                        #region Reflection Code
                                        List<IFailure> failures;
                                        List<Type> activityTypes, extensionTypes;
    
                                        // create a temporary directory using the build def name, to avoid the 'access is denied' errors
                                        string tmpPath = String.Format("{0}\\{1}", Path.GetTempPath(), buildDef.Name);
                                        DirectoryInfo di = Directory.CreateDirectory(tmpPath);
    
                                        assemblies = buildDef.BuildController.LoadCustomActivitiesAndExtensions(tmpPath,
                                                                                        RecursionType.Full,
                                                                                        HostEnvironmentOption.All,
                                                                                        out activityTypes,
                                                                                        out extensionTypes,
                                                                                        out failures);
                                        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
                                        #endregion
    
                                        #region Update .sln paths in the dictionary
                                        var process = WorkflowHelpers.DeserializeProcessParameters(buildDef.ProcessParameters);
                                        BuildSettings buildSettings = new BuildSettings();
                                        buildSettings = (Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings)process["BuildSettings"];
                                        string processParameters = buildDef.ProcessParameters;
    
                                        StringList newSolutionlist = new StringList();
                                        StringList currentSolutionlist = new StringList();
                                        currentSolutionlist = buildSettings.ProjectsToBuild;
    
                                        foreach (string list in currentSolutionlist)
                                        {
                                            StringBuilder tmpSLN = new StringBuilder(list.ToString());
                                            if (list.Contains(oldValue))
                                            {
                                                tmpSLN.Replace(oldValue, newValue);
                                                newSolutionlist.Add(tmpSLN.ToString());
                                            }
                                            else
                                            {
                                                if (OutputSolutionUpdatesMessage)
                                                {
                                                    Console.WriteLine("");
                                                    Console.WriteLine("Solutions to Build Updates");
                                                    OutputSolutionUpdatesMessage = false;
                                                }
                                                newSolutionlist.Add(list.ToString());
                                                Console.WriteLine("   '{0}' was not found in '{1}'.  This solution to build will remain unchanged.", oldValue, tmpSLN.ToString());
                                            }
                                        }
                                        #endregion
    
                                        #region Update sln paths in the build definition
                                        //remove exiting build settings and add new ones
                                        process.Remove("BuildSettings");
                                        buildSettings.ProjectsToBuild = newSolutionlist;
                                        process.Add("BuildSettings", buildSettings);
                                        buildDef.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);
                                        buildDef.Save();
                                        #endregion
    
                                        #region Verify solutions to build changes
                                        BuildSettings bldSettings = new BuildSettings();
                                        bldSettings = (Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings)process["BuildSettings"];
                                        StringList solutionsToBuild = bldSettings.ProjectsToBuild;
                                        Console.WriteLine("");
                                        Console.WriteLine("Verifying solutions to build updates:");
                                        foreach (string sln in solutionsToBuild)
                                        {
                                            Console.WriteLine("   {0}", sln);
                                        }
                                        Console.WriteLine("");
                                        #endregion
    
                                        assemblies.Clear();
                                        failures.Clear();
                                        activityTypes.Clear();
                                        extensionTypes.Clear();
    
                                        wsExistingMappings.Clear();
                                        wsNewMappings.Clear();
                                        OutputWorkspaceUpdatesMessage = true;
                                        OutputSolutionUpdatesMessage = true;
                                    }
                                }
                            }
                            #endregion
    
                            #region output updates complete message
                            if (BuildDefsUpdated)
                            {
                                Console.WriteLine("");
                                Console.WriteLine("");
                                Console.WriteLine("");
                                Console.WriteLine("***** Build definition updates are complete.");
                                Console.WriteLine("");
                                Console.ReadLine();
                            }
                            else
                            {
                                Console.WriteLine("");
                                Console.WriteLine("No build definitions were updated.");
                            }
                            #endregion
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        Console.ReadLine();
                    }
                }
            }
            static Assembly CurrentDomain_AssemblyResolve(Object sender, ResolveEventArgs args)
            {
                if (assemblies == null || assemblies.Count == 0)
                {
                    return null;
                }
                return assemblies.FirstOrDefault(x => x.FullName.Equals(args.Name, StringComparison.OrdinalIgnoreCase));
            }
        }
    }
    
    

    Thursday, June 14, 2012 12:07 PM