Route staging-identity CLI to its darc feed regardless of version shape#17743
Conversation
The synthesized `staging` package channel derived its feed from the CLI build's version shape: a prerelease-shaped staging build (e.g. 13.4.0-preview.1.26280.6) routed Aspire.* to the shared dnceng/dotnet9 daily feed instead of its SHA-specific darc-pub-microsoft-aspire-<commit> feed. C# apphosts masked this because the darc feed is baked into their nuget.config, but polyglot (TypeScript) apphosts resolve solely through the channel's feed, so `aspire add <pkg>` offered the wrong versions. Decouple feed provenance (identity) from version filtering (quality): - Add `ShouldUseSharedStagingFeed(...)`: a staging-identity CLI always uses its own darc feed, any version shape. Override feeds and non-staging identities keep the prior quality-based routing. - Add an injectable `cliInformationalVersionProvider` constructor seam so the derived darc feed URL is deterministic and assertable in tests. - Correct the comments that incorrectly claimed darc feeds only exist for stable-shaped builds. Add tests covering prerelease-shaped staging -> darc, stable-shaped staging -> darc, and override-wins. The prerelease repro fails before the fix (resolves dotnet9) and passes after (resolves darc). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17743Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17743" |
Adds a decision-table theory across PR/daily/staging/stable channel configurations, drops the override-feed crutch from the staging-identity tests so they assert the real darc feed via an injected version seam, adds coverage for the underivable-feed warning path, and adds symmetry asserts for the stable-shaped staging case. Also logs a one-time warning in CreateStagingChannel when a staging channel is permitted but no staging feed URL can be derived, so the channel is omitted visibly instead of silently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds two PackagingService-scoped diagnostic config overrides so a locally built CLI (baked identity 'local', unstamped version) can simulate a staging build and validate end-to-end that 'aspire add' resolves Aspire.* from the correct SHA-specific darc-pub-microsoft-aspire-<sha> feed: - overrideCliIdentityChannel: forces the identity used for staging-feed routing decisions only (validated via IdentityChannelReader.IsValidChannel; invalid values ignored). Does not change the global identity used for hive/packages-directory lookups, keeping blast radius limited. - overrideCliInformationalVersion: forces the version that both the SHA derivation and the stable-shape/quality predicate read. All staging-feed decision points now route through GetEffectiveIdentityChannel. A one-time warning is emitted whenever either override is active. Adds docs/cli-staging-validation.md with the local-validation recipe and nine PackagingServiceTests covering the override permutations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d routing
Add eng/scripts/debug-staging.{sh,ps1} and debug-stable.{sh,ps1} (plus the
shared debug-aspire-channel core) that make an easy-to-get build (an installed
PR build or a local build) resolve Aspire.* packages exactly like an official
staging or stable release-branch build, so the feed-routing fix can be
validated end-to-end.
Each script targets identity 'staging' and the SHA-specific
darc-pub-microsoft-aspire-<sha8> feed, differing only in version shape/quality
(staging => prerelease/Both, #17744; stable => stable/Stable, #17527). Modes:
- default: one-shot 'aspire add --debug' that asserts the darc feed resolves.
- --print-env / -PrintEnv: emit export/$env lines to apply to the current shell.
- --shell / -Shell: interactive subshell with overrides applied and the target
CLI first on PATH, for a full 'aspire new'/'add'/run flow; overrides vanish on exit.
Extend docs/cli-staging-validation.md with the helper-script usage, the
interactive PR-build recipe, and a validation matrix; link it from
docs/contributing.md.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Re-running the failed jobs in the CI workflow for this pull request because 5 jobs were identified as retry-safe transient failures in the CI run attempt.
Matched test failure patterns (1 test)
|
When dropping into the interactive subshell (--shell / -Shell), point NUGET_PACKAGES at an isolated, per-sha directory so packages restored from the simulated staging darc feed can never contaminate the developer's real global package cache. Also commit the staging-override NOTE clarifying the overrides route to but do not create a feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The staging identity now always routes to its build's SHA-specific darc-pub-microsoft-aspire-<sha> feed regardless of version shape, so the feed must be derivable from the CLI's +<commit> informational version. The test host assembly has no commit metadata, so the staging channel could not be synthesized and the test regressed. Stamp a staging-shaped informational version via the overrideCliInformationalVersion config so the derivation matches a real staging build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
Matched test failure patterns (1 test)
|
|
❌ CLI E2E Tests failed — 109 passed, 1 failed, 2 unknown (commit ❌ Failed Tests
View all recordings
📹 Recordings uploaded automatically from CI run #26708726647 |
|
✅ No documentation update needed. docs_optional → bug_fix_restores_documented_behavior Triggered signals (1): Why no docs PR is needed: The PR is a bug fix that makes |
Polyglot apphosts (TS/Python/Go) deliberately don't carry a persistent NuGet.config — that file is a .NET-ism. Restore is done via on-the-fly `TemporaryNuGetConfig`s built from `aspire.config.json#channel` (see `PrebuiltAppHostServer.CreatePackageSourceOverrideNuGetConfigAsync`). The IntegrationPackageSearchService was unconditionally including the Implicit channel whenever the apphost had a pin, even for polyglot. Because polyglot has no project-local NuGet.config, Implicit's `dotnet package search` ran against the user's ambient (typically nuget.org) and surfaced stale/wrong-feed versions alongside the pinned channel's versions. This produced the spurious 'select version' prompt the user reported on TS apphosts pinned to staging (#17743), and also added 'staging' / 'daily' rows to stable packages like azure-appcontainers. Fix: when a polyglot apphost has a pin, search ONLY the pinned channel. The pinned channel materializes its own TemporaryNuGetConfig from its PSM mappings, so it's correctly scoped. This matches C# end-to-end: C#'s `GetConfiguredChannel` returns null, so IPSS runs Implicit against the C# template's project-local NuGet.config (which IS correctly scoped because the C# template writes one). Trade-off knowingly accepted: a stable-pinned polyglot apphost cannot reach prerelease-only packages (e.g. Foundry). This matches C# behavior — a stable-pinned C# project also wouldn't see them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Brings 43 release-branch commits forward onto main now that 13.4.0 has shipped. This PR replaces the original automated merge (microsoft#17804) which had to be closed so that conflict resolution and post-merge cleanups could be made on a non-protected branch. Conflict resolution summary (33 files): * Equivalent backports (took main's commit identity): ChannelUpdateWorkflowTests, LoggingHelpersTests, the four extension test files, AspireEditorCommandProvider, appHostDiscovery. * Release-only forwards (preserved): microsoft#17732 / microsoft#17756 Foundry hosted-agent protocol selection and cross-compute-environment endpoint references, microsoft#17573 stabilize PrebuiltAppHostServer staging globalPackagesFolder path, microsoft#17743 staging-identity CLI darc feed routing. * Main-only forwards (preserved): microsoft#17506 Show discovered AppHosts in Aspire pane, microsoft#17547 Localize Aspire skills metadata errors, microsoft#17801 VS Code v1.12.0, microsoft#17297 Aspire CLI npm package release integration, microsoft#17576 TerminalRun IAsyncDisposable, microsoft#17721 / microsoft#17723 VS Code telemetry, microsoft#17671 ATS baseline fix (re-applied manually on top of Foundry source taken from release). * Hybrid (manually spliced): docs/contributing.md - kept main's restructured layout and inserted release's staging-validation paragraph; HostedAgentBuilder- Extension - took release base then re-applied microsoft#17671 asHostedAgent rename; UpdateCommandTests - took main and injected microsoft#17743's OverrideCliInformationalVersionConfigKey block. Post-merge cleanups included in this PR: * eng/Versions.props: revert StabilizePackageVersion to false (was flipped to true on release/13.4 by microsoft#17520 for shipping 13.4.0; main must stay in preview mode). * .github/workflows/generate-api-diffs.yml: retarget back to main (was pointed at release/13.4 by microsoft#17696 release prep). * .github/workflows/backmerge-release.yml: update from release/13.3 to release/13.4 (was stale - missed the 13.4 release-time bump). * .github/workflows/milestone-assignment.yml: audited - already correct (main -> 13.5, release/13.4 -> 13.4.x); no change. This merge commit must be preserved - do not squash on merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Problem
On a staging build of Aspire,
aspire add <pkg>behaves differently between C# and TypeScript (polyglot) apphosts:The TypeScript path never offers the matching staging version because the synthesized
stagingchannel routesAspire*to the shareddnceng/dotnet9daily feed instead of the build's own SHA-specificdarc-pub-microsoft-aspire-<commit>feed.Root cause
In
PackagingService.CreateStagingChannel,useSharedFeedwas derived from the CLI build's version shape:A prerelease-shaped staging build (e.g.
13.4.0-preview.1.26280.6) defaults toBothquality →useSharedFeed = true→ the shared daily feed (which only carries main-branch daily packages). But darc publishes a per-commitdarc-pub-microsoft-aspire-<commit>feed for every officially published release-branch build, prerelease- or stable-shaped. The old comment's assumption that "darc feeds only exist for stable builds" was wrong.C# apphosts masked the bug because the darc feed is baked into their
nuget.config(written from the channel'sPackageMappings); polyglot apphosts resolve solely through the channel's feed, so they surfaced it.Fix
Decouple feed provenance (identity) from version filtering (quality):
ShouldUseSharedStagingFeed(hasExplicitFeedOverride, stagingQuality, identityChannel): astaging-identity CLI always resolvesAspire*from its own darc feed regardless of version shape. ExplicitoverrideStagingFeedand non-staging identities keep the prior quality-based routing unchanged, so only the prerelease-shaped staging case flips.cliInformationalVersionProviderconstructor seam (mirroring the existingisStableShapedCliVersionseam) so the derived darc feed URL is deterministic and assertable in tests, instead of reading the nondeterministic test-host assembly version.Because
GetChannelsAsync→CreateStagingChannelis the single source of truth foraspire addsearch, polyglot restore, and C# nuget.config writing, fixing it here unifies the C# and TypeScript code paths.Tests
Full
PackagingServiceTestssuite: 70/70 passing. Notable additions:Aspire*source is thedarc-pub-microsoft-aspire-<hash>feed (notdotnet9),ConfigureGlobalPackagesFolder == true,PinnedVersion == null(the bug repro). Verified it fails before the fix (resolvesdotnet9) and passes after (resolves darc).Stablequality (guards Staging build of CLI bakes channel asstable, causingaspire initto drop nuget.config without staging feed (resolves wrong Aspire package versions) #17527).overrideStagingFeed→ override wins.Notes
release/13.4.ConfigureGlobalPackagesFolderbecomestrue, and the CLI-version pin (only applied on the shared feed) is no longer applied since the darc feed carries only the matching build.Relationship to #17744
#17744 reports an adjacent — but distinct — staging symptom that this PR does not fix:
13.4.0+<hash>) withchannel: staging. Its debug log showsResolved 'staging' channel: feed=<staging Aspire feed>, quality=Stable— i.e. the staging channel is already routed to the darc feed (the stable-shaped path this PR leaves unchanged). So the feed-provenance fix here has no effect on that run.aspire addpersists/reports the search-selected version (13.3.5-preview.1.26270.6, which came from the defaultbased on NuGet.configchannel) instead of the versionrestoreactually resolved (13.4.0-preview.1.26280.4). The restore log proves13.3.5-preview.1.26270.6exists on no configured feed (NuGet bumped up to the next available version), so that value is the stale catalog/default-channel candidate, not a darc-feed hit.That is a search-vs-restore version reconciliation gap (the persisted version should reflect what restore resolved), which is independent of which feed the staging channel points at. This PR is a prerequisite (the staging channel must point at the correct darc feed) but is not sufficient to close #17744; that should be tracked/fixed separately.
Validating staging feed routing locally
To make #17744 verifiable without an official build, this PR adds two PackagingService-scoped diagnostic overrides so a locally built CLI (which bakes a
localidentity and an unstamped version, and therefore never synthesizes a staging channel) can be made to behave exactly like a staging build for the purpose of staging feed-routing:overrideCliIdentityChannel— forces the identity used for staging-feed routing decisions only (validated viaIdentityChannelReader.IsValidChannel; invalid values are ignored). It does not change the global identity used for hive/packages-directory lookups, so the blast radius stays limited to feed provenance.overrideCliInformationalVersion— forces the informational version that both the SHA derivation and the stable-shape/quality predicate read (e.g.13.4.0-preview.1.26280.6+<commit>).Both overrides are required to reach the darc path from a local build, and a one-time warning is emitted whenever either is active so a normal CLI invocation can't silently resolve packages from an overridden identity/feed. The full recipe (build locally, set
channel: staging, set the two env vars, runaspire add <pkg> --debug, confirm the resolved darc feed) is documented indocs/cli-staging-validation.md.A follow-up to lift the informational-version seam onto
CliExecutionContextonmainis tracked in #17750.Helper scripts for staging/stable validation
To make the recipe one command — and to support a full interactive flow against an easy-to-get build — this PR also adds
eng/scripts/debug-staging.{sh,ps1}andeng/scripts/debug-stable.{sh,ps1}(sharing adebug-aspire-channelcore). Both target identitystagingand the SHA-specificdarc-pub-microsoft-aspire-<sha8>feed, differing only in version shape/quality:debug-stagingBothdebug-stableStableModes:
aspire add <pkg> --debugin a throwaway dir and asserts the darc feed resolves (exit non-zero otherwise).--print-env/-PrintEnv— emitsexport/$env:lines to apply to the current shell so everyaspirecommand behaves like the simulated build.--shell/-Shell— opens an interactive subshell with the overrides applied and the target CLI first onPATH, for a fullaspire new/add/run flow; overrides vanish on exit. The subshell also pointsNUGET_PACKAGESat a per-SHA isolated cache (<temp>/aspire-debug-nuget/<sha8>) so simulated-staging restores can't contaminate (or be contaminated by) the global package cache.--pr <N>installs that PR's full-bundle build first and targets it, so you can validate against a real installed CLI (not just a local source build). The interactive recipe and a per-identity validation matrix are documented indocs/cli-staging-validation.md, linked fromdocs/contributing.md.