From db901f8522adbdc80eb69c9519b8d99b4cf39be2 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Thu, 27 Aug 2026 15:13:33 +0200 Subject: [PATCH 1/2] ci(release): publish any prerelease tag under its own dist-tag The publish step only special-cased "-alpha", so a v5.8.0-beta.1 tag fell through to the else branch and moved the "latest" dist-tag, shipping a prerelease to every consumer on ^5. Derive the dist-tag from the tag's prerelease identifier instead, which covers beta and rc without a branch per channel, and reserve "latest" for plain vX.Y.Z tags. The draft GitHub release is now flagged --prerelease for those versions too. release.sh gains an optional preid argument: lerna defaults the prerelease identifier to "alpha", so beta was previously unreachable through the script. --- .github/workflows/release.yml | 25 +++++++++++++++++++++---- scripts/release.sh | 20 ++++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c2314f08..743c15dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -71,11 +71,24 @@ jobs: - if: github.event_name == 'push' name: Publish the libraries run: | - if [[ "${{ github.ref }}" == *"-alpha"* ]]; then - pnpm publish -r --access=public --no-git-checks --tag=alpha - else + # Prerelease tags publish under their own identifier (alpha, beta, rc); + # only a plain vX.Y.Z tag is allowed to move the `latest` dist-tag. + VERSION="${GITHUB_REF_NAME#v}" + if [[ "$VERSION" != *-* ]]; then pnpm publish -r --access=public --no-git-checks + exit 0 fi + + PREID="${VERSION#*-}" + PREID="${PREID%%.*}" + # npm rejects a dist-tag that parses as a semver range, so a numeric + # identifier has no channel to publish under, and `latest` is the + # stable channel a prerelease must never take over. + if [[ ! "$PREID" =~ ^[A-Za-z][A-Za-z0-9-]*$ || "${PREID,,}" == "latest" ]]; then + echo "Refusing to publish $GITHUB_REF_NAME: '$PREID' cannot be a prerelease dist-tag" >&2 + exit 1 + fi + pnpm publish -r --access=public --no-git-checks --tag="$PREID" env: NPM_CONFIG_PROVENANCE: true # Surfaces npm's OIDC token exchange, which is otherwise silent. @@ -85,6 +98,10 @@ jobs: name: Create a draft release run: | NEW_VERSION=$(pnpm lerna list --json | jq -r '.[] | select(.name == "@codspeed/core") | .version') - gh release create v$NEW_VERSION --title "v$NEW_VERSION" --generate-notes -d + PRERELEASE="" + if [[ "$NEW_VERSION" == *-* ]]; then + PRERELEASE="--prerelease" + fi + gh release create "v$NEW_VERSION" --title "v$NEW_VERSION" --generate-notes -d $PRERELEASE env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/release.sh b/scripts/release.sh index 46b9b932..1c8adbcf 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Usage: ./scripts/release.sh +# Usage: ./scripts/release.sh [preid] set -ex # Fail if not on main @@ -8,12 +8,24 @@ if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then exit 1 fi -if [ $# -ne 1 ]; then - echo "Usage: ./release.sh " +if [ $# -lt 1 ] || [ $# -gt 2 ]; then + echo "Usage: ./release.sh [preid]" exit 1 fi +# lerna defaults the prerelease identifier to "alpha"; the dist-tag the release +# workflow publishes under is derived from it, so it must be spelled out for +# any other channel. +PREID=() +if [ $# -eq 2 ]; then + if [[ ! "$2" =~ ^[a-z][a-z0-9-]*$ || "$2" == "latest" ]]; then + echo "Invalid prerelease identifier: '$2' (expected e.g. alpha, beta, rc)" + exit 1 + fi + PREID=(--preid "$2") +fi + # Fail if there are any unstaged changes left git diff --exit-code -pnpm lerna version "$1" --force-publish --no-private --sign-git-tag +pnpm lerna version "$1" "${PREID[@]}" --force-publish --no-private --sign-git-tag From 04337539a97808032975ce40c29beb175445a85a Mon Sep 17 00:00:00 2001 From: not-matthias Date: Thu, 27 Aug 2026 15:24:42 +0200 Subject: [PATCH 2/2] docs: document release bump levels and the prerelease identifier The release process was undocumented outside of a one-line usage comment, and the prerelease identifier is the part a maintainer has to get right: it selects the npm dist-tag consumers install from, and lerna silently defaults it to "alpha". Adds a CONTRIBUTING.md with the release and prerelease commands, following the structure used in the runner and pytest-codspeed repos, and expands the usage header of release.sh with the bump levels and worked examples. --- CONTRIBUTING.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++ scripts/release.sh | 36 ++++++++++++++++++--------------- 2 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..f1ce6c8d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing + +## Releasing a New Version + +To create a new version, run: + +```bash +./scripts/release.sh patch # Increment PATCH component (e.g., 1.2.3 -> 1.2.4) +./scripts/release.sh minor # Increment MINOR component (e.g., 1.2.3 -> 1.3.0) +./scripts/release.sh major # Increment MAJOR component (e.g., 1.2.3 -> 2.0.0) +``` + +All packages share a single version, bumped in lockstep by `lerna version`. + +### Prereleases + +A new prerelease series is started by passing the version explicitly, and +continued with `prerelease`, which keeps the identifier it already has (the +label between the `-` and the counter): + +```bash +./scripts/release.sh 5.8.0-beta.0 # 5.7.1 -> 5.8.0-beta.0 +./scripts/release.sh prerelease # 5.8.0-beta.0 -> 5.8.0-beta.1 +``` + +The identifier becomes the npm dist-tag, so a prerelease is installed only by +asking for it: + +```bash +pnpm add @codspeed/vitest-plugin@beta +``` + +`latest` keeps pointing at the most recent stable release, and `^5` never +resolves to a prerelease. + +### What happens + +1. **`scripts/release.sh`**: + - Refuses to run outside `main` or with a dirty working tree + - Runs `lerna version`, which bumps every package, commits, creates a signed + `vX.Y.Z` tag and pushes it + +2. **CI release workflow** (`.github/workflows/release.yml`): + - Triggered automatically when the tag is pushed + - Builds the native addon prebuilds for linux-arm and darwin-arm + - Builds the libraries + - Publishes to npm via OIDC trusted publishing, under the dist-tag derived + from the tag's prerelease identifier (`latest` for a plain `vX.Y.Z` tag) + - Creates a draft GitHub release, flagged as a prerelease when the version + has a prerelease identifier diff --git a/scripts/release.sh b/scripts/release.sh index 1c8adbcf..2a605156 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,5 +1,21 @@ #!/bin/bash -# Usage: ./scripts/release.sh [preid] +# +# Usage: ./scripts/release.sh +# +# version major | minor | patch stable release +# prerelease next prerelease of the current version, +# keeping its identifier +# X.Y.Z-.N explicit version, used to start a new +# prerelease series +# +# The identifier of a prerelease version (e.g. "beta" in 5.8.0-beta.0) becomes +# the npm dist-tag the release workflow publishes under, so consumers opt in +# with `pnpm add @codspeed/core@beta` while `latest` keeps pointing at the last +# stable release. +# +# ./scripts/release.sh patch 5.7.1 -> 5.7.2 (dist-tag latest) +# ./scripts/release.sh 5.8.0-beta.0 5.7.1 -> 5.8.0-beta.0 (dist-tag beta) +# ./scripts/release.sh prerelease 5.8.0-beta.0 -> 5.8.0-beta.1 (dist-tag beta) set -ex # Fail if not on main @@ -8,24 +24,12 @@ if [ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]; then exit 1 fi -if [ $# -lt 1 ] || [ $# -gt 2 ]; then - echo "Usage: ./release.sh [preid]" +if [ $# -ne 1 ]; then + echo "Usage: ./release.sh " exit 1 fi -# lerna defaults the prerelease identifier to "alpha"; the dist-tag the release -# workflow publishes under is derived from it, so it must be spelled out for -# any other channel. -PREID=() -if [ $# -eq 2 ]; then - if [[ ! "$2" =~ ^[a-z][a-z0-9-]*$ || "$2" == "latest" ]]; then - echo "Invalid prerelease identifier: '$2' (expected e.g. alpha, beta, rc)" - exit 1 - fi - PREID=(--preid "$2") -fi - # Fail if there are any unstaged changes left git diff --exit-code -pnpm lerna version "$1" "${PREID[@]}" --force-publish --no-private --sign-git-tag +pnpm lerna version "$1" --force-publish --no-private --sign-git-tag