Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .agents/skills/cli-channel-debugging/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ or `aspire doctor`'s child invocations — treat them as process-local test affo
| Env var | Effect |
|---|---|
| `ASPIRE_CLI_CHANNEL` | Identity channel: `stable`, `staging`, `daily`, `local`, or `pr-<N>`. Drives hive selection and staging-feed provenance. |
| `ASPIRE_CLI_VERSION` | Informational version (e.g. `13.5.0-preview.1.26310.9`). Drives version-shape (quality) decisions, version pins, the skew warning, and `--version` output. |
| `ASPIRE_CLI_VERSION` | Informational version (e.g. `13.5.0-preview.1.26310.9`). Drives version pins, the skew warning, and `--version` output. |
| `ASPIRE_CLI_COMMIT` | Source commit SHA. Drives the staging darc feed name (`darc-pub-microsoft-aspire-<sha8>`). |
| `ASPIRE_CLI_PACKAGES` | A flat directory of `.nupkg` files (e.g. `artifacts/packages/<Config>/Shipping`). The CLI synthesizes a package channel **named after `ASPIRE_CLI_CHANNEL`** that maps `Aspire*` to this directory (everything else → nuget.org), **replacing** any same-named built-in/discovered/PR channel. See the cleanliness caveat below. |
| `ASPIRE_CLI_NUGET_SERVICE_INDEX` | Replaces the canonical `https://api.nuget.org/v3/index.json` URL the CLI writes into **newly generated** `NuGet.config` files. Never rewrites URLs read from existing configs. |
Expand All @@ -73,7 +73,7 @@ lookups, or `--version`. Set with `aspire config set -g <key> <value>`.
| Config key | Effect |
|---|---|
| `overrideCliIdentityChannel` | Identity used for **staging-feed decisions only** (validated against the known channel set). |
| `overrideCliInformationalVersion` | Version that staging SHA-derivation and version-shape checks read. |
| `overrideCliInformationalVersion` | Informational version used to derive the staging SHA-specific feed URL. |
| `overrideStagingFeed` | Forces staging to be available and points it at an explicit feed URL. |
| `stagingPinToCliVersion` | When `true` (and using the shared feed), pins resolution to the CLI version. |

Expand Down Expand Up @@ -192,7 +192,7 @@ Reuse `instanceId`s across turns so "the daily terminal" stays the same panel th
| 3 | PR build identity + CI-built packages, local CLI | `pr-<N>` | `~/.aspire/hives/pr-<N>/packages` | `get-aspire-cli-pr.sh --pr <N>`, then `ASPIRE_CLI_CHANNEL=pr-<N>` |
| 4 | Latest daily, local CLI | `daily` | dnceng/dotnet9 daily feed | `ASPIRE_CLI_CHANNEL=daily` + `ASPIRE_CLI_VERSION` (+ `ASPIRE_CLI_COMMIT`) |
| 5 | Staging, unstable version | `staging` | `darc-pub-microsoft-aspire-<sha8>` feed (quality Both) | `ASPIRE_CLI_CHANNEL=staging` + prerelease `ASPIRE_CLI_VERSION` + `ASPIRE_CLI_COMMIT` |
| 6 | Staging, stable version | `staging` | `darc-pub-microsoft-aspire-<sha8>` feed (quality Stable) | `ASPIRE_CLI_CHANNEL=staging` + stable-shaped `ASPIRE_CLI_VERSION` + `ASPIRE_CLI_COMMIT` |
| 6 | Staging, stable version | `staging` | `darc-pub-microsoft-aspire-<sha8>` feed (quality Both) | `ASPIRE_CLI_CHANNEL=staging` + stable-shaped `ASPIRE_CLI_VERSION` + `ASPIRE_CLI_COMMIT` |
| 7 | Released build repro | `stable` | nuget.org | `ASPIRE_CLI_CHANNEL=stable` + released `ASPIRE_CLI_VERSION` |
| 7b | Released repro + CLI+hosting fix spanning packages | `stable` | locally rebuilt `Shipping` dir | as 7 + `ASPIRE_CLI_PACKAGES=<clean-rebuilt-dir>` |

Expand Down Expand Up @@ -264,13 +264,14 @@ ASPIRE_CLI_VERSION=13.4.0-preview.1.26280.6 \
ASPIRE_CLI_COMMIT=<full-commit-sha> \
dotnet run --project src/Aspire.Cli -- <cmd>

# 6 — stable-shaped version -> quality Stable (the #17527 stabilizing-build scenario)
# 6 — stable-shaped version -> quality Both (the #17527 stabilizing-build scenario)
ASPIRE_CLI_CHANNEL=staging ASPIRE_CLI_VERSION=13.4.0 ASPIRE_CLI_COMMIT=<full-commit-sha> \
dotnet run --project src/Aspire.Cli -- <cmd>
```

Staging feed provenance is derived from the commit: `darc-pub-microsoft-aspire-<sha8>`. The
version **shape** controls only which versions on that feed are eligible (Stable vs Both).
channel uses `Both` for either version shape because a stable-shaped build can still publish
prerelease-only integrations alongside stable packages.
Alternatively, `eng/scripts/debug-staging.sh` / `debug-stable.sh` exercise the same routing via
the legacy config keys — see `docs/cli-staging-validation.md`.

Expand Down
19 changes: 10 additions & 9 deletions docs/cli-staging-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ A staging-identity CLI is an official release-branch build whose own commit alwa
a SHA-specific `darc-pub-microsoft-aspire-<commit>` feed carrying its matching packages
(prerelease-shaped `13.4.0-preview.*` and stable-shaped `13.4.0` alike). Feed
**provenance** is decided by the CLI's baked build **identity** (`AspireCliChannel`),
while version **filtering** (the channel quality) is decided by the CLI's **version
shape**. See `PackagingService.ShouldUseSharedStagingFeed`.
and official staging identities use `Both` quality because one build can publish stable
packages alongside integrations that deliberately remain prerelease. See
`PackagingService.ShouldUseSharedStagingFeed`.

A locally built CLI bakes a `local` identity and an unstamped informational version, so
it never synthesizes a staging channel and never derives a darc feed. The two diagnostic
Expand All @@ -26,7 +27,7 @@ package-directory lookups):
| Config key | Purpose |
| --- | --- |
| `overrideCliIdentityChannel` | Forces the identity used for staging-feed routing decisions. Must be a valid channel (`stable`, `staging`, `daily`, `local`, or `pr-<N>`); invalid values are ignored and the real identity is used. |
| `overrideCliInformationalVersion` | Forces the informational version that both the SHA-derivation provider and the version-shape (quality) predicate read. The part after `+` (truncated to 8 chars) builds the darc URL; the version part determines stable-vs-prerelease shape. |
| `overrideCliInformationalVersion` | Forces the informational version used to derive the darc URL. The part after `+` is truncated to 8 characters for the feed name. |

**Both overrides are required** to reach the darc path from a local build:

Expand Down Expand Up @@ -75,19 +76,19 @@ identity/feed can't silently resolve packages on a normal invocation.
`dnceng/.../dotnet9` daily feed.

To simulate a **stable**-shaped staging build, use a stable-shaped version override
(e.g. `13.4.0+<full-commit-hash>`); the channel quality becomes `Stable` while the feed
stays the darc feed.
(e.g. `13.4.0+<full-commit-hash>`). The channel still uses `Both` quality because the
SHA feed can contain prerelease-only integrations alongside stable packages.

## Helper scripts

`eng/scripts/debug-staging.{sh,ps1}` and `eng/scripts/debug-stable.{sh,ps1}` wrap the
recipe above. Both target identity `staging` and expect the **same** darc feed; they
differ only in version shape/quality:
differ only in version shape:

| Script | Version shape | Expected quality | Scenario |
| --- | --- | --- | --- |
| `debug-staging` | prerelease (`13.4.0-preview.*`) | `Both` | [#17744](https://github.com/microsoft/aspire/issues/17744) — the bug this PR fixes |
| `debug-stable` | stable (`13.4.0`) | `Stable` | [#17527](https://github.com/microsoft/aspire/issues/17527) — stable-shaped release build |
| `debug-stable` | stable (`13.4.0`) | `Both` | [#17527](https://github.com/microsoft/aspire/issues/17527) — stable-shaped release build |

Each script computes the expected `darc-pub-microsoft-aspire-<sha8>` feed and supports
three modes:
Expand Down Expand Up @@ -142,7 +143,7 @@ shell/subshell environment, so nothing is written to global or per-project confi
| Identity | Version shape | Expected feed | Expected quality |
| --- | --- | --- | --- |
| `staging` | prerelease | `darc-pub-microsoft-aspire-<sha8>` | `Both` |
| `staging` | stable | `darc-pub-microsoft-aspire-<sha8>` | `Stable` |
| `daily` | any | shared `dnceng/.../dotnet9` daily feed | `Both` |
| `staging` | stable | `darc-pub-microsoft-aspire-<sha8>` | `Both` |
| `daily` | any | shared `dnceng/.../dotnet9` daily feed | `Prerelease` |
| `local` / `pr-<N>` | any | local/PR hive + implicit (no staging synthesis) | n/a |
| `stable` | stable | nuget.org | `Stable` |
20 changes: 10 additions & 10 deletions eng/scripts/debug-aspire-channel.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

overrideCliIdentityChannel - forces the identity used for staging-feed
routing decisions (here: 'staging').
overrideCliInformationalVersion - forces the informational version the SHA
derivation and version-shape (quality)
checks read, e.g. 13.4.0-preview.1.x+<sha>.
overrideCliInformationalVersion - forces the informational version used to
derive the SHA-specific feed URL, e.g.
13.4.0-preview.1.x+<sha>.

Both flow into IConfiguration from environment variables (used here) OR from
aspire.config.json, and are scoped to staging feed routing only. A CLI run
Expand All @@ -29,8 +29,8 @@
The script runs 'aspire add <package> --debug' in a throwaway directory whose
aspire.config.json pins channel: staging, then asserts the debug log contains
Resolved 'staging' channel: feed=<expected darc feed>, quality=<expected>
The 'aspire add' step is expected to fail later (there is no real apphost
project in the scratch directory); only the feed-routing log line is validated.
A minimal TypeScript AppHost lets 'aspire add' reach package discovery; only
the feed-routing log line is validated.
#>

Set-StrictMode -Version Latest
Expand Down Expand Up @@ -58,7 +58,7 @@ function Invoke-DebugChannel {

switch ($Kind) {
'staging' { $kindLabel = 'staging (prerelease-shaped)'; $defaultVersion = $script:DefaultStagingVersion; $expectedQuality = 'Both' }
'stable' { $kindLabel = 'staging (stable-shaped)'; $defaultVersion = $script:DefaultStableVersion; $expectedQuality = 'Stable' }
'stable' { $kindLabel = 'staging (stable-shaped)'; $defaultVersion = $script:DefaultStableVersion; $expectedQuality = 'Both' }
}

if ([string]::IsNullOrEmpty($Sha)) {
Expand Down Expand Up @@ -161,9 +161,8 @@ function Invoke-DebugChannel {
}

# Throwaway working directory pinned to channel: staging so 'aspire add'
# filters to the synthesized staging channel. No real apphost project lives
# here, so 'add' will ultimately fail after feed routing has already been
# logged -- that is expected.
# filters to the synthesized staging channel. A minimal TypeScript AppHost is
# enough to reach package discovery without scaffolding a complete project.
$scratch = Join-Path ([System.IO.Path]::GetTempPath()) ("aspire-debug-" + [System.Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $scratch | Out-Null
try {
Expand All @@ -172,10 +171,11 @@ function Invoke-DebugChannel {
"channel": "staging"
}
'@ | Set-Content -Path (Join-Path $scratch 'aspire.config.json') -Encoding utf8
Set-Content -Path (Join-Path $scratch 'apphost.ts') -Value '' -NoNewline

$log = Join-Path $scratch 'aspire-debug.log'
Write-Host ">> Running: aspire add $Package --debug $($PassThrough -join ' ')"
Write-Host ' (feed routing is logged before the add step fails on the missing apphost)'
Write-Host ' (only feed routing is validated; the add result itself is ignored)'
Write-Host ''

# The overrides are scoped to THIS invocation only (set then removed), so
Expand Down
21 changes: 11 additions & 10 deletions eng/scripts/debug-aspire-channel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
#
# overrideCliIdentityChannel - forces the identity used for staging-feed
# routing decisions (here: `staging`).
# overrideCliInformationalVersion - forces the informational version the SHA
# derivation and version-shape (quality)
# checks read, e.g. `13.4.0-preview.1.x+<sha>`.
# overrideCliInformationalVersion - forces the informational version used to
# derive the SHA-specific feed URL, e.g.
# `13.4.0-preview.1.x+<sha>`.
#
# Both flow into IConfiguration from environment variables (used here) OR from
# aspire.config.json, and are scoped to staging feed routing only -- they do NOT
Expand All @@ -32,8 +32,8 @@
# aspire.config.json pins `channel: staging`, then asserts the debug log contains
# Resolved 'staging' channel: feed=<expected darc feed>, quality=<expected>
# where the feed is the SHA-specific darc-pub-microsoft-aspire-<first8-of-sha>
# feed. The `aspire add` step is expected to fail later (there is no real apphost
# project in the scratch directory); only the feed-routing log line is validated.
# feed. A minimal TypeScript AppHost lets `aspire add` reach package discovery;
# only the feed-routing log line is validated.

set -euo pipefail

Expand Down Expand Up @@ -102,7 +102,7 @@ run_debug_channel() {

case "$kind" in
staging) KIND_LABEL="staging (prerelease-shaped)"; DEFAULT_VERSION="$DEFAULT_STAGING_VERSION"; EXPECTED_QUALITY="Both" ;;
stable) KIND_LABEL="staging (stable-shaped)"; DEFAULT_VERSION="$DEFAULT_STABLE_VERSION"; EXPECTED_QUALITY="Stable" ;;
stable) KIND_LABEL="staging (stable-shaped)"; DEFAULT_VERSION="$DEFAULT_STABLE_VERSION"; EXPECTED_QUALITY="Both" ;;
*) say_err "unknown kind '$kind'"; return 2 ;;
esac

Expand Down Expand Up @@ -234,9 +234,9 @@ ENV
fi

# Throwaway working directory pinned to channel: staging so 'aspire add'
# filters to the synthesized staging channel. Created securely; cleaned up
# on exit. No real apphost project lives here, so 'add' will ultimately fail
# after feed routing has already been logged -- that is expected.
# filters to the synthesized staging channel. A minimal TypeScript AppHost is
# enough to reach package discovery without scaffolding a complete project.
# Created securely and cleaned up on exit.
local scratch
scratch="$(mktemp -d)"
trap 'rm -rf "$scratch"' RETURN
Expand All @@ -245,10 +245,11 @@ ENV
"channel": "staging"
}
JSON
: > "${scratch}/apphost.ts"

local log="${scratch}/aspire-debug.log"
say ">> Running: aspire add ${package} --debug ${passthrough[*]:-}"
say " (feed routing is logged before the add step fails on the missing apphost)"
say " (only feed routing is validated; the add result itself is ignored)"
say ""

# The overrides are scoped to THIS invocation only (no export, no persisted
Expand Down
3 changes: 2 additions & 1 deletion eng/scripts/debug-stable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
.DESCRIPTION
This is the scenario from https://github.com/microsoft/aspire/issues/17527:
a stable-shaped release-branch build still resolves from its own darc feed
(quality=Stable), not nuget.org.
(quality=Both), not nuget.org. Both keeps prerelease-only integrations from
that same build discoverable.

See docs/cli-staging-validation.md for the full validation matrix.

Expand Down
3 changes: 2 additions & 1 deletion eng/scripts/debug-stable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
#
# This is the scenario from https://github.com/microsoft/aspire/issues/17527:
# a stable-shaped release-branch build still resolves from its own darc feed
# (quality=Stable), not nuget.org.
# (quality=Both), not nuget.org. Both keeps prerelease-only integrations from
# that same build discoverable.
#
# See docs/cli-staging-validation.md for the full validation matrix.

Expand Down
Loading
Loading