Auto-register staging channel for staging CLI#17155
Merged
radical merged 9 commits intoMay 18, 2026
Merged
Conversation
A staging-identity Aspire CLI previously did not register the staging package channel unless users also enabled the staging feature flag or configured channel=staging. That caused channel-aware commands such as aspire new to fall back to the implicit package source instead of using staging by default. Register staging when the running CLI identity is staging, and preserve explicit stable walk-back for guest projects even when package versions are already current. Add regression coverage for new project channel persistence, add/search mixed CLI routes, guest update walk-back, and NuGet.config remapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17155Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17155" |
When staging is selected by the running CLI identity or project configuration, default the staging package channel to Both quality so prerelease staging packages are not filtered out by stable-only package searches. Preserve the existing stable default for the feature-flag-only staging path and the stable fallback for invalid quality overrides. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes #17121 so a CLI built with AspireCliChannel=staging automatically registers the staging package channel, and ensures channel pins persist correctly when users explicitly walk back to stable.
Changes:
PackagingService.GetChannelsAsyncnow also registers the staging channel whenCliExecutionContext.IdentityChannel == "staging"or whenconfiguration["channel"] == "staging", with quality defaulting toBoth(while keeping the safeStablefallback for invalid override values).GuestAppHostProject.UpdatePackagesAsyncpersists an explicit channel name even when no package updates are needed, soaspire update --channel stablefrom a staging-pinned project actually rewritesaspire.config.json#channel.KnownFeatures.IsStagingChannelEnabledremarks updated to remove the now-obsolete "by design, identity does not enable staging" wording.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/Aspire.Cli/Packaging/PackagingService.cs | Adds identity-channel trigger for staging registration; threads default-quality into CreateStagingChannel/GetStagingQuality. |
| src/Aspire.Cli/KnownFeatures.cs | Updates the staging-channel remarks to reflect that callers now combine the helper with an identity check. |
| src/Aspire.Cli/Projects/GuestAppHostProject.cs | Persists explicit channel on the up-to-date path; reports UpdatesApplied=true when only the channel pin changes. |
| tests/Aspire.Cli.Tests/Packaging/PackagingServiceTests.cs | New tests for staging-identity registration and config-channel quality/feed defaults. |
| tests/Aspire.Cli.Tests/Packaging/NuGetConfigMergerTests.cs | New test for remapping Aspire.* from staging source to stable source. |
| tests/Aspire.Cli.Tests/Commands/NewCommandChannelResolutionTests.cs | Flips staging-identity expectation from "fall back to Implicit" to "resolve from staging". |
| tests/Aspire.Cli.Tests/Commands/NewCommandTemplateConfigPersistenceTests.cs | Updates staging-identity test to assert channel: staging pinning. |
| tests/Aspire.Cli.Tests/Commands/AddCommandTests.cs | Adds coverage for staging-pinned project under stable CLI and unpinned project under staging CLI. |
| tests/Aspire.Cli.Tests/Projects/GuestAppHostProjectTests.cs | Adds tests for persisting channel: stable on explicit walk-back, both with and without package changes. |
origin/main moved CLI exit codes to CliExitCodes. Update the staging-channel add/search assertions added on this branch to use the current type after merging main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover the combined origin/main update identity fallback and this branch's staging channel registration so an unpinned project updated by a staging CLI resolves the staging channel instead of the implicit/default channel. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thread requested channel names into PackagingService so stable CLI invocations can materialize staging when --channel or project-local config resolved staging outside the launch directory. Also expose staging in help and self-update prompts for staging-identity CLIs, and refresh the guest update channel persistence comment after the update identity fallback change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover the staging-specific scenarios from the route-crossing analysis: explicit staging update persistence for guest AppHosts, staging NuGet.config materialization for C# empty templates, and project-local staging restore for prebuilt guest AppHosts outside the launch directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a regression test that exercises and verifies a fresh CLI service provider reads the persisted global value when materializing the staging package channel. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mitchdenny
approved these changes
May 18, 2026
Seed overrideStagingFeed through config set -g, then build a fresh provider before running aspire new so the C# template NuGet.config coverage exercises the persisted global setting instead of direct configuration injection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8 tasks
mitchdenny
added a commit
that referenced
this pull request
May 19, 2026
* Refuse 'staging' channel synthesis on daily/local/pr CLI builds Fixes #16652. PackagingService synthesized the 'staging' channel from the running CLI's build context: a stable-quality staging used a SHA-specific darc feed built from the CLI commit, and a Prerelease/Both staging without an override fell back to the shared daily feed. On a daily, local, or per-PR CLI neither produces a real staging feed, so 'aspire update --channel staging' silently resolved to daily package versions. Gate staging synthesis on the CLI's baked identity (CliExecutionContext. IdentityChannel from [AssemblyMetadata("AspireCliChannel", ...)]): - stable: SHA-specific darc-pub-microsoft-aspire-<hash> feed exists. - staging: dogfoods staging packages (per #17155). - daily, local, pr-<N>: refuse and surface a localized reason that names the running identity and points at 'overrideStagingFeed' or installing a staging CLI as recovery paths. Escape hatches preserved: - 'overrideStagingFeed' configuration always allows synthesis. - 'StagingChannelEnabled' feature flag continues to opt in for dev/test. UpdateCommand surfaces the packaging-service reason when --channel staging is requested but refused, instead of the generic 'No channel found matching staging' message that hid the actual fix. When staging IS synthesized, log the resolved feed URL, quality, and pinned version at Information so users can see what '--channel staging' actually selected (the 'show what was resolved' suggestion from the issue RCA). Adds IPackagingService.GetStagingChannelUnavailableReason() and a matching member on TestPackagingService that defaults to reporting staging as available so existing tests stay unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: cache staging reason, log once, surface in NewCommand - Cache GetStagingChannelUnavailableReason via Lazy<string?> so the formatted reason is computed once per process instead of on every GetChannelsAsync call. - Emit the refusal warning and resolved-staging info log at most once per process using Interlocked.Exchange flags. Many code paths invoke GetChannelsAsync repeatedly (NewCommand, IntegrationPackageSearchService, NuGetPackagePrefetcher, etc.); without this, a daily CLI with channel: staging pinned in aspire.config.json would spam the warning on every command. - Surface the staging-specific reason in NewCommand's error path so users scaffolding a project with channel: staging configured get the same actionable message UpdateCommand now produces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Refuse staging channel in PrebuiltAppHostServer on daily/local/pr CLIs Addresses radical's review feedback on #17235. PrebuiltAppHostServer (and any sibling paths) previously treated a missing requested channel as a fallback to "all explicit channels", which silently restored integration packages from the shared daily feed even when the project pinned channel: staging. Refuse those calls with the same actionable GetStagingChannelUnavailableReason() the UpdateCommand/NewCommand paths now use, so the silent-downgrade hole this PR is meant to close is closed for the bundled AppHost restore path too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add isolated feature-flag assertion to staging-channel gate test Addresses JamesNK's review feedback on #17235. The original feature-flag test set overrideStagingFeed for the test-host workaround, which short-circuited IsStagingChannelSynthesisAllowed before the feature-flag branch ever ran. Add a separate assertion that exercises GetStagingChannelUnavailableReason() on a service whose only opt-in is the StagingChannelEnabled feature flag, so a regression that removes the feature-flag branch would now be caught. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Localize remaining inline channel-resolution errors in NewCommand Addresses JamesNK's review feedback on #17235. The two remaining inline English literals in NewCommand.ResolveCliTemplateVersionAsync ("No package channels are available." and "No channel found matching '{0}'. Valid options are: {1}.") are now sourced from the resource file the same way the staging-unavailable message already is, so all three failure paths are localizable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add StringComparisons.ChannelName and use it for channel-name comparisons Addresses JamesNK's review feedback on #17235. Introduces a small StringComparisons helper so the canonical case-insensitive comparison rule for package-channel names lives in one place, and switches the existing call sites in PackagingService, UpdateCommand, NewCommand, PrebuiltAppHostServer, and KnownFeatures from raw StringComparison.OrdinalIgnoreCase to StringComparisons.ChannelName. Behaviour is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify cached staging-unavailable reason in PackagingService The previous code lazily allocated a Lazy<T> via Interlocked.CompareExchange, which is redundant since Lazy<T> already provides thread-safe one-time initialization. Construct the Lazy eagerly in the constructor and let it do the deferral, per JamesNK's review on #17235. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Localize "no channel found matching" error in UpdateCommand Mirrors the same resource extraction that was done for NewCommand earlier in this PR. Adds NoChannelFoundMatching to UpdateCommandStrings.resx + Designer, regenerates xlf for all locales, and switches the ChannelNotFoundException construction site to string.Format against the resource. Per JamesNK on #17235. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Extract overrideStagingFeed config key to a named constant Per JamesNK on #17235: replace the duplicated "overrideStagingFeed" literal in PackagingService (and the test fixtures) with PackagingService.OverrideStagingFeedConfigKey so a single source of truth governs the configuration name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: midenn <midenn@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Mitch Denny <midenn@orangecake.localdomain>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #17121
A CLI binary built with the
stagingidentity did not automatically register the staging package channel. That meant channel-aware commands such asaspire newcould fall back to the implicit/default package source unless users also configuredchannel: stagingor enabled the staging feature flag.This change registers the staging package channel when the running CLI identity is
staging, when project configuration requestschannel: staging, or when a command explicitly requests the staging channel. Staging channel materialization now uses prerelease-capable package quality by default for identity/config/requested staging so staging builds can resolve staging packages correctly.The change also preserves explicit channel precedence and makes mixed CLI routes safer:
channel: staging--apphostpoints outside the launch directoryaspire update --channel stablepersists the stable channel for guest projects even when package versions are already currentaspire config set -g overrideStagingFeed <url>is honored by later CLI invocations and flows into generated NuGet.config for staging C# template creationUser-facing usage
No new command syntax is required. Existing commands now honor the staging CLI identity automatically:
When run from a staging CLI build, channel-pinning templates resolve from the registered staging channel and persist:
{ "channel": "staging" }Users can still override the staging package feed globally:
aspire config set -g overrideStagingFeed https://example.com/nuget/v3/index.jsonUsers can still walk back explicitly:
Validation:
Checklist
<remarks />and<code />elements on your triple slash comments?