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;