From 46af9b706682cdaaf8268a705f09cd5396b13cda Mon Sep 17 00:00:00 2001 From: Sergiu Oala Date: Wed, 2 Sep 2026 12:52:11 +0000 Subject: [PATCH 1/3] ci: publish release candidates --- .github/prerelease-config.json | 11 +++++++++ .github/prerelease-manifest.json | 3 +++ .github/release-config.json | 18 +++++++++++++++ .github/release-manifest.json | 3 +++ .github/workflows/npm-publish.yml | 9 +++++++- .github/workflows/release-please.yml | 34 +++++++++++++++++++++++----- 6 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 .github/prerelease-config.json create mode 100644 .github/prerelease-manifest.json create mode 100644 .github/release-config.json create mode 100644 .github/release-manifest.json diff --git a/.github/prerelease-config.json b/.github/prerelease-config.json new file mode 100644 index 0000000..14cf864 --- /dev/null +++ b/.github/prerelease-config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "node", + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "prerelease-type": "rc", + "packages": { + ".": {} + } +} diff --git a/.github/prerelease-manifest.json b/.github/prerelease-manifest.json new file mode 100644 index 0000000..529b133 --- /dev/null +++ b/.github/prerelease-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "8.1.0" +} diff --git a/.github/release-config.json b/.github/release-config.json new file mode 100644 index 0000000..0df416e --- /dev/null +++ b/.github/release-config.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "node", + "include-component-in-tag": false, + "versioning": "default", + "prerelease": false, + "packages": { + ".": { + "extra-files": [ + { + "type": "json", + "path": ".github/prerelease-manifest.json", + "jsonpath": "$[\".\"]" + } + ] + } + } +} diff --git a/.github/release-manifest.json b/.github/release-manifest.json new file mode 100644 index 0000000..529b133 --- /dev/null +++ b/.github/release-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "8.1.0" +} diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 74d0fbf..3a53652 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -76,4 +76,11 @@ jobs: registry-url: https://registry.npmjs.org - name: publish to npm - run: npm publish --provenance + env: + RELEASE_TAG: ${{ inputs.tag }} + run: | + if [[ "$RELEASE_TAG" == *-rc* ]]; then + npm publish --provenance --tag rc + else + npm publish --provenance + fi diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 7db34f2..adb4330 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -11,21 +11,43 @@ permissions: # npm-publish is dispatched explicitly below. workflow_dispatch is one of the # few events that always creates a run, even from GITHUB_TOKEN. actions: write + +concurrency: + group: release-please + cancel-in-progress: false + jobs: release-please: runs-on: ubuntu-latest steps: - uses: googleapis/release-please-action@v5 - id: release + id: prerelease + with: + token: ${{ secrets.GITHUB_TOKEN }} + config-file: .github/prerelease-config.json + manifest-file: .github/prerelease-manifest.json + target-branch: ${{ github.ref_name }} + + # Once an RC PR is merged and tagged, replace it with the stable Release + # PR. The stable config also synchronizes the prerelease manifest when + # that stable PR is eventually merged. + - name: create stable Release PR + if: >- + steps.prerelease.outputs.releases_created == 'true' && + contains(steps.prerelease.outputs.tag_name, '-rc') + uses: googleapis/release-please-action@v5 with: - release-type: node + token: ${{ secrets.GITHUB_TOKEN }} + config-file: .github/release-config.json + manifest-file: .github/release-manifest.json + target-branch: ${{ github.ref_name }} - # releases_created is only true on the run that tagged a release, which is - # the run triggered by merging the release PR. + # The prerelease action recognizes merges of both RC and stable Release + # PRs. It creates the corresponding tag and GitHub Release in either case. - name: trigger npm-publish - if: steps.release.outputs.releases_created == 'true' + if: steps.prerelease.outputs.releases_created == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - TAG: ${{ steps.release.outputs.tag_name }} + TAG: ${{ steps.prerelease.outputs.tag_name }} run: gh workflow run npm-publish.yml --ref "$GITHUB_REF_NAME" -f tag="$TAG" From 79f4a84b5e946ee89ccce1e90c92505405b0e65c Mon Sep 17 00:00:00 2001 From: Sergiu Oala Date: Wed, 2 Sep 2026 15:43:00 +0000 Subject: [PATCH 2/3] ci: bootstrap manifests at 9.0.0 and document RC releases Co-authored-by: Cursor --- .github/prerelease-manifest.json | 2 +- .github/release-manifest.json | 2 +- README.md | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/prerelease-manifest.json b/.github/prerelease-manifest.json index 529b133..9285669 100644 --- a/.github/prerelease-manifest.json +++ b/.github/prerelease-manifest.json @@ -1,3 +1,3 @@ { - ".": "8.1.0" + ".": "9.0.0" } diff --git a/.github/release-manifest.json b/.github/release-manifest.json index 529b133..9285669 100644 --- a/.github/release-manifest.json +++ b/.github/release-manifest.json @@ -1,3 +1,3 @@ { - ".": "8.1.0" + ".": "9.0.0" } diff --git a/README.md b/README.md index 4692cdd..0876c6e 100644 --- a/README.md +++ b/README.md @@ -545,12 +545,13 @@ make codestyle-fix ### Releasing -Releases are automated with [release-please](https://github.com/googleapis/release-please#readme): +Releases are automated with [release-please](https://github.com/googleapis/release-please#readme). Versioning comes from conventional commits on `master` (`fix:` patches, `feat:` minor, `!` / `BREAKING CHANGE` major). `chore:` does not bump. There is a **single** shared Release PR; RC and stable take turns on it. -1. Merge conventional-commit-style PRs (`fix:`, `feat:`, etc.) into `master`. -2. `release-please` opens or updates a Release PR with the version bump and changelog. -3. Review and merge the Release PR when ready to ship. -4. `release-please` tags the release and dispatches the `npm-publish` workflow, which validates and publishes the package to npm. +1. Merge `fix:` / `feat:` PRs into `master`. `release-please` opens or updates that PR as a **release candidate** (`X.Y.Z-rc`, then `X.Y.Z-rc.1`, …). `package.json` on the PR is already the version that will be tagged. +2. Merge the RC PR when you want to cut an RC. `release-please` tags a GitHub **prerelease** (`vX.Y.Z-rc`) and dispatches `npm-publish`. Approve the **Publish** environment to publish to npm with dist-tag `rc`; withhold approval to skip npm (the git tag still exists). +3. After the RC merge, the shared PR is rewritten as the matching **stable** Release PR (`X.Y.Z`). +4. Merge that stable PR to ship `X.Y.Z` (GitHub Release + `npm-publish` without `--tag rc`, npm dist-tag `latest`). Same **Publish** approval gate. +5. Further `fix:` / `feat:` commits on `master` while the stable PR is still open rewrite it into the **next RC** (`X.Y.Z-rc.1`, …) instead of shipping that stable. Use that when you want another candidate; merge stable with no extra bumping commits when you want to publish `latest`. ## License From f757dffee1a276050771eec3ade336a46f1f415b Mon Sep 17 00:00:00 2001 From: Sergiu Oala Date: Wed, 2 Sep 2026 15:55:31 +0000 Subject: [PATCH 3/3] docs: clarify withholding approval skips npm publishing Co-authored-by: Cursor --- .github/prerelease-manifest.json | 2 +- .github/release-manifest.json | 2 +- .github/workflows/npm-publish.yml | 6 +++--- README.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/prerelease-manifest.json b/.github/prerelease-manifest.json index 9285669..256be89 100644 --- a/.github/prerelease-manifest.json +++ b/.github/prerelease-manifest.json @@ -1,3 +1,3 @@ { - ".": "9.0.0" + ".": "9.0.1" } diff --git a/.github/release-manifest.json b/.github/release-manifest.json index 9285669..256be89 100644 --- a/.github/release-manifest.json +++ b/.github/release-manifest.json @@ -1,3 +1,3 @@ { - ".": "9.0.0" + ".": "9.0.1" } diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 3a53652..d1ec75a 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -75,12 +75,12 @@ jobs: node-version: 26.x registry-url: https://registry.npmjs.org - - name: publish to npm + - name: npm stage publish env: RELEASE_TAG: ${{ inputs.tag }} run: | if [[ "$RELEASE_TAG" == *-rc* ]]; then - npm publish --provenance --tag rc + npm stage publish --provenance --tag rc else - npm publish --provenance + npm stage publish --provenance fi diff --git a/README.md b/README.md index 0876c6e..4344520 100644 --- a/README.md +++ b/README.md @@ -548,9 +548,9 @@ make codestyle-fix Releases are automated with [release-please](https://github.com/googleapis/release-please#readme). Versioning comes from conventional commits on `master` (`fix:` patches, `feat:` minor, `!` / `BREAKING CHANGE` major). `chore:` does not bump. There is a **single** shared Release PR; RC and stable take turns on it. 1. Merge `fix:` / `feat:` PRs into `master`. `release-please` opens or updates that PR as a **release candidate** (`X.Y.Z-rc`, then `X.Y.Z-rc.1`, …). `package.json` on the PR is already the version that will be tagged. -2. Merge the RC PR when you want to cut an RC. `release-please` tags a GitHub **prerelease** (`vX.Y.Z-rc`) and dispatches `npm-publish`. Approve the **Publish** environment to publish to npm with dist-tag `rc`; withhold approval to skip npm (the git tag still exists). +2. Merge the RC PR when you want to cut an RC. `release-please` tags a GitHub **prerelease** (`vX.Y.Z-rc`) and dispatches `npm-publish`. Approve the **Publish** environment to run `npm stage publish --provenance --tag rc`; withhold approval to skip staging (the git tag still exists). A maintainer then approves the staged package on npm (2FA) before it is installable. 3. After the RC merge, the shared PR is rewritten as the matching **stable** Release PR (`X.Y.Z`). -4. Merge that stable PR to ship `X.Y.Z` (GitHub Release + `npm-publish` without `--tag rc`, npm dist-tag `latest`). Same **Publish** approval gate. +4. Merge that stable PR to ship `X.Y.Z` (GitHub Release + `npm stage publish --provenance`, npm dist-tag `latest` after npm approval). Same **Publish** environment gate, then npm 2FA approve. 5. Further `fix:` / `feat:` commits on `master` while the stable PR is still open rewrite it into the **next RC** (`X.Y.Z-rc.1`, …) instead of shipping that stable. Use that when you want another candidate; merge stable with no extra bumping commits when you want to publish `latest`. ## License