[release/13.2] Add WinGet publishing pipeline for Aspire CLI#14502
Draft
radical wants to merge 22 commits intodotnet:release/13.2from
Draft
[release/13.2] Add WinGet publishing pipeline for Aspire CLI#14502radical wants to merge 22 commits intodotnet:release/13.2from
radical wants to merge 22 commits intodotnet:release/13.2from
Conversation
Contributor
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14502Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14502" |
Add WinGet manifest generation, validation, and publishing to the internal pipeline. Includes install/uninstall testing with proper cleanup on failure, and fixes _IsPublishBranch string comparison for template expression evaluation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Get param Add publishReleaseToWinGet pipeline parameter (default: false) so that release branch builds only publish to WinGet when explicitly opted in. Main branch non-PR builds continue to publish automatically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compute the versioned manifest path once in the generate step and emit it as the $(VersionedManifestPath) pipeline variable instead of repeating the same directory search in the validate and test install/uninstall steps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the duplicated branch-matching expressions with a reference to _IsPublishBranch, keeping the inner main check to preserve the "main always publishes, release branches require opt-in" semantics. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…only - azure-pipelines.yml: Always publish to Microsoft.Aspire.Prerelease from CI; release winget publishing is now handled by release-publish-nuget.yml - release-publish-nuget.yml: Add PublishWinGet stage that publishes to Microsoft.Aspire winget package after NuGet publish completes - SkipWinGetPublish parameter for idempotent re-runs - DryRun support via publishToWinGet flag - Version from ReleaseVersion parameter - Aspire-Secrets variable group for winget PAT token Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The release pipeline pool may not have PSGallery registered by default. Add diagnostic output and auto-register PSGallery before installing the Microsoft.WinGet.Client module. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Register-PSRepository -Default fails when the NuGet package provider isn't installed. Bootstrap it with Install-PackageProvider before attempting to register PSGallery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…otnet#14434) * Add Azure portal link for Resource Group in pipeline summary When printing the Resource Group in the pipeline summary of `aspire deploy`, include a clickable link to the Azure portal resource group page. The link uses the format: https://portal.azure.com/#@{tenantId}/resource/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/overview Changes: - AzureEnvironmentResource.AddToPipelineSummary: construct markdown link for resource group - ConsoleActivityLogger.FormatPipelineSummaryKvp: convert markdown to Spectre markup for clickable links - Add ConsoleActivityLoggerTests for the new markdown rendering behavior Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * Clean up the code * Fix tests * More test fixups * Refactor code * Update src/Aspire.Cli/Utils/MarkdownToSpectreConverter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add test for color-enabled non-interactive rendering path Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * fix test --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ondition (dotnet#14494) * Fix tools/list infinite loop by removing notification from ListTools handler and adding change detection The MCP server was entering an infinite tools/list loop because: 1. HandleListToolsAsync sent tools/list_changed notification after refreshing 2. The client responded with another tools/list request 3. This created a feedback loop: list → changed → list → changed Fix: - Remove SendToolsListChangedNotificationAsync from HandleListToolsAsync (the client already gets the fresh list since it requested it) - Add change detection to RefreshResourceToolMapAsync (returns bool Changed) - Only send tools/list_changed in HandleCallToolAsync when tools actually changed - RefreshToolsTool always sends notification (explicit user action) Co-authored-by: maddymontaquila <12660687+maddymontaquila@users.noreply.github.com> * Use HashSet.SetEquals for more efficient tool change detection Co-authored-by: maddymontaquila <12660687+maddymontaquila@users.noreply.github.com> * Address review feedback: use no-allocation key comparison and bounded channel wait in test - Replace HashSet.SetEquals with count check + iterate keys + ContainsKey to avoid allocation under lock in McpResourceToolRefreshService. - Replace Task.Delay(200) in test with Channel.ReadAsync + CancellationTokenSource timeout for more deterministic negative assertion. Co-authored-by: sebastienros <1165805+sebastienros@users.noreply.github.com> * Check for both new and deleted tools in change detection The previous change detection only iterated old→new keys, missing the case where tools are swapped (same count but different keys). Now also checks new→old to detect newly added tools. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clean up comments in AgentMcpCommandTests Removed comments about using TryRead for notifications. * Fix resource name mapping --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: maddymontaquila <12660687+maddymontaquila@users.noreply.github.com> Co-authored-by: sebastienros <1165805+sebastienros@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: sebastienros <sebastienros@users.noreply.github.com>
* Fix permission denied error in Azure Pipelines When we generate temporary dockerfiles, we are generating them directly under the TEMP directory. This can cause issues in some environments because docker build will walk all the files and folders next to the dockerfile as context to the build. For example, in AzDO pipelines, we can get an error like "ERROR: error from sender: lstat /tmp/.mount_azsec-KdAJKO: permission denied". To fix this, we generate the Dockerfile in a subdirectory of TEMP, so it is the only file passed as context to docker build. Fix dotnet#14523
…t#14442) * Add WithCompactResourceNaming() to fix storage name collisions Fixes dotnet#14427. When Azure Container App environment names are long, the uniqueString suffix gets truncated in storage account names, causing naming collisions across deployments. WithCompactResourceNaming() is an opt-in method that shortens storage account and managed storage names to preserve the full 13-char uniqueString while keeping names within Azure's length limits. - Storage accounts: take('{prefix}sv{resourceToken}', 24) - Managed storage: take('{name}-{volume}-{resourceToken}', 32) - File shares: take('{name}-{volume}', 60) Includes unit tests with snapshot verification and E2E deployment tests covering both the fix and upgrade safety scenarios. * Fix upgrade test: handle version prompt and backup/restore dev CLI - Add version selection prompt handling for 'aspire add' (same as passing test) - Back up dev CLI before GA install, restore after GA phase - Update package to dev version after CLI restoration - Set channel back to local after restore * Remove the manifest from verify tests. It is not necessary. * Remove unnecessary suppression * Fix upgrade test: use 'aspire update' to actually upgrade project packages The upgrade test was only swapping the CLI binary but the apphost.cs still had #:package directives pointing to GA 13.1.0 packages. The deployment logic comes from the NuGet packages, not the CLI, so the test was actually redeploying with the old GA naming code both times. Now uses 'aspire update --channel local' to update the #:package directives in apphost.cs from GA → dev version, ensuring the dev naming code is exercised during the second deployment. * Fix upgrade test: handle 'Perform updates?' confirmation prompt aspire update shows a y/n confirmation before applying package updates. The test was waiting for 'Update successful' but the command was stuck at the confirmation prompt. * Fix upgrade test: handle NuGet.config directory prompt from aspire update aspire update shows two prompts when switching channels: 1. 'Perform updates? [y/n]' - package confirmation 2. 'Which directory for NuGet.config file?' - NuGet config placement Both need Enter to accept defaults. * Fix upgrade test: use timed Enter presses for aspire update prompts aspire update has multiple sequential prompts (confirm, NuGet.config dir, NuGet.config apply, potential CLI self-update). Use Wait+Enter pattern to accept all defaults without needing to track each prompt individually. * Fix upgrade test: use explicit WaitUntil for each aspire update prompt Timed Enter presses were unreliable — if prompts appeared at different speeds, extra Enters would leak to the shell and corrupt subsequent commands. Now explicitly waits for each of the 3 prompts: 1. 'Perform updates? [y/n]' 2. 'Which directory for NuGet.config file?' 3. 'Apply these changes to NuGet.config? [y/n]' * Increase deploy WaitForSuccessPrompt timeout from 2 to 5 minutes --------- Co-authored-by: Mitch Denny <mitch@mitchdeny.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
…resh loop (dotnet#14539) TryGetResourceToolMap always returned false because it compared _selectedAppHostPath against _auxiliaryBackchannelMonitor.SelectedAppHostPath, which is only set by explicit select_apphost calls (usually null). After RefreshResourceToolMapAsync sets _selectedAppHostPath to the connection's actual path, the comparison null != "/path/to/AppHost" always failed, so every tools/list call triggered a full refresh instead of using the cached map. Fix: Add ResolvedAppHostPath property to IAuxiliaryBackchannelMonitor that returns SelectedConnection?.AppHostInfo?.AppHostPath, and compare against that. Rename field to _lastRefreshedAppHostPath for clarity. Fixes dotnet#14538 Co-authored-by: Mitch Denny <mitch@mitchdeny.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tnet#14452) * Add AzureServiceTags class with common Azure service tags and tests Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * Use the new constants in more places. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
The winget install step was failing on the NuGet pipeline. Windows hosted agents already have winget pre-installed, so replace the complex installation fallback with a simple version check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 'Install winget' step to run-tests.yml and tests-runner.yml workflows to ensure winget is available on all Windows CI jobs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of expecting winget to be pre-installed on the agent, run eng/install-winget.ps1 when winget is not found. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace standalone install-winget.ps1 with inline steps that use NuGetAuthenticate and the ps-gallery-for-aspire Azure Artifacts feed to install Microsoft.WinGet.Client, then Repair-WinGetPackageManager. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The PowerShell@2 task defaults to Windows PowerShell 5.1 which rejects the Azure DevOps NuGet v2 feed URL in Register-PSRepository. Adding pwsh: true switches to PowerShell 7 which handles the URL correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Register-PSRepository validates the URI with an unauthenticated HTTP probe, which fails on authenticated Azure DevOps feeds. Switch to PSResourceGet (Register-PSResourceRepository + Install-PSResource), which is built into PowerShell 7.4+ and uses the NuGet v3 endpoint without the problematic validation. Also add diagnostic logging for PS version, PSResourceGet availability, and credential provider paths to aid debugging if issues recur. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Feb 21, 2026
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.
Add WinGet publishing pipeline for Aspire CLI
Summary
Adds automated WinGet manifest generation, validation, and publishing to the internal Azure DevOps pipeline so that the Aspire CLI (
aspire) can be installed viawinget install Microsoft.Aspire(release) orwinget install Microsoft.Aspire.Prerelease(preview).Motivation
Today users install the Aspire CLI through acquisition scripts (
aspire.dev/get-aspire-cli.sh/aspire.dev/get-aspire-cli.ps1). Adding WinGet support gives Windows developers a familiar, first-class installation channel (winget install/winget upgrade) with automatic PATH management and upgrade semantics.What's included
Pipeline changes (
eng/pipelines/)publish_wingetstage inazure-pipelines.yml– runs after thebuildstage on non-PR builds frommain,release/*, andinternal/release/*branches.publishReleaseToWinGetparameter (defaultfalse) – gates WinGet publishing on release branches so it only happens when explicitly opted in. Main branch builds publish automatically.Microsoft.Aspire; all other branches useMicrosoft.Aspire.Prerelease.eng/pipelines/templates/winget.ymlthat:wingetcreateand thewingetCLI on the build agent.winget validate.microsoft/winget-pkgsviawingetcreate update --submit(gated behindpublishToWinGet).Manifest generation (
eng/winget/)generate-manifests.ps1– PowerShell script that:win-x64,win-arm64by default).ci.dot.netpublishing pattern.-ValidateUrls).Two sets of YAML templates:
eng/winget/microsoft.aspire/Microsoft.Aspirerelease/*)eng/winget/microsoft.aspire.prerelease/Microsoft.Aspire.Prereleasemain)Each set contains:
Aspire.yaml.template– version manifestAspire.locale.en-US.yaml.template– locale/metadata manifest (description, tags, license, etc.)Aspire.installer.yaml.template– installer manifest (zip → portable withaspire.exe)Testing
winget validate --manifeston every qualifying build.publishToWinGetis false).