Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 19 additions & 28 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ jobs:

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-node@v4
with:
Expand All @@ -37,37 +35,30 @@ jobs:
- name: Build
run: npm run build

- name: Resolve version bump
id: bump
- name: Check if version is already published
id: check
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
RANGE="HEAD"
VERSION=$(node -p "require('./package.json').version")
if git tag -l "v${VERSION}" | grep -q .; then
echo "published=true" >> "$GITHUB_OUTPUT"
else
RANGE="${LAST_TAG}..HEAD"
echo "published=false" >> "$GITHUB_OUTPUT"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

BUMP=""
while IFS= read -r subject; do
[ -z "$subject" ] && continue
if echo "$subject" | grep -qE '^[a-z]+(\(.+\))?!:'; then
BUMP="major"; break
fi
if [ "$BUMP" != "minor" ] && echo "$subject" | grep -qE '^feat(\(.+\))?:'; then
BUMP="minor"
fi
if [ -z "$BUMP" ] && echo "$subject" | grep -qE '^fix(\(.+\))?:'; then
BUMP="patch"
fi
done < <(git log "$RANGE" --format="%s" --no-merges)

echo "type=$BUMP" >> "$GITHUB_OUTPUT"

- name: Publish
if: steps.bump.outputs.type
- name: Tag and publish
if: steps.check.outputs.published == 'false'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
npm version "${{ steps.bump.outputs.type }}" -m "chore(release): %s"
git push --follow-tags
git tag "v${{ steps.check.outputs.version }}"
git push origin "v${{ steps.check.outputs.version }}"
npm publish --provenance --access public

- name: Create GitHub release
if: steps.check.outputs.published == 'false'
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "v${{ steps.check.outputs.version }}" --generate-notes
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"lint:fix": "biome check --fix .",
"check-types": "tsc --noEmit",
"bench": "vitest bench --run",
"release": "./scripts/release.sh",
"prepare": "lefthook install"
},
"engines": {
Expand Down
76 changes: 76 additions & 0 deletions scripts/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
set -euo pipefail

OVERRIDE="${1:-}"

if [[ -n "$OVERRIDE" && ! "$OVERRIDE" =~ ^(patch|minor|major)$ ]]; then
echo "Usage: npm run release [-- patch|minor|major]"
echo " Omit argument to auto-detect from conventional commits."
exit 1
fi

if [[ -n "$(git status --porcelain)" ]]; then
echo "Working directory is not clean. Commit or stash changes first."
exit 1
fi

CURRENT_BRANCH=$(git branch --show-current)
if [[ "$CURRENT_BRANCH" != "master" ]]; then
echo "Switch to master before running release."
exit 1
fi

git pull --ff-only origin master

if [[ -n "$OVERRIDE" ]]; then
BUMP="$OVERRIDE"
else
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [[ -n "$LAST_TAG" ]]; then
RANGE="${LAST_TAG}..HEAD"
else
RANGE="HEAD"
fi

BUMP=""
while IFS= read -r subject; do
[[ -z "$subject" ]] && continue
if [[ "$subject" =~ ^[a-z]+(\(.+\))?!: ]]; then
BUMP="major"; break
fi
if [[ "$BUMP" != "minor" && "$subject" =~ ^feat(\(.+\))?: ]]; then
BUMP="minor"
fi
if [[ -z "$BUMP" && "$subject" =~ ^fix(\(.+\))?: ]]; then
BUMP="patch"
fi
done < <(git log "$RANGE" --format="%s" --no-merges)

if [[ -z "$BUMP" ]]; then
echo "No releasable commits found since ${LAST_TAG:-the beginning}."
echo "Use 'npm run release -- patch|minor|major' to override."
exit 0
fi

echo "Auto-detected bump: $BUMP"
fi

npm version "$BUMP" --no-git-tag-version
VERSION=$(node -p "require('./package.json').version")
BRANCH="release/v${VERSION}"

git checkout -b "$BRANCH"
git add package.json package-lock.json
git commit -m "chore(release): v${VERSION}"
git push -u origin "$BRANCH"

gh pr create \
--base master \
--head "$BRANCH" \
--title "chore(release): v${VERSION}" \
--body "Bumps version to \`${VERSION}\` (${BUMP}).

Merging will tag and publish to npm automatically."

echo ""
echo "PR created. Merge it to publish v${VERSION} to npm."
Loading