From 39536f43fb184db5eb3f259eaf6ae70dcc1c3fe4 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Wed, 28 Oct 2026 14:53:40 -0700 Subject: [PATCH 1/3] CI: Auto-Release NPM types package on package.json merge --- CONTRIBUTING.md | 2 ++ build/azure-pipeline.npm.yml | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ccfab20f..4614fe50 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -167,6 +167,8 @@ this stable baseline: preview-only API publishing needs a separate policy. Public GitHub lookups use bounded retries and fail closed. Local runs can set `GITHUB_TOKEN` to avoid anonymous rate limits; PRs use their read-only token. +- **Releasing:** merging a stable version change in `api/package.json` into `main` automatically starts the [npm pipeline](./build/azure-pipeline.npm.yml), including its existing build, package tests, and MicroBuild approval process. Other manifest edits build and validate the package without publishing. The version check compares the merged commit with its parent, relying on the repository's squash-only merge policy; direct pushes to `main` also trigger it. Preview releases remain manual: queue the pipeline with `quality: preview` and `publishPackage: true`. Manual runs otherwise remain build-only unless `publishPackage` is explicitly enabled. + ## Internal Python agent-tool bridge The extension's existing **flat** export also provides `__pythonTools.version === 1`. diff --git a/build/azure-pipeline.npm.yml b/build/azure-pipeline.npm.yml index de35d4d8..152eae8f 100644 --- a/build/azure-pipeline.npm.yml +++ b/build/azure-pipeline.npm.yml @@ -1,6 +1,12 @@ name: $(Date:yyyyMMdd)$(Rev:.r) -trigger: none +trigger: + branches: + include: + - main + paths: + include: + - api/package.json pr: none resources: @@ -74,12 +80,32 @@ extends: targetPath: $(Build.ArtifactStagingDirectory) artifactName: npm-package steps: + - checkout: self + fetchDepth: 2 + - template: azure-pipelines/extension/templates/steps/setup.yml@templates parameters: installPython: false customNPMRegistry: $(AZURE_ARTIFACTS_FEED) nodeVersion: $(NodeVersion) + - script: | + node -e " + const { execFileSync } = require('node:child_process'); + const versionAt = (ref) => JSON.parse(execFileSync('git', ['show', ref + ':api/package.json'], { encoding: 'utf8' })).version; + const previous = versionAt('HEAD^'); + const current = versionAt('HEAD'); + if (typeof previous !== 'string' || typeof current !== 'string') { + throw new Error('Package version must be a string'); + } + const changed = previous !== current && !current.includes('-'); + process.stdout.write('Package version: ' + previous + ' -> ' + current + '\n'); + process.stdout.write('##vso[task.setvariable variable=versionChanged;isOutput=true]' + changed + '\n'); + " + name: checkVersion + displayName: Check for a stable package version change + condition: and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + - script: npm ci workingDirectory: $(Build.SourcesDirectory)/api displayName: Install package dependencies @@ -106,7 +132,7 @@ extends: - stage: PublishNPM displayName: Publish to NPM dependsOn: Build - condition: and(succeeded(), eq('${{ parameters.publishPackage }}', 'true')) + condition: and(succeeded(), or(eq('${{ parameters.publishPackage }}', 'true'), eq(dependencies.Build.outputs['BuildPackage.checkVersion.versionChanged'], 'true'))) jobs: - job: PublishPackage displayName: Publish npm package From 5470a8107931ba6aad946518b4e2a3ab4b3e6cb4 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Wed, 28 Oct 2026 16:38:06 -0700 Subject: [PATCH 2/3] Replace with bash script --- build/azure-pipeline.npm.yml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/build/azure-pipeline.npm.yml b/build/azure-pipeline.npm.yml index 152eae8f..1643fd50 100644 --- a/build/azure-pipeline.npm.yml +++ b/build/azure-pipeline.npm.yml @@ -89,19 +89,16 @@ extends: customNPMRegistry: $(AZURE_ARTIFACTS_FEED) nodeVersion: $(NodeVersion) - - script: | - node -e " - const { execFileSync } = require('node:child_process'); - const versionAt = (ref) => JSON.parse(execFileSync('git', ['show', ref + ':api/package.json'], { encoding: 'utf8' })).version; - const previous = versionAt('HEAD^'); - const current = versionAt('HEAD'); - if (typeof previous !== 'string' || typeof current !== 'string') { - throw new Error('Package version must be a string'); - } - const changed = previous !== current && !current.includes('-'); - process.stdout.write('Package version: ' + previous + ' -> ' + current + '\n'); - process.stdout.write('##vso[task.setvariable variable=versionChanged;isOutput=true]' + changed + '\n'); - " + - bash: | + set -euo pipefail + previous=$(git show HEAD^:api/package.json | jq -er '.version | strings') + current=$(git show HEAD:api/package.json | jq -er '.version | strings') + changed=false + if [[ "$previous" != "$current" && "$current" != *-* ]]; then + changed=true + fi + echo "Package version: $previous -> $current" + echo "##vso[task.setvariable variable=versionChanged;isOutput=true]$changed" name: checkVersion displayName: Check for a stable package version change condition: and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) From 303dd3d2ed129a8ed8739f76ea88217425d9824c Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Thu, 29 Oct 2026 14:08:25 -0700 Subject: [PATCH 3/3] docs: defer npm version bumps to stable API release PRs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b5e60842-41cd-4ad5-9e2d-37a206dcbda6 --- CONTRIBUTING.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4614fe50..a370c593 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,14 +143,17 @@ prerelease floors, and build metadata are rejected. The helper checks installed extension versions before activation using normal SemVer precedence, including already-active extensions. Published npm releases keep their original minimum. -Any PR editing a shared public API source or `api/runtime/**/*.ts` must bump the -npm version, update [`api/CHANGELOG.md`](./api/CHANGELOG.md), and update -[`docs/README.md`](./docs/README.md). The existing `skip api version`, -`skip api changelog`, and `skip api docs` labels apply to those file checks, but -do not bypass compatibility or publication validation. - -Release in this order: merge API changes, ship the stable extension, update the -npm minimum/version/changelog, then build and publish npm. Development can merge +Defer npm version bumps to release PRs by applying `skip api version` to API +implementation PRs. Any PR editing a shared public API source or +`api/runtime/**/*.ts` must still update [`api/CHANGELOG.md`](./api/CHANGELOG.md) +and [`docs/README.md`](./docs/README.md). The existing `skip api changelog` and +`skip api docs` labels apply to those file checks. None of these labels bypass +compatibility or publication validation. + +Release in this order: merge API changes without an npm version bump, ship the +stable extension, then merge an npm release PR updating +`minimumExtensionVersion`, the npm version, and the changelog. The stable npm +version bump starts the publication pipeline automatically. Development can merge before the extension ships: source provenance is checked at packaging, not on PRs. The npm pipeline resolves the stable release tag to an immutable commit and requires all five shared source files, including their staged copies, to match.