Prefer current CLI template version for aspire new#17564
Conversation
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 -- 17564Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17564" |
There was a problem hiding this comment.
Pull request overview
This PR updates Aspire CLI template resolution so aspire new can prefer the installed CLI/SDK version when resolving templates from selected channels, avoiding mismatches with newer daily/staging template packages.
Changes:
- Broadened current CLI version matching when a channel name is available.
- Adjusted prerelease template package filtering to retain the current CLI/SDK version.
- Added regression tests for named-channel version selection in
aspire newandVersionHelper.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Aspire.Cli/Utils/VersionHelper.cs |
Updates current-version matching eligibility for selected channels. |
src/Aspire.Cli/Packaging/PackageChannel.cs |
Keeps the current CLI/SDK version in prerelease template package results. |
tests/Aspire.Cli.Tests/Utils/VersionHelperTests.cs |
Adds unit coverage for named-channel matching behavior. |
tests/Aspire.Cli.Tests/Commands/NewCommandChannelResolutionTests.cs |
Adds CLI channel-resolution regression coverage for daily/staging selection. |
| { Quality: PackageChannelQuality.Both } => true, | ||
| { Quality: PackageChannelQuality.Stable, SemVer: { IsPrerelease: false } } => true, | ||
| { Quality: PackageChannelQuality.Prerelease, SemVer: { IsPrerelease: true } } => true, | ||
| { Quality: PackageChannelQuality.Prerelease, SemVer: { IsPrerelease: false } } when string.Equals(p.Version, currentCliVersion, StringComparison.OrdinalIgnoreCase) => true, |
Ensure CLI-runtime templates selected from explicit package channels use the current bundled CLI/SDK version instead of floating to newer channel packages that can mismatch the bundled AppHost server. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When --channel is specified, aspire new now pins the template version to the current installed CLI/SDK version, preventing version mismatches where pre-release channel feeds could otherwise float to a newer template package (e.g. 13.5 preview when the CLI is 13.4). Documents changes from microsoft/aspire#17564. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Pull request created: #1106
|
|
📝 Documentation has been drafted in microsoft/aspire.dev#1106 targeting Updated Note This draft PR needs human review before merging. |
PR #17564 introduced a new fallback in TryGetCurrentCliTemplateVersionPackage that pins the template package to the running CLI's SDK version whenever the selected channel is explicit and not local-build. That preserved the intended fix for prerelease channels (daily, staging) where the channel feed filters the running CLI's package out of search results even though the feed can still restore it. But it also fired for the stable channel, where the filter does not apply. For a non-stable-shape CLI (PR build like '13.4.0-pr.X.gY' or a daily-shape preview) invoked with '--channel stable', it forced an unpublishable version into the generated apphost.cs, breaking the SmokeTests LatestCliCanStartStableChannelAppHost and LatestCliCanStartStableChannelTypeScriptAppHost. Exclude the stable channel from the new fallback so that case falls through to the OrderByDescending picker and the user gets the highest shipped stable package they explicitly asked for. The original prerelease-channel motivation ('Aspire.TypeSystem version mismatch when 13.4 CLI floats templates to a 13.5 daily preview') is preserved unchanged. Test updates: - NewCommandChannelResolutionTests.NewCommand_NoChannelArg_ResolvesTemplateFromIdentityChannel gets an expectedVersion theory parameter so the daily case still pins to the CLI version while the stable case asserts the highest shipped stable. - NewCommandChannelResolutionTests.NewCommand_ExplicitChannelArg_OverridesIdentityChannel asserts highest shipped stable (matching the SmokeTest contract). - New NewCommand_ExplicitStableChannel_NonStableCliVersion_FallsBackToHighestShippedStable regression test covers both daily-shape and PR-shape CLI identities. - NewCommandTests.NewCommandWithTypeScriptEmptyTemplatePassesResolvedVersionAndChannelToScaffolding reverts to its pre-#17564 assertion of '9.2.0' from the stable feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Folder path (#17573) * Stabilize PrebuiltAppHostServer staging globalPackagesFolder path PackagingService creates the staging channel with ConfigureGlobalPackagesFolder=true so each darc/override feed restore lands in an isolated cache (two staging builds of the same release branch ship as 13.4.0 but from different feeds, and NuGet keys by (id,version) only). PrebuiltAppHostServer was wiring that flag into a TemporaryNuGetConfig whose default globalPackagesFolder value is the relative '.nugetpackages' -- NuGet resolved it under the temp config's own directory, BundleNuGetService baked those temp paths into integration-package-probe-manifest.json, and TemporaryNuGetConfig.Dispose then recursively deleted the cache out from under the manifest. On macOS osx-arm64 polyglot staging builds this surfaced as a hang during DI / assembly loading in aspire-managed. Preserve the per-feed cache isolation behavior and anchor the override at a stable absolute path instead: <ASPIRE_HOME>/.nugetpackages/<first-8-of-CLI-commit-sha> Keying by the truncated commit hash matches the existing darc-pub-microsoft-aspire-<hash> feed URL convention in PackagingService.GetStagingFeedUrl, so the cache key and feed key stay aligned at 8 hex chars. 8 chars is short enough to avoid Windows MAX_PATH blow-ups on deep integration cache trees while keeping SHA collisions negligible. The cache lives under ASPIRE_HOME (not the per-AppHost working directory) so multiple AppHosts on the same machine running against the same staging build can share a single restore -- the unit of isolation here is the staging build, not the individual restore command. Mechanics: - TemporaryNuGetConfig.CreateAsync now accepts an optional globalPackagesFolderValue and propagates it through AddGlobalPackagesFolderToConfigAsync into the merger. - NuGetConfigMerger.AddGlobalPackagesFolderConfiguration takes the optional override and falls back to the workspace-relative default ('.nugetpackages') for the non-temp workspace-merge path. - PrebuiltAppHostServer.ResolveStableGlobalPackagesFolder routes both temp config branches (channel and package-source-override) through the new helper. - VersionHelper.TryGetCurrentCommitHashShort surfaces the truncated SHA from the running CLI's AssemblyInformationalVersion (returns null on clean release builds with no '+sha' suffix; callers fall back to 'default'). - CliPathHelper centralizes the '<ASPIRE_HOME>/.nugetpackages' path so the producer (PrebuiltAppHostServer) and consumer (CacheCommand) can't drift. - CacheCommand.ClearCommand now wipes <ASPIRE_HOME>/.nugetpackages so a wedged staging restore is recoverable through the same UX as every other CLI cache. Tests: - Updated existing PrebuiltAppHostServerTests staging cases to assert the globalPackagesFolder value is absolute and lives outside the temp config directory. - New PrebuiltAppHostServerTests case wires a real PackagingService with overrideStagingFeed on a stable-shaped CLI and pins the same invariant end-to-end. - New TemporaryNuGetConfigTests for the override propagation and for the no-override-when-disabled invariant. - New CacheCommandTests covering the staging cache wipe and the missing-cache no-op path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Key staging globalPackagesFolder cache by feed URL hash The staging globalPackagesFolder fix in the previous commit keyed the \`.nugetpackages\` subdirectory off the CLI's own commit SHA (first 8 hex chars of \`AssemblyInformationalVersionAttribute\`). That handles two darc-shipped staging builds of the same release branch, but it breaks the local-dev case where one CLI is repeatedly retargeted at different \`overrideStagingFeed\` values: the URL changes but the SHA doesn't, so every override silently shares one cache bucket and the second restore reuses the first feed's now-stale \`13.4.0\` assemblies. Switch the cache key to the first 8 hex chars of \`XxHash3\` over the trimmed, lower-cased resolved feed URL: - Override branch passes the explicit \`--source\` URL. - Channel branch passes the channel's \`Aspire*\` mapping source (or the first mapping for forward compatibility). Trim + lower-case before hashing so a stray whitespace from a config file or a hostname-case change doesn't fragment the cache. Non-cryptographic hashing is fine here — the key is a directory name, not a security boundary — and 8 hex chars keep deep integration cache paths well under Windows MAX_PATH while giving ~4 billion buckets, so collisions are negligible across the handful of staging feeds any user ever sees. Removes the now-unused \`VersionHelper.TryGetCurrentCommitHashShort\` helper (added in the previous commit, no remaining callers). Tests: - New \`CliPathHelperTests.ComputeStagingFeedCacheKey_*\` cover determinism, normalization, length defaults, and null/empty input. - Existing \`PrebuiltAppHostServerTests\` strengthened to assert the emitted globalPackagesFolder equals \`<aspireHome>/.nugetpackages/<hash(feed)>\`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Narrow #17564 CLI-pin fallback to prerelease channels PR #17564 introduced a new fallback in TryGetCurrentCliTemplateVersionPackage that pins the template package to the running CLI's SDK version whenever the selected channel is explicit and not local-build. That preserved the intended fix for prerelease channels (daily, staging) where the channel feed filters the running CLI's package out of search results even though the feed can still restore it. But it also fired for the stable channel, where the filter does not apply. For a non-stable-shape CLI (PR build like '13.4.0-pr.X.gY' or a daily-shape preview) invoked with '--channel stable', it forced an unpublishable version into the generated apphost.cs, breaking the SmokeTests LatestCliCanStartStableChannelAppHost and LatestCliCanStartStableChannelTypeScriptAppHost. Exclude the stable channel from the new fallback so that case falls through to the OrderByDescending picker and the user gets the highest shipped stable package they explicitly asked for. The original prerelease-channel motivation ('Aspire.TypeSystem version mismatch when 13.4 CLI floats templates to a 13.5 daily preview') is preserved unchanged. Test updates: - NewCommandChannelResolutionTests.NewCommand_NoChannelArg_ResolvesTemplateFromIdentityChannel gets an expectedVersion theory parameter so the daily case still pins to the CLI version while the stable case asserts the highest shipped stable. - NewCommandChannelResolutionTests.NewCommand_ExplicitChannelArg_OverridesIdentityChannel asserts highest shipped stable (matching the SmokeTest contract). - New NewCommand_ExplicitStableChannel_NonStableCliVersion_FallsBackToHighestShippedStable regression test covers both daily-shape and PR-shape CLI identities. - NewCommandTests.NewCommandWithTypeScriptEmptyTemplatePassesResolvedVersionAndChannelToScaffolding reverts to its pre-#17564 assertion of '9.2.0' from the stable feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Prefer current CLI template version Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Pin aspire new template version to CLI Ensure CLI-runtime templates selected from explicit package channels use the current bundled CLI/SDK version instead of floating to newer channel packages that can mismatch the bundled AppHost server. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Folder path (#17573) * Stabilize PrebuiltAppHostServer staging globalPackagesFolder path PackagingService creates the staging channel with ConfigureGlobalPackagesFolder=true so each darc/override feed restore lands in an isolated cache (two staging builds of the same release branch ship as 13.4.0 but from different feeds, and NuGet keys by (id,version) only). PrebuiltAppHostServer was wiring that flag into a TemporaryNuGetConfig whose default globalPackagesFolder value is the relative '.nugetpackages' -- NuGet resolved it under the temp config's own directory, BundleNuGetService baked those temp paths into integration-package-probe-manifest.json, and TemporaryNuGetConfig.Dispose then recursively deleted the cache out from under the manifest. On macOS osx-arm64 polyglot staging builds this surfaced as a hang during DI / assembly loading in aspire-managed. Preserve the per-feed cache isolation behavior and anchor the override at a stable absolute path instead: <ASPIRE_HOME>/.nugetpackages/<first-8-of-CLI-commit-sha> Keying by the truncated commit hash matches the existing darc-pub-microsoft-aspire-<hash> feed URL convention in PackagingService.GetStagingFeedUrl, so the cache key and feed key stay aligned at 8 hex chars. 8 chars is short enough to avoid Windows MAX_PATH blow-ups on deep integration cache trees while keeping SHA collisions negligible. The cache lives under ASPIRE_HOME (not the per-AppHost working directory) so multiple AppHosts on the same machine running against the same staging build can share a single restore -- the unit of isolation here is the staging build, not the individual restore command. Mechanics: - TemporaryNuGetConfig.CreateAsync now accepts an optional globalPackagesFolderValue and propagates it through AddGlobalPackagesFolderToConfigAsync into the merger. - NuGetConfigMerger.AddGlobalPackagesFolderConfiguration takes the optional override and falls back to the workspace-relative default ('.nugetpackages') for the non-temp workspace-merge path. - PrebuiltAppHostServer.ResolveStableGlobalPackagesFolder routes both temp config branches (channel and package-source-override) through the new helper. - VersionHelper.TryGetCurrentCommitHashShort surfaces the truncated SHA from the running CLI's AssemblyInformationalVersion (returns null on clean release builds with no '+sha' suffix; callers fall back to 'default'). - CliPathHelper centralizes the '<ASPIRE_HOME>/.nugetpackages' path so the producer (PrebuiltAppHostServer) and consumer (CacheCommand) can't drift. - CacheCommand.ClearCommand now wipes <ASPIRE_HOME>/.nugetpackages so a wedged staging restore is recoverable through the same UX as every other CLI cache. Tests: - Updated existing PrebuiltAppHostServerTests staging cases to assert the globalPackagesFolder value is absolute and lives outside the temp config directory. - New PrebuiltAppHostServerTests case wires a real PackagingService with overrideStagingFeed on a stable-shaped CLI and pins the same invariant end-to-end. - New TemporaryNuGetConfigTests for the override propagation and for the no-override-when-disabled invariant. - New CacheCommandTests covering the staging cache wipe and the missing-cache no-op path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Key staging globalPackagesFolder cache by feed URL hash The staging globalPackagesFolder fix in the previous commit keyed the \`.nugetpackages\` subdirectory off the CLI's own commit SHA (first 8 hex chars of \`AssemblyInformationalVersionAttribute\`). That handles two darc-shipped staging builds of the same release branch, but it breaks the local-dev case where one CLI is repeatedly retargeted at different \`overrideStagingFeed\` values: the URL changes but the SHA doesn't, so every override silently shares one cache bucket and the second restore reuses the first feed's now-stale \`13.4.0\` assemblies. Switch the cache key to the first 8 hex chars of \`XxHash3\` over the trimmed, lower-cased resolved feed URL: - Override branch passes the explicit \`--source\` URL. - Channel branch passes the channel's \`Aspire*\` mapping source (or the first mapping for forward compatibility). Trim + lower-case before hashing so a stray whitespace from a config file or a hostname-case change doesn't fragment the cache. Non-cryptographic hashing is fine here — the key is a directory name, not a security boundary — and 8 hex chars keep deep integration cache paths well under Windows MAX_PATH while giving ~4 billion buckets, so collisions are negligible across the handful of staging feeds any user ever sees. Removes the now-unused \`VersionHelper.TryGetCurrentCommitHashShort\` helper (added in the previous commit, no remaining callers). Tests: - New \`CliPathHelperTests.ComputeStagingFeedCacheKey_*\` cover determinism, normalization, length defaults, and null/empty input. - Existing \`PrebuiltAppHostServerTests\` strengthened to assert the emitted globalPackagesFolder equals \`<aspireHome>/.nugetpackages/<hash(feed)>\`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Narrow #17564 CLI-pin fallback to prerelease channels PR #17564 introduced a new fallback in TryGetCurrentCliTemplateVersionPackage that pins the template package to the running CLI's SDK version whenever the selected channel is explicit and not local-build. That preserved the intended fix for prerelease channels (daily, staging) where the channel feed filters the running CLI's package out of search results even though the feed can still restore it. But it also fired for the stable channel, where the filter does not apply. For a non-stable-shape CLI (PR build like '13.4.0-pr.X.gY' or a daily-shape preview) invoked with '--channel stable', it forced an unpublishable version into the generated apphost.cs, breaking the SmokeTests LatestCliCanStartStableChannelAppHost and LatestCliCanStartStableChannelTypeScriptAppHost. Exclude the stable channel from the new fallback so that case falls through to the OrderByDescending picker and the user gets the highest shipped stable package they explicitly asked for. The original prerelease-channel motivation ('Aspire.TypeSystem version mismatch when 13.4 CLI floats templates to a 13.5 daily preview') is preserved unchanged. Test updates: - NewCommandChannelResolutionTests.NewCommand_NoChannelArg_ResolvesTemplateFromIdentityChannel gets an expectedVersion theory parameter so the daily case still pins to the CLI version while the stable case asserts the highest shipped stable. - NewCommandChannelResolutionTests.NewCommand_ExplicitChannelArg_OverridesIdentityChannel asserts highest shipped stable (matching the SmokeTest contract). - New NewCommand_ExplicitStableChannel_NonStableCliVersion_FallsBackToHighestShippedStable regression test covers both daily-shape and PR-shape CLI identities. - NewCommandTests.NewCommandWithTypeScriptEmptyTemplatePassesResolvedVersionAndChannelToScaffolding reverts to its pre-#17564 assertion of '9.2.0' from the stable feed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The cherry-picks of #17564 and #17573 alone do not address the `aspire new` + C# Blazor scenario from #17596 because that path runs through `TemplateNuGetConfigService.ResolveTemplatePackageAsync` (DotNet templates), not `NewCommand.ResolveCliTemplateVersionAsync` (CLI-runtime templates) where #17564's `TryGetCurrentCliTemplateVersionPackage` synthesis lives. Teach `ResolveTemplatePackageAsync` to mirror the identity-channel preference that `ResolveCliTemplateVersionAsync` (NewCommand.cs:376-389) already does for CLI templates: when no `--channel` is supplied and no PR hives exist, prefer the channel whose name matches the running CLI's `CliExecutionContext.IdentityChannel` before falling back to Implicit. Without this, a daily 13.5 CLI on a clean `~/.aspire` silently restricts the template search to nuget.org and returns the shipped stable `Aspire.ProjectTemplates 13.3.5` instead of the matching `13.5.0-preview.1.*` daily prerelease from the `dotnet9` feed. The Implicit fallback preserves prior behavior when the identity channel isn't a registered channel (e.g. a "local" CLI without a corresponding local-build hive). See #17596 for full repro. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
Fixes a release/13.4
aspire newversion selection issue where a shipped 13.4 CLI using an explicit channel such as--channel dailycould float to the newestAspire.ProjectTemplatespackage from that channel, for example a 13.5 preview. That caused the bundled 13.4 AppHost server to restore/load 13.5 TypeScript codegen dependencies and fail withAspire.TypeSystem, Version=13.5.0.0loader errors followed byNo language support found for: typescript/nodejs.The fix keeps CLI-runtime templates pinned to the current bundled CLI/SDK version after a channel is selected. If the channel search returns the exact current version, that package is selected. If prerelease channel search filters out the shipped stable-shaped version,
aspire newstill passes the current CLI/SDK version through so restore uses packages that match the bundled server. Local/PR hive behavior remains on the existing exact-match path.User-facing usage
A shipped 13.4 CLI now keeps generated TypeScript AppHosts on 13.4 instead of resolving newer daily packages:
Tests
dotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-restore -- --filter-class Aspire.Cli.Tests.Commands.NewCommandChannelResolutionTests --filter-class Aspire.Cli.Tests.Commands.NewCommandTests --filter-class Aspire.Cli.Tests.Utils.VersionHelperTests --no-progressdotnet test --project tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj --no-restore -- --no-progressChecklist
<remarks />and<code />elements on your triple slash comments?