From ea11daa53e7a5a3fe1695febdbe8259003175977 Mon Sep 17 00:00:00 2001 From: Giulia Stocco <98900+gfs@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:28:29 -0700 Subject: [PATCH 1/2] Fix VS Code release publish failing with npm E401 The publish step ran `npx @vscode/vsce publish`. npx only reuses an already-installed binary when its first argument matches a bin name, so passing the package name `@vscode/vsce` always forces a manifest fetch from the npm registry. Inside the AzureCLI@2 task that fetch is unauthenticated against the Azure Artifacts feed and returns E401, even though the preceding step already installed vsce globally. Invoke the globally installed `vsce.cmd` by its full path instead, so publishing needs no registry access at all, and throw a clear error if the binary is missing or the publish exits non-zero. Drop the `npm_config_registry` env var that was added to make the npx fetch resolve. It is redundant with the `.npmrc` copied into the staging directory and has no bearing on the publish target, since `vsce publish` uploads to the Visual Studio Marketplace rather than an npm registry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a61244f3-4b6b-4a24-8e49-a12ce295259e --- Changelog.md | 5 +++++ Pipelines/vscode/devskim-vscode-release.yml | 19 +++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 9927e158..8e177cb2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.97] - 2026-08-11 +### Pipeline +- Fixed the VS Code extension release pipeline failing at the publish step with `npm error code E401`. The step ran `npx @vscode/vsce`, and because the argument is a package name rather than a bin name, npx cannot short circuit to the copy installed by the preceding `npm install -g @vscode/vsce` step and always fetches the package manifest from the npm registry, which is not authenticated inside the `AzureCLI@2` task. The step now invokes the globally installed `vsce.cmd` by its full path, so publishing needs no registry access, and fails with an explicit message if the binary is missing. +- Removed the `npm_config_registry` environment variable from the publish step. It was only there to make the `npx` fetch resolve, is redundant with the `.npmrc` copied into the staging directory, and does not affect where the extension is published - `vsce publish` uploads to the Visual Studio Marketplace, not to an npm registry. + ## [1.0.96] - 2026-08-03 ### Dependencies - Consolidated the open Dependabot pull requests (#765, #766, #767, #768, #769) into a single update for the VS Code extension: `linkify-it` 5.0.1 to 5.0.2, `fast-uri` 3.1.2 to 3.1.4, `undici` 7.24.6 to 7.29.0, and `brace-expansion` 1.1.14 to 1.1.16 and 5.0.5 to 5.0.8. diff --git a/Pipelines/vscode/devskim-vscode-release.yml b/Pipelines/vscode/devskim-vscode-release.yml index eda4fc50..e68403e7 100644 --- a/Pipelines/vscode/devskim-vscode-release.yml +++ b/Pipelines/vscode/devskim-vscode-release.yml @@ -184,18 +184,29 @@ extends: workingDirectory: '$(Build.StagingDirectory)' inlineScript: | $packPath = Resolve-Path $env:BUILD_STAGINGDIRECTORY\*.vsix + # Invoke the vsce installed globally in the previous step by its full path. + # `npx @vscode/vsce` cannot be used here: npx only short circuits to an already + # installed binary when the argument matches a bin name, so a package name always + # forces a manifest fetch from the npm registry, which fails with E401 in this task. + $vsce = Join-Path (npm prefix -g) 'vsce.cmd' + if (-not (Test-Path $vsce)) + { + throw "vsce was not found at $vsce - check the 'Install vsce and dependencies' step" + } if ("$(ReleaseVersion)".Contains("-")) { echo "Publishing as --pre-release = $(ReleaseVersion)" - npx @vscode/vsce publish --packagePath $packPath --pre-release --azure-credential + & $vsce publish --packagePath $packPath --pre-release --azure-credential } else { echo "Publishing as official release = $(ReleaseVersion)" - npx @vscode/vsce publish --packagePath $packPath --azure-credential + & $vsce publish --packagePath $packPath --azure-credential + } + if ($LASTEXITCODE -ne 0) + { + throw "vsce publish failed with exit code $LASTEXITCODE" } - env: - npm_config_registry: "https://pkgs.dev.azure.com/microsoft-sdl/General/_packaging/PublicRegistriesFeed/npm/registry/" - job: gitHubReleaseJob # Based on Documentation: https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-pipeline-templates/features/releasepipelines/releaseworkflows/releasejob?tabs=standardreleasejob From 8b998e69ca934a06b8ded65a0641053fb8076bee Mon Sep 17 00:00:00 2001 From: Giulia Stocco <98900+gfs@users.noreply.github.com> Date: Mon, 3 Aug 2026 10:55:10 -0700 Subject: [PATCH 2/2] Fail fast unless staging holds exactly one vsix Address review feedback on the publish step. `Resolve-Path` returns `$null` when no `.vsix` is present and an array when more than one matches, and neither is safe to hand to `--packagePath`: the first silently passes no path, and the second splats into multiple native arguments. Enumerate the artifacts explicitly and throw unless exactly one is found, which keeps the failure attributable to signing or staging instead of surfacing as a confusing vsce error. Also record why `npm prefix -g` is used rather than `npm bin -g`, since `npm bin` was removed in npm v9 and the global bin directory is the global prefix itself on Windows. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a61244f3-4b6b-4a24-8e49-a12ce295259e --- Changelog.md | 1 + Pipelines/vscode/devskim-vscode-release.yml | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 8e177cb2..6c3a721a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Pipeline - Fixed the VS Code extension release pipeline failing at the publish step with `npm error code E401`. The step ran `npx @vscode/vsce`, and because the argument is a package name rather than a bin name, npx cannot short circuit to the copy installed by the preceding `npm install -g @vscode/vsce` step and always fetches the package manifest from the npm registry, which is not authenticated inside the `AzureCLI@2` task. The step now invokes the globally installed `vsce.cmd` by its full path, so publishing needs no registry access, and fails with an explicit message if the binary is missing. - Removed the `npm_config_registry` environment variable from the publish step. It was only there to make the `npx` fetch resolve, is redundant with the `.npmrc` copied into the staging directory, and does not affect where the extension is published - `vsce publish` uploads to the Visual Studio Marketplace, not to an npm registry. +- Hardened the VS Code publish step against an unexpected artifact count. It previously passed a `Resolve-Path` result straight to `--packagePath`, which yields `$null` when signing produced no `.vsix` and an array that splats into multiple arguments when it produced more than one. The step now resolves the artifact explicitly and fails with a clear message unless exactly one is present. ## [1.0.96] - 2026-08-03 ### Dependencies diff --git a/Pipelines/vscode/devskim-vscode-release.yml b/Pipelines/vscode/devskim-vscode-release.yml index e68403e7..69720cb8 100644 --- a/Pipelines/vscode/devskim-vscode-release.yml +++ b/Pipelines/vscode/devskim-vscode-release.yml @@ -183,11 +183,20 @@ extends: scriptLocation: 'inlineScript' workingDirectory: '$(Build.StagingDirectory)' inlineScript: | - $packPath = Resolve-Path $env:BUILD_STAGINGDIRECTORY\*.vsix + # Fail fast if signing/staging did not produce exactly one artifact, rather than + # passing a null or multi-element Resolve-Path result to --packagePath. + $vsixFiles = @(Get-ChildItem -Path $env:BUILD_STAGINGDIRECTORY -Filter '*.vsix' -File) + if ($vsixFiles.Count -ne 1) + { + throw "Expected exactly one .vsix in $env:BUILD_STAGINGDIRECTORY, found $($vsixFiles.Count)" + } + $packPath = $vsixFiles[0].FullName # Invoke the vsce installed globally in the previous step by its full path. # `npx @vscode/vsce` cannot be used here: npx only short circuits to an already # installed binary when the argument matches a bin name, so a package name always # forces a manifest fetch from the npm registry, which fails with E401 in this task. + # On Windows npm's global bin directory is the global prefix itself, so `npm prefix -g` + # locates the shim (`npm bin` was removed in npm v9 and is not an option). $vsce = Join-Path (npm prefix -g) 'vsce.cmd' if (-not (Test-Path $vsce)) {