feat(ci): add alpha/beta/rc pre-release support to publish workflow (#167)

This commit is contained in:
James Russo
2026-03-31 14:16:57 -07:00
committed by GitHub
parent b866a28545
commit e6a38c9e0f
3 changed files with 59 additions and 10 deletions
+23 -8
View File
@@ -29,11 +29,23 @@ jobs:
id: version
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
VERSION="${GITHUB_REF_NAME#v}"
else
BRANCH="${{ github.event.pull_request.head.ref }}"
echo "version=${BRANCH#release/v}" >> "$GITHUB_OUTPUT"
VERSION="${BRANCH#release/v}"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
# Detect pre-release tag (e.g. 0.1.16-alpha.1 → alpha, 0.1.16-beta.2 → beta)
if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then
DIST_TAG="${BASH_REMATCH[1]}"
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
DIST_TAG="latest"
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi
echo "dist_tag=${DIST_TAG}" >> "$GITHUB_OUTPUT"
echo "Resolved version=${VERSION} dist_tag=${DIST_TAG}"
- name: Create release tag
if: github.event_name == 'pull_request'
@@ -56,6 +68,7 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
DIST_TAG="${{ steps.version.outputs.dist_tag }}"
FAILED=0
publish_pkg() {
@@ -69,7 +82,7 @@ jobs:
fi
echo "📦 Publishing ${name}@${VERSION}..."
if pnpm --filter "$filter" publish --access public --no-git-checks; then
if pnpm --filter "$filter" publish --access public --no-git-checks --tag "$DIST_TAG"; then
echo "✅ ${name}@${VERSION} published"
else
echo "❌ ${name}@${VERSION} failed to publish"
@@ -96,7 +109,7 @@ jobs:
fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n');
"
echo "📦 Publishing hyperframes@${VERSION}..."
if (cd packages/cli && npm publish --access public); then
if (cd packages/cli && npm publish --access public --tag "$DIST_TAG"); then
echo "✅ hyperframes@${VERSION} published"
else
echo "❌ hyperframes@${VERSION} failed to publish"
@@ -114,12 +127,14 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.version.outputs.version }}"
PRERELEASE="${{ steps.version.outputs.prerelease }}"
# Skip if release already exists (idempotent re-runs)
if gh release view "v${VERSION}" --repo "${{ github.repository }}" >/dev/null 2>&1; then
echo "Release v${VERSION} already exists — skipping"
else
gh release create "v${VERSION}" \
--repo "${{ github.repository }}" \
--title "v${VERSION}" \
--generate-notes
FLAGS=(--repo "${{ github.repository }}" --title "v${VERSION}" --generate-notes)
if [ "$PRERELEASE" = "true" ]; then
FLAGS+=(--prerelease)
fi
gh release create "v${VERSION}" "${FLAGS[@]}"
fi
+22
View File
@@ -59,6 +59,8 @@ Git hooks (via [lefthook](https://github.com/evilmartians/lefthook)) run automat
All packages use **fixed versioning** — every release bumps all packages to the same version.
### Stable releases
```bash
bun run set-version 0.2.0 # bumps all packages, commits, and creates git tag
git push origin main --tags # triggers the publish workflow
@@ -66,6 +68,26 @@ git push origin main --tags # triggers the publish workflow
The `set-version` script automatically creates a `chore: release v<version>` commit and a `v<version>` git tag. Pushing the tag triggers CI to publish all packages to npm and create a GitHub Release.
### Pre-releases (alpha / beta / rc)
Use a pre-release suffix to publish to a named npm dist-tag instead of `latest`:
```bash
bun run set-version 0.2.0-alpha.1 # first alpha
git push origin v0.2.0-alpha.1 # publishes to npm with --tag alpha
bun run set-version 0.2.0-alpha.2 # iterate
bun run set-version 0.2.0-beta.1 # promote to beta (--tag beta)
bun run set-version 0.2.0-rc.1 # release candidate (--tag rc)
bun run set-version 0.2.0 # final stable release (--tag latest)
```
Consumers install pre-releases with `npm install @hyperframes/core@alpha` (or `@beta`, `@rc`). The `latest` tag is never touched by pre-releases, so `npm install @hyperframes/core` always gets the last stable version.
Pre-releases also create GitHub Releases marked as **pre-release**.
### Options
If you need to bump versions without committing (e.g., for a release PR), pass `--no-tag`:
```bash
+14 -2
View File
@@ -4,10 +4,13 @@
* then create a git commit and tag.
*
* Usage:
* bun run set-version 0.1.1 # bump, commit, and tag
* bun run set-version 0.1.1 # stable release → npm "latest" tag
* bun run set-version 0.1.1-alpha.1 # pre-release → npm "alpha" tag
* bun run set-version 0.1.1 --no-tag # bump only (no commit or tag)
*
* All packages share a single version number (fixed versioning).
* Pre-release suffixes (-alpha, -beta, -rc, etc.) are detected by the
* publish workflow and published to the corresponding npm dist-tag.
*/
import { readFileSync, writeFileSync } from "fs";
@@ -79,7 +82,16 @@ function main() {
execSync(`git commit -m "chore: release v${version}"`, { cwd: ROOT, stdio: "inherit" });
execSync(`git tag v${version}`, { cwd: ROOT, stdio: "inherit" });
console.log(`\nCreated commit and tag v${version}`);
console.log(`Run 'git push origin main --tags' to trigger the publish workflow.`);
const isPrerelease = version.includes("-");
if (isPrerelease) {
const distTag = version.replace(/^.*-([a-zA-Z]+).*$/, "$1");
console.log(`\nThis is a pre-release — npm dist-tag will be "${distTag}" (not "latest").`);
console.log(`Consumers install with: npm install @hyperframes/core@${distTag}`);
console.log(`\nRun 'git push origin v${version}' to trigger the publish workflow.`);
} else {
console.log(`Run 'git push origin main --tags' to trigger the publish workflow.`);
}
}
main();