diff --git a/appsettings.json b/appsettings.json index 8dfba0693..9d301c515 100644 --- a/appsettings.json +++ b/appsettings.json @@ -58,9 +58,7 @@ "CommonTools": { "FieldMappingTool": { "Enabled": false, - "FieldMaps": [], - "FieldMapDefaults": { - } + "FieldMaps": [] }, "TfsChangeSetMappingTool": { "Enabled": false, @@ -148,6 +146,12 @@ } }, "CommonToolSamples": { + "TfsGitRepositoryTool": { + "Enabled": true, + "Mappings": { + "RepoInSource": "RepoInTarget" + } + }, "FieldMappingTool": { "Enabled": true, "FieldMaps": [ @@ -159,13 +163,42 @@ "formatExpression": "{0} \n {1}" }, { - "FieldMapType": "FieldLiteralMap", + "FieldMapType": "FieldValueMap", + "ApplyTo": [ "SomeWorkItemType" ], + "sourceField": "System.State", + "targetField": "System.State", + "defaultValue": "New", + "valueMapping": { + "Active": "InProgress", + "Resolved": "InProgress", + "Closed": "Done" + } + }, + { + "FieldMapType": "FieldToFieldMap", + "ApplyTo": [ "SomeWorkItemType" ], + "sourceField": "Microsoft.VSTS.Common.BacklogPriority", + "targetField": "Microsoft.VSTS.Common.StackRank", + "defaultValue": 42 + } + ], + "FieldMapSamples": { + "FieldClearMap": { + "ApplyTo": [ "SomeWorkItemType" ], + "targetField": "Custom.FieldC" + }, + "FieldMergeMap": { + "ApplyTo": [ "SomeWorkItemType" ], + "sourceFields": [ "Custom.FieldA", "Custom.FieldB" ], + "targetField": "Custom.FieldC", + "formatExpression": "{0} \n {1}" + }, + "FieldLiteralMap": { "ApplyTo": [ "SomeWorkItemType" ], "targetField": "Custom.SomeField", "value": "New field value" }, - { - "FieldMapType": "MultiValueConditionalMap", + "MultiValueConditionalMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceFieldsAndValues": { "Field1": "Value1", @@ -176,13 +209,11 @@ "Field2": "Value2" } }, - { - "FieldMapType": "FieldSkipMap", + "targetFieldsAndValues": { "ApplyTo": [ "SomeWorkItemType" ], "targetField": "Custom.ReflectedWorkItemId" }, - { - "FieldMapType": "FieldValueMap", + "FieldValueMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceField": "System.State", "targetField": "System.State", @@ -191,29 +222,25 @@ "StateA": "StateB" } }, - { - "FieldMapType": "FieldToFieldMap", + "FieldToFieldMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceField": "Microsoft.VSTS.Common.BacklogPriority", "targetField": "Microsoft.VSTS.Common.StackRank", "defaultValue": 42 }, - { - "FieldMapType": "FieldToFieldMultiMap", + "FieldToFieldMultiMap": { "ApplyTo": [ "SomeWorkItemType", "SomeOtherWorkItemType" ], "SourceToTargetMappings": { "SourceField1": "TargetField1", "SourceField2": "TargetField2" } }, - { - "FieldMapType": "FieldToTagMap", + "FieldToTagMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceField": "System.State", "formatExpression": "ScrumState:{0}" }, - { - "FieldMapType": "FieldToTagFieldMap", + "FieldToTagFieldMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceFields": [ "System.Description", @@ -222,29 +249,25 @@ "targetField": "System.Description", "formatExpression": "{0}

Acceptance Criteria

{1}" }, - { - "FieldMapType": "RegexFieldMap", + "RegexFieldMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceField": "COMPANY.PRODUCT.Release", "targetField": "COMPANY.DEVISION.MinorReleaseVersion", "pattern": "PRODUCT \\d{4}.(\\d{1})", "replacement": "$1" }, - { - "FieldMapType": "FieldValueToTagMap", + "FieldValueToTagMap": { "ApplyTo": [ "SomeWorkItemType" ], "sourceField": "Microsoft.VSTS.CMMI.Blocked", "pattern": "Yes", "formatExpression": "{0}" }, - { - "FieldMapType": "TreeToTagMap", + "TreeToTagMap": { "ApplyTo": [ "SomeWorkItemType" ], "toSkip": 3, "timeTravel": 1 } - ] - + } }, "TfsChangeSetMappingTool": { "Enabled": true, @@ -330,12 +353,6 @@ }, "TfsEmbededImagesTool": { "Enabled": true - }, - "GitRepositoryTool": { - "Enabled": true, - "Mappings": { - "Repo1": "Repo2" - } } }, "ProcessorDefaults": { diff --git a/docs/Reference/Generated/MigrationTools.Clients.AzureDevops.ObjectModel.xml b/docs/Reference/Generated/MigrationTools.Clients.AzureDevops.ObjectModel.xml index ff49060cd..84cdced43 100644 --- a/docs/Reference/Generated/MigrationTools.Clients.AzureDevops.ObjectModel.xml +++ b/docs/Reference/Generated/MigrationTools.Clients.AzureDevops.ObjectModel.xml @@ -455,6 +455,12 @@ from https://gist.github.com/pietergheysens/792ed505f09557e77ddfc1b83531e4fb + + + List of work item mappings. + + {} + The TfsNodeStructureToolEnricher is used to create missing nodes in the target project. To configure it add a `TfsNodeStructureToolOptions` section to `CommonEnrichersConfig` in the config file. Otherwise defaults will be applied. diff --git a/docs/Reference/Generated/MigrationTools.xml b/docs/Reference/Generated/MigrationTools.xml index 5f4728aed..ae68ade4f 100644 --- a/docs/Reference/Generated/MigrationTools.xml +++ b/docs/Reference/Generated/MigrationTools.xml @@ -201,17 +201,6 @@ If set to `true` then the tool will run. Set to `false` and the processor will not run. - - - Used to process the String fields of a work item. This is useful for cleaning up data. It will limit fields to a max length and apply regex replacements based on what is configured. Each regex replacement is applied in order and can be enabled or disabled. - - - - - List of work item mappings. - - {} - Used to process the String fields of a work item. This is useful for cleaning up data. It will limit fields to a max length and apply regex replacements based on what is configured. Each regex replacement is applied in order and can be enabled or disabled. @@ -274,27 +263,27 @@ - => @"91912a6b" + => @"7eaf4f78" - => @"91912a6b094734882a9067fd23d5d7bbda82b191" + => @"7eaf4f78b693a09be4ba34347308121603371a18" - => @"2024-08-28T10:20:42+01:00" + => @"2024-08-28T10:49:54+01:00" - => @"216" + => @"217" - => @"v15.2.1-216-g91912a6b" + => @"v15.2.1-217-g7eaf4f78" @@ -329,7 +318,7 @@ - => @"217" + => @"218" diff --git a/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryTool.cs b/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryTool.cs index 2223758a7..a717c129b 100644 --- a/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryTool.cs +++ b/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryTool.cs @@ -81,7 +81,6 @@ public int Enrich(TfsProcessor processor, WorkItemData sourceWorkItem, WorkItem Log.LogInformation("GitRepositoryEnricher: Enriching {Id} To fix Git Repo Links", targetWorkItem.Id); var changeSetMappings = Services.GetService(); - var gitRepoMaps = Services.GetService(); List newEL = new List(); List removeEL = new List(); int count = 0; @@ -110,7 +109,7 @@ public int Enrich(TfsProcessor processor, WorkItemData sourceWorkItem, WorkItem { var anyProjectSourceRepoInfo = TfsGitRepositoryInfo.Create(el, allSourceRepos, changeSetMappings, sourceWorkItem?.ProjectName); // if repo is found in a different project and the repo Name is listed in repo mappings, use it - if (anyProjectSourceRepoInfo.GitRepo != null && gitRepoMaps.Mappings.ContainsKey(anyProjectSourceRepoInfo.GitRepo.Name)) + if (anyProjectSourceRepoInfo.GitRepo != null && Options.Mappings.ContainsKey(anyProjectSourceRepoInfo.GitRepo.Name)) { sourceRepoInfo = anyProjectSourceRepoInfo; } @@ -122,7 +121,7 @@ public int Enrich(TfsProcessor processor, WorkItemData sourceWorkItem, WorkItem if (sourceRepoInfo.GitRepo != null) { - string targetRepoName = GetTargetRepoName(gitRepoMaps.Mappings, sourceRepoInfo); + string targetRepoName = GetTargetRepoName(Options.Mappings, sourceRepoInfo); string sourceProjectName = sourceRepoInfo?.GitRepo?.ProjectReference?.Name ?? _processor.Target.Options.Project; string targetProjectName = _processor.Target.Options.Project; @@ -130,7 +129,7 @@ public int Enrich(TfsProcessor processor, WorkItemData sourceWorkItem, WorkItem // if repo was not found in the target project, try to find it in the whole target project collection if (targetRepoInfo.GitRepo == null) { - if (gitRepoMaps.Mappings.Values.Contains(targetRepoName)) + if (Options.Mappings.Values.Contains(targetRepoName)) { var anyTargetRepoInCollectionInfo = TfsGitRepositoryInfo.Create(targetRepoName, sourceRepoInfo, allTargetRepos); if (anyTargetRepoInCollectionInfo.GitRepo != null) @@ -233,7 +232,7 @@ where gitWits.Contains(lq.ArtifactLinkType.Name) return count; } - private string GetTargetRepoName(ReadOnlyDictionary gitRepoMappings, TfsGitRepositoryInfo repoInfo) + private string GetTargetRepoName(Dictionary gitRepoMappings, TfsGitRepositoryInfo repoInfo) { if (gitRepoMappings.ContainsKey(repoInfo.GitRepo.Name)) { diff --git a/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryToolOptions.cs b/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryToolOptions.cs index efaf4b74f..ca248b643 100644 --- a/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryToolOptions.cs +++ b/src/MigrationTools.Clients.AzureDevops.ObjectModel/Tools/TfsGitRepositoryToolOptions.cs @@ -8,6 +8,10 @@ namespace MigrationTools.Tools { public class TfsGitRepositoryToolOptions : ToolOptions { - + /// + /// List of work item mappings. + /// + /// {} + public Dictionary Mappings { get; set; } } } \ No newline at end of file diff --git a/src/MigrationTools.ConsoleDataGenerator/ClassDataLoader.cs b/src/MigrationTools.ConsoleDataGenerator/ClassDataLoader.cs index 8adf7ff48..e21b1e3ae 100644 --- a/src/MigrationTools.ConsoleDataGenerator/ClassDataLoader.cs +++ b/src/MigrationTools.ConsoleDataGenerator/ClassDataLoader.cs @@ -96,7 +96,7 @@ private ClassData CreateClassDataFromOptions(List allTy data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "defaults", SampleFor = data.OptionsClassFullName, Code = json.Trim() }); } else { - data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "defaults", SampleFor = data.OptionsClassFullName, Code = "Default Unavailable" }); + data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "defaults", SampleFor = data.OptionsClassFullName, Code = "There are no defaults! Check the sample for options!" }); } } if (!string.IsNullOrEmpty(instanceOfOption.ConfigurationMetadata.PathToSample)) @@ -111,7 +111,7 @@ private ClassData CreateClassDataFromOptions(List allTy } else { - data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "sample", SampleFor = data.OptionsClassFullName, Code = "Sample Unavailable" }); + data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "sample", SampleFor = data.OptionsClassFullName, Code = "There is no sample, but you can check the classic below for a general feel." }); } } data.ConfigurationSamples.Add(new ConfigurationSample() { Name = "classic", SampleFor = data.OptionsClassFullName, Code = saveData.SeraliseDataToJson(instanceOfOption).Trim() }); diff --git a/src/MigrationTools.ConsoleDataGenerator/Program.cs b/src/MigrationTools.ConsoleDataGenerator/Program.cs index dc5cfea8d..5c68e0a6a 100644 --- a/src/MigrationTools.ConsoleDataGenerator/Program.cs +++ b/src/MigrationTools.ConsoleDataGenerator/Program.cs @@ -54,11 +54,11 @@ static void Main(string[] args) List classDataList = new List(); classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "Processors")); - //classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "Tools")); - //classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "FieldMaps")); - //classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "ProcessorEnrichers")); - //classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "Endpoints")); - //classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "EndpointEnrichers")); + classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "Tools")); + classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "FieldMaps")); + classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "ProcessorEnrichers")); + classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "Endpoints")); + classDataList.AddRange(cdLoader.GetClassDataFromOptions(allMigrationTypes, "EndpointEnrichers")); diff --git a/src/MigrationTools/ServiceCollectionExtensions.cs b/src/MigrationTools/ServiceCollectionExtensions.cs index 6d03db4ff..742d23e87 100644 --- a/src/MigrationTools/ServiceCollectionExtensions.cs +++ b/src/MigrationTools/ServiceCollectionExtensions.cs @@ -45,12 +45,12 @@ public static void AddMigrationToolServices(this IServiceCollection context, ICo case MigrationConfigSchema.v1: context.AddSingleton().AddSingleton>(Microsoft.Extensions.Options.Options.Create(configuration.GetSectionCommonEnrichers_v15())); context.AddSingleton().AddSingleton>(Microsoft.Extensions.Options.Options.Create(configuration.GetSectionCommonEnrichers_v15())); - context.AddSingleton().AddSingleton>(Microsoft.Extensions.Options.Options.Create(configuration.GetSectionCommonEnrichers_v15())); + //context.AddSingleton().AddSingleton>(Microsoft.Extensions.Options.Options.Create(configuration.GetSectionCommonEnrichers_v15())); break; case MigrationConfigSchema.v160: context.AddSingleton().AddMigrationToolsOptions(configuration); context.AddSingleton().AddMigrationToolsOptions(configuration); - context.AddSingleton().AddMigrationToolsOptions(configuration); + // context.AddSingleton().AddMigrationToolsOptions(configuration); break; } context.AddSingleton() diff --git a/src/MigrationTools/Tools/FieldMappingTool/Infrastructure/FieldMapOptions.cs b/src/MigrationTools/Tools/FieldMappingTool/Infrastructure/FieldMapOptions.cs index 0029621d9..eb43bb5ba 100644 --- a/src/MigrationTools/Tools/FieldMappingTool/Infrastructure/FieldMapOptions.cs +++ b/src/MigrationTools/Tools/FieldMappingTool/Infrastructure/FieldMapOptions.cs @@ -15,11 +15,12 @@ public abstract class FieldMapOptions : IFieldMapOptions [JsonIgnore] public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata { - PathToInstance = $"MigrationTools:CommonTools:FieldMappingTool:FieldMaps:{OptionFor}", + IsCollection = true, + PathToInstance = $"MigrationTools:CommonTools:FieldMappingTool:FieldMaps", ObjectName = $"FieldMapType", OptionFor = OptionFor, - PathToDefault = $"MigrationTools::CommonToolDefaults:FieldMappingTool:FieldMaps:{OptionFor}", - PathToSample = $"MigrationTools::CommonToolSamples:FieldMappingTool:FieldMaps:{OptionFor}" + PathToDefault = $"MigrationTools:CommonTools:FieldMappingTool:FieldMapDefaults:{OptionFor}", + PathToSample = $"MigrationTools:CommonToolSamples:FieldMappingTool:FieldMapSamples:{OptionFor}" }; protected FieldMapOptions() diff --git a/src/MigrationTools/Tools/GitRepoMappingTool.cs b/src/MigrationTools/Tools/GitRepoMappingTool.cs deleted file mode 100644 index f98f3e76e..000000000 --- a/src/MigrationTools/Tools/GitRepoMappingTool.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using MigrationTools.DataContracts; -using MigrationTools.Enrichers; -using MigrationTools.Processors; -using MigrationTools.Tools.Infrastructure; -using static Microsoft.VisualStudio.Services.Graph.GraphResourceIds.Users; - -namespace MigrationTools.Tools -{ - /// - /// Used to process the String fields of a work item. This is useful for cleaning up data. It will limit fields to a max length and apply regex replacements based on what is configured. Each regex replacement is applied in order and can be enabled or disabled. - /// - public class GitRepoMappingTool : Tool - { - public ReadOnlyDictionary Mappings { get; private set; } - - public GitRepoMappingTool(IOptions options, IServiceProvider services, ILogger logger, ITelemetryLogger telemetryLogger) - : base(options, services, logger, telemetryLogger) - { - - Mappings = new ReadOnlyDictionary(Options.Mappings); - } - - } - -} - diff --git a/src/MigrationTools/Tools/GitRepoMappingToolOptions.cs b/src/MigrationTools/Tools/GitRepoMappingToolOptions.cs deleted file mode 100644 index 5bd749d48..000000000 --- a/src/MigrationTools/Tools/GitRepoMappingToolOptions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using MigrationTools.Enrichers; -using MigrationTools.Options; -using MigrationTools.Tools.Infrastructure; - -namespace MigrationTools.Tools -{ - public class GitRepoMappingToolOptions : ToolOptions - { - - /// - /// List of work item mappings. - /// - /// {} - public Dictionary Mappings { get; set; } - } - -} \ No newline at end of file diff --git a/src/MigrationTools/Tools/Infrastructure/ToolOptions.cs b/src/MigrationTools/Tools/Infrastructure/ToolOptions.cs index 6727be5bc..f856cd34d 100644 --- a/src/MigrationTools/Tools/Infrastructure/ToolOptions.cs +++ b/src/MigrationTools/Tools/Infrastructure/ToolOptions.cs @@ -9,7 +9,7 @@ namespace MigrationTools.Tools.Infrastructure public abstract class ToolOptions : IToolOptions { [JsonIgnore] - public string OptionFor => $"{GetType().Name.Replace("Options", "")}"; + private string OptionFor => $"{GetType().Name.Replace("Options", "")}"; [JsonIgnore] public ConfigurationMetadata ConfigurationMetadata => new ConfigurationMetadata