Background
#16652 (PR #16717) makes the synthesized staging channel refuse to load when the running CLI is a daily/CI build, surfacing GetStagingChannelUnavailableReason() to explain why. After validating that fix in conjunction with PR #16716 ("Honor configured channel in 'aspire update'"), two gaps remain.
Gap 1: aspire update --self (and the post-project-update CLI prompt) bypass the friendly error
UpdateCommand.ExecuteSelfUpdateAsync (src/Aspire.Cli/Commands/UpdateCommand.cs:303) calls _cliDownloader!.DownloadLatestCliAsync(channel, cancellationToken) directly without consulting PackagingService.GetStagingChannelUnavailableReason() first. Result: when a daily/PR/CI CLI has channel = staging configured, the user gets:
❌ Failed to update CLI: Unsupported channel 'staging'. Available channels: …
(thrown by CliDownloader.cs:39) instead of the friendly explanation that BuildChannelNotFoundMessage produces for the project-update flow.
Repro
- Build/install a PR or daily Aspire CLI (e.g.
13.4.0-pr.NNNNN.gXXXXXXXX).
aspire config set channel staging --global
aspire update --self → unfriendly error.
Suggested fix
Before calling _cliDownloader.DownloadLatestCliAsync, if the resolved channel is staging, call _packagingService.GetStagingChannelUnavailableReason() and throw ChannelNotFoundException with that message — mirror the wiring already present in BuildChannelNotFoundMessage.
Gap 2: pure-local-dev CLI versions (13.4.0-dev) are not classified as daily
PackagingService.IsCliPrereleaseDailyBuild treats a version as daily only when PrereleaseIdentifiers.Count > 2. A pure local build produces 13.4.0-dev (1 identifier) and is therefore NOT caught — so CreateStagingChannel() falls through to GetStagingFeedUrl(useSharedFeed:false), which silently returns null because local-dev versions have no +commitHash either. The channel is dropped without a logged warning.
Repro
- Build the CLI locally with no
OfficialBuildId and no PR VersionSuffix.
aspire config set channel staging --global (with features.stagingChannelEnabled on).
aspire update → Unsupported channel 'staging' with no explanation.
Suggested fix
Treat any prerelease that is not a "blessed" shape (preview.N, rc.N, alpha, beta) as a daily/local build. Concretely: change IsCliPrereleaseDailyBuild from Count > 2 to "any prerelease whose first identifier is not in {preview, rc, alpha, beta}", or add a separate IsCliLocalDevBuild clause.
Suggested test additions
Add InlineData cases to PackagingServiceTests.IsCliPrereleaseDailyBuild_HeuristicProducesExpectedResult:
[InlineData("13.4.0-pr.16716.ge3bf5815", true)] — PR-build shape produced by ci.yml
[InlineData("13.4.0-dev", true)] — pure local dev (after fix)
Related
Background
#16652 (PR #16717) makes the synthesized
stagingchannel refuse to load when the running CLI is a daily/CI build, surfacingGetStagingChannelUnavailableReason()to explain why. After validating that fix in conjunction with PR #16716 ("Honor configured channel in 'aspire update'"), two gaps remain.Gap 1:
aspire update --self(and the post-project-update CLI prompt) bypass the friendly errorUpdateCommand.ExecuteSelfUpdateAsync(src/Aspire.Cli/Commands/UpdateCommand.cs:303) calls_cliDownloader!.DownloadLatestCliAsync(channel, cancellationToken)directly without consultingPackagingService.GetStagingChannelUnavailableReason()first. Result: when a daily/PR/CI CLI haschannel = stagingconfigured, the user gets:(thrown by
CliDownloader.cs:39) instead of the friendly explanation thatBuildChannelNotFoundMessageproduces for the project-update flow.Repro
13.4.0-pr.NNNNN.gXXXXXXXX).aspire config set channel staging --globalaspire update --self→ unfriendly error.Suggested fix
Before calling
_cliDownloader.DownloadLatestCliAsync, if the resolved channel isstaging, call_packagingService.GetStagingChannelUnavailableReason()and throwChannelNotFoundExceptionwith that message — mirror the wiring already present inBuildChannelNotFoundMessage.Gap 2: pure-local-dev CLI versions (
13.4.0-dev) are not classified as dailyPackagingService.IsCliPrereleaseDailyBuildtreats a version as daily only whenPrereleaseIdentifiers.Count > 2. A pure local build produces13.4.0-dev(1 identifier) and is therefore NOT caught — soCreateStagingChannel()falls through toGetStagingFeedUrl(useSharedFeed:false), which silently returnsnullbecause local-dev versions have no+commitHasheither. The channel is dropped without a logged warning.Repro
OfficialBuildIdand no PRVersionSuffix.aspire config set channel staging --global(withfeatures.stagingChannelEnabledon).aspire update→Unsupported channel 'staging'with no explanation.Suggested fix
Treat any prerelease that is not a "blessed" shape (
preview.N,rc.N,alpha,beta) as a daily/local build. Concretely: changeIsCliPrereleaseDailyBuildfromCount > 2to "any prerelease whose first identifier is not in{preview, rc, alpha, beta}", or add a separateIsCliLocalDevBuildclause.Suggested test additions
Add InlineData cases to
PackagingServiceTests.IsCliPrereleaseDailyBuild_HeuristicProducesExpectedResult:[InlineData("13.4.0-pr.16716.ge3bf5815", true)]— PR-build shape produced byci.yml[InlineData("13.4.0-dev", true)]— pure local dev (after fix)Related
aspire update