From 37df67839a25bbf503c4faddf517eaabe3bcc82c Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Wed, 21 Oct 2026 11:08:18 +0000 Subject: [PATCH 1/4] Automate post-release development version bumps Avoid leaving main on a released version by opening a reviewed alpha.0 bump after stable releases or a manual dispatch. Keep the root manifest and lockfile synchronized, guard against repeat bumps, and explicitly start CI for token-created PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/scripts/bump-version.cjs | 78 +++++++++ .github/scripts/bump-version.test.cjs | 165 ++++++++++++++++++ .github/workflows/bump-version-pr.yaml | 86 ++++++++- .github/workflows/main.yml | 3 + CONTRIBUTING.md | 23 +++ .../features/build-and-test-stack/README.md | 10 ++ .../features/build-and-test-stack/design.md | 15 ++ .../build-and-test-stack/pipelines.md | 7 +- 8 files changed, 376 insertions(+), 11 deletions(-) create mode 100644 .github/scripts/bump-version.cjs create mode 100644 .github/scripts/bump-version.test.cjs diff --git a/.github/scripts/bump-version.cjs b/.github/scripts/bump-version.cjs new file mode 100644 index 000000000..7b4349177 --- /dev/null +++ b/.github/scripts/bump-version.cjs @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const { execFileSync } = require('node:child_process'); +const fs = require('node:fs'); + +function readVersion() { + const manifest = JSON.parse(fs.readFileSync('package.json', 'utf8')); + const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); + if ( + typeof manifest.version !== 'string' || + lock.version !== manifest.version || + lock.packages?.['']?.version !== manifest.version + ) { + throw new Error('package.json and both root package-lock.json versions must match before and after the bump.'); + } + return manifest.version; +} + +function report(outputs, message) { + console.log(message); + if (process.env.GITHUB_OUTPUT) { + fs.appendFileSync( + process.env.GITHUB_OUTPUT, + Object.entries(outputs) + .map(([key, value]) => `${key}=${value}\n`) + .join(''), + ); + } + if (process.env.GITHUB_STEP_SUMMARY) { + fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, `## Development version bump\n\n${message}\n`); + } +} + +function main() { + const oldVersion = readVersion(); + const releaseTag = process.env.RELEASE_TAG; + if (releaseTag && releaseTag !== oldVersion && releaseTag !== `v${oldVersion}`) { + report( + { changed: false }, + `Skipped: release ${releaseTag} does not match the current main version ${oldVersion}.`, + ); + return; + } + if (/^\d+\.\d+\.\d+-/.test(oldVersion)) { + report({ changed: false }, `Skipped: main is already on development version ${oldVersion}.`); + return; + } + if (!/^\d+\.\d+\.\d+$/.test(oldVersion)) { + throw new Error(`Expected a numeric release version, received ${oldVersion}.`); + } + + execFileSync( + 'npm', + [ + 'version', + 'prerelease', + '--preid=alpha', + '--no-git-tag-version', + '--ignore-scripts', + '--workspaces=false', + '--package-lock=true', + ], + { stdio: 'inherit' }, + ); + const newVersion = readVersion(); + if (!/^\d+\.\d+\.\d+-alpha\.0$/.test(newVersion)) { + throw new Error(`Expected the first alpha of the next patch version, received ${newVersion}.`); + } + report( + { changed: true, 'old-version': oldVersion, 'new-version': newVersion }, + `Updated package.json and both root package-lock.json versions: **${oldVersion} -> ${newVersion}**.`, + ); +} + +main(); diff --git a/.github/scripts/bump-version.test.cjs b/.github/scripts/bump-version.test.cjs new file mode 100644 index 000000000..f0158c6f7 --- /dev/null +++ b/.github/scripts/bump-version.test.cjs @@ -0,0 +1,165 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const assert = require('node:assert/strict'); +const { execFileSync, spawnSync } = require('node:child_process'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { test } = require('node:test'); + +const script = path.join(__dirname, 'bump-version.cjs'); + +function fixture(t, version = '1.0.1') { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'documentdb-version-bump-')); + t.after(() => fs.rmSync(directory, { recursive: true, force: true })); + const lifecycle = 'node -e "throw new Error(\'Version lifecycle scripts must not run\')"'; + const manifest = { + name: 'version-bump-fixture', + version, + private: true, + workspaces: ['packages/*'], + dependencies: { 'fixture-dependency': '7.8.9' }, + scripts: { preversion: lifecycle, version: lifecycle, postversion: lifecycle }, + }; + const lock = { + name: manifest.name, + version, + lockfileVersion: 3, + requires: true, + packages: { + '': { + name: manifest.name, + version, + workspaces: manifest.workspaces, + dependencies: manifest.dependencies, + }, + 'packages/example': { name: 'fixture-workspace', version: '4.5.6' }, + 'node_modules/fixture-workspace': { resolved: 'packages/example', link: true }, + 'node_modules/fixture-dependency': { version: '7.8.9' }, + }, + }; + fs.mkdirSync(path.join(directory, 'packages/example'), { recursive: true }); + fs.writeFileSync(path.join(directory, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`); + fs.writeFileSync(path.join(directory, 'package-lock.json'), `${JSON.stringify(lock, null, 2)}\n`); + fs.writeFileSync( + path.join(directory, 'packages/example/package.json'), + `${JSON.stringify({ name: 'fixture-workspace', version: '4.5.6' }, null, 2)}\n`, + ); + return { directory, manifest, lock }; +} + +function run(directory, releaseTag = '') { + return spawnSync(process.execPath, [script], { + cwd: directory, + encoding: 'utf8', + env: { + ...process.env, + RELEASE_TAG: releaseTag, + GITHUB_OUTPUT: path.join(directory, 'outputs'), + GITHUB_STEP_SUMMARY: path.join(directory, 'summary'), + npm_config_update_notifier: 'false', + }, + }); +} + +function read(directory, file) { + return JSON.parse(fs.readFileSync(path.join(directory, file), 'utf8')); +} + +for (const releaseTag of ['', 'v1.0.1', '1.0.1']) { + test(`Bumps only the root manifest and lockfile to alpha.0 (${releaseTag || 'manual'})`, (t) => { + const { directory, manifest, lock } = fixture(t); + const workspace = fs.readFileSync(path.join(directory, 'packages/example/package.json'), 'utf8'); + execFileSync('git', ['init', '--quiet'], { cwd: directory }); + + const result = run(directory, releaseTag); + + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(read(directory, 'package.json'), { ...manifest, version: '1.0.2-alpha.0' }); + assert.deepEqual(read(directory, 'package-lock.json'), { + ...lock, + version: '1.0.2-alpha.0', + packages: { ...lock.packages, '': { ...lock.packages[''], version: '1.0.2-alpha.0' } }, + }); + assert.equal(fs.readFileSync(path.join(directory, 'packages/example/package.json'), 'utf8'), workspace); + assert.equal( + fs.readFileSync(path.join(directory, 'outputs'), 'utf8'), + 'changed=true\nold-version=1.0.1\nnew-version=1.0.2-alpha.0\n', + ); + assert.match(fs.readFileSync(path.join(directory, 'summary'), 'utf8'), /1\.0\.1 -> 1\.0\.2-alpha\.0/); + assert.equal(execFileSync('git', ['tag', '--list'], { cwd: directory, encoding: 'utf8' }), ''); + assert.notEqual(spawnSync('git', ['rev-parse', '--verify', 'HEAD'], { cwd: directory }).status, 0); + }); +} + +for (const version of ['1.0.2-alpha.0', '1.0.2-alpha.1', '1.1.0-beta.0']) { + test(`Does not advance an existing development version (${version})`, (t) => { + const { directory, manifest, lock } = fixture(t, version); + + const result = run(directory); + + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(read(directory, 'package.json'), manifest); + assert.deepEqual(read(directory, 'package-lock.json'), lock); + assert.equal(fs.readFileSync(path.join(directory, 'outputs'), 'utf8'), 'changed=false\n'); + assert.match(result.stdout, /already on development version/); + }); +} + +for (const releaseTag of ['v0.11.2', 'v1.1.0', 'unrelated-package-v1.0.1']) { + test(`Skips a release that does not match main (${releaseTag})`, (t) => { + const { directory, manifest, lock } = fixture(t); + + const result = run(directory, releaseTag); + + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(read(directory, 'package.json'), manifest); + assert.deepEqual(read(directory, 'package-lock.json'), lock); + assert.equal(fs.readFileSync(path.join(directory, 'outputs'), 'utf8'), 'changed=false\n'); + assert.match(result.stdout, /does not match the current main version/); + }); +} + +test('A repeated manual run does not produce alpha.1', (t) => { + const { directory } = fixture(t); + assert.equal(run(directory).status, 0); + fs.writeFileSync(path.join(directory, 'outputs'), ''); + + const result = run(directory); + + assert.equal(result.status, 0, result.stderr); + assert.equal(read(directory, 'package.json').version, '1.0.2-alpha.0'); + assert.equal(fs.readFileSync(path.join(directory, 'outputs'), 'utf8'), 'changed=false\n'); +}); + +for (const field of ['version', 'root-package']) { + test(`Fails before modifying files if the lockfile is out of sync (${field})`, (t) => { + const { directory, manifest, lock } = fixture(t); + if (field === 'version') { + lock.version = '1.0.0'; + } else { + lock.packages[''].version = '1.0.0'; + } + fs.writeFileSync(path.join(directory, 'package-lock.json'), JSON.stringify(lock)); + + const result = run(directory); + + assert.notEqual(result.status, 0); + assert.match(result.stderr, /both root package-lock.json versions must match/); + assert.deepEqual(read(directory, 'package.json'), manifest); + assert.deepEqual(read(directory, 'package-lock.json'), lock); + assert.equal(fs.existsSync(path.join(directory, 'outputs')), false); + }); +} + +test('Fails explicitly for an unsupported version', (t) => { + const { directory } = fixture(t, 'not-a-version'); + + const result = run(directory); + + assert.notEqual(result.status, 0); + assert.match(result.stderr, /Expected a numeric release version/); +}); diff --git a/.github/workflows/bump-version-pr.yaml b/.github/workflows/bump-version-pr.yaml index f1d679e2b..7f086fb52 100644 --- a/.github/workflows/bump-version-pr.yaml +++ b/.github/workflows/bump-version-pr.yaml @@ -1,30 +1,98 @@ name: Bump version after release -# Disabled for now โ€” comment out the trigger block to prevent execution on: - # release: - # types: [published] + release: + types: [published] workflow_dispatch: +permissions: + actions: write + contents: write + pull-requests: write + +concurrency: + group: bump-version-after-release + cancel-in-progress: false + jobs: bump: + if: github.event_name == 'workflow_dispatch' || !github.event.release.prerelease runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: main + + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 + with: + node-version-file: .nvmrc - name: Bump version id: bump - uses: alexweininger/bump-prerelease-version@91183ecfa908d49e9e7c1c62e9c781a49aa7c307 # v0.1.1 + run: node .github/scripts/bump-version.cjs + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} - name: Create pull request + id: pr + if: steps.bump.outputs.changed == 'true' uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: - title: ${{ env.MESSAGE }} - body: Automatically created by ${{ env.RUN_LINK }} - commit-message: ${{ env.MESSAGE }} + title: 'chore: prepare ${{ steps.bump.outputs.new-version }} development' + body: | + ## Why this PR exists + + Move `main` to the next development version after a release, so ongoing + development is no longer labelled with an already released version. + The published release and its tag are unchanged. + + ## Version change + + | File | Old version | New version | + | --- | --- | --- | + | `package.json` | `${{ steps.bump.outputs.old-version }}` | **`${{ steps.bump.outputs.new-version }}`** | + | `package-lock.json` (both root version entries) | `${{ steps.bump.outputs.old-version }}` | **`${{ steps.bump.outputs.new-version }}`** | + + `alpha.0` means the **first alpha of the next patch version**. The `.0` + is the prerelease counter, not an additional patch number. Re-running + this workflow does not advance it to `alpha.1`. + + Only the root extension version is updated; workspace package versions + and dependency versions are unchanged. This PR does **not** publish an + extension, create a release, or change release notes. Before publishing + the next release, replace the alpha version with its intended numeric + release version. + + ## Review and merge + + This PR is **ready for review**, not a draft. The workflow explicitly + starts **full CI** on this branch, so no separate token secret or manual + CI dispatch is needed. Review the changes and merge after the required + checks pass. + + GitHub may also request approval for PR-triggered workflows because + this PR was created with `GITHUB_TOKEN`. If shown, select + **Approve workflows to run** for those additional runs. + + ## Source + + - Trigger: ${{ github.event_name == 'release' && format('[Release {0}]({1})', github.event.release.tag_name, github.event.release.html_url) || 'Manual workflow run' }} + - [Workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) + commit-message: 'chore: prepare ${{ steps.bump.outputs.new-version }} development' branch: bot/bump-${{ steps.bump.outputs.new-version }} base: main + draft: false + delete-branch: true + add-paths: | + package.json + package-lock.json author: GitHub + + - name: Start full CI for the pull request + if: steps.pr.outputs.pull-request-number != '' + run: gh workflow run main.yml --ref "$PR_BRANCH" -f enforce_full_run=true env: - RUN_LINK: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - MESSAGE: Bump version after release + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + PR_BRANCH: ${{ steps.pr.outputs.pull-request-branch }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a5a03f05..e5fec20fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -242,6 +242,9 @@ jobs: - name: ๐Ÿงช Run Unit Tests (Vitest) run: npm test + - name: Test release automation + run: node --test .github/scripts/*.test.cjs + package-checks: name: 'npm packages: verify tarballs' needs: [plan] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8f9bec79..705f88a25 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -423,6 +423,29 @@ Always ship the signed artifact from the pipeline. A locally packaged `.vsix` is 3. Attach the **signed** `.vsix` downloaded in the previous step. 4. Save the release. +Publishing a stable GitHub release also starts [Bump version after release](.github/workflows/bump-version-pr.yaml). +When its tag matches the version on `main`, the workflow opens a ready-for-review PR for the next patch's +first development version, for example `1.0.1` โ†’ `1.0.2-alpha.0`. It updates `package.json` and +both root version entries in `package-lock.json`, leaving workspace package versions unchanged. +The workflow explicitly starts full CI on the PR's branch. Review and merge it once the required +checks pass. If GitHub requests approval for additional PR-triggered workflows, select +**Approve workflows to run**. The published release and tag are not modified. +The alpha suffix is for development only; use the intended numeric release +version at [ยง7.4](#74-bump-the-version) before the next publication. + +To catch up after a release, select **Actions โ†’ Bump version after release โ†’ Run workflow** on +`main`, or run: + +```bash +gh workflow run bump-version-pr.yaml --ref main +``` + +The workflow always operates on `main`. Re-running it reuses the same version-specific PR while +`main` is still on the released version; after the bump is merged, it leaves the existing alpha +version alone. GitHub prereleases are ignored, as are releases whose tags do not match the version +on `main` (for example, a patch release from an older release branch). The repository's +**Settings โ†’ Actions โ†’ General โ†’ Workflow permissions** must allow Actions to create pull requests. + ### 7.9 Publish to the Marketplace Run the second internal Azure DevOps pipeline, the **release** pipeline, which publishes to the Visual Studio Marketplace from whichever branch holds the release commit โ€” `main` for a normal release, or the `release/` branch when a patch was cut off a tag ([ยง1.3](#13-releases)). This is a separate pipeline from the build in ยง7.7: one produces and signs the artifact, the other ships it. diff --git a/docs/ai-and-plans/features/build-and-test-stack/README.md b/docs/ai-and-plans/features/build-and-test-stack/README.md index 82144c333..beda84aae 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/README.md +++ b/docs/ai-and-plans/features/build-and-test-stack/README.md @@ -127,6 +127,16 @@ coverage into installed-workbench E2E; see the 5. Tests for verification tooling belong beside that tool and run through `npm run test:verification`, not the main Vitest project unless the local config says otherwise. +## Post-release version automation + +[`bump-version-pr.yaml`](../../../../.github/workflows/bump-version-pr.yaml) runs after stable +GitHub releases and on manual dispatch. It always operates on `main`, requires release tags to +match its current version, and proposes the next patch's first alpha in a ready-for-review PR. The root +manifest and both lockfile version entries stay synchronized; workspace versions are not bumped. +Reruns reuse the same PR or skip an existing development version. The workflow explicitly +dispatches full CI on the PR branch without a separate token secret. +See [the release process](../../../../CONTRIBUTING.md#78-create-the-github-release). + ## Durable documents - [Design and invariants](./design.md) diff --git a/docs/ai-and-plans/features/build-and-test-stack/design.md b/docs/ai-and-plans/features/build-and-test-stack/design.md index 70b87b996..04aca81b2 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/design.md +++ b/docs/ai-and-plans/features/build-and-test-stack/design.md @@ -161,6 +161,21 @@ representative calls through every public entry point. The real-VS-Code unbundle CommonJS `await import()` and ESM loading to pass, and records synchronous CommonJS `require()` as the known unsupported case. +### Post-release version bumps are root-only, idempotent, and reviewed + +The release-bump workflow checks out `main`, not the release tag or the manually selected ref. +Automatic runs ignore GitHub prereleases and tags that do not match `main`'s package version. +Both automatic and manual runs propose only the next patch's `alpha.0`; they never increment an +existing development version to `alpha.1`. The root manifest and both root lockfile versions must +agree before and after npm runs. Workspace package and dependency versions stay unchanged. + +The workflow creates or updates a version-specific, ready-for-review PR using `GITHUB_TOKEN`, +with explicit actions, contents and pull-request write permissions. It dispatches `main.yml` on +the PR branch with `enforce_full_run=true`, so the complete CI suite and required `Merge gate` +run without a separate token secret or approval. Additional PR-triggered workflows may require +a maintainer's approval under GitHub's token-event rules. No release is published or tag modified. +The development alpha must be replaced with a numeric release version before publication. + ## Change discipline Change a config and the relevant rationale together. Package before claiming a bundle change works, diff --git a/docs/ai-and-plans/features/build-and-test-stack/pipelines.md b/docs/ai-and-plans/features/build-and-test-stack/pipelines.md index 129118062..82173ed68 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/pipelines.md +++ b/docs/ai-and-plans/features/build-and-test-stack/pipelines.md @@ -42,11 +42,14 @@ the operator-run ADO build and the G0 manual checklist passed on 2026-10-02 (G0) | `api-extractor.yaml` | Push to `main` and `release/**`; PRs | Extracts the public API typings | | `api-publish.yaml` | Manual | Publishes the API typings package to npm | | `npm-publish-documentdb-js.yml` | Manual; `dry_run` defaults to `true`, one checkbox per package | Builds, type-checks package tests, tests and verifies packages, and dry-runs publication; explicit real publication to npmjs with provenance requires successful verification and environment approval | -| `bump-version-pr.yaml` | Manual | Opens the version bump PR after a release | +| `bump-version-pr.yaml` | Stable GitHub release published; manual | Opens or updates a ready-for-review PR into `main` for the next patch's `alpha.0`, updating the root manifest and lockfile, then explicitly dispatches full CI on its branch. Release tags must match `main`; existing development versions are left alone. | | `deploy-documentation-production.yml` | Push to `main` touching `docs/**`; manual | Deploys the documentation site | | `seed-build-cache.yml` | Manual (`seed` / `verify`) | Build-size cache | -All of them install from **public npmjs**: there is no `.npmrc` at the repository root. +Workflows that install dependencies use **public npmjs**: there is no `.npmrc` at the repository +root. The version-bump workflow needs no dependency installation; it runs the repository's +`.github/scripts/bump-version.cjs` with Node from `.nvmrc` and npm. Its integration tests run in +the CI unit-tests job. All checkouts in `main.yml` use `actions/checkout`'s default ref: GitHub's synthetic **merge ref for PRs**, and `github.sha` for push/manual runs. Stage 6 restores this policy From d9dc4d0970990ac132d23f7e0862290e94c4da32 Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Wed, 21 Oct 2026 13:14:04 +0000 Subject: [PATCH 2/4] docs: restore CI formatting for release automation inventory Align the workflow inventory table with the repository formatter so the required static check no longer fails after the release-bump entry changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/ai-and-plans/features/build-and-test-stack/pipelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ai-and-plans/features/build-and-test-stack/pipelines.md b/docs/ai-and-plans/features/build-and-test-stack/pipelines.md index 82173ed68..4b54cd5e6 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/pipelines.md +++ b/docs/ai-and-plans/features/build-and-test-stack/pipelines.md @@ -42,7 +42,7 @@ the operator-run ADO build and the G0 manual checklist passed on 2026-10-02 (G0) | `api-extractor.yaml` | Push to `main` and `release/**`; PRs | Extracts the public API typings | | `api-publish.yaml` | Manual | Publishes the API typings package to npm | | `npm-publish-documentdb-js.yml` | Manual; `dry_run` defaults to `true`, one checkbox per package | Builds, type-checks package tests, tests and verifies packages, and dry-runs publication; explicit real publication to npmjs with provenance requires successful verification and environment approval | -| `bump-version-pr.yaml` | Stable GitHub release published; manual | Opens or updates a ready-for-review PR into `main` for the next patch's `alpha.0`, updating the root manifest and lockfile, then explicitly dispatches full CI on its branch. Release tags must match `main`; existing development versions are left alone. | +| `bump-version-pr.yaml` | Stable GitHub release published; manual | Opens or updates a ready-for-review PR into `main` for the next patch's `alpha.0`, updating the root manifest and lockfile, then explicitly dispatches full CI on its branch. Release tags must match `main`; existing development versions are left alone. | | `deploy-documentation-production.yml` | Push to `main` touching `docs/**`; manual | Deploys the documentation site | | `seed-build-cache.yml` | Manual (`seed` / `verify`) | Build-size cache | From c99ebd824fbbf834eaff08df7c94b8b0d85fb34f Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Wed, 21 Oct 2026 13:15:06 +0000 Subject: [PATCH 3/4] docs: preserve release automation review and fix provenance Record the confirmed formatting failure, the operator's instruction, the separately pushed fix, and verification limits so remaining review gates are explicit rather than implied complete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../features/build-and-test-stack/README.md | 1 + .../02-post-release-version-review.md | 75 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md diff --git a/docs/ai-and-plans/features/build-and-test-stack/README.md b/docs/ai-and-plans/features/build-and-test-stack/README.md index beda84aae..7fd7f7ada 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/README.md +++ b/docs/ai-and-plans/features/build-and-test-stack/README.md @@ -144,5 +144,6 @@ See [the release process](../../../../CONTRIBUTING.md#78-create-the-github-relea - [Pipeline guide](./pipelines.md) - [Deferred work](./future-work.md) - [Modernization iteration](./iterations/01-modernization/build-and-test-stack.md) and its reviews +- [Post-release version automation review](./iterations/02-post-release-version-review.md) - [E2E strategy](../e2e-testing/strategy.md) - [Data-grid replacement plan](../data-grid/slickgrid-removal.md) diff --git a/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md b/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md new file mode 100644 index 000000000..75702431e --- /dev/null +++ b/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md @@ -0,0 +1,75 @@ +--- +feature: build-and-test-stack +kind: review +status: active +prs: [1042] +created: 2026-10-21 +--- + +# Post-release version automation review + +- **PR:** [#1042](https://github.com/microsoft/vscode-documentdb/pull/1042). +- **Reviewed commit:** `37df67839a25bbf503c4faddf517eaabe3bcc82c`. +- **Scope:** release filtering, the root-only version bump and its integration tests, rerun behavior, + pull-request action inputs and outputs, explicit full-CI dispatch, merge requirements, and related + contributor and feature documentation. +- **Method:** direct diff and code review; checked the pinned pull-request action's declared outputs, + the repository's required checks, CI logs, and GitHub's token-trigger rules. The local build and all + 13 release-automation integration tests passed during the review. +- **Author instruction:** after receiving the review, the operator requested: "good, document and fix + fixable issues according to the contributing md file." + +## F01: pipeline inventory formatting fails the required merge gate + +- **Severity:** low; merge-blocking CI failure, not a release-automation logic defect. +- **Where:** the GitHub Actions inventory table in [pipelines.md](../pipelines.md#github-actions-githubworkflows). +- **Evidence:** [CI run 39589761800](https://github.com/microsoft/vscode-documentdb/actions/runs/39589761800), + [static-check job](https://github.com/microsoft/vscode-documentdb/actions/runs/39589761800/job/119187582908). + Prettier reports only `docs/ai-and-plans/features/build-and-test-stack/pipelines.md`. + The final quality check reports `l10n=success, lint=success, prettier=failure`, causing both + `Static checks` and the required `Merge gate` to fail. +- **Recommended fix:** format the affected Markdown document with the repository's existing Prettier + configuration. This repairs the required check without changing workflow behavior. +- **Author decision:** fix under the operator's instruction above. The confirmed formatting failure + is the fixable issue from the review; no new product or workflow design decision is required. +- **Implementation:** F01 fixed in + [d9dc4d09](https://github.com/microsoft/vscode-documentdb/commit/d9dc4d09): + formatted the pipeline inventory table to restore the required Prettier check, without changing + release-automation behavior. Targeted formatting, the Case 1 build, and all 13 release-automation + integration tests passed. The fix was committed and pushed separately under CONTRIBUTING section 6.3. +- **Validation:** `npm run build` passed; `node --test .github/scripts/bump-version.test.cjs` + passed all 13 tests. The focused Prettier check passed for the affected guide, this review record, + and the feature README; `git diff --check` passed. The repository-wide `prettier-fix` command + was not run because the PR remains a draft. + +## C01: bot pull-request creation remains an operational check + +- **Classification:** verification limitation, not a confirmed code defect. +- **Evidence:** the workflow-permissions endpoint returned HTTP 403 with the available credentials. + No live bump run was performed, so actual bot PR creation and the subsequent CI dispatch have not + been exercised together. +- **Disposition:** leave repository settings and live automation unchanged. The operator authorized + fixing confirmed issues, not publishing a release or creating a test bump PR. Existing + [release instructions](../../../../../CONTRIBUTING.md#78-create-the-github-release) already describe + the required Actions PR-creation permission and the catch-up command. +- **Remaining check:** a maintainer must confirm Actions may create pull requests and observe the + first intended bump run after merge. + +## Review stages and handoff + +- The initial direct review found no blocking logic defects. +- The active PR had no inline review threads or GitHub Copilot reviewer findings to merge when + checked on 2026-10-21. Its only timeline feedback was the CI report. +- This record does not claim completion of the different-vendor validation gate or independent + sweep in [CONTRIBUTING.md section 6.1](../../../../../CONTRIBUTING.md#61-stage-1-ai-review-pass-run-by-the-contributor). + Those stages remain prerequisites before requesting human review. +- Keep PR #1042 in draft: this is **Case 1**, not a ready-for-review handoff. The full Case 2 + checks, including repository-wide `prettier-fix`, remain deferred until that handoff. + +## Outcome + +The confirmed formatting failure is fixed, validated locally, and pushed without changing the +automation implementation. F01 records the implementation commit and verification inline. +The review record and its feature-index link accompany the fix, and implementation comments are +posted on the PR. Live bot permissions and end-to-end operation remain explicitly unverified. +PR #1042 remains a draft; this is not a claim that the full pre-review or Case 2 checks have run. From feec7fe554b7da1e23073afbc3cb378986521597 Mon Sep 17 00:00:00 2001 From: Tomasz Naumowicz Date: Wed, 21 Oct 2026 14:05:06 +0000 Subject: [PATCH 4/4] Record completed release automation handoff checks Preserve the full Case 2 verification results and distinguish the remaining review-stage evidence gap from completed build and test validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../02-post-release-version-review.md | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md b/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md index 75702431e..1a05ffea9 100644 --- a/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md +++ b/docs/ai-and-plans/features/build-and-test-stack/iterations/02-post-release-version-review.md @@ -63,8 +63,8 @@ created: 2026-10-21 - This record does not claim completion of the different-vendor validation gate or independent sweep in [CONTRIBUTING.md section 6.1](../../../../../CONTRIBUTING.md#61-stage-1-ai-review-pass-run-by-the-contributor). Those stages remain prerequisites before requesting human review. -- Keep PR #1042 in draft: this is **Case 1**, not a ready-for-review handoff. The full Case 2 - checks, including repository-wide `prettier-fix`, remain deferred until that handoff. +- At the initial follow-up, PR #1042 remained in draft under **Case 1**. The full Case 2 + checks, including repository-wide `prettier-fix`, were deferred until the handoff below. ## Outcome @@ -72,4 +72,33 @@ The confirmed formatting failure is fixed, validated locally, and pushed without automation implementation. F01 records the implementation commit and verification inline. The review record and its feature-index link accompany the fix, and implementation comments are posted on the PR. Live bot permissions and end-to-end operation remain explicitly unverified. -PR #1042 remains a draft; this is not a claim that the full pre-review or Case 2 checks have run. +The initial follow-up did not claim that the full pre-review or Case 2 checks had run. + +## Ready-for-review handoff checks, 2026-10-21 + +The operator requested: "review completed, move forward to marking it as ready for review." +The full **Case 2** suite ran on the branch at `c99ebd82`, even though the review-stage +evidence described above remains incomplete. + +| Check | Result | +| --------------------------------------------------- | ----------------------------------------------- | +| `npm run prettier-fix` | Passed; no tracked changes | +| `npm run lint` | Passed | +| `npx vitest run` | 314 files passed; 5,184 tests passed, 1 skipped | +| `npm run build` | Passed | +| `npm run package` | Passed; VSIX produced | +| `node --test .github/scripts/bump-version.test.cjs` | All 13 tests passed | +| `npm run l10n` | Not applicable; no localized strings changed | + +The PR was assigned to milestone **1.0.2**. Packaging emitted non-failing CSS warnings; no +unrelated source changes were made. + +**Remaining handoff blocker:** this committed record explicitly leaves the cross-vendor +validation gate and independent sweep incomplete. The operator's review-completed statement +does not identify those stages or their results. A follow-up request for confirmation was +unanswered; no completion evidence or author decisions have been invented. The PR remains a +draft until those stages are confirmed and recorded. The successful Case 2 checks are no +longer deferred. + +The separate operational limitation in C01 remains: Actions PR-creation permission and a live +bot-PR/CI-dispatch run still require observation after merge.