Skip to content

[release/13.4] Fix five aspire ls bugs from #17620 (L1–L5)#17688

Merged
davidfowl merged 6 commits into
release/13.4from
backport/pr-17631-to-release/13.4
May 30, 2026
Merged

[release/13.4] Fix five aspire ls bugs from #17620 (L1–L5)#17688
davidfowl merged 6 commits into
release/13.4from
backport/pr-17631-to-release/13.4

Conversation

@aspire-repo-bot
Copy link
Copy Markdown
Contributor

Backport of #17631 to release/13.4

/cc @joperezr @adamint

Customer Impact

Testing

Risk

Regression?

adamint and others added 6 commits May 29, 2026 20:55
Fixes #17615, #17620, #17621, #17624, #17626.

- L1 (#17615): Remove the eager-migration block in
  ConfigurationHelper.RegisterSettingsFiles. Read commands like
  `aspire ls` no longer silently materialize an aspire.config.json
  next to a user's legacy .aspire/settings.json. Migration now happens
  lazily/explicitly via the existing write paths.

- L2 (#17620): Drop the `silent` parameter from
  ProjectLocator.GetAppHostProjectFileFromSettingsAsync so the legacy
  branch unconditionally surfaces the migration warning, and surface
  the actual user-authored `.aspire/settings.json` path in the warning
  text rather than the auto-created `aspire.config.json` path.

- L3 (#17621): Remove the dead post-emission `appHosts.Sort()` in
  LsCommand.FindAppHostsWithJsonStreamAsync (--stream emits candidates
  as they are discovered, so the sort had no effect on already-emitted
  output). Update the --stream option description and
  docs/specs/cli-output-formats.md to declare the arrival-ordered
  contract.

- L4 (#17624): Add an IsValidConfiguredAppHostPath helper in
  ProjectLocator that rejects `\0` and Path.GetInvalidPathChars()
  before the path is passed to Path.IsPathRooted / Path.Combine.
  Wired into both the modern `aspire.config.json` (`appHost.path`)
  branch and the legacy `.aspire/settings.json` (`appHostPath`)
  branch. Validation is intentionally at the consumption point rather
  than in AspireConfigFile.Load, which has 12+ unrelated callers.
  Adds a new ConfiguredAppHostPathHasInvalidCharacters resource string
  and refreshes the xlf set via UpdateXlf.

- L5 (#17626): Add PathNormalizer.ResolveSymlinks in src/Shared, a
  recursive segment-walker that canonicalizes intermediate symlinks
  (Directory.ResolveLinkTarget only reads exactly the path it is given,
  and returns the link target as stored on disk — so a single call on
  /tmp/x/y.cs does not unwrap /tmp -> /private/tmp, and following a
  link whose stored target is /var/.../app keeps the un-canonical
  /var prefix). The recursion has a hard depth limit of 40 and falls
  back to the un-resolved input on broken or circular links. Use it in
  AddSettingsAppHostCandidateAsync as a comparison key only — the
  surfaced AppHostProjectCandidate keeps its original FileInfo so the
  displayed path matches what the user authored in settings.

Tests: 158 of 160 targeted tests pass (2 Windows-only skipped on
macOS). New tests cover L1 (no migration on read), L2 (legacy warning
references settings.json), L3 (arrival-order under --stream), L4
(NUL byte in modern and legacy branches), L5 (symlink dedupe via a
node_modules-hosted link the discovery walk excludes), plus 5 unit
tests on PathNormalizer.ResolveSymlinks itself.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #17671 owns the Foundry ATS baseline update; this branch should only contain the AppHost and CLI fixes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 29, 2026 20:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions
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 -- 17688

Or

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

@joperezr joperezr added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label May 29, 2026
@github-actions
Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 109 passed, 0 failed, 2 unknown (commit 0fd60f5)

View all recordings
Status Test Recording Job Artifacts
AddPackageInteractiveWhileAppHostRunningDetached Recording #78618867073 Logs
AddPackageWhileAppHostRunningDetached Recording #78618867073 Logs
AgentCommands_AllHelpOutputs_AreCorrect Recording #78618866868 Logs
AgentInitCommand_DefaultSelection_InstallsDefaultSkills Recording #78618866868 Logs
AgentInitCommand_MigratesDeprecatedConfig Recording #78618866868 Logs
AgentInitCommand_NonInteractive_BundleOnlySkillsBeyondCliCatalog_AreInstallable Recording #78618866868 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp Recording #78618867270 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost Recording #78618867270 Logs
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_Isolated Recording #78618867270 Logs
AllPublishMethodsBuildDockerImages Recording #78618867103 Logs
AspireAddAndStartWorkAgainstLegacyAppHostTs Recording #78618867101 Logs
AspireAddPackageVersionToDirectoryPackagesProps Recording #78618866922 Logs
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost Recording #78618867053 Logs
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles Recording #78618867221 Logs
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive Recording #78618867221 Logs
AspireStartUpdatesStaleTypeScriptAppHostPath Recording #78618867254 Logs
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps Recording #78618866922 Logs
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent Recording #78618866922 Logs
Banner_DisplayedOnFirstRun Recording #78618867157 Logs
Banner_DisplayedWithExplicitFlag Recording #78618867157 Logs
Banner_NotDisplayedWithNoLogoFlag Recording #78618867157 Logs
CertificatesClean_RemovesCertificates Recording #78618867239 Logs
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate Recording #78618867239 Logs
CertificatesTrust_WithUntrustedCert_TrustsCertificate Recording #78618867239 Logs
ConfigSetGet_CreatesNestedJsonFormat Recording #78618867067 Logs
CreateAndRunAspireStarterProject Recording #78618866948 Logs
CreateAndRunAspireStarterProjectWithBundle Recording #78618867197 Logs
CreateAndRunEmptyAppHostProject Recording #78618866826 Logs
CreateAndRunJavaEmptyAppHostProject Recording #78618866890 Logs
CreateAndRunJsReactProject Recording #78618867275 Logs
CreateAndRunPolyglotAppHostWithDevLocalhostUrls Recording #78618866948 Logs
CreateAndRunPythonReactProject Recording #78618867176 Logs
CreateAndRunTypeScriptEmptyAppHostProject Recording #78618867148 Logs
CreateAndRunTypeScriptStarterProject Recording #78618867201 Logs
CreateJavaAppHostWithViteApp Recording #78618867370 Logs
CreateTypeScriptAppHostWithViteApp_AllowsGuestAppPackageManagerToDiffer Recording #78618866895 Logs
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain Recording #78618866895 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces Recording #78618866936 Logs
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost Recording #78618866936 Logs
DashboardRunWithOtelTracesReturnsNoTraces Recording #78618866936 Logs
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost Recording #78618866936 Logs
DeployK8sBasicApiService Recording #78618866993 Logs
DeployK8sWithExternalHelmChart Recording #78618867290 Logs
DeployK8sWithGarnet Recording #78618867346 Logs
DeployK8sWithMongoDB Recording #78618867084 Logs
DeployK8sWithMySql Recording #78618867313 Logs
DeployK8sWithPostgres Recording #78618867162 Logs
DeployK8sWithRabbitMQ Recording #78618867015 Logs
DeployK8sWithRedis Recording #78618866916 Logs
DeployK8sWithSqlServer Recording #78618867146 Logs
DeployK8sWithValkey Recording #78618867283 Logs
DeployTypeScriptAppToKubernetes Recording #78618867297 Logs
DescribeCommandResolvesReplicaNames Recording #78618867274 Logs
DescribeCommandShowsRunningResources Recording #78618867274 Logs
DetachFormatJsonProducesValidJson Recording #78618867273 Logs
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance Recording #78618867273 Logs
DoPublishAndDeployListStepsWork Recording #78618866918 Logs
DocsCommand_RendersInteractiveMarkdownFromLocalSource Recording #78618866897 Logs
DoctorCommand_DetectsDeprecatedAgentConfig Recording #78618866868 Logs
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain Recording #78618867070 Logs
DoctorCommand_WithSslCertDir_ShowsTrusted Recording #78618867070 Logs
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted Recording #78618867070 Logs
GatewayWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78618866952 Logs
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain Recording #78618866895 Logs
GlobalMigration_HandlesCommentsAndTrailingCommas Recording #78618867067 Logs
GlobalMigration_HandlesMalformedLegacyJson Recording #78618867067 Logs
GlobalMigration_PreservesAllValueTypes Recording #78618867067 Logs
GlobalMigration_SkipsWhenNewConfigExists Recording #78618867067 Logs
GlobalSettings_MigratedFromLegacyFormat Recording #78618867067 Logs
IngressWithoutExternalEndpoint_FailsPublishWithGuidance Recording #78618866952 Logs
InitTypeScriptAppHost_AugmentsExistingViteRepoInWorkspaceSubdirectory Recording #78618866895 Logs
InteractiveCSharpInitCreatesExpectedFiles Recording #78618867226 Logs
InvalidAppHostPathWithComments_IsHealedOnRun Recording #78618866945 Logs
JavaScriptHostingApisRunFromTypeScriptAppHost Recording #78618867103 Logs
LatestCliCanStartStableChannelAppHost Recording #78618866948 Logs
LatestCliCanStartStableChannelTypeScriptAppHost Recording #78618866948 Logs
LegacySettingsMigration_AdjustsRelativeAppHostPath Recording #78618867254 Logs
LogsCommandShowsResourceLogs Recording #78618867376 Logs
OtelLogsReturnsStructuredLogsFromStarterApp Recording #78618866974 Logs
OtelLogsReturnsStructuredLogsFromStarterAppIsolated Recording #78618866974 Logs
PsCommandListsRunningAppHost Recording #78618867113 Logs
PsFormatJsonOutputsOnlyJsonToStdout Recording #78618867113 Logs
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts Recording #78618867066 Logs
PublishWithConfigureEnvFileUpdatesEnvOutput Recording #78618867066 Logs
PublishWithDockerComposeServiceCallbackSucceeds Recording #78618867066 Logs
PublishWithoutOutputPathUsesAppHostDirectoryDefault Recording #78618867066 Logs
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries Recording #78618866893 Logs
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput Recording #78618866893 Logs
RestoreGeneratesSdkFiles Recording #78618867244 Logs
RestoreGeneratesSdkFiles_WithConfiguredToolchain Recording #78618866866 Logs
RestoreRefreshesGeneratedSdkAfterAddingIntegration Recording #78618866866 Logs
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes Recording #78618867076 Logs
RunFromParentDirectory_UsesExistingConfigNearAppHost Recording #78618867262 Logs
RunReportsSyntaxErrorsForDotNetAppHost Recording #78618867048 Logs
RunReportsSyntaxErrorsForTypeScriptAppHost Recording #78618867048 Logs
SecretCrudOnDotNetAppHost Recording #78618867116 Logs
SecretCrudOnTypeScriptAppHost Recording #78618867023 Logs
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels Recording #78618866976 Logs
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets Recording #78618867158 Logs
StartReportsSyntaxErrorsForDotNetAppHost Recording #78618867048 Logs
StartReportsSyntaxErrorsForTypeScriptAppHost Recording #78618867048 Logs
StopAllAppHostsFromAppHostDirectory Recording #78618867147 Logs
StopJavaPolyglotAppHostUsingApphostDirectory Recording #78618867055 Logs
StopNonInteractiveSingleAppHost Recording #78618867147 Logs
StopTypeScriptPolyglotAppHostUsingApphostDirectory Recording #78618867160 Logs
StopWithNoRunningAppHostExitsSuccessfully Recording #78618867073 Logs
UnAwaitedChainsCompileWithAutoResolvePromises Recording #78618866866 Logs
UpdateProjectChannelToStable_CSharpEmptyAppHost_PreservesAspireConfigChannel Recording #78618867115 Logs
UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel Recording #78618867115 Logs
UpdateProjectChannelToStable_TypeScriptSingleFileInit_PreservesAspireConfigChannel Recording #78618867115 Logs
UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel Recording #78618867115 Logs

📹 Recordings uploaded automatically from CI run #26661737572

@davidfowl davidfowl merged commit 11bea2e into release/13.4 May 30, 2026
617 of 620 checks passed
@davidfowl davidfowl deleted the backport/pr-17631-to-release/13.4 branch May 30, 2026 03:48
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.4 milestone May 30, 2026
aspire-repo-bot Bot added a commit to microsoft/aspire.dev that referenced this pull request May 30, 2026
Documents the aspire ls command which discovers and lists AppHost
project candidates, including:
- Table and JSON output formats
- Streaming mode (--format json --stream) and its ordering behavior
- The --all flag for including all candidates
- Configuration file path validation error messages

Fixes noted in microsoft/aspire#17688 (backport of fixes L1-L5):
- Stream output is emitted in arrival order (not sorted); non-streaming
  JSON output is sorted by path
- Guidance on sorting streamed output with jq

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aspire-repo-bot
Copy link
Copy Markdown
Contributor Author

Pull request created: #1134

Generated by PR Documentation Check

@aspire-repo-bot
Copy link
Copy Markdown
Contributor Author

📝 Documentation has been drafted in microsoft/aspire.dev#1134 targeting release/13.4.

Created a new aspire ls command reference page on microsoft/aspire.dev targeting release/13.4. The page documents the command's table and JSON output formats, streaming mode ordering behavior (arrival order, not sorted — fixed by this PR), --all flag, and configuration path validation. The sidebar entry was also added.

Files changed:

  • src/frontend/src/content/docs/reference/cli/commands/aspire-ls.mdx (new)
  • src/frontend/config/sidebar/reference.topics.ts (updated — added aspire ls entry)

Note

This draft PR needs human review before merging.

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

Labels

NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants