From ac5a8675b00dea30f8022bdfea89e484fdc52827 Mon Sep 17 00:00:00 2001 From: John Campion Jr <1094820+JohnCampionJr@users.noreply.github.com> Date: Mon, 8 Jun 2026 15:12:40 -0400 Subject: [PATCH] Update Spectre.Console Updates Spectre.Console to 0.56.0 and Spectre.Console.Cli to 0.55.0 (not released in lockstep), plus the matching testing packages. Adapts to two breaking changes: commands' ExecuteAsync now takes a CancellationToken and is protected, and CommandAppTester/CommandAppResult moved to the new Spectre.Console.Cli.Testing package and is now single-use (tests that ran it more than once use a fresh tester per run). Removes the CommandAppTesterExtensions reflection hack now that input can go through the tester's own console. --- .changeset/upgrade-spectre-console.md | 5 +++ Directory.Packages.props | 7 +-- .../Commands/Init/InitChangesetCommand.cs | 3 +- .../Shared/ConfigurationCommandBase.cs | 2 +- .../Add/AddCommandTests.cs | 30 +++++++------ .../Add/CommandAppTesterExtensions.cs | 45 ------------------- .../Init/InitCommandTests.cs | 24 +++++----- .../Publish/PublishChangesetCommandTests.cs | 9 ++-- .../SolarWinds.Changesets.Tests.csproj | 1 + .../Status/StatusChangesetCommandTests.cs | 9 ++-- .../Version/VersionChangesetCommandTests.cs | 2 +- 11 files changed, 56 insertions(+), 81 deletions(-) create mode 100644 .changeset/upgrade-spectre-console.md delete mode 100644 tests/SolarWinds.Changesets.Tests/Add/CommandAppTesterExtensions.cs diff --git a/.changeset/upgrade-spectre-console.md b/.changeset/upgrade-spectre-console.md new file mode 100644 index 0000000..13ff94f --- /dev/null +++ b/.changeset/upgrade-spectre-console.md @@ -0,0 +1,5 @@ +--- +"SolarWinds.Changesets": Patch +--- + +Upgrade Spectre.Console to 0.56.0 and Spectre.Console.Cli to 0.55.0 (with matching testing packages). Adapts to the new command `ExecuteAsync(CommandContext, CancellationToken)` signature and the move of `CommandAppTester` into the new `Spectre.Console.Cli.Testing` package. diff --git a/Directory.Packages.props b/Directory.Packages.props index 4cdc0e9..5a788e6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -22,9 +22,10 @@ - + - - + + + diff --git a/src/SolarWinds.Changesets/Commands/Init/InitChangesetCommand.cs b/src/SolarWinds.Changesets/Commands/Init/InitChangesetCommand.cs index 75e48d9..84dd207 100644 --- a/src/SolarWinds.Changesets/Commands/Init/InitChangesetCommand.cs +++ b/src/SolarWinds.Changesets/Commands/Init/InitChangesetCommand.cs @@ -46,13 +46,14 @@ IConfigurationService configurationService /// Executes Init command. /// /// Command context. + /// A token to observe for cancellation requests. /// /// An integer indicating the result of the initialization: /// - 0: Initialization succeeded. /// - 1: Directory existed but config file was missing; default config created. /// - 2: Changesets already initialized; no further action needed. /// - public override async Task ExecuteAsync(CommandContext context) + protected override async Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) { if (Directory.Exists(Constants.ChangesetDirectoryFullPath)) { diff --git a/src/SolarWinds.Changesets/Shared/ConfigurationCommandBase.cs b/src/SolarWinds.Changesets/Shared/ConfigurationCommandBase.cs index 0c609d6..6823346 100644 --- a/src/SolarWinds.Changesets/Shared/ConfigurationCommandBase.cs +++ b/src/SolarWinds.Changesets/Shared/ConfigurationCommandBase.cs @@ -16,7 +16,7 @@ protected ConfigurationCommandBase(IConfigurationService configurationService) _configurationService = configurationService; } - public sealed override async Task ExecuteAsync(CommandContext context) + protected sealed override async Task ExecuteAsync(CommandContext context, CancellationToken cancellationToken) { if (!Directory.Exists(Constants.ChangesetDirectoryFullPath)) { diff --git a/tests/SolarWinds.Changesets.Tests/Add/AddCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Add/AddCommandTests.cs index 47cb88f..968eadf 100644 --- a/tests/SolarWinds.Changesets.Tests/Add/AddCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Add/AddCommandTests.cs @@ -6,6 +6,7 @@ using SolarWinds.Changesets.Infrastructure; using SolarWinds.Changesets.Shared; using Spectre.Console.Cli; +using Spectre.Console.Cli.Testing; using Spectre.Console.Testing; namespace SolarWinds.Changesets.Tests.Add; @@ -14,8 +15,8 @@ namespace SolarWinds.Changesets.Tests.Add; internal sealed class AddCommandTests { private readonly Mock _projectFileNameLocator = new(); + private TypeRegistrar _typeRegistrar = null!; private CommandAppTester _app = null!; - private TestConsole _console = null!; private ChangesetsRepository _changesetsRepository = null!; [SetUp] @@ -29,8 +30,8 @@ public void SetUp() _changesetsRepository = new ChangesetsRepository(); serviceCollection.AddSingleton(_changesetsRepository); - TypeRegistrar typeRegistrar = new(serviceCollection); - _app = new(typeRegistrar); + _typeRegistrar = new(serviceCollection); + _app = new(_typeRegistrar); _app.Configure(config => { config @@ -51,27 +52,28 @@ public async Task AddCommand_HappyPath_ChangesetIsCreated() // Arrange _projectFileNameLocator.Setup(x => x.GetProjectFileNames(It.IsAny())).Returns(["A", "B"]); - _console = new(); - _console.Interactive(); + CommandAppTester initApp = new(_typeRegistrar); + initApp.SetDefaultCommand(); + await initApp.RunAsync(); + + _app.Console.Interactive(); // MultiSelectionPrompt - Select 2nd project 'B' - _console.Input.PushKey(ConsoleKey.DownArrow); - _console.Input.PushKey(ConsoleKey.Spacebar); - _console.Input.PushKey(ConsoleKey.Enter); + _app.Console.Input.PushKey(ConsoleKey.DownArrow); + _app.Console.Input.PushKey(ConsoleKey.Spacebar); + _app.Console.Input.PushKey(ConsoleKey.Enter); // SelectionPrompt - Select BumpType 'Minor' - _console.Input.PushKey(ConsoleKey.DownArrow); - _console.Input.PushKey(ConsoleKey.Enter); + _app.Console.Input.PushKey(ConsoleKey.DownArrow); + _app.Console.Input.PushKey(ConsoleKey.Enter); // TextPrompt - Describe changes string expectedDescription = "Test example description"; - _console.Input.PushTextWithEnter(expectedDescription); + _app.Console.Input.PushTextWithEnter(expectedDescription); // Act - _app.SetDefaultCommand(); - await _app.RunAsync(); _app.SetDefaultCommand(); - CommandAppResult result = _app.RunWithCustomConsole([], _console); + CommandAppResult result = await _app.RunAsync(); // Assert result.ExitCode.Should().Be(ResultCodes.Success, result.Output); diff --git a/tests/SolarWinds.Changesets.Tests/Add/CommandAppTesterExtensions.cs b/tests/SolarWinds.Changesets.Tests/Add/CommandAppTesterExtensions.cs deleted file mode 100644 index 6feaff3..0000000 --- a/tests/SolarWinds.Changesets.Tests/Add/CommandAppTesterExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Reflection; -using Spectre.Console.Testing; - -namespace SolarWinds.Changesets.Tests.Add; - -internal static class CommandAppTesterExtensions -{ - /// - /// This method is used to run the command app tester with a custom console. - /// - /// - /// This can be deleted once we upgrade Spectre.Console.Testing to version 0.51.X or higher. - /// - /// CommandAppTester instance. - /// CLI arguments. - /// Custom test console. - /// Command result. - /// Thrown when the command failed to run with the custom console. - public static CommandAppResult RunWithCustomConsole( - this CommandAppTester tester, - string[] args, - TestConsole console - ) - { - Type testerType = tester.GetType(); - - MethodInfo? runMethod = testerType.GetMethod("Run", BindingFlags.NonPublic | BindingFlags.Instance); - - if (runMethod == null) - { - throw new InvalidOperationException("The method 'Run' was not found."); - } - - object[] parameters = [args, console, null!]; - - object? result = runMethod.Invoke(tester, parameters); - - if (result is CommandAppResult commandAppResult) - { - return commandAppResult; - } - - throw new InvalidOperationException("The method 'Run' returned unexpected type."); - } -} diff --git a/tests/SolarWinds.Changesets.Tests/Init/InitCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Init/InitCommandTests.cs index 2ea4712..0a3149c 100644 --- a/tests/SolarWinds.Changesets.Tests/Init/InitCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Init/InitCommandTests.cs @@ -3,14 +3,14 @@ using SolarWinds.Changesets.Commands.Init; using SolarWinds.Changesets.Infrastructure; using SolarWinds.Changesets.Shared; -using Spectre.Console.Testing; +using Spectre.Console.Cli.Testing; namespace SolarWinds.Changesets.Tests.Init; [TestFixture] internal sealed class InitCommandTests { - private CommandAppTester _app = null!; + private TypeRegistrar _typeRegistrar = null!; [SetUp] public void SetUp() @@ -19,10 +19,14 @@ public void SetUp() ServiceCollection serviceCollection = new(); serviceCollection.AddSingleton(); - TypeRegistrar typeRegistrar = new(serviceCollection); - CommandAppTester app = new(typeRegistrar); + _typeRegistrar = new(serviceCollection); + } + + private CommandAppTester CreateApp() + { + CommandAppTester app = new(_typeRegistrar); app.SetDefaultCommand(); - _app = app; + return app; } [TearDown] @@ -35,7 +39,7 @@ public void TearDown() public void InitCommand_HappyPath_FolderAndFilesAreCreated() { // Arrange, Act - CommandAppResult result = _app.Run(); + CommandAppResult result = CreateApp().Run(); // Assert AssertInitCommand(result, ResultCodes.Success); @@ -45,12 +49,12 @@ public void InitCommand_HappyPath_FolderAndFilesAreCreated() public void InitCommand_HappyPathRunTwice_ConfigIsMissingAndWillBeGenerated() { // Arrange, Act, Assert - CommandAppResult result = _app.Run(); + CommandAppResult result = CreateApp().Run(); AssertInitCommand(result, ResultCodes.Success); File.Delete(Constants.ChangesetConfigFileFullPath); - CommandAppResult result2 = _app.Run(); + CommandAppResult result2 = CreateApp().Run(); AssertInitCommand(result2, ResultCodes.ConfigFileWasGenerated); } @@ -58,10 +62,10 @@ public void InitCommand_HappyPathRunTwice_ConfigIsMissingAndWillBeGenerated() public void InitCommand_HappyPathRunTwice_ConsoleContainMessageThatAlreadyExists() { // Arrange, Act, Assert - CommandAppResult result = _app.Run(); + CommandAppResult result = CreateApp().Run(); AssertInitCommand(result, ResultCodes.Success); - CommandAppResult result2 = _app.Run(); + CommandAppResult result2 = CreateApp().Run(); AssertInitCommand(result2, ResultCodes.AlreadyInitialized); } diff --git a/tests/SolarWinds.Changesets.Tests/Publish/PublishChangesetCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Publish/PublishChangesetCommandTests.cs index 94722b8..997d4ca 100644 --- a/tests/SolarWinds.Changesets.Tests/Publish/PublishChangesetCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Publish/PublishChangesetCommandTests.cs @@ -5,7 +5,7 @@ using SolarWinds.Changesets.Commands.Publish.Services; using SolarWinds.Changesets.Infrastructure; using SolarWinds.Changesets.Shared; -using Spectre.Console.Testing; +using Spectre.Console.Cli.Testing; namespace SolarWinds.Changesets.Tests.Publish; @@ -31,9 +31,12 @@ public void SetUp() _configurationServiceMock.Setup(x => x.GetConfigAsync(It.IsAny())).Returns(Task.FromResult(new ChangesetConfig())); TypeRegistrar typeRegistrar = new(serviceCollection); + + CommandAppTester initApp = new(typeRegistrar); + initApp.SetDefaultCommand(); + initApp.Run(); + _app = new(typeRegistrar); - _app.SetDefaultCommand(); - _app.Run(); _app.SetDefaultCommand(); } diff --git a/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj b/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj index 87d24dc..b5092d8 100644 --- a/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj +++ b/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj @@ -23,6 +23,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/tests/SolarWinds.Changesets.Tests/Status/StatusChangesetCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Status/StatusChangesetCommandTests.cs index a5da30c..4aca3a9 100644 --- a/tests/SolarWinds.Changesets.Tests/Status/StatusChangesetCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Status/StatusChangesetCommandTests.cs @@ -4,7 +4,7 @@ using SolarWinds.Changesets.Commands.Status; using SolarWinds.Changesets.Infrastructure; using SolarWinds.Changesets.Shared; -using Spectre.Console.Testing; +using Spectre.Console.Cli.Testing; namespace SolarWinds.Changesets.Tests.Status; @@ -23,9 +23,12 @@ public void SetUp() serviceCollection.AddSingleton(_changesetsRepositoryMock.Object); TypeRegistrar typeRegistrar = new(serviceCollection); + + CommandAppTester initApp = new(typeRegistrar); + initApp.SetDefaultCommand(); + initApp.Run(); + _app = new(typeRegistrar); - _app.SetDefaultCommand(); - _app.Run(); _app.SetDefaultCommand(); } diff --git a/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs index fa5c89f..57060de 100644 --- a/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs @@ -6,7 +6,7 @@ using SolarWinds.Changesets.Commands.Version.Helpers; using SolarWinds.Changesets.Infrastructure; using SolarWinds.Changesets.Shared; -using Spectre.Console.Testing; +using Spectre.Console.Cli.Testing; namespace SolarWinds.Changesets.Tests.Version;