Skip to content

Replace custom RemoveSpectreFormatting with Spectre.Console's Markup.Remove#18209

Open
JamesNK wants to merge 2 commits into
mainfrom
replace-remove-spectre-formatting-with-markup-remove
Open

Replace custom RemoveSpectreFormatting with Spectre.Console's Markup.Remove#18209
JamesNK wants to merge 2 commits into
mainfrom
replace-remove-spectre-formatting-with-markup-remove

Conversation

@JamesNK

@JamesNK JamesNK commented Jun 15, 2026

Copy link
Copy Markdown
Member

Summary

Replace the custom RemoveSpectreFormatting() extension method with Spectre.Console's built-in Markup.Remove() static method.

Changes

  • Replaced all 21 usages of StringUtils.RemoveSpectreFormatting() with Markup.Remove() across ExtensionInteractionService.cs, ConsoleInteractionService.cs, and ExtensionBackchannel.cs
  • Removed the RemoveSpectreFormatting extension method and its GeneratedRegex from StringUtils.cs
  • Removed the now-unnecessary partial modifier and System.Text.RegularExpressions using from StringUtils.cs

Motivation

Markup.Remove() is the official Spectre.Console API for stripping markup tags. It properly handles edge cases (escaped brackets, nested tags) that the simple regex \[[^\]]+\] could miss. Using the built-in method reduces maintenance burden and improves correctness.

Testing

All 4106 CLI tests pass.

Copilot AI review requested due to automatic review settings June 15, 2026 06:52
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18209

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18209"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces a custom regex-based RemoveSpectreFormatting() extension method with Spectre.Console's built-in Markup.Remove() static method across the CLI codebase. The change improves correctness (proper handling of escaped brackets and nested tags) and reduces maintenance of a custom regex pattern.

Changes:

  • Replaced all usages of StringUtils.RemoveSpectreFormatting() with Markup.Remove() across three files
  • Removed the RemoveSpectreFormatting extension method, its GeneratedRegex, the partial modifier, and the System.Text.RegularExpressions using from StringUtils.cs

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/Aspire.Cli/Utils/StringUtils.cs Removed the RemoveSpectreFormatting extension method, associated regex, partial modifier, and regex using
src/Aspire.Cli/Interaction/ExtensionInteractionService.cs Replaced 17 call sites from .RemoveSpectreFormatting() to Markup.Remove(...)
src/Aspire.Cli/Interaction/ConsoleInteractionService.cs Replaced 1 call site from .RemoveSpectreFormatting() to Markup.Remove(...)
src/Aspire.Cli/Backchannel/ExtensionBackchannel.cs Replaced 2 call sites from .RemoveSpectreFormatting() to Markup.Remove(...)

Comment thread src/Aspire.Cli/Utils/StringUtils.cs
@JamesNK

JamesNK commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

PR Testing Report

PR Information

Artifact Version Verification

  • Expected Commit: 74c4e21
  • Installed Version: 13.5.0-dev (source build from PR branch)
  • Status: ✅ Verified

Changes Analyzed

Files Changed

  • src/Aspire.Cli/Backchannel/ExtensionBackchannel.cs - Modified (2 call sites)
  • src/Aspire.Cli/Interaction/ConsoleInteractionService.cs - Modified (1 call site)
  • src/Aspire.Cli/Interaction/ExtensionInteractionService.cs - Modified (18 call sites)
  • src/Aspire.Cli/Utils/StringUtils.cs - Modified (removed method + regex)

Change Categories

  • CLI changes detected
  • Hosting integration changes
  • Dashboard changes
  • Template changes
  • Client/Component changes
  • VS Code extension changes
  • CI infrastructure changes

Test Scenarios Executed

Scenario 1: Unit Tests

Objective: Verify all CLI unit tests pass with the replacement
Coverage Type: Comprehensive unit coverage
Status: ✅ Passed

Results: 4106 tests executed, 0 failed, 4080 succeeded, 26 skipped


Scenario 2: Template Creation (aspire-starter)

Objective: Exercise DisplayMessage/ShowStatus paths that use Markup.Remove
Coverage Type: Happy path
Status: ✅ Passed

Steps:

  1. Created aspire-starter project with --non-interactive
  2. Verified emoji output, status messages, and success message rendered correctly

Observations:

  • All status text displayed correctly with no markup tag leakage
  • Project created successfully

Scenario 3: Error Display (invalid apphost path)

Objective: Verify error display through Markup.Remove renders cleanly
Coverage Type: Unhappy path
Status: ✅ Passed

Steps:

  1. Ran aspire run --apphost C:\nonexistent\path\to\AppHost.csproj --non-interactive
  2. Verified error message displayed correctly

Observations:

  • Error message rendered cleanly (no [bold red]...[/] tags leaked)
  • Exit code 7 as expected

Scenario 4: Doctor Command

Objective: Exercise multiple status/warning/success display paths
Coverage Type: Happy path (bonus)
Status: ✅ Passed

Steps:

  1. Ran aspire doctor --non-interactive
  2. Verified all status messages, warnings, and formatted output

Observations:

  • All output categories (success ✓, warning ⚠️, info) rendered correctly

Summary

Scenario Status Notes
Unit Tests (4106) ✅ Passed 0 failures
Template Creation ✅ Passed All display paths work
Error Display ✅ Passed Clean error output, correct exit code
Doctor Command ✅ Passed All formatting categories correct

Overall Result

✅ PR VERIFIED

Low-risk internal refactoring. Markup.Remove() is the official Spectre.Console API and handles edge cases (escaped brackets, nested tags) better than the custom regex \[[^\]]+\].

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@JamesNK JamesNK closed this Jun 15, 2026
@JamesNK JamesNK reopened this Jun 15, 2026
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.5 milestone Jun 15, 2026
@JamesNK

JamesNK commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

@adamint The VS Code E2E tests have failed 6 times on this PR. Please fix them.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 114 passed, 0 failed, 3 unknown (commit 74c4e21)

View all recordings
- Test Detail
AddPackageInteractiveWhileAppHostRunningDetached Recording · Job · CLI logs
AddPackageWhileAppHostRunningDetached Recording · Job · CLI logs
AgentCommands_AllHelpOutputs_AreCorrect Recording · Job · CLI logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording · Job · CLI logs
AgentInitCommand_MigratesDeprecatedConfig Recording · Job · CLI logs
AgentInit_NonInteractive_BundleOnlySkillsNotInCatalog Recording · Job · CLI logs
AgentMcpListResources_ExcludesResourceMarkedWithExcludeFromMcp Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording · Job · CLI logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording · Job · CLI logs
AllPublishMethodsBuildDockerImages Recording · Job · CLI logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording · Job · CLI logs
AspireAddPackageVersionToDirectoryPackagesProps Recording · Job · CLI logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording · Job · CLI logs
AspireInit_ExistingAppHostDir_RecreatesNuGetConfigKeepsFiles Recording · Job · CLI logs
AspireInit_SolutionFile_BuildsAgainstChannelHive Recording · Job · CLI logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording · Job · CLI logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording · Job · CLI logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording · Job · CLI logs
Banner_DisplayedOnFirstRun Recording · Job · CLI logs
Banner_DisplayedWithExplicitFlag Recording · Job · CLI logs
Banner_NotDisplayedWithNoLogoFlag Recording · Job · CLI logs
CertificatesClean_RemovesCertificates Recording · Job · CLI logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording · Job · CLI logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording · Job · CLI logs
ConfigSetGet_CreatesNestedJsonFormat Recording · Job · CLI logs
CreateAndRunAspireStarterProject Recording · Job · CLI logs
CreateAndRunAspireStarterProjectWithBundle Recording · Job · CLI logs
CreateAndRunEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunJavaEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunJsReactProject Recording · Job · CLI logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording · Job · CLI logs
CreateAndRunPythonReactProject Recording · Job · CLI logs
CreateAndRunTypeScriptEmptyAppHostProject Recording · Job · CLI logs
CreateAndRunTypeScriptStarterProject Recording · Job · CLI logs
CreateJavaAppHostWithViteApp Recording · Job · CLI logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording · Job · CLI logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTraces Recording · Job · CLI logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording · Job · CLI logs
DeployK8sBasicApiService Recording · Job · CLI logs
DeployK8sWithExternalHelmChart Recording · Job · CLI logs
DeployK8sWithGarnet Recording · Job · CLI logs
DeployK8sWithMongoDB Recording · Job · CLI logs
DeployK8sWithMySql Recording · Job · CLI logs
DeployK8sWithPostgres Recording · Job · CLI logs
DeployK8sWithRabbitMQ Recording · Job · CLI logs
DeployK8sWithRedis Recording · Job · CLI logs
DeployK8sWithSqlServer Recording · Job · CLI logs
DeployK8sWithValkey Recording · Job · CLI logs
DeployTypeScriptAppToKubernetes Recording · Job · CLI logs
DescribeCommandResolvesReplicaNames Recording · Job · CLI logs
DescribeCommandShowsRunningResources Recording · Job · CLI logs
DetachFormatJsonProducesValidJson Recording · Job · CLI logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording · Job · CLI logs
DoPublishAndDeployListStepsWork Recording · Job · CLI logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording · Job · CLI logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording · Job · CLI logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording · Job · CLI logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording · Job · CLI logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording · Job · CLI logs
DotNetRunFileBasedAppHostUsesAspireCliBundle Recording · Job · CLI logs
DotNetRunProjectAppHostUsesAspireCliBundle Recording · Job · CLI logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording · Job · CLI logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording · Job · CLI logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording · Job · CLI logs
GlobalMigration_HandlesMalformedLegacyJson Recording · Job · CLI logs
GlobalMigration_PreservesAllValueTypes Recording · Job · CLI logs
GlobalMigration_SkipsWhenNewConfigExists Recording · Job · CLI logs
GlobalSettings_MigratedFromLegacyFormat Recording · Job · CLI logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording · Job · CLI logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording · Job · CLI logs
InteractiveCSharpInitCreatesExpectedFiles Recording · Job · CLI logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording · Job · CLI logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording · Job · CLI logs
LatestCliCanStartStableChannelAppHost Recording · Job · CLI logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording · Job · CLI logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording · Job · CLI logs
LogsCommandShowsResourceLogs Recording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording · Job · CLI logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording · Job · CLI logs
ProcessCommandCallbackReceivesCliArguments Recording · Job · CLI logs
PsCommandListsRunningAppHost Recording · Job · CLI logs
PsFormatJsonOutputsOnlyJsonToStdout Recording · Job · CLI logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording · Job · CLI logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording · Job · CLI logs
PublishWithDockerComposeServiceCallbackSucceeds Recording · Job · CLI logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording · Job · CLI logs
ResourceCommand_FailedExec_ShowsLogPathAndLogHasEntries Recording · Job · CLI logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording · Job · CLI logs
RestoreGeneratesSdkFiles Recording · Job · CLI logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording · Job · CLI logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording · Job · CLI logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording · Job · CLI logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording · Job · CLI logs
RunReportsSyntaxErrorsForDotNetAppHost Recording · Job · CLI logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording · Job · CLI logs
SecretCrudOnDotNetAppHost Recording · Job · CLI logs
SecretCrudOnTypeScriptAppHost Recording · Job · CLI logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording · Job · CLI logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording · Job · CLI logs
StartReportsSyntaxErrorsForDotNetAppHost Recording · Job · CLI logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording · Job · CLI logs
StopAllAppHostsFromAppHostDirectory Recording · Job · CLI logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording · Job · CLI logs
StopNonInteractiveSingleAppHost Recording · Job · CLI logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording · Job · CLI logs
StopWithNoRunningAppHostExitsSuccessfully Recording · Job · CLI logs
TerminalAttachFrontend_ShowsViteHelpAndDetaches Recording · Job · CLI logs
TypeScriptAppHostRunDoesNotDeadlockWhenLazyOptionsInvokeAsyncCallback Recording · Job · CLI logs
TypeScriptAppHostWithVite_AllowsDifferentGuestPkgManager Recording · Job · CLI logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording · Job · CLI logs
UpdateToStable_CSharpEmptyAppHost_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_CSharpSingleFileInit_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_TypeScriptSingleFileInit_KeepsConfigChannel Recording · Job · CLI logs
UpdateToStable_TypeScript_PreviewsStablePkgsAndKeepsChannel Recording · Job · CLI logs

📹 Recordings uploaded automatically from CI run #27551911405

…in choice label throws InvalidOperationException

Tests that Markup.Remove throws InvalidOperationException when a choice
formatter returns text with unescaped ']' characters, which was previously
silently stripped by the regex-based RemoveSpectreFormatting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants