Skip to content

[release/13.4] Add Aspire CLI npm package release integration#17766

Merged
joperezr merged 2 commits into
microsoft:release/13.4from
adamint:backport/pr-17297-to-release/13.4
Jun 2, 2026
Merged

[release/13.4] Add Aspire CLI npm package release integration#17766
joperezr merged 2 commits into
microsoft:release/13.4from
adamint:backport/pr-17297-to-release/13.4

Conversation

@adamint
Copy link
Copy Markdown
Member

@adamint adamint commented May 31, 2026

Backport of #17297 to release/13.4

/cc @adamint

The /backport bot couldn't do this one — git am hit conflicts because release/13.4 has drifted from main in release-publish-nuget.yml, common-variables.yml, BuildAndTest.yml, and docs/release-process.md. I checked though, and the conflicts are purely textual — nothing here actually depends on npm/corepack pipeline bits that aren't on this branch (none of the backported files reference NPM_REGISTRY or corepack). 39 of 43 files applied clean; I placed the other 4 hunks by hand.

I dropped the docs/release-process.md changes on purpose. On main they're tangled up with the VS Code extension/Marketplace release docs, which don't apply here since we don't ship the extension from 13.4. Nothing depends on that doc, so we can add the npm bits separately if we want them.

Customer Impact

Lets us ship the Aspire CLI over npm (npm install -g @microsoft/aspire-cli) from 13.4 servicing. Without it there's no npm channel on this branch. It's additive to the release pipeline and the publish path is gated behind the SkipNpm* params, so it only runs on real release runs.

Testing

Ran the backported npm tests against 13.4 locally and they pass: 31 Infrastructure pipeline tests (these assert on the exact pipeline/variables YAML, so they cover the hunks I hand-merged) and 93 CLI tests for the npm-install detection + update messaging. src/Aspire.Cli builds clean and all three edited YAMLs parse. CI will do the full build/test.

Risk

Low. Pipeline-only and default-skipped off release runs. The one runtime change is the CLI update-notification messaging (npm-install detection), which the CLI tests cover. I left out all the VS Code/Marketplace publishing.

Regression?

No — this is a new feature (npm distribution channel), not a regression fix.


Dogfood the npm package from this PR's CI artifacts

The auto dogfood comment above uses the install script, not npm. To actually try the npm package built by this PR, grab the tarballs from CI and npm install -g them. Both the pointer package and your platform's RID package live in the same built-nugets-for-<RID> artifact, and you have to install them together (the pointer pins the RID package at this exact prerelease version, which isn't on the public registry yet).

Pick your RID: osx-arm64 · osx-x64 · linux-x64 · linux-arm64 · linux-musl-x64 (Alpine) · win-x64 · win-arm64.

Get the run id from this PR's Checks tab (the CI run → Artifacts), or with gh below. The artifact is produced even on a partially-failed CI run as long as that platform's build leg succeeded.

macOS / Linux (bash)

RID=osx-arm64   # change to match your machine

# download both tarballs (pointer + RID) into ./dog
RUN_ID=<ci-run-id-from-the-Checks-tab>
gh run download "$RUN_ID" --repo microsoft/aspire -n "built-nugets-for-$RID" -D dog
cd dog

# install BOTH together. the leading ./ matters — without it npm treats
# "microsoft-...tgz" as a github owner/repo and dies with "npm error code 128"
PKGVER=$(ls microsoft-aspire-cli-$RID-*.tgz | sed -E "s/microsoft-aspire-cli-$RID-(.+)\.tgz/\1/")
npm install -g "./microsoft-aspire-cli-$RID-$PKGVER.tgz" "./microsoft-aspire-cli-$PKGVER.tgz"

aspire --version

Windows (PowerShell)

$RID = "win-x64"   # or win-arm64

$RunId = "<ci-run-id-from-the-Checks-tab>"
gh run download $RunId --repo microsoft/aspire -n "built-nugets-for-$RID" -D dog
Set-Location dog

# install BOTH together. the leading .\ matters — same code-128 gotcha as above
$PkgVer = (Get-ChildItem "microsoft-aspire-cli-$RID-*.tgz").Name -replace "microsoft-aspire-cli-$RID-(.+)\.tgz",'$1'
npm install -g ".\microsoft-aspire-cli-$RID-$PkgVer.tgz" ".\microsoft-aspire-cli-$PkgVer.tgz"

aspire --version

If aspire --version shows an old version, aspire is probably resolving to a previous script install (~/.aspire/bin/aspire, or %USERPROFILE%\.aspire\bin on Windows) that's shadowing the npm shim — check which -a aspire / where.exe aspire. Linux needs glibc ≥ 2.38 (use linux-musl-x64 on Alpine) and libicu installed.

Uninstall:

npm uninstall -g @microsoft/aspire-cli "@microsoft/aspire-cli-$RID"

Following up in #17764 to fold this npm flow into get-aspire-cli-pr so it's a one-liner.

Backport of microsoft#17297 to release/13.4.

Adds npm packaging and release-pipeline publishing for the Aspire CLI:
pack/sign/verify of the @microsoft/aspire-cli pointer package and its
seven RID packages, npm install validation steps, npm publish + registry
validation stages in release-publish-nuget.yml, npm pipeline variables,
and CLI npm-install detection/update messaging.

The docs/release-process.md changes from the source PR are intentionally
omitted: on main they are interleaved with VS Code extension / Marketplace
release documentation that does not apply to release/13.4 (the VS Code
extension is not released from this branch).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 31, 2026 21:20
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 31, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17766

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17766"

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Backports npm distribution support for the Aspire CLI into release/13.4, integrating package creation, validation, signing, staging, publishing, and npm-specific update guidance.

Changes:

  • Adds npm package generation and verification for @microsoft/aspire-cli plus RID-specific packages.
  • Extends CI/release pipelines to validate, sign, stage, and publish npm artifacts via MicroBuild/ESRP.
  • Adds CLI runtime detection for npm installs and tests for launcher/update behavior.

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.github/workflows/build-cli-native-archives.yml Installs Node and verifies/uploads npm CLI packages in native archive workflow.
docs/specs/npm-cli-package.md Documents npm package design, validation, publishing, and tradeoffs.
eng/clipack/Common.projitems Wires npm packing into the native CLI package target.
eng/clipack/npm/aspire.js Adds npm launcher for RID detection, caching, env propagation, and child execution.
eng/Publishing.props Publishes npm tarballs/signatures as flat blob artifacts and validates RID coverage.
eng/Signing.props Adds signing rules for npm tarballs and launcher content.
eng/pipelines/azure-pipelines.yml Stages npm packages and adds npm install validation jobs.
eng/pipelines/azure-pipelines-unofficial.yml Stages npm packages in unofficial pipeline.
eng/pipelines/common-variables.yml Adds npm validation artifact and ESRP contact variables.
eng/pipelines/release-publish-nuget.yml Adds npm publish parameters, validation, ESRP publish flow, and registry smoke tests.
eng/pipelines/templates/BuildAndTest.yml Validates npm detached signature sidecars.
eng/pipelines/templates/build_sign_native.yml Installs Node and verifies npm packages per RID.
eng/pipelines/templates/npm-cli-install-validation-steps.yml Adds shared npm install validation steps.
eng/pipelines/templates/prepare-npm-cli-packages.yml Adds npm package locate/install/version/cache/uninstall validation.
eng/scripts/pack-cli-npm-package.ps1 Generates pointer and RID npm packages.
eng/scripts/stage-native-cli-tool-packages.ps1 Stages npm tarballs alongside native CLI NuGet packages.
eng/scripts/verify-cli-npm-package.ps1 Verifies npm package layout and binary parity with native archive.
src/Aspire.Cli/Commands/UpdateCommand.cs Routes npm-installed CLI self-update guidance through npm.
src/Aspire.Cli/Resources/UpdateCommandStrings.Designer.cs Adds strongly typed resource accessor.
src/Aspire.Cli/Resources/UpdateCommandStrings.resx Adds npm self-update message.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.cs.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.de.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.es.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.fr.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.it.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.ja.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.ko.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.pl.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.pt-BR.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.ru.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.tr.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.zh-Hans.xlf Updates localized resource metadata.
src/Aspire.Cli/Resources/xlf/UpdateCommandStrings.zh-Hant.xlf Updates localized resource metadata.
src/Aspire.Cli/Utils/CliUpdateNotifier.cs Includes npm update command in update notifications.
src/Aspire.Cli/Utils/NpmInstallDetection.cs Adds npm install detection helpers.
tests/Aspire.Cli.Tests/Commands/UpdateCommandTests.cs Covers npm update command behavior.
tests/Aspire.Cli.Tests/Npm/AspireJsLauncherTests.cs Covers launcher behavior and package layout assumptions.
tests/Aspire.Cli.Tests/Utils/CliUpdateNotificationServiceTests.cs Covers npm update notification command.
tests/Aspire.Cli.Tests/Utils/NpmInstallDetectionTests.cs Covers npm install detection helpers.
tests/Infrastructure.Tests/Pipelines/NpmCliPackageTests.cs Adds infrastructure assertions for npm packaging/pipeline behavior.
tests/Infrastructure.Tests/Pipelines/ReleasePublishNugetPipelineTests.cs Adds release pipeline regression assertions.
tests/Infrastructure.Tests/PowerShellScripts/StageNativeCliToolPackagesTests.cs Extends staging script tests for npm packages.
Files not reviewed (1)
  • src/Aspire.Cli/Resources/UpdateCommandStrings.Designer.cs: Language not supported

Comment thread eng/clipack/npm/aspire.js
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mitchdenny
Copy link
Copy Markdown
Member

Do we support the same thing with homebrew and winget? Why is npm special in this case?

@adamint
Copy link
Copy Markdown
Member Author

adamint commented Jun 1, 2026

Do we support the same thing with homebrew and winget? Why is npm special in this case?

?

}

Write-Host "Prepared $($ridPackages.Count) RID npm package(s), pointer package version $($versions[0]), and $($signatureSidecars.Count) detached signature sidecar(s)."
displayName: 'Prepare npm Artifacts for Publishing'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random thought — none of the other publish targets (NuGet/WinGet/Homebrew/GitHub) actually depend on the npm artifacts, so should we make this whole npm branch soft-fail for now? Especially for the first few real runs — if the validation summary download lags, the MicroBuild template hiccups, or registry propagation times out, it''d be nicer to bubble it up as a warning and let the rest of the release roll forward rather than blocking shipping NuGet on it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's worth doing that when you can just run a separate build with SkipNpmPublish=true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the point is just to not have to requeue the whole release just because npm failed. Sure, if it fails you can requeue and say SkipNpmPublish, what I'm suggesting is that I don't think it should block the rest of the release.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior isn't unique to the npm job - ie, homebrew will fail the entire pipeline too if it fails. I don't see why npm should be different

Copy link
Copy Markdown
Member Author

@adamint adamint Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point and do agree that it would be better to allow the rest of the release to continue, but maybe that should be a follow-up since we have the same issue across all of our installer publishing. Followed the same conventions

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, the main reason why I was adding this comment is because this was a net-new step that had never ran, unlike the others. Anyway, I'll go ahead and merge for now and we can iterate on this on a follow up.

Comment thread eng/pipelines/release-publish-nuget.yml
Comment thread eng/pipelines/release-publish-nuget.yml
Comment thread docs/specs/npm-cli-package.md
var updateCommand = newerVersion is null
? null
: DotNetToolDetection.GetDotNetToolUpdateCommand()
?? NpmInstallDetection.GetNpmUpdateCommand()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth thinking about — should the notifier hold off on showing the npm-specific update message until that version is actually live on npm? Since the RID packages and pointer publish in two stages with a propagation delay (and the whole npm publish can be skipped per the release flow), there''s a window where we''d nudge an npm user toward npm install -g ...@latest and they''d just reinstall the same version they already have. Maybe a quick npm view probe (or check that the npm pointer is at-or-above the suggested version) before showing this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn’t add an npm view probe to the notifier. The notifier only chooses package-manager-specific guidance from local install detection; release sequencing already publishes RID packages first, waits for propagation, and publishes the pointer last. If npm publishing is skipped or delayed, that’s a release-flow issue, not something CLI should query the registry for.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point, and it is valid, but I do think that the experience of the cli saying that there is an update and suggesting you to run a command, and then you running it and that saying that there are no updates available is kind of busted. Perhaps not something to block this PR on, but something worth doing a bit more thinking down the line.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that’s fair. I still don’t think we need to block this backport or put an npm view call directly in the notifier path here, but I agree the UX is weird if our update metadata has moved ahead and npm can’t actually serve that version yet. Filed #17808 to track this for 13.5 — I think the follow-up is probably either using npm metadata for npm-installed CLIs, or suppressing the npm hint until npm agrees the version is available.

Comment thread eng/clipack/npm/aspire.js
@@ -0,0 +1,373 @@
#!/usr/bin/env node
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I''d like to gut-check — npm has a long history of bugs where optionalDependencies don''t get installed cleanly (lockfile mismatches across platforms, --no-optional somewhere up the stack, the classic npm/cli issue, etc.), and when that happens the user just sees "no Aspire CLI native package is available for RID X." Did we look at how the GitHub Copilot CLI (or other Microsoft CLIs shipping the same shape) handle this in practice? Mostly worried we''re signing ourselves up for a steady trickle of support questions from people whose RID package silently didn''t install.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the standard shape. Aspire currently fails with reinstall/optional-dependencies guidance when the RID package is missing, plus stricter version-mismatch checks. GitHub Copilot CLI packages and @vscode/ripgrep use the same optional-dependency/platform-package pattern; they don’t auto-repair missing optional deps either. The practical answer is docs + clearer error text, and the spec already tracks --no-optional guidance as an open follow-up.

@joperezr joperezr merged commit 7535685 into microsoft:release/13.4 Jun 2, 2026
616 of 619 checks passed
@github-actions github-actions Bot added this to the 13.4.x milestone Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants