From a63261f69d3dd625035a416878513bbd021488a3 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Tue, 23 Jul 2024 16:49:45 +0100 Subject: [PATCH 01/10] build(Directory.Build.props): reset version to 0.0.0.0 and add FileVersion and InformationalVersion for better versioning control feat(MigrationTools.sln): add NKDAgility.AzureDevOps.Tools.CommandHost project to solution for extended functionality chore(test projects): update MSTest.TestAdapter and MSTest.TestFramework to version 3.5.0 for latest features and bug fixes chore(MigrationTools.ConsoleDataGenerator.csproj): update YamlDotNet to version 16.0.0 for improved YAML processing chore(MigrationTools.Host.csproj): update Serilog.Settings.Configuration to version 8.0.2 for enhanced logging configuration chore: update MSTest.TestAdapter and MSTest.TestFramework versions from 3.4.3 to 3.5.0 in MigrationTools.Integration.Tests, MigrationTools.Tests, and VstsSyncMigrator.Core.Tests projects for latest features and bug fixes feat: add new project NKDAgility.AzureDevOps.Tools.CommandHost with .NET 8.0 and Newtonsoft.Json 13.0.3 package reference for new functionality --- Directory.Build.props | 6 ++++-- MigrationTools.sln | 7 +++++++ ...Clients.AzureDevops.ObjectModel.Tests.csproj | 4 ++-- ...nTools.Clients.AzureDevops.Rest.Tests.csproj | 4 ++-- ...grationTools.Clients.FileSystem.Tests.csproj | 4 ++-- ...MigrationTools.Clients.InMemory.Tests.csproj | 4 ++-- .../MigrationTools.ConsoleDataGenerator.csproj | 2 +- .../MigrationTools.Host.Tests.csproj | 4 ++-- .../MigrationTools.Host.csproj | 2 +- .../MigrationTools.Integration.Tests.csproj | 4 ++-- .../MigrationTools.Tests.csproj | 4 ++-- ...Agility.AzureDevOps.Tools.CommandHost.csproj | 17 +++++++++++++++++ .../VstsSyncMigrator.Core.Tests.csproj | 4 ++-- 13 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 src/NKDAgility.AzureDevOps.Tools.CommandHost/NKDAgility.AzureDevOps.Tools.CommandHost.csproj diff --git a/Directory.Build.props b/Directory.Build.props index f3fe61328..2d94db4f3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,10 +1,12 @@ - 0.0.0.1 + 0.0.0.0 + 0.0.0.0 + 0.0.0-local Martin Hinshelwood naked Agility with Martin Hinshelwood - 9.0 MigrationTools.CommandLine + default 1701;1702;1591 diff --git a/MigrationTools.sln b/MigrationTools.sln index 3c1027118..d0209cc7e 100644 --- a/MigrationTools.sln +++ b/MigrationTools.sln @@ -126,6 +126,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{88C358 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{BB497233-248C-49DF-AE12-F7A76F775E74}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NKDAgility.AzureDevOps.Tools.CommandHost", "src\NKDAgility.AzureDevOps.Tools.CommandHost\NKDAgility.AzureDevOps.Tools.CommandHost.csproj", "{60EF98A1-5AA4-4589-8B6F-A77B3940025D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -208,6 +210,10 @@ Global {6A259EA6-860B-448A-8943-594DC1A15105}.Debug|Any CPU.Build.0 = Debug|Any CPU {6A259EA6-860B-448A-8943-594DC1A15105}.Release|Any CPU.ActiveCfg = Release|Any CPU {6A259EA6-860B-448A-8943-594DC1A15105}.Release|Any CPU.Build.0 = Release|Any CPU + {60EF98A1-5AA4-4589-8B6F-A77B3940025D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60EF98A1-5AA4-4589-8B6F-A77B3940025D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60EF98A1-5AA4-4589-8B6F-A77B3940025D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60EF98A1-5AA4-4589-8B6F-A77B3940025D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -241,6 +247,7 @@ Global {6A259EA6-860B-448A-8943-594DC1A15105} = {83F36820-E9BC-4F48-8202-5EAF9530405E} {AC3B5101-83F5-4C28-976C-C325425D1988} = {1F5E9C8C-AD05-4C4F-B370-FF3D080A6541} {BB497233-248C-49DF-AE12-F7A76F775E74} = {83F36820-E9BC-4F48-8202-5EAF9530405E} + {60EF98A1-5AA4-4589-8B6F-A77B3940025D} = {BB497233-248C-49DF-AE12-F7A76F775E74} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {62EE0B27-C55A-46EE-8D17-1691DE9BBD50} diff --git a/src/MigrationTools.Clients.AzureDevops.ObjectModel.Tests/MigrationTools.Clients.AzureDevops.ObjectModel.Tests.csproj b/src/MigrationTools.Clients.AzureDevops.ObjectModel.Tests/MigrationTools.Clients.AzureDevops.ObjectModel.Tests.csproj index 5e080088e..5d9ce7e47 100644 --- a/src/MigrationTools.Clients.AzureDevops.ObjectModel.Tests/MigrationTools.Clients.AzureDevops.ObjectModel.Tests.csproj +++ b/src/MigrationTools.Clients.AzureDevops.ObjectModel.Tests/MigrationTools.Clients.AzureDevops.ObjectModel.Tests.csproj @@ -13,8 +13,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.Clients.AzureDevops.Rest.Tests/MigrationTools.Clients.AzureDevops.Rest.Tests.csproj b/src/MigrationTools.Clients.AzureDevops.Rest.Tests/MigrationTools.Clients.AzureDevops.Rest.Tests.csproj index 87b4321b5..1fa84dae1 100644 --- a/src/MigrationTools.Clients.AzureDevops.Rest.Tests/MigrationTools.Clients.AzureDevops.Rest.Tests.csproj +++ b/src/MigrationTools.Clients.AzureDevops.Rest.Tests/MigrationTools.Clients.AzureDevops.Rest.Tests.csproj @@ -9,8 +9,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.Clients.FileSystem.Tests/MigrationTools.Clients.FileSystem.Tests.csproj b/src/MigrationTools.Clients.FileSystem.Tests/MigrationTools.Clients.FileSystem.Tests.csproj index d98ce49cb..4558dd485 100644 --- a/src/MigrationTools.Clients.FileSystem.Tests/MigrationTools.Clients.FileSystem.Tests.csproj +++ b/src/MigrationTools.Clients.FileSystem.Tests/MigrationTools.Clients.FileSystem.Tests.csproj @@ -12,8 +12,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.Clients.InMemory.Tests/MigrationTools.Clients.InMemory.Tests.csproj b/src/MigrationTools.Clients.InMemory.Tests/MigrationTools.Clients.InMemory.Tests.csproj index eef5132cf..51b90f725 100644 --- a/src/MigrationTools.Clients.InMemory.Tests/MigrationTools.Clients.InMemory.Tests.csproj +++ b/src/MigrationTools.Clients.InMemory.Tests/MigrationTools.Clients.InMemory.Tests.csproj @@ -12,8 +12,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.ConsoleDataGenerator/MigrationTools.ConsoleDataGenerator.csproj b/src/MigrationTools.ConsoleDataGenerator/MigrationTools.ConsoleDataGenerator.csproj index cdb982d3c..d0e7d87e5 100644 --- a/src/MigrationTools.ConsoleDataGenerator/MigrationTools.ConsoleDataGenerator.csproj +++ b/src/MigrationTools.ConsoleDataGenerator/MigrationTools.ConsoleDataGenerator.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/MigrationTools.Host.Tests/MigrationTools.Host.Tests.csproj b/src/MigrationTools.Host.Tests/MigrationTools.Host.Tests.csproj index ba9e76aae..757a1e4c5 100644 --- a/src/MigrationTools.Host.Tests/MigrationTools.Host.Tests.csproj +++ b/src/MigrationTools.Host.Tests/MigrationTools.Host.Tests.csproj @@ -17,8 +17,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.Host/MigrationTools.Host.csproj b/src/MigrationTools.Host/MigrationTools.Host.csproj index 943535143..3174b6c22 100644 --- a/src/MigrationTools.Host/MigrationTools.Host.csproj +++ b/src/MigrationTools.Host/MigrationTools.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/MigrationTools.Integration.Tests/MigrationTools.Integration.Tests.csproj b/src/MigrationTools.Integration.Tests/MigrationTools.Integration.Tests.csproj index aa821c455..6dd6dca23 100644 --- a/src/MigrationTools.Integration.Tests/MigrationTools.Integration.Tests.csproj +++ b/src/MigrationTools.Integration.Tests/MigrationTools.Integration.Tests.csproj @@ -11,8 +11,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/MigrationTools.Tests/MigrationTools.Tests.csproj b/src/MigrationTools.Tests/MigrationTools.Tests.csproj index 3b5aed8fa..2d71c7fc5 100644 --- a/src/MigrationTools.Tests/MigrationTools.Tests.csproj +++ b/src/MigrationTools.Tests/MigrationTools.Tests.csproj @@ -11,8 +11,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/NKDAgility.AzureDevOps.Tools.CommandHost/NKDAgility.AzureDevOps.Tools.CommandHost.csproj b/src/NKDAgility.AzureDevOps.Tools.CommandHost/NKDAgility.AzureDevOps.Tools.CommandHost.csproj new file mode 100644 index 000000000..b72bcacd8 --- /dev/null +++ b/src/NKDAgility.AzureDevOps.Tools.CommandHost/NKDAgility.AzureDevOps.Tools.CommandHost.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/src/VstsSyncMigrator.Core.Tests/VstsSyncMigrator.Core.Tests.csproj b/src/VstsSyncMigrator.Core.Tests/VstsSyncMigrator.Core.Tests.csproj index 75eef0a0c..d32f05042 100644 --- a/src/VstsSyncMigrator.Core.Tests/VstsSyncMigrator.Core.Tests.csproj +++ b/src/VstsSyncMigrator.Core.Tests/VstsSyncMigrator.Core.Tests.csproj @@ -9,8 +9,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From d15c9a38d72502a721624000c99fd4d9fc506131 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Tue, 23 Jul 2024 17:44:34 +0100 Subject: [PATCH 02/10] refactor(MigrationTools.Host): restructure command line options and commands for better organization and clarity feat(MigrationTools.Host): introduce new command classes for migration execution and initialization fix(MigrationTools.Host): update command options to use Spectre.Console.Cli for better command line interface handling refactor(MigrationTools.Host): remove ExecuteHostedService.cs and InitHostedService.cs, replace with MigrationService.cs for simplified service execution feat(MigrationTools.Host): add Spectre.Console.Cli and YamlDotNet packages for enhanced CLI and YAML support chore(MigrationTools.Host): remove unused CommandLineParser package reference from MigrationTools.Host.csproj style(MigrationTools.Host): remove unused imports in MigrationToolHost.cs for cleaner code --- .../CommandLine/ExecuteOptions.cs | 32 ----- .../CommandLine/InitOptions.cs | 14 -- .../CommandLine/OptionsMode.cs | 11 -- .../Commands/BaseMigrationCommandSettings.cs | 22 ++++ .../Commands/MigrationExecuteCommand.cs | 54 ++++++++ .../MigrationExecuteCommandSettings.cs | 37 ++++++ .../Commands/MigrationInitCommand.cs | 103 +++++++++++++++ .../Commands/MigrationInitCommandSettings.cs | 22 ++++ .../ExecuteHostedService.cs | 71 ----------- src/MigrationTools.Host/InitHostedService.cs | 120 ------------------ src/MigrationTools.Host/MigrationService.cs | 32 +++++ src/MigrationTools.Host/MigrationToolHost.cs | 2 - .../MigrationTools.Host.csproj | 3 +- 13 files changed, 272 insertions(+), 251 deletions(-) delete mode 100644 src/MigrationTools.Host/CommandLine/ExecuteOptions.cs delete mode 100644 src/MigrationTools.Host/CommandLine/InitOptions.cs delete mode 100644 src/MigrationTools.Host/CommandLine/OptionsMode.cs create mode 100644 src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs create mode 100644 src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs create mode 100644 src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs create mode 100644 src/MigrationTools.Host/Commands/MigrationInitCommand.cs create mode 100644 src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs delete mode 100644 src/MigrationTools.Host/ExecuteHostedService.cs delete mode 100644 src/MigrationTools.Host/InitHostedService.cs create mode 100644 src/MigrationTools.Host/MigrationService.cs diff --git a/src/MigrationTools.Host/CommandLine/ExecuteOptions.cs b/src/MigrationTools.Host/CommandLine/ExecuteOptions.cs deleted file mode 100644 index 1a327176e..000000000 --- a/src/MigrationTools.Host/CommandLine/ExecuteOptions.cs +++ /dev/null @@ -1,32 +0,0 @@ -using CommandLine; - -namespace MigrationTools.Host.CommandLine -{ - [Verb("execute", HelpText = "Record changes to the repository.")] - public class ExecuteOptions - { - [Option('c', "config", Required = true, HelpText = "Configuration file to be processed.")] - public string ConfigFile { get; set; } - - [Option("sourceDomain", Required = false, HelpText = "Domain used to connect to the source TFS instance.")] - public string SourceDomain { get; set; } - - [Option("sourceUserName", Required = false, HelpText = "User Name used to connect to the source TFS instance.")] - public string SourceUserName { get; set; } - - [Option("sourcePassword", Required = false, HelpText = "Password used to connect to source TFS instance.")] - public string SourcePassword { get; set; } - - [Option("targetDomain", Required = false, HelpText = "Domain used to connect to the target TFS instance.")] - public string TargetDomain { get; set; } - - [Option("targetUserName", Required = false, HelpText = "User Name used to connect to the target TFS instance.")] - public string TargetUserName { get; set; } - - [Option("targetPassword", Required = false, HelpText = "Password used to connect to target TFS instance.")] - public string TargetPassword { get; set; } - - [Option("disableTelemetry", Required = false, HelpText = "Pass 'true' to turn temimetery off. No data will be colected.")] - public string DisableTelemetry { get; set; } - } -} \ No newline at end of file diff --git a/src/MigrationTools.Host/CommandLine/InitOptions.cs b/src/MigrationTools.Host/CommandLine/InitOptions.cs deleted file mode 100644 index 41ed4921d..000000000 --- a/src/MigrationTools.Host/CommandLine/InitOptions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using CommandLine; - -namespace MigrationTools.Host.CommandLine -{ - [Verb("init", HelpText = "Creates initial config file")] - public class InitOptions - { - [Option('c', "config", Required = false, HelpText = "Configuration file to be processed.")] - public string ConfigFile { get; set; } - - [Option('o', "options", Required = false, Default = OptionsMode.Basic, HelpText = "Configuration file to be generated: Basic, Reference, WorkItemTracking, Fullv2, WorkItemTrackingv2")] - public OptionsMode Options { get; set; } - } -} \ No newline at end of file diff --git a/src/MigrationTools.Host/CommandLine/OptionsMode.cs b/src/MigrationTools.Host/CommandLine/OptionsMode.cs deleted file mode 100644 index 5e2feb3e4..000000000 --- a/src/MigrationTools.Host/CommandLine/OptionsMode.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MigrationTools.Host.CommandLine -{ - public enum OptionsMode - { - Reference = 0, - WorkItemTracking = 1, - Fullv2 = 2, - WorkItemTrackingv2 = 3, - Basic = 4 - } -} \ No newline at end of file diff --git a/src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs b/src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs new file mode 100644 index 000000000..d1f15f040 --- /dev/null +++ b/src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Xml.Serialization; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Spectre.Console.Cli; +using YamlDotNet.Serialization; + +namespace MigrationTools.Host.Commands +{ + internal class BaseMigrationCommandSettings : CommandSettings + { + [Description("Pre configure paramiters using this config file. Run `Init` to create it.")] + [CommandOption("--config|--configFile")] + [DefaultValue("configuration.json")] + [JsonIgnore, YamlIgnore] + public string ConfigFile { get; set; } + } +} diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs b/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs new file mode 100644 index 000000000..81f95fc76 --- /dev/null +++ b/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using MigrationTools.Host.Commands; +using Spectre.Console.Cli; + +namespace MigrationTools.Host.Commands +{ + internal class MigrationExecuteCommand : AsyncCommand + { + private readonly IServiceProvider _services; + private readonly ILogger _logger; + private readonly IHostApplicationLifetime _appLifetime; + private readonly ITelemetryLogger Telemetery; + + public MigrationExecuteCommand(IServiceProvider services, + ILogger logger, + IHostApplicationLifetime appLifetime, ITelemetryLogger telemetryLogger) + { + Telemetery = telemetryLogger; + _services = services; + _logger = logger; + _appLifetime = appLifetime; + } + + public override async Task ExecuteAsync(CommandContext context, MigrationExecuteCommandSettings settings) + { + int _exitCode; + try + { + var migrationEngine = _services.GetRequiredService(); + migrationEngine.Run(); + _exitCode = 0; + } + catch (Exception ex) + { + Telemetery.TrackException(ex, null, null); + _logger.LogError(ex, "Unhandled exception!"); + _exitCode = 1; + } + finally + { + // Stop the application once the work is done + _appLifetime.StopApplication(); + } + return _exitCode; + } + } +} + diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs b/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs new file mode 100644 index 000000000..916504402 --- /dev/null +++ b/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs @@ -0,0 +1,37 @@ +using System.ComponentModel; +using Microsoft.VisualStudio.Services.Common.CommandLine; +using Spectre.Console.Cli; + +namespace MigrationTools.Host.Commands +{ + internal class MigrationExecuteCommandSettings : BaseMigrationCommandSettings + { + [Description("Domain used to connect to the source TFS instance.")] + [CommandOption("--sourceDomain")] + public string SourceDomain { get; set; } + + [Description("User Name used to connect to the source TFS instance.")] + [CommandOption("--sourceUserName")] + public string SourceUserName { get; set; } + + [Description("Password used to connect to source TFS instance.")] + [CommandOption("--sourcePassword")] + public string SourcePassword { get; set; } + + [Description("Domain used to connect to the target TFS instance.")] + [CommandOption("--targetDomain")] + public string TargetDomain { get; set; } + + [Description("User Name used to connect to the target TFS instance.")] + [CommandOption("--targetUserName")] + public string TargetUserName { get; set; } + + [Description("Password used to connect to target TFS instance.")] + [CommandOption("--targetPassword")] + public string TargetPassword { get; set; } + + [Description("Add this paramiter to turn Telemetry off")] + [CommandOption("--disableTelemetry")] + public bool DisableTelemetry { get; set; } + } +} \ No newline at end of file diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommand.cs b/src/MigrationTools.Host/Commands/MigrationInitCommand.cs new file mode 100644 index 000000000..084096c1b --- /dev/null +++ b/src/MigrationTools.Host/Commands/MigrationInitCommand.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using MigrationTools._EngineV1.Configuration; +using Spectre.Console.Cli; + +namespace MigrationTools.Host.Commands +{ + internal class MigrationInitCommand : AsyncCommand + { + private readonly IEngineConfigurationBuilder _configurationBuilder; + private readonly ISettingsWriter _settingWriter; + private readonly ILogger _logger; + private readonly ITelemetryLogger Telemetery; + private readonly IHostApplicationLifetime _appLifetime; + + public MigrationInitCommand( + IEngineConfigurationBuilder configurationBuilder, + ISettingsWriter settingsWriter, + ILogger logger, + ITelemetryLogger telemetryLogger, + IHostApplicationLifetime appLifetime) + { + _configurationBuilder = configurationBuilder; + _settingWriter = settingsWriter; + _logger = logger; + Telemetery = telemetryLogger; + _appLifetime = appLifetime; + } + + + public override Task ExecuteAsync(CommandContext context, MigrationInitCommandSettings settings) + { + int _exitCode; + try + { + Telemetery.TrackEvent(new EventTelemetry("InitCommand")); + string configFile = settings.ConfigFile; + if (string.IsNullOrEmpty(configFile)) + { + configFile = "configuration.json"; + } + _logger.LogInformation("ConfigFile: {configFile}", configFile); + if (File.Exists(configFile)) + { + _logger.LogInformation("Deleting old configuration.json reference file"); + File.Delete(configFile); + } + if (!File.Exists(configFile)) + { + _logger.LogInformation("Populating config with {Options}", settings.Options.ToString()); + EngineConfiguration config; + switch (settings.Options) + { + case OptionsMode.Reference: + config = _configurationBuilder.BuildReference(); + break; + case OptionsMode.Basic: + config = _configurationBuilder.BuildGettingStarted(); + break; + + case OptionsMode.WorkItemTracking: + config = _configurationBuilder.BuildWorkItemMigration(); + break; + + case OptionsMode.Fullv2: + config = _configurationBuilder.BuildDefault2(); + break; + + case OptionsMode.WorkItemTrackingv2: + config = _configurationBuilder.BuildWorkItemMigration2(); + break; + + default: + config = _configurationBuilder.BuildGettingStarted(); + break; + } + _settingWriter.WriteSettings(config, configFile); + _logger.LogInformation($"New {configFile} file has been created"); + } + _exitCode = 0; + } + catch (Exception ex) + { + Telemetery.TrackException(ex, null, null); + _logger.LogError(ex, "Unhandled exception!"); + _exitCode = 1; + } + finally + { + // Stop the application once the work is done + _appLifetime.StopApplication(); + } + return _exitCode; + } + } +} diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs b/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs new file mode 100644 index 000000000..2d7b77d46 --- /dev/null +++ b/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; +using Spectre.Console.Cli; + +namespace MigrationTools.Host.Commands +{ + internal class MigrationInitCommandSettings : BaseMigrationCommandSettings + { + [Description("What type of config do you want to output? WorkItemTracking is the default.")] + [CommandOption("--outputMode|--options")] + [DefaultValue(OptionsMode.WorkItemTracking)] + public OptionsMode Options { get; set; } + } + + public enum OptionsMode + { + Reference = 0, + WorkItemTracking = 1, + Fullv2 = 2, + WorkItemTrackingv2 = 3, + Basic = 4 + } +} \ No newline at end of file diff --git a/src/MigrationTools.Host/ExecuteHostedService.cs b/src/MigrationTools.Host/ExecuteHostedService.cs deleted file mode 100644 index ef7e59137..000000000 --- a/src/MigrationTools.Host/ExecuteHostedService.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.ApplicationInsights.Channel; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace MigrationTools.Host -{ - public class ExecuteHostedService : IHostedService - { - private readonly IServiceProvider _services; - private readonly ILogger _logger; - private readonly IHostApplicationLifetime _appLifetime; - private readonly ITelemetryLogger Telemetery; - - private int? _exitCode; - - public ExecuteHostedService( - IServiceProvider services, - ILogger logger, - IHostApplicationLifetime appLifetime, ITelemetryLogger telemetryLogger) - { - Telemetery = telemetryLogger; - _services = services; - _logger = logger; - _appLifetime = appLifetime; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - _appLifetime.ApplicationStarted.Register(() => - { - Task.Run(() => - { - try - { - var migrationEngine = _services.GetRequiredService(); - migrationEngine.Run(); - _exitCode = 0; - } - catch (Exception ex) - { - Telemetery.TrackException(ex, null, null); - _logger.LogError(ex, "Unhandled exception!"); - _exitCode = 1; - } - finally - { - // Stop the application once the work is done - _appLifetime.StopApplication(); - } - }); - }); - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - _logger.LogDebug($"Exiting with return code: {_exitCode}"); - - if (_exitCode.HasValue) - { - Environment.ExitCode = _exitCode.Value; - } - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/MigrationTools.Host/InitHostedService.cs b/src/MigrationTools.Host/InitHostedService.cs deleted file mode 100644 index 0140ff544..000000000 --- a/src/MigrationTools.Host/InitHostedService.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.ApplicationInsights.DataContracts; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using MigrationTools._EngineV1.Configuration; -using MigrationTools.Host.CommandLine; - -namespace MigrationTools.Host -{ - public class InitHostedService : IHostedService - { - private readonly IEngineConfigurationBuilder _configurationBuilder; - private readonly ISettingsWriter _settingWriter; - private readonly InitOptions _initOptions; - private readonly ILogger _logger; - private readonly ITelemetryLogger _telemetryLogger; - private readonly IHostApplicationLifetime _appLifetime; - private int? _exitCode; - - public InitHostedService( - IEngineConfigurationBuilder configurationBuilder, - ISettingsWriter settingsWriter, - IOptions initOptions, - ILogger logger, - ITelemetryLogger telemetryLogger, - IHostApplicationLifetime appLifetime) - { - _configurationBuilder = configurationBuilder; - _settingWriter = settingsWriter; - _initOptions = initOptions.Value; - _logger = logger; - _telemetryLogger = telemetryLogger; - _appLifetime = appLifetime; - } - - public Task StartAsync(CancellationToken cancellationToken) - { - _appLifetime.ApplicationStarted.Register(() => - { - Task.Run(() => - { - try - { - _telemetryLogger.TrackEvent(new EventTelemetry("InitCommand")); - string configFile = _initOptions.ConfigFile; - if (string.IsNullOrEmpty(configFile)) - { - configFile = "configuration.json"; - } - _logger.LogInformation("ConfigFile: {configFile}", configFile); - if (File.Exists(configFile)) - { - _logger.LogInformation("Deleting old configuration.json reference file"); - File.Delete(configFile); - } - if (!File.Exists(configFile)) - { - _logger.LogInformation("Populating config with {Options}", _initOptions.Options.ToString()); - EngineConfiguration config; - switch (_initOptions.Options) - { - case OptionsMode.Reference: - config = _configurationBuilder.BuildReference(); - break; - case OptionsMode.Basic: - config = _configurationBuilder.BuildGettingStarted(); - break; - - case OptionsMode.WorkItemTracking: - config = _configurationBuilder.BuildWorkItemMigration(); - break; - - case OptionsMode.Fullv2: - config = _configurationBuilder.BuildDefault2(); - break; - - case OptionsMode.WorkItemTrackingv2: - config = _configurationBuilder.BuildWorkItemMigration2(); - break; - - default: - config = _configurationBuilder.BuildGettingStarted(); - break; - } - _settingWriter.WriteSettings(config, configFile); - _logger.LogInformation($"New {configFile} file has been created"); - } - _exitCode = 0; - } - catch (Exception ex) - { - _telemetryLogger.TrackException(ex, null, null); - _logger.LogError(ex, "Unhandled exception!"); - _exitCode = 1; - } - finally - { - // Stop the application once the work is done - _appLifetime.StopApplication(); - } - }); - }); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - _logger.LogDebug($"Exiting with return code: {_exitCode}"); - if (_exitCode.HasValue) - { - Environment.ExitCode = _exitCode.Value; - } - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/MigrationTools.Host/MigrationService.cs b/src/MigrationTools.Host/MigrationService.cs new file mode 100644 index 000000000..d12b97bcb --- /dev/null +++ b/src/MigrationTools.Host/MigrationService.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Serilog.Core; +using Spectre.Console.Cli; + +namespace MigrationTools.Host +{ + internal class MigrationService : BackgroundService + { + private ICommandApp AppCommand { get; } + private IHostApplicationLifetime AppLifetime { get; } + private ILogger Logger { get; } + + public MigrationService(ICommandApp appCommand, IHostApplicationLifetime appLifetime, ILogger logger) + { + AppCommand = appCommand; + AppLifetime = appLifetime; + Logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + await AppCommand.RunAsync(Environment.GetCommandLineArgs()); + AppLifetime.StopApplication(); + } + } +} diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index acbc9869f..5d31e84bc 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -2,7 +2,6 @@ using System.IO; using System.Reflection; using System.Threading.Tasks; -using CommandLine; using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.WorkerService; @@ -12,7 +11,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MigrationTools._EngineV1.Configuration; -using MigrationTools.Host.CommandLine; using MigrationTools.Host.CustomDiagnostics; using MigrationTools.Host.Services; using MigrationTools.Options; diff --git a/src/MigrationTools.Host/MigrationTools.Host.csproj b/src/MigrationTools.Host/MigrationTools.Host.csproj index 3174b6c22..4b84da626 100644 --- a/src/MigrationTools.Host/MigrationTools.Host.csproj +++ b/src/MigrationTools.Host/MigrationTools.Host.csproj @@ -13,7 +13,6 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -32,7 +31,9 @@ + + From e02601edbf7ff757b0ef053c86c5be28f65313a3 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Tue, 23 Jul 2024 18:30:36 +0100 Subject: [PATCH 03/10] feat(launchSettings.json): add empty commandName to support new project commands refactor(MigrationExecuteCommand.cs, MigrationInitCommand.cs): change logger type to improve logging context refactor(MigrationInitCommand.cs): change ExecuteAsync method to async to improve readability and performance refactor(MigrationService.cs): skip first command line argument to avoid application name in arguments refactor(MigrationToolHost.cs): refactor host configuration and services setup to improve code readability and maintainability style(HostExtensions.cs): remove unused import to improve code cleanliness style(MigrationToolHost.cs): remove commented out code to improve code cleanliness feat(MigrationTools.Host.csproj): add Spectre.Console.Cli.Extensions.DependencyInjection package to support dependency injection --- .../Properties/launchSettings.json | 3 + .../Commands/MigrationExecuteCommand.cs | 2 +- .../Commands/MigrationInitCommand.cs | 4 +- src/MigrationTools.Host/HostExtensions.cs | 1 - src/MigrationTools.Host/MigrationService.cs | 3 +- src/MigrationTools.Host/MigrationToolHost.cs | 201 ++++++++---------- .../MigrationTools.Host.csproj | 1 + 7 files changed, 92 insertions(+), 123 deletions(-) diff --git a/src/MigrationTools.ConsoleCore/Properties/launchSettings.json b/src/MigrationTools.ConsoleCore/Properties/launchSettings.json index 0ad86d657..3c30516d4 100644 --- a/src/MigrationTools.ConsoleCore/Properties/launchSettings.json +++ b/src/MigrationTools.ConsoleCore/Properties/launchSettings.json @@ -3,6 +3,9 @@ "MigrationTools.ConsoleUI": { "commandName": "Project", "commandLineArgs": "execute --config \"configuration.json\"" + }, + "empty": { + "commandName": "Project" } } } \ No newline at end of file diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs b/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs index 81f95fc76..49e4664af 100644 --- a/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs +++ b/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs @@ -18,7 +18,7 @@ internal class MigrationExecuteCommand : AsyncCommand logger, + ILogger logger, IHostApplicationLifetime appLifetime, ITelemetryLogger telemetryLogger) { Telemetery = telemetryLogger; diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommand.cs b/src/MigrationTools.Host/Commands/MigrationInitCommand.cs index 084096c1b..1ce50c035 100644 --- a/src/MigrationTools.Host/Commands/MigrationInitCommand.cs +++ b/src/MigrationTools.Host/Commands/MigrationInitCommand.cs @@ -23,7 +23,7 @@ internal class MigrationInitCommand : AsyncCommand public MigrationInitCommand( IEngineConfigurationBuilder configurationBuilder, ISettingsWriter settingsWriter, - ILogger logger, + ILogger logger, ITelemetryLogger telemetryLogger, IHostApplicationLifetime appLifetime) { @@ -35,7 +35,7 @@ public MigrationInitCommand( } - public override Task ExecuteAsync(CommandContext context, MigrationInitCommandSettings settings) + public override async Task ExecuteAsync(CommandContext context, MigrationInitCommandSettings settings) { int _exitCode; try diff --git a/src/MigrationTools.Host/HostExtensions.cs b/src/MigrationTools.Host/HostExtensions.cs index ac26aace5..9e07b8294 100644 --- a/src/MigrationTools.Host/HostExtensions.cs +++ b/src/MigrationTools.Host/HostExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using MigrationTools.Host.CommandLine; namespace MigrationTools.Host { diff --git a/src/MigrationTools.Host/MigrationService.cs b/src/MigrationTools.Host/MigrationService.cs index d12b97bcb..d4b2f69ff 100644 --- a/src/MigrationTools.Host/MigrationService.cs +++ b/src/MigrationTools.Host/MigrationService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -25,7 +26,7 @@ public MigrationService(ICommandApp appCommand, IHostApplicationLifetime appLife protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - await AppCommand.RunAsync(Environment.GetCommandLineArgs()); + await AppCommand.RunAsync(Environment.GetCommandLineArgs().Skip(1)); AppLifetime.StopApplication(); } } diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index 5d31e84bc..ce5033e5f 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -18,6 +18,8 @@ using Serilog.Core; using Serilog.Events; using Serilog.Sinks.SystemConsole.Themes; +using Spectre.Console.Cli.Extensions.DependencyInjection; +using Spectre.Console.Cli; namespace MigrationTools.Host { @@ -25,75 +27,65 @@ public static class MigrationToolHost { public static IHostBuilder CreateDefaultBuilder(string[] args) { - (var initOptions, var executeOptions) = ParseOptions(args); + var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args); - if (initOptions is null && executeOptions is null) + hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => { - return null; - } - - - - var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) - .UseSerilog((hostingContext, services, loggerConfiguration) => + string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetVersionTextForLog() + "] {Message:lj}{NewLine}{Exception}"; + string logsPath = CreateLogsPath(); + var logPath = Path.Combine(logsPath, "migration.log"); + var logLevel = hostingContext.Configuration.GetValue("LogLevel"); + var levelSwitch = new LoggingLevelSwitch(logLevel); + loggerConfiguration + .MinimumLevel.ControlledBy(levelSwitch) + .ReadFrom.Configuration(hostingContext.Configuration) + .Enrich.FromLogContext() + .Enrich.WithMachineName() + .Enrich.WithProcessId() + .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug, theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate) + .WriteTo.ApplicationInsights(services.GetService(), new CustomConverter(), LogEventLevel.Error) + .WriteTo.File(logPath, LogEventLevel.Verbose, outputTemplate: outputTemplate); + }); + + hostBuilder.ConfigureLogging((context, logBuilder) => { - string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetVersionTextForLog() + "] {Message:lj}{NewLine}{Exception}"; - string logsPath = CreateLogsPath(); - var logPath = Path.Combine(logsPath, "migration.log"); - var logLevel = hostingContext.Configuration.GetValue("LogLevel"); - var levelSwitch = new LoggingLevelSwitch(logLevel); - loggerConfiguration - .MinimumLevel.ControlledBy(levelSwitch) - .ReadFrom.Configuration(hostingContext.Configuration) - .Enrich.FromLogContext() - .Enrich.WithMachineName() - .Enrich.WithProcessId() - .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug, theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate) - .WriteTo.ApplicationInsights(services.GetService(), new CustomConverter(), LogEventLevel.Error) - .WriteTo.File(logPath, LogEventLevel.Verbose, outputTemplate: outputTemplate); - }) - .ConfigureLogging((context, logBuilder) => - { - }) - .ConfigureAppConfiguration(builder => - { - if (executeOptions is not null) - { - builder.AddJsonFile(executeOptions.ConfigFile); - } - }) - .ConfigureServices((context, services) => + }); + //.ConfigureAppConfiguration(builder => + //{ + // if (executeOptions is not null) + // { + // builder.AddJsonFile(executeOptions.ConfigFile); + // } + //}) + + hostBuilder.ConfigureServices((context, services) => { services.AddOptions(); services.Configure((config) => { - if(executeOptions is null) - { - return; - } - var sp = services.BuildServiceProvider(); var logger = sp.GetService().CreateLogger(); - if (!File.Exists(executeOptions.ConfigFile)) - { - logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", executeOptions.ConfigFile, Assembly.GetEntryAssembly().GetName().Name); - throw new ArgumentException("missing configfile"); - } - logger.LogInformation("Config Found, creating engine host"); - var reader = sp.GetRequiredService(); - var parsed = reader.BuildFromFile(executeOptions.ConfigFile); - config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; - config.FieldMaps = parsed.FieldMaps; - config.GitRepoMapping = parsed.GitRepoMapping; - config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; - config.Processors = parsed.Processors; - config.Source = parsed.Source; - config.Target = parsed.Target; - config.Version = parsed.Version; - config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; - config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; + //if (!File.Exists(executeOptions.ConfigFile)) + //{ + // logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", executeOptions.ConfigFile, Assembly.GetEntryAssembly().GetName().Name); + // throw new ArgumentException("missing configfile"); + //} + //logger.LogInformation("Config Found, creating engine host"); + //var reader = sp.GetRequiredService(); + //var parsed = reader.BuildFromFile(executeOptions.ConfigFile); + //config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; + //config.FieldMaps = parsed.FieldMaps; + //config.GitRepoMapping = parsed.GitRepoMapping; + //config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; + //config.Processors = parsed.Processors; + //config.Source = parsed.Source; + //config.Target = parsed.Target; + //config.Version = parsed.Version; + //config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; + //config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; }); + // Application Insights ApplicationInsightsServiceOptions aiso = new ApplicationInsightsServiceOptions(); aiso.ApplicationVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); @@ -102,7 +94,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) //aiso.DeveloperMode = true; //#endif services.AddApplicationInsightsTelemetryWorkerService(aiso); - + // Services services.AddTransient(); //services.AddTransient(); @@ -120,36 +112,30 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) // Host Services services.AddTransient(); - if (initOptions is not null) - { - services.Configure((opts) => - { - opts.ConfigFile = initOptions.ConfigFile; - opts.Options = initOptions.Options; - }); - services.AddHostedService(); - } - if (executeOptions is not null) - { - services.Configure(cred => - { - cred.Source = new Credentials - { - Domain = executeOptions.SourceDomain, - UserName = executeOptions.SourceUserName, - Password = executeOptions.SourcePassword - }; - cred.Target = new Credentials - { - Domain = executeOptions.TargetDomain, - UserName = executeOptions.TargetUserName, - Password = executeOptions.TargetPassword - }; - }); - services.AddHostedService(); - } - }) - .UseConsoleLifetime(); + + }); + + hostBuilder.ConfigureServices((context, services) => + { + using var registrar = new DependencyInjectionRegistrar(services); + var app = new CommandApp(registrar); + app.Configure(config => + { + config.PropagateExceptions(); + config.AddCommand("execute"); + config.AddCommand("init"); + + }); + services.AddSingleton(app); + }); + + hostBuilder.ConfigureServices((context, services) => + { + services.AddHostedService(); + }); + + hostBuilder.UseConsoleLifetime(); + return hostBuilder; @@ -173,19 +159,14 @@ public static async Task RunMigrationTools(this IHostBuilder hostBuilder, string // Disanle telemitery from options - (var initOptions, var executeOptions) = ParseOptions(args); - if (initOptions is null && executeOptions is null) - { - return; - } - bool DisableTelemetry = false; - Serilog.ILogger logger = host.Services.GetService(); - if (executeOptions is not null && bool.TryParse(executeOptions.DisableTelemetry, out DisableTelemetry)) - { - TelemetryConfiguration ai = host.Services.GetService(); - ai.DisableTelemetry = DisableTelemetry; - } - logger.Information("Telemetry: {status}", !DisableTelemetry); + //bool DisableTelemetry = false; + //Serilog.ILogger logger = host.Services.GetService(); + //if (executeOptions is not null && bool.TryParse(executeOptions.DisableTelemetry, out DisableTelemetry)) + //{ + // TelemetryConfiguration ai = host.Services.GetService(); + // ai.DisableTelemetry = DisableTelemetry; + //} + //logger.Information("Telemetry: {status}", !DisableTelemetry); await host.RunAsync(); } @@ -202,21 +183,5 @@ private static string CreateLogsPath() return exportPath; } - - private static (InitOptions init, ExecuteOptions execute) ParseOptions(string[] args) - { - InitOptions initOptions = null; - ExecuteOptions executeOptions = null; - Parser.Default.ParseArguments(args) - .WithParsed(opts => - { - initOptions = opts; - }) - .WithParsed(opts => - { - executeOptions = opts; - }); - return (initOptions, executeOptions); - } } } \ No newline at end of file diff --git a/src/MigrationTools.Host/MigrationTools.Host.csproj b/src/MigrationTools.Host/MigrationTools.Host.csproj index 4b84da626..97a7c8baa 100644 --- a/src/MigrationTools.Host/MigrationTools.Host.csproj +++ b/src/MigrationTools.Host/MigrationTools.Host.csproj @@ -32,6 +32,7 @@ + From cf63831fff31e1fbe6bff88c6dc667b8b1d8da46 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Tue, 23 Jul 2024 18:38:53 +0100 Subject: [PATCH 04/10] feat(CommandSettingsBase.cs): add new base class for command settings to reduce code duplication refactor(MigrationExecuteCommandSettings.cs, MigrationInitCommandSettings.cs): change base class to CommandSettingsBase to utilize common settings fix(MigrationExecuteCommandSettings.cs): remove DisableTelemetry property as it's now in CommandSettingsBase --- ...ationCommandSettings.cs => CommandSettingsBase.cs} | 11 ++++++++++- .../Commands/MigrationExecuteCommandSettings.cs | 6 +----- .../Commands/MigrationInitCommandSettings.cs | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) rename src/MigrationTools.Host/Commands/{BaseMigrationCommandSettings.cs => CommandSettingsBase.cs} (61%) diff --git a/src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs b/src/MigrationTools.Host/Commands/CommandSettingsBase.cs similarity index 61% rename from src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs rename to src/MigrationTools.Host/Commands/CommandSettingsBase.cs index d1f15f040..397d47f5d 100644 --- a/src/MigrationTools.Host/Commands/BaseMigrationCommandSettings.cs +++ b/src/MigrationTools.Host/Commands/CommandSettingsBase.cs @@ -11,12 +11,21 @@ namespace MigrationTools.Host.Commands { - internal class BaseMigrationCommandSettings : CommandSettings + internal class CommandSettingsBase : CommandSettings { [Description("Pre configure paramiters using this config file. Run `Init` to create it.")] [CommandOption("--config|--configFile")] [DefaultValue("configuration.json")] [JsonIgnore, YamlIgnore] public string ConfigFile { get; set; } + + [Description("Add this paramiter to turn Telemetry off")] + [CommandOption("--disableTelemetry")] + public bool DisableTelemetry { get; set; } + + [Description("Add this paramiter to turn version check off")] + [CommandOption("--skipVersionCheck")] + public bool skipVersionCheck { get; set; } + } } diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs b/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs index 916504402..9a21d7b43 100644 --- a/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs +++ b/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs @@ -4,7 +4,7 @@ namespace MigrationTools.Host.Commands { - internal class MigrationExecuteCommandSettings : BaseMigrationCommandSettings + internal class MigrationExecuteCommandSettings : CommandSettingsBase { [Description("Domain used to connect to the source TFS instance.")] [CommandOption("--sourceDomain")] @@ -29,9 +29,5 @@ internal class MigrationExecuteCommandSettings : BaseMigrationCommandSettings [Description("Password used to connect to target TFS instance.")] [CommandOption("--targetPassword")] public string TargetPassword { get; set; } - - [Description("Add this paramiter to turn Telemetry off")] - [CommandOption("--disableTelemetry")] - public bool DisableTelemetry { get; set; } } } \ No newline at end of file diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs b/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs index 2d7b77d46..62fc4552d 100644 --- a/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs +++ b/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs @@ -3,7 +3,7 @@ namespace MigrationTools.Host.Commands { - internal class MigrationInitCommandSettings : BaseMigrationCommandSettings + internal class MigrationInitCommandSettings : CommandSettingsBase { [Description("What type of config do you want to output? WorkItemTracking is the default.")] [CommandOption("--outputMode|--options")] From ae9c366cf5cb5feff01ab6b0b719de6ec55560b6 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Wed, 24 Jul 2024 11:28:51 +0100 Subject: [PATCH 05/10] =?UTF-8?q?Simplifying=20hosted=20stuff=20=E2=9C=A8?= =?UTF-8?q?=20(MigrationTools.Host):=20add=20base=20command=20and=20execut?= =?UTF-8?q?e=20migration=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce `CommandBase` class to handle common command logic, including startup logic, telemetry, and version checks. Add `ExecuteMigrationCommand` to handle the execution of migration tasks, utilizing the `CommandBase` class for shared functionality. Also, add `ExecuteMigrationCommandSettings` to define the settings required for the migration command. These changes are made to modularize the command logic, making it easier to manage and extend. The `CommandBase` class centralizes common tasks like telemetry and version checks, reducing code duplication. The `ExecuteMigrationCommand` class focuses on the specific logic needed to execute a migration, improving code readability and maintainability. ✨ (InitMigrationCommand): add InitMigrationCommand to initialize migration configurations ✨ (InitMigrationCommandSettings): add settings for InitMigrationCommand 🔧 (MigrationToolHost): update command registration for InitMigrationCommand The InitMigrationCommand is introduced to allow users to initialize migration configurations with various options. This command supports different configuration modes such as Reference, Basic, WorkItemTracking, Fullv2, and WorkItemTrackingv2, making it flexible for different migration scenarios. The InitMigrationCommandSettings class is added to handle the settings for the InitMigrationCommand, including the output mode which determines the type of configuration to be generated. The MigrationToolHost is updated to register the new InitMigrationCommand, ensuring it is available for use within the application. This enhances the tool's functionality by providing a straightforward way to set up migration configurations. ♻️ (StartupService.cs): remove version check and telemetry logging for simplification Remove the extensive version check and telemetry logging to simplify the startup process. This reduces the complexity and potential overhead during application startup, making the codebase easier to maintain and understand. The removed code includes checks for package manager installation, version updates, and telemetry notes, which are deemed unnecessary for the current scope of the application. --- .../Commands/CommandBase.cs | 176 ++++++++++++++++++ ...eCommand.cs => ExecuteMigrationCommand.cs} | 11 +- ....cs => ExecuteMigrationCommandSettings.cs} | 2 +- ...InitCommand.cs => InitMigrationCommand.cs} | 8 +- ...ngs.cs => InitMigrationCommandSettings.cs} | 2 +- src/MigrationTools.Host/MigrationToolHost.cs | 4 +- src/MigrationTools.Host/StartupService.cs | 135 +------------- 7 files changed, 192 insertions(+), 146 deletions(-) create mode 100644 src/MigrationTools.Host/Commands/CommandBase.cs rename src/MigrationTools.Host/Commands/{MigrationExecuteCommand.cs => ExecuteMigrationCommand.cs} (71%) rename src/MigrationTools.Host/Commands/{MigrationExecuteCommandSettings.cs => ExecuteMigrationCommandSettings.cs} (94%) rename src/MigrationTools.Host/Commands/{MigrationInitCommand.cs => InitMigrationCommand.cs} (94%) rename src/MigrationTools.Host/Commands/{MigrationInitCommandSettings.cs => InitMigrationCommandSettings.cs} (89%) diff --git a/src/MigrationTools.Host/Commands/CommandBase.cs b/src/MigrationTools.Host/Commands/CommandBase.cs new file mode 100644 index 000000000..29dfc42e3 --- /dev/null +++ b/src/MigrationTools.Host/Commands/CommandBase.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using MigrationTools.Host.Services; +using Serilog; +using Spectre.Console; +using Spectre.Console.Cli; + +namespace MigrationTools.Host.Commands +{ + internal abstract class CommandBase : AsyncCommand where TSettings : CommandSettingsBase + { + private readonly IHostApplicationLifetime _LifeTime; + private readonly IDetectOnlineService _detectOnlineService; + private readonly IDetectVersionService2 _detectVersionService; + private readonly ILogger> _logger; + private readonly ITelemetryLogger _telemetryLogger; + private static Stopwatch _mainTimer = new Stopwatch(); + + public CommandBase(IHostApplicationLifetime appLifetime, IDetectOnlineService detectOnlineService, IDetectVersionService2 detectVersionService, ILogger> logger, ITelemetryLogger telemetryLogger) + { + _LifeTime = appLifetime; + _detectOnlineService = detectOnlineService; + _detectVersionService = detectVersionService; + _logger = logger; + _telemetryLogger = telemetryLogger; + } + + public override async Task ExecuteAsync(CommandContext context, TSettings settings) + { + _mainTimer.Start(); + _logger.LogTrace("Starting {CommandName}", this.GetType().Name); + _telemetryLogger.TrackEvent(this.GetType().Name); + RunStartupLogic(settings); + try + { + return await ExecuteInternalAsync(context, settings); + } + catch (Exception ex) + { + _telemetryLogger.TrackException(ex, null, null); + _logger.LogError(ex, "Unhandled exception!"); + return 1; + } + finally + { + _LifeTime.StopApplication(); + _mainTimer.Stop(); + _logger.LogInformation("Command {CommandName} completed in {Elapsed}", this.GetType().Name, _mainTimer.Elapsed); + } + } + + internal virtual async Task ExecuteInternalAsync(CommandContext context, TSettings settings) + { + // no-op + return 0; + } + + public void RunStartupLogic(TSettings settings) + { + ApplicationStartup(settings); + if (!settings.skipVersionCheck && _detectOnlineService.IsOnline()) + { + _logger.LogTrace("Package Management Info:"); + Log.Debug(" IsPackageManagerInstalled: {IsPackageManagerInstalled}", _detectVersionService.IsPackageManagerInstalled); + Log.Debug(" IsPackageInstalled: {IsPackageInstalled}", _detectVersionService.IsPackageInstalled); + Log.Debug(" IsUpdateAvailable: {IsUpdateAvailable}", _detectVersionService.IsUpdateAvailable); + Log.Debug(" IsNewLocalVersionAvailable: {IsNewLocalVersionAvailable}", _detectVersionService.IsNewLocalVersionAvailable); + Log.Debug(" IsRunningInDebug: {IsRunningInDebug}", _detectVersionService.IsRunningInDebug); + Log.Verbose("Full version data: ${_detectVersionService}", _detectVersionService); + + Log.Information("Verion Info:"); + Log.Information(" Running: {RunningVersion}", _detectVersionService.RunningVersion); + Log.Information(" Installed: {InstalledVersion}", _detectVersionService.InstalledVersion); + Log.Information(" Available: {AvailableVersion}", _detectVersionService.AvailableVersion); + + if (_detectVersionService.RunningVersion.Major == 0) + { + Log.Information("Git Info:"); + Log.Information(" Repo: {GitRepositoryUrl}", ThisAssembly.Git.RepositoryUrl); + Log.Information(" Tag: {GitTag}", ThisAssembly.Git.Tag); + Log.Information(" Branch: {GitBranch}", ThisAssembly.Git.Branch); + Log.Information(" Commits: {GitCommits}", ThisAssembly.Git.Commits); + + } + + if (!_detectVersionService.IsPackageManagerInstalled) + { + Log.Warning("Windows Client: The Windows Package Manager is not installed, we use it to determine if you have the latest version, and to make sure that this application is up to date. You can download and install it from https://aka.ms/getwinget. After which you can call `winget install {PackageId}` from the Windows Terminal to get a manged version of this program.", _detectVersionService.PackageId); + Log.Warning("Windows Server: If you are running on Windows Server you can use the experimental version of Winget, or you can still use Chocolatey to manage the install. Install chocolatey from https://chocolatey.org/install and then use `choco install vsts-sync-migrator` to install, and `choco upgrade vsts-sync-migrator` to upgrade to newer versions.", _detectVersionService.PackageId); + } + else + { + if (!_detectVersionService.IsRunningInDebug) + { + if (!_detectVersionService.IsPackageInstalled) + { + Log.Information("It looks like this application has been installed from a zip, would you like to use the managed version?"); + Console.WriteLine("Do you want exit and install the managed version? (y/n)"); + if (Console.ReadKey().Key == ConsoleKey.Y) + { + Thread.Sleep(2000); + Environment.Exit(0); + } + } + if (_detectVersionService.IsUpdateAvailable && _detectVersionService.IsPackageInstalled) + { + Log.Information("It looks like an updated version is available from Winget, would you like to exit and update?"); + Console.WriteLine("Do you want to exit and update? (y/n)"); + if (Console.ReadKey().Key == ConsoleKey.Y) + { + Thread.Sleep(2000); + Environment.Exit(0); + } + } + } + else + { + Log.Information("Running in Debug! No further version checkes....."); + } + } + } + else + { + /// not online or you have specified not to + Log.Warning("You are either not online or have chosen `skipVersionCheck`. We will not check for a newer version of the tools.", _detectVersionService.PackageId); + } + } + + + private void ApplicationStartup( TSettings settings) + { + _mainTimer.Start(); + AsciiLogo(DetectVersionService2.GetRunningVersion().versionString); + TelemetryNote(); + _logger.LogInformation("Start Time: {StartTime}", DateTime.Now.ToUniversalTime().ToLocalTime()); + _logger.LogInformation("Running with settings: {@settings}", settings); + _logger.LogInformation("OSVersion: {OSVersion}", Environment.OSVersion.ToString()); + _logger.LogInformation("Version (Assembly): {Version}", DetectVersionService2.GetRunningVersion().versionString); + } + + private void TelemetryNote() + { + _logger.LogInformation("Telemetry Note:"); + _logger.LogInformation(" We use Application Insights to collect usage and error information in order to improve the quality of the tools."); + _logger.LogInformation(" Currently we collect the following anonymous data:"); + _logger.LogInformation(" -Event data: application version, client city/country, hosting type, item count, error count, warning count, elapsed time."); + _logger.LogInformation(" -Exceptions: application errors and warnings."); + _logger.LogInformation(" -Dependencies: REST/ObjectModel calls to Azure DevOps to help us understand performance issues."); + _logger.LogInformation(" This data is tied to a session ID that is generated on each run of the application and shown in the logs. This can help with debugging. If you want to disable telemetry you can run the tool with '--disableTelemetry' on the command prompt."); + _logger.LogInformation(" Note: Exception data cannot be 100% guaranteed to not leak production data"); + _logger.LogInformation("--------------------------------------"); + } + + private void AsciiLogo(string thisVersion) + { + AnsiConsole.Write(new FigletText("Azure DevOps").LeftJustified().Color(Color.Purple)); + AnsiConsole.Write(new FigletText("Migration Tools").LeftJustified().Color(Color.Purple)); + var productName = ((AssemblyProductAttribute)Assembly.GetEntryAssembly() + .GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product; + _logger.LogInformation("{productName} ", productName); + _logger.LogInformation("{thisVersion}", thisVersion); + var companyName = ((AssemblyCompanyAttribute)Assembly.GetEntryAssembly() + .GetCustomAttributes(typeof(AssemblyCompanyAttribute), true)[0]).Company; + _logger.LogInformation("{companyName} ", companyName); + _logger.LogInformation("==============================================================================="); + } + } +} diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs b/src/MigrationTools.Host/Commands/ExecuteMigrationCommand.cs similarity index 71% rename from src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs rename to src/MigrationTools.Host/Commands/ExecuteMigrationCommand.cs index 49e4664af..2ef1afa75 100644 --- a/src/MigrationTools.Host/Commands/MigrationExecuteCommand.cs +++ b/src/MigrationTools.Host/Commands/ExecuteMigrationCommand.cs @@ -6,20 +6,21 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MigrationTools.Host.Commands; +using MigrationTools.Host.Services; using Spectre.Console.Cli; namespace MigrationTools.Host.Commands { - internal class MigrationExecuteCommand : AsyncCommand + internal class ExecuteMigrationCommand : CommandBase { private readonly IServiceProvider _services; private readonly ILogger _logger; private readonly IHostApplicationLifetime _appLifetime; private readonly ITelemetryLogger Telemetery; - public MigrationExecuteCommand(IServiceProvider services, - ILogger logger, - IHostApplicationLifetime appLifetime, ITelemetryLogger telemetryLogger) + public ExecuteMigrationCommand(IServiceProvider services, + ILogger logger, + IHostApplicationLifetime appLifetime, ITelemetryLogger telemetryLogger, IDetectOnlineService detectOnlineService, IDetectVersionService2 detectVersionService) : base(appLifetime, detectOnlineService, detectVersionService, logger, telemetryLogger) { Telemetery = telemetryLogger; _services = services; @@ -27,7 +28,7 @@ public MigrationExecuteCommand(IServiceProvider services, _appLifetime = appLifetime; } - public override async Task ExecuteAsync(CommandContext context, MigrationExecuteCommandSettings settings) + internal override async Task ExecuteInternalAsync(CommandContext context, ExecuteMigrationCommandSettings settings) { int _exitCode; try diff --git a/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs b/src/MigrationTools.Host/Commands/ExecuteMigrationCommandSettings.cs similarity index 94% rename from src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs rename to src/MigrationTools.Host/Commands/ExecuteMigrationCommandSettings.cs index 9a21d7b43..54f275418 100644 --- a/src/MigrationTools.Host/Commands/MigrationExecuteCommandSettings.cs +++ b/src/MigrationTools.Host/Commands/ExecuteMigrationCommandSettings.cs @@ -4,7 +4,7 @@ namespace MigrationTools.Host.Commands { - internal class MigrationExecuteCommandSettings : CommandSettingsBase + internal class ExecuteMigrationCommandSettings : CommandSettingsBase { [Description("Domain used to connect to the source TFS instance.")] [CommandOption("--sourceDomain")] diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommand.cs b/src/MigrationTools.Host/Commands/InitMigrationCommand.cs similarity index 94% rename from src/MigrationTools.Host/Commands/MigrationInitCommand.cs rename to src/MigrationTools.Host/Commands/InitMigrationCommand.cs index 1ce50c035..4beb5730d 100644 --- a/src/MigrationTools.Host/Commands/MigrationInitCommand.cs +++ b/src/MigrationTools.Host/Commands/InitMigrationCommand.cs @@ -12,7 +12,7 @@ namespace MigrationTools.Host.Commands { - internal class MigrationInitCommand : AsyncCommand + internal class InitMigrationCommand : AsyncCommand { private readonly IEngineConfigurationBuilder _configurationBuilder; private readonly ISettingsWriter _settingWriter; @@ -20,10 +20,10 @@ internal class MigrationInitCommand : AsyncCommand private readonly ITelemetryLogger Telemetery; private readonly IHostApplicationLifetime _appLifetime; - public MigrationInitCommand( + public InitMigrationCommand( IEngineConfigurationBuilder configurationBuilder, ISettingsWriter settingsWriter, - ILogger logger, + ILogger logger, ITelemetryLogger telemetryLogger, IHostApplicationLifetime appLifetime) { @@ -35,7 +35,7 @@ public MigrationInitCommand( } - public override async Task ExecuteAsync(CommandContext context, MigrationInitCommandSettings settings) + public override async Task ExecuteAsync(CommandContext context, InitMigrationCommandSettings settings) { int _exitCode; try diff --git a/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs b/src/MigrationTools.Host/Commands/InitMigrationCommandSettings.cs similarity index 89% rename from src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs rename to src/MigrationTools.Host/Commands/InitMigrationCommandSettings.cs index 62fc4552d..19245b65a 100644 --- a/src/MigrationTools.Host/Commands/MigrationInitCommandSettings.cs +++ b/src/MigrationTools.Host/Commands/InitMigrationCommandSettings.cs @@ -3,7 +3,7 @@ namespace MigrationTools.Host.Commands { - internal class MigrationInitCommandSettings : CommandSettingsBase + internal class InitMigrationCommandSettings : CommandSettingsBase { [Description("What type of config do you want to output? WorkItemTracking is the default.")] [CommandOption("--outputMode|--options")] diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index ce5033e5f..1f402435f 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -122,8 +122,8 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) app.Configure(config => { config.PropagateExceptions(); - config.AddCommand("execute"); - config.AddCommand("init"); + config.AddCommand("execute"); + config.AddCommand("init"); }); services.AddSingleton(app); diff --git a/src/MigrationTools.Host/StartupService.cs b/src/MigrationTools.Host/StartupService.cs index 6ffeaa7e9..cad76110e 100644 --- a/src/MigrationTools.Host/StartupService.cs +++ b/src/MigrationTools.Host/StartupService.cs @@ -42,69 +42,6 @@ public void RunStartupLogic(string[] args) { ApplicationStartup(args); Configure(_LifeTime); - if (_detectOnlineService.IsOnline() && !args.Contains("skipVersionCheck")) - { - Log.Verbose("Package Management Info:"); - Log.Debug(" IsPackageManagerInstalled: {IsPackageManagerInstalled}", _detectVersionService.IsPackageManagerInstalled); - Log.Debug(" IsPackageInstalled: {IsPackageInstalled}", _detectVersionService.IsPackageInstalled); - Log.Debug(" IsUpdateAvailable: {IsUpdateAvailable}", _detectVersionService.IsUpdateAvailable); - Log.Debug(" IsNewLocalVersionAvailable: {IsNewLocalVersionAvailable}", _detectVersionService.IsNewLocalVersionAvailable); - Log.Debug(" IsRunningInDebug: {IsRunningInDebug}", _detectVersionService.IsRunningInDebug); - Log.Verbose("Full version data: ${_detectVersionService}", _detectVersionService); - - Log.Information("Verion Info:"); - Log.Information(" Running: {RunningVersion}", _detectVersionService.RunningVersion); - Log.Information(" Installed: {InstalledVersion}", _detectVersionService.InstalledVersion); - Log.Information(" Available: {AvailableVersion}", _detectVersionService.AvailableVersion); - - if (_detectVersionService.RunningVersion.Major == 0) - { - Log.Information("Git Info:"); - Log.Information(" Repo: {GitRepositoryUrl}", ThisAssembly.Git.RepositoryUrl); - Log.Information(" Tag: {GitTag}", ThisAssembly.Git.Tag); - Log.Information(" Branch: {GitBranch}", ThisAssembly.Git.Branch); - Log.Information(" Commits: {GitCommits}", ThisAssembly.Git.Commits); - - } - - if (!_detectVersionService.IsPackageManagerInstalled) - { - Log.Warning("Windows Client: The Windows Package Manager is not installed, we use it to determine if you have the latest version, and to make sure that this application is up to date. You can download and install it from https://aka.ms/getwinget. After which you can call `winget install {PackageId}` from the Windows Terminal to get a manged version of this program.", _detectVersionService.PackageId); - Log.Warning("Windows Server: If you are running on Windows Server you can use the experimental version of Winget, or you can still use Chocolatey to manage the install. Install chocolatey from https://chocolatey.org/install and then use `choco install vsts-sync-migrator` to install, and `choco upgrade vsts-sync-migrator` to upgrade to newer versions.", _detectVersionService.PackageId); - } else - { - if (!_detectVersionService.IsRunningInDebug) - { - if (!_detectVersionService.IsPackageInstalled) - { - Log.Information("It looks like this application has been installed from a zip, would you like to use the managed version?"); - Console.WriteLine("Do you want exit and install the managed version? (y/n)"); - if (Console.ReadKey().Key == ConsoleKey.Y) - { - Thread.Sleep(2000); - Environment.Exit(0); - } - } - if (_detectVersionService.IsUpdateAvailable && _detectVersionService.IsPackageInstalled) - { - Log.Information("It looks like an updated version is available from Winget, would you like to exit and update?"); - Console.WriteLine("Do you want to exit and update? (y/n)"); - if (Console.ReadKey().Key == ConsoleKey.Y) - { - Thread.Sleep(2000); - Environment.Exit(0); - } - } - } else - { - Log.Information("Running in Debug! No further version checkes....."); - } - } - } else - { - /// not online or you have specified not to - Log.Warning("You are either not online or have chosen `skipVersionCheck`. We will not check for a newer version of the tools.", _detectVersionService.PackageId); - } } public void Configure(IHostApplicationLifetime appLifetime) @@ -122,7 +59,7 @@ public void Configure(IHostApplicationLifetime appLifetime) public void RunExitLogic() { - _logger.LogInformation("Application Ending"); + _logger.LogTrace("Application Ending"); _mainTimer.Stop(); _telemetryLogger.TrackEvent("ApplicationEnd", null, new Dictionary { @@ -136,13 +73,7 @@ private void ApplicationStartup(string[] args) { _mainTimer.Start(); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - _logger.LogInformation("Application Starting"); - AsciiLogo(DetectVersionService2.GetRunningVersion().versionString); - TelemetryNote(); - _logger.LogInformation("Start Time: {StartTime}", DateTime.Now.ToUniversalTime().ToLocalTime()); - _logger.LogInformation("Running with args: {@Args}", args); - _logger.LogInformation("OSVersion: {OSVersion}", Environment.OSVersion.ToString()); - _logger.LogInformation("Version (Assembly): {Version}", DetectVersionService2.GetRunningVersion().versionString); + _logger.LogTrace("Application Starting"); } protected void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -152,67 +83,5 @@ protected void CurrentDomain_UnhandledException(object sender, UnhandledExceptio System.Threading.Thread.Sleep(5000); } - private void TelemetryNote() - { - _logger.LogInformation("Telemetry Note:"); - _logger.LogInformation(" We use Application Insights to collect usage and error information in order to improve the quality of the tools."); - _logger.LogInformation(" Currently we collect the following anonymous data:"); - _logger.LogInformation(" -Event data: application version, client city/country, hosting type, item count, error count, warning count, elapsed time."); - _logger.LogInformation(" -Exceptions: application errors and warnings."); - _logger.LogInformation(" -Dependencies: REST/ObjectModel calls to Azure DevOps to help us understand performance issues."); - _logger.LogInformation(" This data is tied to a session ID that is generated on each run of the application and shown in the logs. This can help with debugging. If you want to disable telemetry you can run the tool with '--disableTelemetry true' on the command prompt."); - _logger.LogInformation(" Note: Exception data cannot be 100% guaranteed to not leak production data"); - _logger.LogInformation("--------------------------------------"); - } - - private void AsciiLogo(string thisVersion) - { - _logger.LogInformation(" &@& "); - _logger.LogInformation(" @@(((((@ "); - _logger.LogInformation(" @(((((((((@ "); - _logger.LogInformation(" @(((((((((((((& "); - _logger.LogInformation(" ##((((((@ @((((((@@ "); - _logger.LogInformation(" @((((((@ @((((((& "); - _logger.LogInformation(" @(((((# @((((((@ "); - _logger.LogInformation(" &(((((& &(((((@ "); - _logger.LogInformation(" @(((((& &(((((@ "); - _logger.LogInformation(" &(((((@#&@((.((&@@@(#(((((@ "); - _logger.LogInformation(" #((((#..................#@((& "); - _logger.LogInformation(" &@(((((&......................(@ "); - _logger.LogInformation(" @.(&((((&...&& &@&..........&@ "); - _logger.LogInformation(" @...@(((((@ @#.......(( "); - _logger.LogInformation(" &.....@(((((@ @((@.......& "); - _logger.LogInformation(" @......@((((( #((((&.......& "); - _logger.LogInformation(" #.....( &((((( @@@ ((((((@@......@ "); - _logger.LogInformation(" &.....@ @(((&@@#(((((((((((((((((#@(((((& ......@ "); - _logger.LogInformation(" @.....@ &@&((((((((((((((((((((((((@(((((@# ......@ "); - _logger.LogInformation(" @.....&@(((((((((((((((&&@@@@@(((((@((((#(((#@(....& "); - _logger.LogInformation(" @.....&((((((((&@@& @(((((@(((((((@...# "); - _logger.LogInformation(" &....((((((@@(((((@ &@(((((@&((((((((#&& "); - _logger.LogInformation(" @(....&((@ @(((((@ @(((((@ @(((((((## "); - _logger.LogInformation(" @(#(....& &(((((@ @(((((& &@(((((((& "); - _logger.LogInformation(" &@(((&..... @((((((& @((((( &.(&((((((@ "); - _logger.LogInformation(" @(((((@.....& (((((@ &@(((((& @....@((((((@ "); - _logger.LogInformation(" @(((((#@.....( &(((((@& ##(((((& @.....@@((((((@ "); - _logger.LogInformation(" (&(((((@ &.....@& @((((((@ @((((((@ @...... @(((((@ "); - _logger.LogInformation(" &(((((@ @.....#& @#((((((@((((((# @......& @(((((@ "); - _logger.LogInformation(" @(((((@ &......& @(((((((@#((@ &@...... @(((((@ "); - _logger.LogInformation(" @(((((@ @......@& @@@(((((((&@& @......( #(((((@ "); - _logger.LogInformation(" #((((& &.......@ &@&(((((@#((((((((@@& &@.......@ ((((& "); - _logger.LogInformation("&(((((@@ @(....&@#((((((((((@ @(((((((#@........@ &@(((((@"); - _logger.LogInformation("&(((((((((((((((((((((((((((((((((&@@@@@@@@@&...........@(((((((((((((((((((((@"); - _logger.LogInformation("@(((((((((((((((((((((((((((((&@(....................@#((((((((((((((((((((((#@"); - _logger.LogInformation(" @((((((((((((((&@& &&...................@ @@#((((((((((((((#@@ "); - _logger.LogInformation(" "); - _logger.LogInformation("==============================================================================="); - var productName = ((AssemblyProductAttribute)Assembly.GetEntryAssembly() - .GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product; - _logger.LogInformation("{productName} ", productName); - _logger.LogInformation("{thisVersion}", thisVersion); - var companyName = ((AssemblyCompanyAttribute)Assembly.GetEntryAssembly() - .GetCustomAttributes(typeof(AssemblyCompanyAttribute), true)[0]).Company; - _logger.LogInformation("{companyName} ", companyName); - _logger.LogInformation("==============================================================================="); - } } } \ No newline at end of file From 3d40c8825050d68106d6d7efe6f343f588ec2d0b Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Wed, 24 Jul 2024 15:06:43 +0100 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=94=A7=20(launchSettings.json):=20u?= =?UTF-8?q?pdate=20launch=20profiles=20for=20better=20clarity=20and=20orga?= =?UTF-8?q?nization=20=E2=99=BB=EF=B8=8F=20(MigrationToolHost.cs):=20refac?= =?UTF-8?q?tor=20logging=20configuration=20for=20improved=20log=20manageme?= =?UTF-8?q?nt=20and=20filtering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The launch profiles in `launchSettings.json` are updated to rename and reorganize the profiles for better clarity. The "MigrationTools.ConsoleUI" profile is renamed to "execute" to better reflect its purpose. In `MigrationToolHost.cs`, the logging configuration is refactored to: - Introduce a static variable `logs` to manage log file naming. - Add filtering to exclude logs from specific sources. - Update the Application Insights connection string to include additional endpoints. - Use a static `logDate` variable to ensure consistent log directory naming. These changes improve log management, make the configuration more maintainable, and enhance the clarity of the launch profiles. --- .../Properties/launchSettings.json | 8 +-- src/MigrationTools.Host/MigrationToolHost.cs | 72 +++++++++++-------- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/MigrationTools.ConsoleCore/Properties/launchSettings.json b/src/MigrationTools.ConsoleCore/Properties/launchSettings.json index 3c30516d4..cb8b11e02 100644 --- a/src/MigrationTools.ConsoleCore/Properties/launchSettings.json +++ b/src/MigrationTools.ConsoleCore/Properties/launchSettings.json @@ -1,11 +1,11 @@ { "profiles": { - "MigrationTools.ConsoleUI": { - "commandName": "Project", - "commandLineArgs": "execute --config \"configuration.json\"" - }, "empty": { "commandName": "Project" + }, + "execute ": { + "commandName": "Project", + "commandLineArgs": "execute --config \"configuration.json\"" } } } \ No newline at end of file diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index 1f402435f..71a3be507 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -20,20 +20,24 @@ using Serilog.Sinks.SystemConsole.Themes; using Spectre.Console.Cli.Extensions.DependencyInjection; using Spectre.Console.Cli; +using Serilog.Filters; namespace MigrationTools.Host { public static class MigrationToolHost { + static int logs = 1; + public static IHostBuilder CreateDefaultBuilder(string[] args) { var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args); hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => { - string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetVersionTextForLog() + "] {Message:lj}{NewLine}{Exception}"; + string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetVersionTextForLog() + "] {Message:lj}{NewLine}{Exception}"; // {SourceContext} string logsPath = CreateLogsPath(); - var logPath = Path.Combine(logsPath, "migration.log"); + var logPath = Path.Combine(logsPath, $"migration{logs}.log"); + var logLevel = hostingContext.Configuration.GetValue("LogLevel"); var levelSwitch = new LoggingLevelSwitch(logLevel); loggerConfiguration @@ -42,9 +46,15 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) .Enrich.FromLogContext() .Enrich.WithMachineName() .Enrich.WithProcessId() - .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug, theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate) - .WriteTo.ApplicationInsights(services.GetService(), new CustomConverter(), LogEventLevel.Error) - .WriteTo.File(logPath, LogEventLevel.Verbose, outputTemplate: outputTemplate); + .WriteTo.File(logPath, LogEventLevel.Verbose, outputTemplate) + .WriteTo.Logger(lc => lc + .Filter.ByExcluding(Matching.FromSource("Microsoft")) + .Filter.ByExcluding(Matching.FromSource("MigrationTools.Host.StartupService")) + .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug, theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate)) + .WriteTo.Logger(lc => lc + .Filter.ByExcluding(Matching.FromSource("Microsoft")) + .WriteTo.ApplicationInsights(services.GetService(), new CustomConverter(), LogEventLevel.Error)); + logs++; }); hostBuilder.ConfigureLogging((context, logBuilder) => @@ -61,35 +71,35 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) hostBuilder.ConfigureServices((context, services) => { services.AddOptions(); - services.Configure((config) => - { - var sp = services.BuildServiceProvider(); - var logger = sp.GetService().CreateLogger(); - //if (!File.Exists(executeOptions.ConfigFile)) - //{ - // logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", executeOptions.ConfigFile, Assembly.GetEntryAssembly().GetName().Name); - // throw new ArgumentException("missing configfile"); - //} - //logger.LogInformation("Config Found, creating engine host"); - //var reader = sp.GetRequiredService(); - //var parsed = reader.BuildFromFile(executeOptions.ConfigFile); - //config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; - //config.FieldMaps = parsed.FieldMaps; - //config.GitRepoMapping = parsed.GitRepoMapping; - //config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; - //config.Processors = parsed.Processors; - //config.Source = parsed.Source; - //config.Target = parsed.Target; - //config.Version = parsed.Version; - //config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; - //config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; - }); + //services.Configure((config) => + //{ + // var sp = services.BuildServiceProvider(); + // var logger = sp.GetService().CreateLogger(); + // //if (!File.Exists(executeOptions.ConfigFile)) + // //{ + // // logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", executeOptions.ConfigFile, Assembly.GetEntryAssembly().GetName().Name); + // // throw new ArgumentException("missing configfile"); + // //} + // //logger.LogInformation("Config Found, creating engine host"); + // //var reader = sp.GetRequiredService(); + // //var parsed = reader.BuildFromFile(executeOptions.ConfigFile); + // //config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; + // //config.FieldMaps = parsed.FieldMaps; + // //config.GitRepoMapping = parsed.GitRepoMapping; + // //config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; + // //config.Processors = parsed.Processors; + // //config.Source = parsed.Source; + // //config.Target = parsed.Target; + // //config.Version = parsed.Version; + // //config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; + // //config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; + //}); // Application Insights ApplicationInsightsServiceOptions aiso = new ApplicationInsightsServiceOptions(); aiso.ApplicationVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); - aiso.ConnectionString = "InstrumentationKey=2d666f84-b3fb-4dcf-9aad-65de038d2772"; + aiso.ConnectionString = "InstrumentationKey=2d666f84-b3fb-4dcf-9aad-65de038d2772;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/;LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/;ApplicationId=9146fe72-5c18-48d7-a0f2-8fb891ef1277"; //# if DEBUG //aiso.DeveloperMode = true; //#endif @@ -171,11 +181,13 @@ public static async Task RunMigrationTools(this IHostBuilder hostBuilder, string await host.RunAsync(); } + static string logDate = DateTime.Now.ToString("yyyyMMddHHmmss"); + private static string CreateLogsPath() { string exportPath; string assPath = Assembly.GetEntryAssembly().Location; - exportPath = Path.Combine(Path.GetDirectoryName(assPath), "logs", DateTime.Now.ToString("yyyyMMddHHmmss")); + exportPath = Path.Combine(Path.GetDirectoryName(assPath), "logs", logDate); if (!Directory.Exists(exportPath)) { Directory.CreateDirectory(exportPath); From aa725a083e43a959b48b49513479698727a3678b Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 25 Jul 2024 13:39:12 +0100 Subject: [PATCH 07/10] =?UTF-8?q?=E2=9C=A8=20(CommandSettingsBase.cs,=20Mi?= =?UTF-8?q?grationToolHost.cs):=20add=20support=20for=20command-line=20con?= =?UTF-8?q?fig=20file=20option=20=E2=AC=86=EF=B8=8F=20(MigrationTools.Host?= =?UTF-8?q?.csproj):=20add=20System.CommandLine=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for specifying the configuration file via command-line options `--config`, `--configFile`, or `-c`. This enhances flexibility by allowing users to specify a custom configuration file when running the application. The `System.CommandLine` package is added to facilitate this functionality. The `ForceGetConfigFile` method is introduced to parse the command-line arguments and extract the configuration file path. The `CreateDefaultBuilder` method in `MigrationToolHost.cs` is updated to use this configuration file path, ensuring the application loads the correct configuration. --- .../Commands/CommandSettingsBase.cs | 25 ++++--- src/MigrationTools.Host/MigrationToolHost.cs | 72 +++++++++---------- .../MigrationTools.Host.csproj | 1 + 3 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/MigrationTools.Host/Commands/CommandSettingsBase.cs b/src/MigrationTools.Host/Commands/CommandSettingsBase.cs index 397d47f5d..fe6071e9b 100644 --- a/src/MigrationTools.Host/Commands/CommandSettingsBase.cs +++ b/src/MigrationTools.Host/Commands/CommandSettingsBase.cs @@ -1,20 +1,15 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text; -using System.Xml.Serialization; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; +using System.ComponentModel; using Newtonsoft.Json; using Spectre.Console.Cli; using YamlDotNet.Serialization; +using System.CommandLine; namespace MigrationTools.Host.Commands { internal class CommandSettingsBase : CommandSettings { [Description("Pre configure paramiters using this config file. Run `Init` to create it.")] - [CommandOption("--config|--configFile")] + [CommandOption("--config|--configFile|-c")] [DefaultValue("configuration.json")] [JsonIgnore, YamlIgnore] public string ConfigFile { get; set; } @@ -27,5 +22,19 @@ internal class CommandSettingsBase : CommandSettings [CommandOption("--skipVersionCheck")] public bool skipVersionCheck { get; set; } + public static string ForceGetConfigFile(string[] args) + { + var fileOption = new Option("--config"); + fileOption.AddAlias("-c"); + fileOption.AddAlias("--configFile"); + + var rootCommand = new RootCommand(); + rootCommand.AddOption(fileOption); + + var file = rootCommand.Parse(args); + return file.GetValueForOption(fileOption); + + } } + } diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index 71a3be507..9e40eb1f4 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -21,6 +21,7 @@ using Spectre.Console.Cli.Extensions.DependencyInjection; using Spectre.Console.Cli; using Serilog.Filters; +using MigrationTools.Host.Commands; namespace MigrationTools.Host { @@ -30,6 +31,8 @@ public static class MigrationToolHost public static IHostBuilder CreateDefaultBuilder(string[] args) { + var configFile = CommandSettingsBase.ForceGetConfigFile(args); + var hostBuilder = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args); hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => @@ -59,43 +62,40 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) hostBuilder.ConfigureLogging((context, logBuilder) => { - }); - //.ConfigureAppConfiguration(builder => - //{ - // if (executeOptions is not null) - // { - // builder.AddJsonFile(executeOptions.ConfigFile); - // } - //}) + }) + .ConfigureAppConfiguration(builder => + { + builder.AddJsonFile(configFile); + }); hostBuilder.ConfigureServices((context, services) => { services.AddOptions(); - //services.Configure((config) => - //{ - // var sp = services.BuildServiceProvider(); - // var logger = sp.GetService().CreateLogger(); - // //if (!File.Exists(executeOptions.ConfigFile)) - // //{ - // // logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", executeOptions.ConfigFile, Assembly.GetEntryAssembly().GetName().Name); - // // throw new ArgumentException("missing configfile"); - // //} - // //logger.LogInformation("Config Found, creating engine host"); - // //var reader = sp.GetRequiredService(); - // //var parsed = reader.BuildFromFile(executeOptions.ConfigFile); - // //config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; - // //config.FieldMaps = parsed.FieldMaps; - // //config.GitRepoMapping = parsed.GitRepoMapping; - // //config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; - // //config.Processors = parsed.Processors; - // //config.Source = parsed.Source; - // //config.Target = parsed.Target; - // //config.Version = parsed.Version; - // //config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; - // //config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; - //}); - - + services.Configure((config) => + { + var sp = services.BuildServiceProvider(); + var logger = sp.GetService().CreateLogger(); + if (!File.Exists(configFile)) + { + logger.LogInformation("The config file {ConfigFile} does not exist, nor does the default 'configuration.json'. Use '{ExecutableName}.exe init' to create a configuration file first", configFile, Assembly.GetEntryAssembly().GetName().Name); + throw new ArgumentException("missing configfile"); + } + logger.LogInformation("Config Found, creating engine host"); + var reader = sp.GetRequiredService(); + var parsed = reader.BuildFromFile(configFile); + config.ChangeSetMappingFile = parsed.ChangeSetMappingFile; + config.FieldMaps = parsed.FieldMaps; + config.GitRepoMapping = parsed.GitRepoMapping; + config.CommonEnrichersConfig = parsed.CommonEnrichersConfig; + config.Processors = parsed.Processors; + config.Source = parsed.Source; + config.Target = parsed.Target; + config.Version = parsed.Version; + config.workaroundForQuerySOAPBugEnabled = parsed.workaroundForQuerySOAPBugEnabled; + config.WorkItemTypeDefinition = parsed.WorkItemTypeDefinition; + }); + + // Application Insights ApplicationInsightsServiceOptions aiso = new ApplicationInsightsServiceOptions(); aiso.ApplicationVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); @@ -122,7 +122,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) // Host Services services.AddTransient(); - + }); hostBuilder.ConfigureServices((context, services) => @@ -144,7 +144,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) services.AddHostedService(); }); - hostBuilder.UseConsoleLifetime(); + hostBuilder.UseConsoleLifetime(); @@ -181,7 +181,7 @@ public static async Task RunMigrationTools(this IHostBuilder hostBuilder, string await host.RunAsync(); } - static string logDate = DateTime.Now.ToString("yyyyMMddHHmmss"); + static string logDate = DateTime.Now.ToString("yyyyMMddHHmmss"); private static string CreateLogsPath() { diff --git a/src/MigrationTools.Host/MigrationTools.Host.csproj b/src/MigrationTools.Host/MigrationTools.Host.csproj index 97a7c8baa..966f7654b 100644 --- a/src/MigrationTools.Host/MigrationTools.Host.csproj +++ b/src/MigrationTools.Host/MigrationTools.Host.csproj @@ -33,6 +33,7 @@ + From 3a2c737011911c5b1e68261733d02c1ef8f40cc1 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 25 Jul 2024 13:50:46 +0100 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=93=9D=20(MigrationTools.xml):=20up?= =?UTF-8?q?date=20Git=20metadata=20to=20reflect=20new=20branch=20and=20com?= =?UTF-8?q?mit=20details=20=E2=99=BB=EF=B8=8F=20(MigrationToolHost.cs):=20?= =?UTF-8?q?refactor=20version=20logging=20to=20use=20GetRunningVersion=20m?= =?UTF-8?q?ethod=20=F0=9F=94=A7=20(MigrationTools.csproj):=20add=20GitVers?= =?UTF-8?q?ion=20property=20to=20disable=20GitVersion=20during=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Git metadata in the MigrationTools.xml file is updated to reflect the new branch, commit, and version details. The version logging in MigrationToolHost.cs is refactored to use a new method, GetRunningVersion, which provides a more accurate and detailed version string. Additionally, the GitVersion property is added to the MigrationTools.csproj file to disable GitVersion during the build process, ensuring that the build process does not rely on Git metadata. --- docs/Reference/Generated/MigrationTools.xml | 22 +++++++++--------- src/MigrationTools.Host/MigrationToolHost.cs | 24 +++++++++++++++----- src/MigrationTools/MigrationTools.csproj | 4 ++++ 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/docs/Reference/Generated/MigrationTools.xml b/docs/Reference/Generated/MigrationTools.xml index c2aa0f267..d9a811187 100644 --- a/docs/Reference/Generated/MigrationTools.xml +++ b/docs/Reference/Generated/MigrationTools.xml @@ -604,37 +604,37 @@ - => @"main" + => @"topic/move-cmd" - => @"d10bad5" + => @"59960e1" - => @"d10bad52221de4cd9849d63033095613211d5ce0" + => @"59960e13eb86f14681119cee2f9465f6a4bca67a" - => @"2024-07-24T16:56:23+01:00" + => @"2024-07-25T13:40:51+01:00" - => @"0" + => @"10" - => @"v15.1.4-Preview.7" + => @"v15.1.5-Preview.2-10-g59960e1" - => @"v15.1.4-Preview.7" + => @"v15.1.5-Preview.2" @@ -649,7 +649,7 @@ - => @"4" + => @"5" @@ -664,17 +664,17 @@ - => @"4" + => @"15" - => @"Preview.7" + => @"Preview.2" - => @"-Preview.7" + => @"-Preview.2" diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index 9e40eb1f4..5959c754e 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -22,6 +22,8 @@ using Spectre.Console.Cli; using Serilog.Filters; using MigrationTools.Host.Commands; +using System.Diagnostics; +using System.Text.RegularExpressions; namespace MigrationTools.Host { @@ -37,7 +39,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => { - string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetVersionTextForLog() + "] {Message:lj}{NewLine}{Exception}"; // {SourceContext} + string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetRunningVersion().versionString + "] {Message:lj}{NewLine}{Exception}"; // {SourceContext} string logsPath = CreateLogsPath(); var logPath = Path.Combine(logsPath, $"migration{logs}.log"); @@ -52,7 +54,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) .WriteTo.File(logPath, LogEventLevel.Verbose, outputTemplate) .WriteTo.Logger(lc => lc .Filter.ByExcluding(Matching.FromSource("Microsoft")) - .Filter.ByExcluding(Matching.FromSource("MigrationTools.Host.StartupService")) + //.Filter.ByExcluding(Matching.FromSource("MigrationTools.Host.StartupService")) .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug, theme: AnsiConsoleTheme.Code, outputTemplate: outputTemplate)) .WriteTo.Logger(lc => lc .Filter.ByExcluding(Matching.FromSource("Microsoft")) @@ -151,11 +153,21 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) return hostBuilder; } - private static string GetVersionTextForLog() + public static (Version version, string PreReleaseLabel, string versionString) GetRunningVersion() { - Version runningVersion = DetectVersionService2.GetRunningVersion().version; - string textVersion = "v" + DetectVersionService2.GetRunningVersion().version + "-" + DetectVersionService2.GetRunningVersion().PreReleaseLabel; - return textVersion; + FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()?.Location); + var matches = Regex.Matches(myFileVersionInfo.ProductVersion, @"^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-((? - => @"true" + => @"false" @@ -609,27 +609,27 @@ - => @"59960e1" + => @"3a2c737" - => @"59960e13eb86f14681119cee2f9465f6a4bca67a" + => @"3a2c737011911c5b1e68261733d02c1ef8f40cc1" - => @"2024-07-25T13:40:51+01:00" + => @"2024-07-25T13:50:46+01:00" - => @"10" + => @"11" - => @"v15.1.5-Preview.2-10-g59960e1" + => @"v15.1.5-Preview.2-11-g3a2c737" @@ -664,7 +664,7 @@ - => @"15" + => @"16" diff --git a/src/MigrationTools.Host/MigrationToolHost.cs b/src/MigrationTools.Host/MigrationToolHost.cs index 5959c754e..191ee5b03 100644 --- a/src/MigrationTools.Host/MigrationToolHost.cs +++ b/src/MigrationTools.Host/MigrationToolHost.cs @@ -39,7 +39,7 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) hostBuilder.UseSerilog((hostingContext, services, loggerConfiguration) => { - string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + GetRunningVersion().versionString + "] {Message:lj}{NewLine}{Exception}"; // {SourceContext} + string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] [" + DetectVersionService2.GetRunningVersion().versionString + "] {Message:lj}{NewLine}{Exception}"; // {SourceContext} string logsPath = CreateLogsPath(); var logPath = Path.Combine(logsPath, $"migration{logs}.log"); @@ -153,23 +153,6 @@ public static IHostBuilder CreateDefaultBuilder(string[] args) return hostBuilder; } - public static (Version version, string PreReleaseLabel, string versionString) GetRunningVersion() - { - FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly()?.Location); - var matches = Regex.Matches(myFileVersionInfo.ProductVersion, @"^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-((?