Skip to content

Clarify Aspire update channel resolution#17561

Draft
danegsta wants to merge 6 commits into
mainfrom
danegsta/fix-update-channel-pin
Draft

Clarify Aspire update channel resolution#17561
danegsta wants to merge 6 commits into
mainfrom
danegsta/fix-update-channel-pin

Conversation

@danegsta
Copy link
Copy Markdown
Member

@danegsta danegsta commented May 27, 2026

Description

This change makes aspire update channel resolution easier to reason about for existing AppHosts. Missing project/global channel config now consistently means the stable/default channel, while PR dogfood CLIs still get a visible convenience default to their concrete pr-N channel when no channel is configured.

The update flow now:

  • honors explicit --channel and configured project/global channels before any dogfood behavior
  • supports --channel pr as an alias for the current PR dogfood CLI's concrete channel
  • prints a notice when a PR dogfood CLI default is applied, including the opt-out setting
  • presents channel pin changes consistently for .NET and polyglot AppHosts through a shared update-step helper

Behavior changes

Existing project state Command / CLI context Previous behavior New behavior
None aspire update from a daily CLI Could resolve the update channel from the CLI identity and update toward daily. Resolves as stable/default. Missing project channel config no longer inherits daily from the CLI install.
None aspire update from a staging CLI Could resolve the update channel from the CLI identity when staging was registered. Resolves as stable/default. Existing projects must opt into staging via config or --channel staging.
None aspire update from a PR dogfood CLI with matching pr-N channel Could silently use the CLI identity channel. Defaults to the concrete pr-N channel, but prints an explicit notice and can be disabled with update.prDogfoodDefaultChannelEnabled=false.
None aspire update with hives present but no applicable PR dogfood default Could prompt for channel selection based on available hives. Resolves as stable/default without prompting. Use --channel to intentionally move to a hive or other channel.
Existing "channel": "daily" aspire update --channel stable Version resolution could use stable while later restore/regeneration still saw the daily pin. Shows aspire.config.json#channel daily to stable, clears the persisted channel if accepted, and restore/regeneration use the selected stable/default channel.
Any project state aspire update --channel pr from a PR dogfood CLI Required knowing and typing the concrete pr-N channel. Resolves to the current CLI's concrete PR channel.

User-facing usage

Existing projects without aspire.config.json#channel resolve as stable/default unless a PR dogfood CLI default applies:

aspire update

PR dogfood CLI users can explicitly target the current PR channel:

aspire update --channel pr

Users can disable the PR dogfood default with:

aspire config set update.prDogfoodDefaultChannelEnabled false -g

When a channel pin changes, both .NET and polyglot AppHosts show an explicit update step before confirmation, for example:

📦 aspire.config.json#channel daily to stable

Perform updates? [Y/n]:

Validation:

  • dotnet build /t:UpdateXlf src/Aspire.Cli/Aspire.Cli.csproj --no-restore --verbosity minimal
  • dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-launch-profile -- --filter-class "*.UpdateCommandTests" --filter-class "*.GuestAppHostProjectTests" --filter-class "*.ProjectUpdaterTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"
  • Manual smoke tests for .NET and polyglot AppHosts changing daily to stable.

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

Treat missing project channel configuration as the stable/default channel for existing app hosts, while preserving explicit PR dogfood defaulting with visible CLI output and an opt-out setting.

Share channel update step formatting across .NET and polyglot update flows so channel changes are presented consistently before confirmation.

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

github-actions Bot commented May 27, 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 -- 17561

Or

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

danegsta and others added 2 commits May 27, 2026 14:53
Use the shared channel persistence rule when scaffolding projects so stable remains represented by an absent channel while non-stable explicit channels are still pinned.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a regression test that PR dogfood identity does not change the prompt-based channel selection behavior for aspire update --self.

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

CLI E2E Tests unknown — 34 passed, 0 failed, 50 unknown (commit af6d5cc)

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
AgentMcpListStructuredLogsReturnsLogsFromStarterApp ▶️ View recording
AgentMcpListStructuredLogsReturnsLogsFromStarterApp_DevLocalhost ▶️ View recording
AllPublishMethodsBuildDockerImages ▶️ View recording
AspireAddAndStartWorkAgainstLegacyAppHostTs ▶️ View recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View recording
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles ▶️ View recording
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive ▶️ View recording
AspireStartUpdatesStaleTypeScriptAppHostPath ▶️ 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
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
DashboardRunWithAgentMcpListTracesReturnsNoTraces_DevLocalhost ▶️ View recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View recording
DashboardRunWithOtelTracesReturnsNoTraces_DevLocalhost ▶️ View recording
DeployK8sBasicApiService ▶️ View recording
DeployK8sWithExternalHelmChart ▶️ View recording
DeployK8sWithGarnet ▶️ View recording
DeployK8sWithMongoDB ▶️ View recording
DeployK8sWithPostgres ▶️ 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
DoPublishAndDeployListStepsWork ▶️ View recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View recording
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain ▶️ View recording
IngressWithoutExternalEndpoint_FailsPublishWithGuidance ▶️ View recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View recording
JavaScriptHostingApisRunFromTypeScriptAppHost ▶️ View recording
LatestCliCanStartStableChannelAppHost ▶️ View recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View recording
LogsCommandShowsResourceLogs ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterAppIsolated ▶️ View recording
PsCommandListsRunningAppHost ▶️ View recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View recording
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries ▶️ View recording
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput ▶️ View recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ 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
StopNonInteractiveSingleAppHost ▶️ View recording
StopTypeScriptPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View recording
UpdateProjectChannelToStable_CSharpSingleFileInit_PreservesAspireConfigChannel ▶️ View recording
UpdateProjectChannelToStable_TypeScript_PreviewsStablePackagesAndPreservesChannel ▶️ View recording

📹 Recordings uploaded automatically from CI run #26540139192

danegsta and others added 3 commits May 27, 2026 15:12
The new channel-resolution model treats an explicit '--channel stable' against
a project pinned to a non-stable channel as a request to change the project's
pinned channel. The preview now surfaces an 'aspire.config.json#channel' change
step alongside any package updates.

Update ChannelUpdateWorkflowTests to assert that the preview includes the
channel-change line (flipping the previous regression-guard assertion), and
refresh class-level documentation and the deep TypeScript test's step
comments to describe the new invariant. Declining the preview still leaves
the on-disk channel value unchanged, so the existing preservation checks
remain valid.

Drop the stale 'aspire update --self saves the channel to global settings'
description and the 'simulating what update --self does' Step 5 comment from
StagingChannelTests — the test exercises only 'aspire config set' and the
self-update path no longer writes channel to global config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Commit 85d9591 stopped scaffolding from stamping 'stable' into
aspire.config.json#channel (the new model treats absent as stable).
NewCommand_NoChannelArg_ResolvesTemplateFromIdentityChannel was still
asserting the old behavior where TemplateInputs.Channel was always set
to the identity channel name, so the stable inline-data case began
failing in CI with 'Expected stable, Actual null'.

Add a third theory parameter for the expected persisted channel value
(null for stable, identity for non-stable) and document why in a
remarks block. The daily inline-data case continues to assert the
identity is passed through.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant