From 4c9882000c8628d6aad3727ee769836102522bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stano=20Gabo=20Pe=C5=A5ko?= Date: Wed, 20 Nov 2024 14:32:15 +0100 Subject: [PATCH] Export all users --- .../TfsExportUsersForMappingProcessor.cs | 52 ++++++++++++++----- ...fsExportUsersForMappingProcessorOptions.cs | 17 ++++-- .../TfsWorkItemMigrationProcessor.cs | 12 ++--- .../Tools/TfsUserMappingTool.cs | 23 +++++--- .../DataContracts/IdentityItemData.cs | 11 +++- 5 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessor.cs b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessor.cs index 9ee383af9..984636bc0 100644 --- a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessor.cs +++ b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -42,30 +43,26 @@ protected override void InternalExecute() { Stopwatch stopwatch = Stopwatch.StartNew(); - if (string.IsNullOrEmpty(CommonTools.UserMapping.Options.UserMappingFile)) - { - Log.LogError("UserMappingFile is not set"); - throw new ArgumentNullException("UserMappingFile must be set on the TfsUserMappingToolOptions in CommonEnrichersConfig."); - } + CheckOptions(); - List usersToMap = new List(); + IdentityMapResult data; if (Options.OnlyListUsersInWorkItems) { Log.LogInformation("OnlyListUsersInWorkItems is true, only users in work items will be listed"); List sourceWorkItems = Source.WorkItems.GetWorkItems(Options.WIQLQuery); Log.LogInformation("Processed {0} work items from Source", sourceWorkItems.Count); - usersToMap = CommonTools.UserMapping.GetUsersInSourceMappedToTargetForWorkItems(this, sourceWorkItems); - Log.LogInformation("Found {usersToMap} total mapped", usersToMap.Count); + data = CommonTools.UserMapping.GetUsersInSourceMappedToTargetForWorkItems(this, sourceWorkItems); + Log.LogInformation("Found {usersToMap} total mapped", data.IdentityMap.Count); } else { Log.LogInformation("OnlyListUsersInWorkItems is false, all users will be listed"); - usersToMap = CommonTools.UserMapping.GetUsersInSourceMappedToTarget(this); - Log.LogInformation("Found {usersToMap} total mapped", usersToMap.Count); + data = CommonTools.UserMapping.GetUsersInSourceMappedToTarget(this); + Log.LogInformation("Found {usersToMap} total mapped", data.IdentityMap.Count); } - usersToMap = usersToMap.Where(x => x.Source.DisplayName != x.Target?.DisplayName).ToList(); + List usersToMap = data.IdentityMap.Where(x => x.Source.DisplayName != x.Target?.DisplayName).ToList(); Log.LogInformation("Filtered to {usersToMap} total viable mappings", usersToMap.Count); Dictionary usermappings = []; foreach (IdentityMapData userMapping in usersToMap) @@ -74,11 +71,40 @@ protected override void InternalExecute() // it would throw with duplicate key. This way we just overwrite the value – last item in source wins. usermappings[userMapping.Source.DisplayName] = userMapping.Target?.DisplayName; } - System.IO.File.WriteAllText(CommonTools.UserMapping.Options.UserMappingFile, JsonConvert.SerializeObject(usermappings, Formatting.Indented)); - Log.LogInformation("Writen to: {LocalExportJsonFile}", CommonTools.UserMapping.Options.UserMappingFile); + File.WriteAllText(CommonTools.UserMapping.Options.UserMappingFile, JsonConvert.SerializeObject(usermappings, Formatting.Indented)); + Log.LogInformation("User mappings writen to: {LocalExportJsonFile}", CommonTools.UserMapping.Options.UserMappingFile); + if (Options.ExportAllUsers) + { + ExportAllUsers(data); + } stopwatch.Stop(); Log.LogInformation("DONE in {Elapsed} seconds", stopwatch.Elapsed); } + + private void ExportAllUsers(IdentityMapResult data) + { + var allUsers = new + { + data.SourceUsers, + data.TargetUsers + }; + File.WriteAllText(Options.UserExportFile, JsonConvert.SerializeObject(allUsers, Formatting.Indented)); + Log.LogInformation("All user writen to: {exportFile}", Options.UserExportFile); + } + + private void CheckOptions() + { + if (string.IsNullOrEmpty(CommonTools.UserMapping.Options.UserMappingFile)) + { + Log.LogError("UserMappingFile is not set"); + throw new ArgumentNullException("UserMappingFile must be set on the TfsUserMappingToolOptions in CommonTools."); + } + if (Options.ExportAllUsers && string.IsNullOrEmpty(Options.UserExportFile)) + { + Log.LogError($"Flag ExportAllUsers is set but export file UserExportFile is not set."); + throw new ArgumentNullException("UserExportFile must be set on the TfsExportUsersForMappingProcessorOptions in Processors."); + } + } } } diff --git a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessorOptions.cs b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessorOptions.cs index 90110f8fc..54fd6ebd8 100644 --- a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessorOptions.cs +++ b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsExportUsersForMappingProcessorOptions.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using MigrationTools._EngineV1.Configuration; -using MigrationTools.Enrichers; -using MigrationTools.Processors.Infrastructure; +using MigrationTools.Processors.Infrastructure; namespace MigrationTools.Processors { @@ -16,5 +13,17 @@ public class TfsExportUsersForMappingProcessorOptions : ProcessorOptions /// true public bool OnlyListUsersInWorkItems { get; set; } = true; + /// + /// Set to , if you want to export all users in source and target server. + /// The lists of user can be useful, if you need tu manually edit mapping file. + /// Users will be exported to file set in . + /// + public bool ExportAllUsers { get; set; } + + /// + /// Path to export file where all source and target servers' users will be exported. + /// Users are exported only if is set to . + /// + public string UserExportFile { get; set; } } } diff --git a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemMigrationProcessor.cs b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemMigrationProcessor.cs index fdad90607..2dd8b86ae 100644 --- a/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemMigrationProcessor.cs +++ b/src/MigrationTools.Clients.TfsObjectModel/Processors/TfsWorkItemMigrationProcessor.cs @@ -227,15 +227,15 @@ protected override void InternalExecute() private void ValidateAllUsersExistOrAreMapped(List sourceWorkItems) { - contextLog.Information("Validating::Check that all users in the source exist in the target or are mapped!"); - List usersToMap = new List(); - usersToMap = CommonTools.UserMapping.GetUsersInSourceMappedToTargetForWorkItems(this, sourceWorkItems); - if (usersToMap != null && usersToMap?.Count > 0) + IdentityMapResult usersToMap = CommonTools.UserMapping.GetUsersInSourceMappedToTargetForWorkItems(this, sourceWorkItems); + if (usersToMap.IdentityMap != null && usersToMap.IdentityMap.Count > 0) { - Log.LogWarning("Validating Failed! There are {usersToMap} users that exist in the source that do not exist in the target. This will not cause any errors, but may result in disconnected users that could have been mapped. Use the ExportUsersForMapping processor to create a list of mappable users. Then Import using ", usersToMap.Count); + Log.LogWarning("Validating Failed! There are {usersToMap} users that exist in the source that do not exist " + + "in the target. This will not cause any errors, but may result in disconnected users that could have " + + "been mapped. Use the ExportUsersForMapping processor to create a list of mappable users.", + usersToMap.IdentityMap.Count); } - } //private void ValidateAllNodesExistOrAreMapped(List sourceWorkItems) diff --git a/src/MigrationTools.Clients.TfsObjectModel/Tools/TfsUserMappingTool.cs b/src/MigrationTools.Clients.TfsObjectModel/Tools/TfsUserMappingTool.cs index 7e64f5470..c522e9e6a 100644 --- a/src/MigrationTools.Clients.TfsObjectModel/Tools/TfsUserMappingTool.cs +++ b/src/MigrationTools.Clients.TfsObjectModel/Tools/TfsUserMappingTool.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -121,11 +121,12 @@ private List GetUsersListFromServer(IGroupSecurityService gss) Log.LogWarning("TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Failed With {Exception}", sid, ex.Message); } } + foundUsers.Sort((x, y) => x.AccountName.CompareTo(y.AccountName)); Log.LogInformation("TfsUserMappingTool::GetUsersListFromServer {count} user identities are applicable for mapping", foundUsers.Count); return foundUsers; } - public List GetUsersInSourceMappedToTarget(TfsProcessor processor) + public IdentityMapResult GetUsersInSourceMappedToTarget(TfsProcessor processor) { Log.LogDebug("TfsUserMappingTool::GetUsersInSourceMappedToTarget"); if (Options.Enabled) @@ -162,25 +163,31 @@ public List GetUsersInSourceMappedToTarget(TfsProcessor process targetUser ??= targetUsers.SingleOrDefault(x => x.DisplayName == sourceUser.DisplayName); identityMap.Add(new IdentityMapData { Source = sourceUser, Target = targetUser }); } - return identityMap; + return new() + { + IdentityMap = identityMap, + SourceUsers = sourceUsers, + TargetUsers = targetUsers + }; } else { Log.LogWarning("TfsUserMappingTool is disabled in settings. You may have users in the source that are not mapped to the target. "); - return []; + return new(); } } - public List GetUsersInSourceMappedToTargetForWorkItems(TfsProcessor processor, List sourceWorkItems) + public IdentityMapResult GetUsersInSourceMappedToTargetForWorkItems(TfsProcessor processor, List sourceWorkItems) { if (Options.Enabled) { Dictionary result = new Dictionary(); HashSet workItemUsers = GetUsersFromWorkItems(sourceWorkItems, Options.IdentityFieldsToCheck); Log.LogDebug($"TfsUserMappingTool::GetUsersInSourceMappedToTargetForWorkItems [workItemUsers|{workItemUsers.Count}]"); - List mappedUsers = GetUsersInSourceMappedToTarget(processor); - Log.LogDebug($"TfsUserMappingTool::GetUsersInSourceMappedToTargetForWorkItems [mappedUsers|{mappedUsers.Count}]"); - return mappedUsers.Where(x => workItemUsers.Contains(x.Source.DisplayName)).ToList(); + IdentityMapResult mappedUsers = GetUsersInSourceMappedToTarget(processor); + Log.LogDebug($"TfsUserMappingTool::GetUsersInSourceMappedToTargetForWorkItems [mappedUsers|{mappedUsers.IdentityMap.Count}]"); + mappedUsers.IdentityMap = mappedUsers.IdentityMap.Where(x => workItemUsers.Contains(x.Source.DisplayName)).ToList(); + return mappedUsers; } else { diff --git a/src/MigrationTools/DataContracts/IdentityItemData.cs b/src/MigrationTools/DataContracts/IdentityItemData.cs index 0cfcac7d3..336a9e3f3 100644 --- a/src/MigrationTools/DataContracts/IdentityItemData.cs +++ b/src/MigrationTools/DataContracts/IdentityItemData.cs @@ -1,4 +1,6 @@ -namespace MigrationTools.DataContracts +using System.Collections.Generic; + +namespace MigrationTools.DataContracts { public class IdentityItemData { @@ -14,4 +16,11 @@ public class IdentityMapData public IdentityItemData Source { get; set; } public IdentityItemData Target { get; set; } } + + public class IdentityMapResult + { + public List IdentityMap { get; set; } = []; + public List SourceUsers { get; set; } = []; + public List TargetUsers { get; set; } = []; + } }