public WorkItemTypeInfo(TeamProjectInfo teamProject, string name, string description, int?workItemCount, ICollection <string> workItemCategories, WorkItemTypeDefinition workItemTypeDefinition) { this.TeamProject = teamProject; this.Name = name; this.Description = description; this.WorkItemCount = workItemCount; this.WorkItemCategories = workItemCategories; this.WorkItemCategoriesList = this.WorkItemCategories == null ? null : string.Join(", ", this.WorkItemCategories); this.WorkItemTypeDefinition = workItemTypeDefinition; }
private void Import(object argument) { var options = ImportOptions.None; if (this.Simulate) { options |= ImportOptions.Simulate; } if (this.SaveCopy) { options |= ImportOptions.SaveCopy; } var workItemTypes = new List <WorkItemConfigurationItem>(); foreach (var workItemTypeFile in this.WorkItemTypeFiles) { try { workItemTypes.Add(WorkItemTypeDefinition.FromFile(workItemTypeFile)); } catch (Exception exc) { this.Logger.Log(string.Format(CultureInfo.CurrentCulture, "An error occurred while loading the work item type from \"{0}\"", workItemTypeFile), exc); MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "An error occurred while loading the work item type from \"{0}\". See the log file for details", workItemTypeFile), "Error", MessageBoxButton.OK, MessageBoxImage.Warning); } } var teamProjectsWithWorkItemTypes = this.SelectedTeamProjects.ToDictionary(p => p, p => workItemTypes); if (!options.HasFlag(ImportOptions.Simulate)) { var result = MessageBox.Show("This will import the selected work item types. Are you sure you want to continue?", "Confirm Import", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result != MessageBoxResult.Yes) { return; } } PerformImport(options, teamProjectsWithWorkItemTypes); }
public static WorkItemConfiguration FromProcessTemplate(string processTemplateFileName) { // Load the process template XML. if (!File.Exists(processTemplateFileName)) { throw new FileNotFoundException("The process template file does not exist: " + processTemplateFileName); } var processTemplate = new XmlDocument(); processTemplate.Load(processTemplateFileName); var baseDir = Path.GetDirectoryName(processTemplateFileName); var items = new List <WorkItemConfigurationItem>(); string processTemplateName = null; var processTemplateNameNode = processTemplate.SelectSingleNode("/ProcessTemplate/metadata/name"); if (processTemplateNameNode != null) { processTemplateName = processTemplateNameNode.InnerText; } // Find the work item tracking XML file. var workItemFileNameAttribute = processTemplate.SelectSingleNode("/ProcessTemplate/groups/group[@id='WorkItemTracking']/taskList/@filename"); if (workItemFileNameAttribute != null) { // Load the work item tracking XML. var workItemConfigurationTemplateFileName = Path.Combine(baseDir, workItemFileNameAttribute.InnerText); if (!File.Exists(workItemConfigurationTemplateFileName)) { throw new FileNotFoundException("The work item configuration file defined in the process template file does not exist: " + workItemConfigurationTemplateFileName); } var workItemConfigurationTemplate = new XmlDocument(); workItemConfigurationTemplate.Load(workItemConfigurationTemplateFileName); // Find all work item type definition XML files. foreach (XmlAttribute witFileNameAttribute in workItemConfigurationTemplate.SelectNodes("/tasks/task[@id='WITs']/taskXml/WORKITEMTYPES/WORKITEMTYPE/@fileName")) { var witFileName = Path.Combine(baseDir, witFileNameAttribute.InnerText); items.Add(WorkItemTypeDefinition.FromFile(witFileName)); } // Find the categories XML file. var categoriesFileNameAttribute = workItemConfigurationTemplate.SelectSingleNode("/tasks/task[@id='Categories']/taskXml/CATEGORIES/@fileName"); if (categoriesFileNameAttribute != null) { var categoriesFileName = Path.Combine(baseDir, categoriesFileNameAttribute.InnerText); items.Add(WorkItemConfigurationItem.FromFile(categoriesFileName)); } else { // If the process template doesn't specify any categories (typically because it's an old // process template from before Work Item Categories existed), load an empty list anyway. // This will improve comparisons because a Team Project will always have a Work Item // Categories configuration item (even if it's empty). items.Add(WorkItemConfigurationItem.FromXml("<cat:CATEGORIES xmlns:cat=\"http://schemas.microsoft.com/VisualStudio/2008/workitemtracking/categories\"/>")); } // Find the common configuration XML file. var commonConfigurationFileNameAttribute = workItemConfigurationTemplate.SelectSingleNode("/tasks/task[@id='ProcessConfiguration']/taskXml/PROCESSCONFIGURATION/CommonConfiguration/@fileName"); if (commonConfigurationFileNameAttribute != null) { var commonConfigurationFileName = Path.Combine(baseDir, commonConfigurationFileNameAttribute.InnerText); items.Add(WorkItemConfigurationItem.FromFile(commonConfigurationFileName)); } // Find the agile configuration XML file. var agileConfigurationFileNameAttribute = workItemConfigurationTemplate.SelectSingleNode("/tasks/task[@id='ProcessConfiguration']/taskXml/PROCESSCONFIGURATION/AgileConfiguration/@fileName"); if (agileConfigurationFileNameAttribute != null) { var agileConfigurationFileName = Path.Combine(baseDir, agileConfigurationFileNameAttribute.InnerText); items.Add(WorkItemConfigurationItem.FromFile(agileConfigurationFileName)); } // Find the process configuration XML file. var processConfigurationFileNameAttribute = workItemConfigurationTemplate.SelectSingleNode("/tasks/task[@id='ProcessConfiguration']/taskXml/PROCESSCONFIGURATION/ProjectConfiguration/@fileName"); if (processConfigurationFileNameAttribute != null) { var processConfigurationFileName = Path.Combine(baseDir, processConfigurationFileNameAttribute.InnerText); items.Add(WorkItemConfigurationItem.FromFile(processConfigurationFileName)); } } return(new WorkItemConfiguration(processTemplateName, items)); }
private void GetWorkItemTypes(object argument) { var teamProjects = this.SelectedTeamProjects.ToList(); var task = new ApplicationTask("Retrieving work item types", teamProjects.Count, true); PublishStatus(new StatusEventArgs(task)); var step = 0; var worker = new BackgroundWorker(); worker.DoWork += (sender, e) => { var tfs = GetSelectedTfsTeamProjectCollection(); var store = tfs.GetService <WorkItemStore>(); var results = new List <WorkItemTypeInfo>(); foreach (var teamProject in teamProjects) { task.SetProgress(step++, string.Format(CultureInfo.CurrentCulture, "Processing Team Project \"{0}\"", teamProject.Name)); try { var project = store.Projects[teamProject.Name]; var categoriesXml = WorkItemConfigurationItemImportExport.GetCategoriesXml(project); var categoryList = WorkItemCategoryList.Load(categoriesXml); foreach (WorkItemType workItemType in project.WorkItemTypes) { var parameters = new Dictionary <string, object>() { { "WorkItemType", workItemType.Name }, { "TeamProject", workItemType.Project.Name } }; var workItemCount = default(int?); try { workItemCount = store.QueryCount("SELECT [System.Id] FROM WorkItems WHERE [System.WorkItemType] = @WorkItemType AND [System.TeamProject] = @TeamProject", parameters); } catch (ClientException) { // Exceptions while running the query are not important and can be ignored. // An example is "VS402337: The number of work items returned exceeds the size limit of 20000". } var referencingCategories = categoryList.Categories.Where(c => c.WorkItemTypes.Concat(new WorkItemTypeReference[] { c.DefaultWorkItemType }).Any(w => string.Equals(w.Name, workItemType.Name, StringComparison.OrdinalIgnoreCase))).Select(c => c.Name); var workItemTypeDefinition = default(WorkItemTypeDefinition); try { workItemTypeDefinition = WorkItemTypeDefinition.FromXml(workItemType.Export(false)); } catch (VssServiceResponseException) { // A VssServiceResponseException with message "VS403207: The object does not exist or access is denied" // happens when trying to export a work item type in the inherited model. workItemTypeDefinition = new WorkItemTypeDefinition(workItemType.Name, null); } results.Add(new WorkItemTypeInfo(teamProject, workItemType.Name, workItemType.Description, workItemCount, referencingCategories.ToList(), workItemTypeDefinition)); } } catch (Exception exc) { task.SetWarning(string.Format(CultureInfo.CurrentCulture, "An error occurred while processing Team Project \"{0}\"", teamProject.Name), exc); } if (task.IsCanceled) { task.Status = "Canceled"; break; } } e.Result = results; }; worker.RunWorkerCompleted += (sender, e) => { if (e.Error != null) { Logger.Log("An unexpected exception occurred while retrieving work item types", e.Error); task.SetError(e.Error); task.SetComplete("An unexpected exception occurred"); } else { this.WorkItemTypes = (ICollection <WorkItemTypeInfo>)e.Result; task.SetComplete("Retrieved " + this.WorkItemTypes.Count.ToCountString("work item type")); } }; worker.RunWorkerAsync(); }
private void ApplyTransformations(object argument) { var simulate = this.Simulate; var saveCopy = this.SaveCopy; if (!simulate) { var result = MessageBox.Show("This will apply the specified transformations to all selected Team Projects. Are you sure you want to continue?", "Confirm Transformation", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result != MessageBoxResult.Yes) { return; } } var teamProjects = this.SelectedTeamProjects.ToList(); var transformations = this.Transformations.ToList(); var task = new ApplicationTask("Transforming work item configuration", teamProjects.Count, true); PublishStatus(new StatusEventArgs(task)); var step = 0; var worker = new BackgroundWorker(); worker.DoWork += (sender, e) => { var tfs = GetSelectedTfsTeamProjectCollection(); var store = tfs.GetService <WorkItemStore>(); var numTransformations = 0; foreach (var teamProject in teamProjects) { task.SetProgress(step++, string.Format(CultureInfo.CurrentCulture, "Processing Team Project \"{0}\"", teamProject.Name)); try { var project = store.Projects[teamProject.Name]; // Apply the transformations only if everything succeeded for the Team Project; cache them in the mean time. var transformedItems = new List <WorkItemConfigurationItem>(); foreach (var transformation in transformations) { if (transformation.WorkItemConfigurationItemType == WorkItemConfigurationItemType.WorkItemType) { // Apply work item type definition transformation, which can apply to multiple work item type definitions (semicolon separated). // If no work item type names are specified, apply to all work item types in the project. var workItemTypeNames = (string.IsNullOrEmpty(transformation.WorkItemTypeNames) ? project.WorkItemTypes.Cast <WorkItemType>().Select(w => w.Name) : transformation.WorkItemTypeNames.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); foreach (var workItemTypeName in workItemTypeNames) { // If the work item type has already been processed before, continue with that version. var itemToTransform = transformedItems.FirstOrDefault(w => string.Equals(w.Name, workItemTypeName, StringComparison.OrdinalIgnoreCase)); if (itemToTransform == null) { // If the work item type wasn't processed yet, find the one with the specified name (if it exists). var wit = project.WorkItemTypes.Cast <WorkItemType>().FirstOrDefault(w => string.Equals(w.Name, workItemTypeName, StringComparison.OrdinalIgnoreCase)); if (wit != null) { try { itemToTransform = WorkItemTypeDefinition.FromXml(wit.Export(false)); } catch (VssServiceResponseException) { // A VssServiceResponseException with message "VS403207: The object does not exist or access is denied" // happens when trying to export a work item type in the inherited model. task.Status = string.Format(CultureInfo.CurrentCulture, "Skipping work item type \"{0}\" as it cannot be modified.", wit.Name); } } } if (itemToTransform != null) { task.Status = "Transforming " + itemToTransform.DisplayName; var transformed = WorkItemConfigurationTransformer.Transform(transformation.TransformationType, itemToTransform.XmlDefinition, transformation.TransformationXml); if (string.Equals(itemToTransform.XmlDefinition.DocumentElement.OuterXml, transformed.DocumentElement.OuterXml)) { task.Status = "The transformation was applied but did not result in any changes, skipping."; } else { itemToTransform.XmlDefinition = transformed; transformedItems.Add(itemToTransform); } } else { task.Status = "Skipping \"{0}\": a work item type with this name was not found in the Team Project".FormatCurrent(workItemTypeName); } } } else if (transformation.WorkItemConfigurationItemType == WorkItemConfigurationItemType.Categories) { var itemToTransform = transformedItems.FirstOrDefault(w => w.Type == WorkItemConfigurationItemType.Categories); if (itemToTransform == null) { itemToTransform = WorkItemConfigurationItemImportExport.GetCategories(project); } task.Status = "Transforming " + itemToTransform.DisplayName; var transformed = WorkItemConfigurationTransformer.Transform(transformation.TransformationType, itemToTransform.XmlDefinition, transformation.TransformationXml); if (string.Equals(itemToTransform.XmlDefinition.DocumentElement.OuterXml, transformed.DocumentElement.OuterXml)) { task.Status = "The transformation was applied but did not result in any changes, skipping."; } else { itemToTransform.XmlDefinition = transformed; transformedItems.Add(itemToTransform); } } else if (transformation.WorkItemConfigurationItemType == WorkItemConfigurationItemType.AgileConfiguration) { var itemToTransform = transformedItems.FirstOrDefault(w => w.Type == WorkItemConfigurationItemType.AgileConfiguration); if (itemToTransform == null) { itemToTransform = WorkItemConfigurationItemImportExport.GetAgileConfiguration(project); } if (itemToTransform != null) { task.Status = "Transforming " + itemToTransform.DisplayName; var transformed = WorkItemConfigurationTransformer.Transform(transformation.TransformationType, itemToTransform.XmlDefinition, transformation.TransformationXml); if (string.Equals(itemToTransform.XmlDefinition.DocumentElement.OuterXml, transformed.DocumentElement.OuterXml)) { task.Status = "The transformation was applied but did not result in any changes, skipping."; } else { itemToTransform.XmlDefinition = transformed; transformedItems.Add(itemToTransform); } } } else if (transformation.WorkItemConfigurationItemType == WorkItemConfigurationItemType.CommonConfiguration) { var itemToTransform = transformedItems.FirstOrDefault(w => w.Type == WorkItemConfigurationItemType.CommonConfiguration); if (itemToTransform == null) { itemToTransform = WorkItemConfigurationItemImportExport.GetCommonConfiguration(project); } if (itemToTransform != null) { task.Status = "Transforming " + itemToTransform.DisplayName; var transformed = WorkItemConfigurationTransformer.Transform(transformation.TransformationType, itemToTransform.XmlDefinition, transformation.TransformationXml); if (string.Equals(itemToTransform.XmlDefinition.DocumentElement.OuterXml, transformed.DocumentElement.OuterXml)) { task.Status = "The transformation was applied but did not result in any changes, skipping."; } else { itemToTransform.XmlDefinition = transformed; transformedItems.Add(itemToTransform); } } } else if (transformation.WorkItemConfigurationItemType == WorkItemConfigurationItemType.ProcessConfiguration) { var itemToTransform = transformedItems.FirstOrDefault(w => w.Type == WorkItemConfigurationItemType.ProcessConfiguration); if (itemToTransform == null) { itemToTransform = WorkItemConfigurationItemImportExport.GetProcessConfiguration(project); } if (itemToTransform != null) { task.Status = "Transforming " + itemToTransform.DisplayName; var transformed = WorkItemConfigurationTransformer.Transform(transformation.TransformationType, itemToTransform.XmlDefinition, transformation.TransformationXml); if (string.Equals(itemToTransform.XmlDefinition.DocumentElement.OuterXml, transformed.DocumentElement.OuterXml)) { task.Status = "The transformation was applied but did not result in any changes, skipping."; } else { itemToTransform.XmlDefinition = transformed; transformedItems.Add(itemToTransform); } } } else { throw new ArgumentException("The Work Item Configuration Item Type is unknown: " + transformation.WorkItemConfigurationItemType.ToString()); } if (task.IsCanceled) { break; } } // Only apply the transformations if they all succeeded (i.e. there was no exception). if (task.IsCanceled) { break; } else { var teamProjectsWithConfigurationItems = new Dictionary <TeamProjectInfo, List <WorkItemConfigurationItem> >() { { teamProject, transformedItems } }; var options = ImportOptions.None; if (simulate) { options |= ImportOptions.Simulate; } if (saveCopy) { options |= ImportOptions.SaveCopy; } WorkItemConfigurationItemImportExport.Import(this.Logger, task, false, store, teamProjectsWithConfigurationItems, options); } numTransformations += transformedItems.Count; } catch (Exception exc) { task.SetWarning(string.Format(CultureInfo.CurrentCulture, "An error occurred while processing Team Project \"{0}\"", teamProject.Name), exc); } if (task.IsCanceled) { task.Status = "Canceled"; break; } } e.Result = numTransformations; }; worker.RunWorkerCompleted += (sender, e) => { if (e.Error != null) { Logger.Log("An unexpected exception occurred while transforming work item configuration", e.Error); task.SetError(e.Error); task.SetComplete("An unexpected exception occurred"); } else { var numTransformations = (int)e.Result; task.SetComplete("Applied transformation to " + numTransformations.ToCountString("work item configuration item")); } }; worker.RunWorkerAsync(); }