Automatically merge work item type modifications into existing team projects – part 1

by Ewald Hofman 21. July 2009 03:09

Introduction

When you are working in an enterprise that has a lot of team projects, it is hard to make generic modifications to the work item types. Imagine that you want to add a field to all work item types in all team projects, first in the staging environment, then in the production environment. This means a lot of modifications!

Fortunately it is possible to automate this process. A work item type is nothing more then xml, what you can modify. This post shows you how you can automate this process. The post is divided into multiple parts:

  • Part 1: Download and upload the work item type from/to the TFS server
  • Part 2: Make the modifications to the work item type
  • Part 3: Add new elements to the work item type

This part of the post covers downloading and uploading the work item type from/to the TFS Server. The prerequisite is that you have installed Team Explorer onto the system that runs the application.

The application that is build, is making use of a library that wraps the functionality to communicate with the TFS server and perform the modifications to the work item type. There is a UI, which is in this case a unit test project, to tell the library what you want to change.

Preparations

  1. Open Visual Studio 2008 and create a new C# class library and call it MergeWitModifications.
  2. Add the following references to the project. The files can be found in the folder: %ProgramFiles%\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies.
    - Microsoft.TeamFoundation.dll
    - Microsoft.TeamFoundation.Client.dll
    - Microsoft.TeamFoundation.Common.dll
    - Microsoft.TeamFoundation.WorkItemTracking.Client.dll
  3. Rename the Class1.cs file to AutoModifyWit.cs
  4. Paste the following code to the file:
  5. using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Diagnostics;
    using Microsoft.TeamFoundation.Client;
    using System.Net;
    using Microsoft.TeamFoundation.WorkItemTracking.Client;
    using System.Xml;
     
    namespace MergeWitModifications
    {
        struct Info
        {
            public string Project { get; set; }
            public string WorkItemType { get; set; }
        }
        
        public class AutoModifyWit
        {
            /// <summary>
            /// Creates a new instance of this class.
            /// </summary>
            /// <param name="tfsServer">The uri to the tfs server, in the form 
            /// of http://MyTfsServer:8080.</param>
            public AutoModifyWit(string tfsServer)
            {
                TfsServer = tfsServer;
            }
     
            /// <summary>
            /// The uri to the TFS server that contains the work item types that
            /// will be modified
            /// </summary>
            private string TfsServer { get; set; }
     
            /// <summary>
            /// Executes the modifications to the work items.
            /// </summary>
            /// <param name="teamProjects">The list of team projects that must be 
            /// modified. Pass null or the empty array when you want to update all 
            /// team projects.</param>
            /// <param name="workItemTypes">The list of work item types that must be 
            /// modified. Pass null or the empty array when you want to update all 
            /// work item types.</param>
            public void Start(string[] teamProjects, string[] workItemTypes)
            {
                // The base folder where the backup of the work item type definition 
                // will be stored.
                string backupDirectory = string.Format(@"{0}\Backup{1:yyyyMMddhhmm}\", Directory.GetCurrentDirectory(), DateTime.Now);
     
                // Iterate through all work item types in all team projects. When
                // you do this without creating a new tfs instance, a write
                // access violation will occur (a bug in the TFS SDK?)
                foreach (var info in GetAllWITs())
                {
                    // Check whether the team project and/or the work item type should be skipped
                    if ((teamProjects != null && teamProjects.Length != 0 &&
                         !new List<string>(teamProjects).Contains(info.Project)) ||
                        (workItemTypes != null && workItemTypes.Length != 0 &&
                         !new List<string>(workItemTypes).Contains(info.WorkItemType)))
                        continue;
     
                    Debug.WriteLine(info.Project + ", " + info.WorkItemType);
     
                    // Open the work item store
                    using (var tfs = new TeamFoundationServer(TfsServer,
                                                              CredentialCache.DefaultCredentials))
                    {
                        var store = (WorkItemStore) tfs.GetService(typeof (WorkItemStore));
     
                        // For the Team Project
                        var project = store.Projects[info.Project];
     
                        // For the Work Item Type
                        var workItemType = project.WorkItemTypes[info.WorkItemType];
     
                        // Download the work item type from the server
                        var doc = workItemType.Export(false);
     
                        // Backup the original work item type to support a fallback scenario
                        Directory.CreateDirectory(backupDirectory + @"\" + info.Project);
                        doc.Save(backupDirectory + @"\" + info.Project + @"\" + info.WorkItemType + @".xml");
     
                        ///////////////////////////////////
                        /// 
                        /// TODO: Make the modifications to the work item type
                        /// handled in part 2.
                        /// 
                        ///////////////////////////////////
     
                        // Validate the modifications to the work item type
                        WorkItemType.Validate(project, doc.OuterXml);
     
                        // Upload the work item type to TFS
                        project.WorkItemTypes.Import(doc.OuterXml);
                    }
                }
            }
     
            /// <summary>
            /// Returns the list of all available work item types on the server
            /// </summary>
            private List<Info> GetAllWITs()
            {
                var list = new List<Info>();
     
                // Open the work item store
                using (var tfs = new TeamFoundationServer(TfsServer,
                                                          CredentialCache.DefaultCredentials))
                {
                    var store = (WorkItemStore) tfs.GetService(typeof (WorkItemStore));
                    // For all Team Projects
                    foreach (Project project in store.Projects)
                    {
                        // For all Work Item Types
                        foreach (WorkItemType workItemType in project.WorkItemTypes)
                        {
                            // Add the work item type
                            list.Add(new Info
                                         {
                                             Project = project.Name,
                                             WorkItemType = workItemType.Name
                                         });
                        }
                    }
                }
     
                return list;
            }
        }
    }
  6. Right click on the line “public void Start(string[] teamProjects, string[] workItemTypes)” and choose for the option Create Unit Tests…
  7. A dialog pops up after a while. In there you can choose the settings for the new test project. Accept the defaults by clicking on the OK button. You can name the project MergeWitModificationsTest.
  8. Paste the following code in the AutoModifyWitTest.cs file.
  9. using MergeWitModifications;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    namespace MergeWitModificationsTest
    {
        
        
        /// <summary>
        ///This is a test class for AutoModifyWitTest and is intended
        ///to contain all AutoModifyWitTest Unit Tests
        ///</summary>
        [TestClass()]
        public class AutoModifyWitTest
        {
            /// <summary>
            /// Starts the modifications of the work item types.
            ///</summary>
            [TestMethod()]
            public void StartAutoModifyWit()
            {
                // The server that contains the work item types that must be modified
                const string tfsServer = "http://MyTfsServer:8080";
     
                // The list of team projects that must be modified. Pass null or the 
                // empty array when you want to update all team projects.
                var teamProjects = new string[] { };
     
                // The list of work item types that must be modified. Pass null or the 
                // empty array when you want to update all work item types.
                var workItemTypes = new string[] { };
     
                var target = new AutoModifyWit(tfsServer);
     
                target.Start(teamProjects, workItemTypes)
            }
        }
    }

You have now created the base of the library. The library is not able to communicate with the TFS server to download and upload work item types. In the next part the library will be extended to modify the work item type with XPath expressions.

Tags:

VSTS 2008 | Work items

Comments are closed

Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen


ClusterMap

Widget Statistics not found.

There is an error in XML document (0, 0).X

Recent comments

Comment RSS