Skip to content

Clarify Aspire update notification#17366

Draft
DamianEdwards wants to merge 3 commits into
mainfrom
damianedwards/update-shutdown-message
Draft

Clarify Aspire update notification#17366
DamianEdwards wants to merge 3 commits into
mainfrom
damianedwards/update-shutdown-message

Conversation

@DamianEdwards
Copy link
Copy Markdown
Member

Description

The shutdown update notification currently only says to run aspire update, which can make it unclear whether users are updating the AppHost or the CLI binary. This clarifies the notification so users see separate guidance for updating the AppHost and updating the Aspire CLI.

User-facing usage

When an aspire run session ends and an Aspire update is available, the notification now distinguishes the commands:

A new version of Aspire is available: 13.3.4
To update this AppHost, run: aspire update
To update the Aspire CLI, run: aspire update --self
For more information, see: https://aka.ms/aspire/update

The fallback standalone CLI update recommendation now uses aspire update --self, while dotnet tool installs still show their appropriate dotnet tool update ... command.

Validation

  • ./restore.cmd
  • dotnet build /t:UpdateXlf ./src/Aspire.Cli/Aspire.Cli.csproj
  • dotnet test --project ./tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.ConsoleInteractionServiceTests" --filter-class "*.CliUpdateNotificationServiceTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"

Fixes # (issue)

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

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

github-actions Bot commented May 21, 2026

🚀 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 -- 17366

Or

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

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.

Pull request overview

This PR clarifies the Aspire CLI “update available” shutdown banner by separating guidance for updating the AppHost (project packages) vs updating the Aspire CLI binary itself, reducing ambiguity for users.

Changes:

  • Updates the notification text to always include an AppHost update instruction (aspire update) plus a separate CLI update instruction (from detection/fallback).
  • Changes the standalone/non-dotnet-tool fallback recommendation from aspire update to aspire update --self.
  • Updates unit tests and localization resources to reflect the new wording and commands.

Reviewed changes

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

Show a summary per file
File Description
tests/Aspire.Cli.Tests/Utils/CliUpdateNotificationServiceTests.cs Updates test expectations to use aspire update --self for standalone archive installs.
tests/Aspire.Cli.Tests/Interaction/ConsoleInteractionServiceTests.cs Updates notification output assertions to expect separate AppHost vs CLI guidance and to validate markup escaping with the new command.
src/Aspire.Cli/Utils/CliUpdateNotifier.cs Changes the non-dotnet-tool fallback update command to aspire update --self.
src/Aspire.Cli/Interaction/ConsoleInteractionService.cs Updates the displayed notification to show distinct AppHost and CLI update lines.
src/Aspire.Cli/Resources/InteractionServiceStrings.resx Replaces the single “To update” string with separate AppHost and CLI update string resources.
src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs Updates generated resource accessors to match the new resource keys.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.cs.xlf Adds new trans-units for AppHost/CLI update lines and removes the old combined one.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.de.xlf Same as above for de.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.es.xlf Same as above for es.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.fr.xlf Same as above for fr.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.it.xlf Same as above for it.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ja.xlf Same as above for ja.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ko.xlf Same as above for ko.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pl.xlf Same as above for pl.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.pt-BR.xlf Same as above for pt-BR.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.ru.xlf Same as above for ru.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.tr.xlf Same as above for tr.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hans.xlf Same as above for zh-Hans.
src/Aspire.Cli/Resources/xlf/InteractionServiceStrings.zh-Hant.xlf Same as above for zh-Hant.
Files not reviewed (1)
  • src/Aspire.Cli/Resources/InteractionServiceStrings.Designer.cs: Language not supported

Comment thread src/Aspire.Cli/Interaction/ConsoleInteractionService.cs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@adamint adamint left a comment

Choose a reason for hiding this comment

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

Approved, consider comments

_errorConsole.MarkupLine(string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.ToUpdateCliRunCommand, updateCommand.EscapeMarkup()));
}

_errorConsole.MarkupLine(string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.MoreInfoNewCliVersion, MarkupHelpers.SafeLink(this, UpdateUrl)));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Append this to the end of "A new version of.."? 4 lines is visually heavy.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated. The AppHost guidance is now appended to the version line as (use aspire update for this AppHost), so the AppHost case is three lines instead of four.

<data name="ToUpdateRunCommand" xml:space="preserve">
<value>[dim]To update, run: {0}[/]</value>
<data name="ToUpdateAppHostRunCommand" xml:space="preserve">
<value>[dim]To update this AppHost, run: {0}[/]</value>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
<value>[dim]To update this AppHost, run: {0}[/]</value>
<value>[dim]To update this AppHost, use: {0}[/]</value>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the AppHost wording to use use instead of
un.

<comment>Do not translate [dim]. Also leave [/] as-is. {0} is the command to run</comment>
</data>
<data name="ToUpdateCliRunCommand" xml:space="preserve">
<value>[dim]To update the Aspire CLI, run: {0}[/]</value>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
<value>[dim]To update the Aspire CLI, run: {0}[/]</value>
<value>[dim]To update the Aspire CLI, use: {0}[/]</value>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the CLI wording to use use instead of
un.

private static readonly TimeSpan s_detachedStartupStabilityWindow = TimeSpan.FromSeconds(2);

protected override bool UpdateNotificationsEnabled => !_isDetachMode;
protected override bool IncludeAppHostUpdateCommandInUpdateNotification => _hasAppHostContext;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also add to StartCommand?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added this for start too. AppHostLauncher now reports when it has selected an AppHost, so start includes the AppHost guidance only after that context is known.

Comment on lines +702 to +705
if (includeAppHostUpdateCommand)
{
_errorConsole.MarkupLine(string.Format(CultureInfo.CurrentCulture, InteractionServiceStrings.ToUpdateAppHostRunCommand, "aspire update"));
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will only display if the CLI is out of date. And it will display if the CLI is out of date and the app host is up to date.

Really there should be seperate checks for the CLI version and app host version, and then the correct notifications are displayed based on each result.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yep ideally they'd be separate checks, but today we always ship them together. Today it won't display if the CLI is up to date but the apphost is not IIUC. I think this is a good incremental improvement though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can get the app host version from the backchannel. It's displayed in aspire ps. We should be able to get it from the app host and compare it with either the installed version of the CLI. Only comparing it with the installed version makes sense because aspire update won't do anything if there is a newer version of the CLI until it is installed.

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

CLI E2E Tests unknown — 95 passed, 0 failed, 5 unknown (commit d9c96ba)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View recording
AddPackageWhileAppHostRunningDetached ▶️ View recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View recording
AgentInitCommand_DefaultSelection_InstallsDefaultSkills ▶️ View recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View recording
AgentMcpListStructuredLogsFromStarterAppCore ▶️ View recording
AllPublishMethodsBuildDockerImages ▶️ View recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View recording
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles ▶️ View recording
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive ▶️ View recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View recording
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent ▶️ View recording
Banner_DisplayedOnFirstRun ▶️ View recording
Banner_DisplayedWithExplicitFlag ▶️ View recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View recording
CertificatesClean_RemovesCertificates ▶️ View recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View recording
CreateAndRunAspireStarterProject ▶️ View recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View recording
CreateAndRunEmptyAppHostProject ▶️ View recording
CreateAndRunJavaEmptyAppHostProject ▶️ View recording
CreateAndRunJsReactProject ▶️ View recording
CreateAndRunPythonReactProject ▶️ View recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View recording
CreateAndRunTypeScriptStarterProject ▶️ View recording
CreateJavaAppHostWithViteApp ▶️ View recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View recording
DashboardRunWithAgentMcpCore ▶️ View recording
DashboardRunWithOtelTracesReturnsNoTracesCore ▶️ View recording
DeployK8sBasicApiService ▶️ View recording
DeployK8sWithExternalHelmChart ▶️ View recording
DeployK8sWithGarnet ▶️ View recording
DeployK8sWithMongoDB ▶️ View recording
DeployK8sWithMySql ▶️ View recording
DeployK8sWithPostgres ▶️ View recording
DeployK8sWithRabbitMQ ▶️ View recording
DeployK8sWithRedis ▶️ View recording
DeployK8sWithSqlServer ▶️ View recording
DeployK8sWithValkey ▶️ View recording
DeployTypeScriptAppToKubernetes ▶️ View recording
DescribeCommandResolvesReplicaNames ▶️ View recording
DescribeCommandShowsRunningResources ▶️ View recording
DetachFormatJsonProducesValidJson ▶️ View recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View recording
DoListStepsShowsPipelineSteps ▶️ View recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View recording
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain ▶️ View recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View recording
GlobalMigration_PreservesAllValueTypes ▶️ View recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View recording
JavaScriptHostingApisRunFromTypeScriptAppHost ▶️ View recording
LatestCliCanStartStableChannelAppHost ▶️ View recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View recording
LogLevelTrace_ProducesTraceEntriesInCliLogFile ▶️ View recording
LogsCommandShowsResourceLogs ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterAppIsolated ▶️ View recording
PsCommandListsRunningAppHost ▶️ View recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View recording
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts ▶️ View recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View recording
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries ▶️ View recording
ResourceCommand_FailsWhenInteractionServiceIsRequired ▶️ View recording
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput ▶️ View recording
RestoreGeneratesSdkFiles ▶️ View recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View recording
RunPublishFailureScenarioAsync ▶️ View recording
RunReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
RunReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
SecretCrudOnDotNetAppHost ▶️ View recording
SecretCrudOnTypeScriptAppHost ▶️ View recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View recording
StartReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
StartReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
StopAllAppHostsFromAppHostDirectory ▶️ View recording
StopJavaPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopNonInteractiveSingleAppHost ▶️ View recording
StopTypeScriptPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View recording
UpdateProjectChannelToStable_TypeScript_PicksUpStablePackages ▶️ View recording

📹 Recordings uploaded automatically from CI run #26260499367

@DamianEdwards DamianEdwards marked this pull request as draft May 22, 2026 00:57
@DamianEdwards
Copy link
Copy Markdown
Member Author

Moving this to draft while we clarify some things.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants