chore: switch releases to tag-based publishing
Some checks failed
Release / release (push) Has been cancelled

This commit is contained in:
Onur 2026-03-10 17:48:41 +01:00
parent 88f9742221
commit 706e31b23d
5 changed files with 80 additions and 3648 deletions

View File

@ -1,17 +1,9 @@
name: Release
on:
workflow_dispatch:
inputs:
increment:
description: "Version bump (patch, minor, major)"
required: true
default: "patch"
type: choice
options:
- patch
- minor
- major
push:
tags:
- "v*.*.*"
concurrency:
group: release-${{ github.workflow }}-${{ github.ref }}
@ -30,7 +22,7 @@ jobs:
# "Unsupported GitHub Actions runner environment: self-hosted".
runs-on: ubuntu-latest
permissions:
contents: write
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
@ -47,8 +39,6 @@ jobs:
check-latest: true
cache: pnpm
- run: git config user.name "github-actions[bot]"
- run: git config user.email "github-actions[bot]@users.noreply.github.com"
- run: pnpm install --frozen-lockfile
- name: Validate package metadata for trusted publishing
@ -92,47 +82,73 @@ jobs:
console.log("Package metadata validated.");
NODE
- name: Validate release tag
env:
RELEASE_SHA: ${{ github.sha }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
git fetch --no-tags origin main --depth=1
node - <<'NODE'
const { execFileSync } = require("node:child_process");
const { readFileSync } = require("node:fs");
const releaseTag = process.env.RELEASE_TAG ?? "";
const releaseSha = process.env.RELEASE_SHA ?? "";
const semverTag = /^v\d+\.\d+\.\d+$/;
if (!semverTag.test(releaseTag)) {
console.error(
`Release tags must match vX.Y.Z; received ${releaseTag || "<missing>"}.`
);
process.exit(1);
}
const pkg = JSON.parse(readFileSync("package.json", "utf8"));
const expectedTag = `v${pkg.version}`;
if (releaseTag !== expectedTag) {
console.error(
`Release tag ${releaseTag} does not match package.json version ${pkg.version}; expected ${expectedTag}.`
);
process.exit(1);
}
try {
execFileSync(
"git",
["merge-base", "--is-ancestor", releaseSha, "origin/main"],
{ stdio: "ignore" }
);
} catch {
console.error(
`Tagged commit ${releaseSha} is not contained in origin/main.`
);
process.exit(1);
}
console.log(
`Release tag ${releaseTag} matches package.json and points to a commit on origin/main.`
);
NODE
- name: Ensure version is not already published
run: |
set -euo pipefail
PACKAGE_VERSION=$(node -p "require('./package.json').version")
PUBLISHED_VERSION=$(npm view acpx version 2>/dev/null || true)
if [ "$PUBLISHED_VERSION" = "$PACKAGE_VERSION" ]; then
echo "acpx@$PACKAGE_VERSION is already published on npm."
exit 1
fi
echo "Publishing acpx@$PACKAGE_VERSION"
- run: pnpm run lint
- run: pnpm run typecheck
- run: pnpm run build
# Sync the working tree to the currently published version, then let
# release-it perform the requested bump from that baseline.
- name: Bump version from npm registry
run: |
LATEST=$(npm view acpx version 2>/dev/null || echo "0.0.0")
echo "Latest on npm: $LATEST"
TARGET=$(node - "$LATEST" "${{ inputs.increment }}" <<'NODE'
const [version, increment] = process.argv.slice(2);
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
if (!match) {
throw new Error(`Unsupported semver: ${version}`);
}
const [major, minor, patch] = match.slice(1).map(Number);
if (increment === "patch") {
console.log(`${major}.${minor}.${patch + 1}`);
process.exit(0);
}
if (increment === "minor") {
console.log(`${major}.${minor + 1}.0`);
process.exit(0);
}
if (increment === "major") {
console.log(`${major + 1}.0.0`);
process.exit(0);
}
throw new Error(`Unsupported increment: ${increment}`);
NODE
)
npm version --no-git-tag-version "$LATEST" --allow-same-version
echo "VERSION=$TARGET" >> "$GITHUB_ENV"
echo "Releasing: $TARGET"
- name: Release
run: |
pnpm exec release-it "$VERSION" --ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_CONFIG_PROVENANCE: "true"
- name: Publish
run: npm publish --access public --provenance

View File

@ -178,11 +178,12 @@ CI lives in [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
Release automation lives in [`.github/workflows/release.yml`](.github/workflows/release.yml).
- Releases are manual (`workflow_dispatch`)
- Releases run when a `vX.Y.Z` tag is pushed
- The workflow installs dependencies with `pnpm install --frozen-lockfile`
- It validates `package.json` release metadata before publishing
- It validates that the tag matches `package.json` version and that the tagged commit is on `main`
- It runs `pnpm run lint`, `pnpm run typecheck`, and `pnpm run build`
- It bumps from the latest npm version and publishes through `release-it`
- It publishes directly to npm with trusted publishing and provenance
The release workflow currently requires these `package.json` values:

2207
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,6 @@
"precommit": "pnpm exec lint-staged && pnpm run -s build",
"prepack": "pnpm run build",
"prepare": "husky",
"release": "release-it",
"release:ci": "release-it --ci",
"test": "pnpm run build:test && node --test dist-test/test/*.test.js",
"test:coverage": "pnpm run build:test && node --experimental-test-coverage --test-coverage-lines=83 --test-coverage-branches=76 --test-coverage-functions=86 --test dist-test/test/*.test.js",
"typecheck": "tsgo --noEmit",
@ -67,7 +65,6 @@
"oxfmt": "^0.36.0",
"oxlint": "^1.51.0",
"oxlint-tsgolint": "^0.16.0",
"release-it": "^19.2.4",
"tsdown": "^0.21.0-beta.2",
"tsx": "^4.0.0",
"typescript": "^5.7.0"

1389
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff