Files
better-auth/.github/workflows/verify-changesets.yml

143 lines
5.6 KiB
YAML

name: Verify Changesets
on:
pull_request:
types: [opened, synchronize, labeled, unlabeled, edited]
branches:
- main
- next
- 'release/**'
paths:
- '.changeset/**'
- 'packages/**'
permissions: {}
jobs:
verify:
runs-on: ubuntu-latest
if: >
!startsWith(github.head_ref, 'changeset-release/') &&
!(github.head_ref == 'next' && github.base_ref == 'main' && github.event.pull_request.head.repo.full_name == github.repository) &&
!(github.head_ref == 'main' && github.base_ref == 'next' && github.event.pull_request.head.repo.full_name == github.repository) &&
github.actor != 'github-actions[bot]' &&
github.actor != 'better-release[bot]'
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Block pre.json on main
if: github.base_ref == 'main'
env:
BASE_REF: ${{ github.base_ref }}
run: |
if git diff --diff-filter=d --name-only "origin/$BASE_REF"...HEAD | grep -q '^\.changeset/pre\.json$'; then
echo "::error::.changeset/pre.json must not be committed to main. Pre-release mode belongs on the 'next' branch only."
exit 1
fi
- name: Get changed changeset files
id: changed
env:
BASE_REF: ${{ github.base_ref }}
run: |
FILES=$(git diff --diff-filter=dr --name-only "origin/$BASE_REF"...HEAD -- '.changeset/*.md' | grep -v 'README.md' || true)
COUNT=$(echo "$FILES" | grep -c '.' || true)
{
echo "files<<EOF"
echo "$FILES"
echo "EOF"
echo "count=$COUNT"
echo "has_changesets=$( [ "$COUNT" -gt 0 ] && echo true || echo false )"
} >> "$GITHUB_OUTPUT"
- name: Check package changes require changeset
if: steps.changed.outputs.has_changesets == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BASE_REF: ${{ github.base_ref }}
run: |
LABELS=$(gh pr view "$PR_NUMBER" --json labels --jq '.labels[].name' 2>/dev/null || echo "")
if echo "$LABELS" | grep -q "skip-changeset"; then
echo "Skipping changeset requirement (skip-changeset label found)"
exit 0
fi
PKG_CHANGES=$(git diff --name-only "origin/$BASE_REF"...HEAD -- 'packages/' | grep -c '.' || true)
if [ "$PKG_CHANGES" -eq 0 ]; then
echo "No package changes detected, changeset not required"
exit 0
fi
echo "::error::Missing changeset. Add one with 'pnpm changeset' or add the 'skip-changeset' label."
exit 1
- name: Validate changeset files
if: steps.changed.outputs.has_changesets == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BASE_REF: ${{ github.base_ref }}
CHANGESET_FILES: ${{ steps.changed.outputs.files }}
run: |
HAS_ERROR=0
for f in $CHANGESET_FILES; do
if [ -L "$f" ]; then
echo "::error::Changeset $f is a symlink, which is not allowed."
HAS_ERROR=1
continue
fi
BASENAME=$(basename "$f")
if ! echo "$BASENAME" | grep -qE '^[a-z][a-z0-9-]*\.md$'; then
echo "::error::Changeset $f has an invalid filename. Use only lowercase letters, digits, and hyphens."
HAS_ERROR=1
continue
fi
if ! head -1 "$f" | grep -q '^---$'; then
echo "::error::Changeset $f is missing YAML frontmatter opening fence."
HAS_ERROR=1
continue
fi
if ! sed -n '2,$ p' "$f" | grep -q '^---$'; then
echo "::error::Changeset $f is missing YAML frontmatter closing fence."
HAS_ERROR=1
continue
fi
BODY=$(sed -n '2,/^---$/p' "$f" | head -n -1)
while IFS= read -r line; do
[ -z "$line" ] && continue
if ! echo "$line" | grep -qE '^"[^"]+"\s*:\s*(major|minor|patch|none)\s*$'; then
echo "::error::Changeset $f has invalid entry: $line — expected '\"package-name\": patch|minor|major|none'"
HAS_ERROR=1
fi
done <<< "$BODY"
done
[ "$HAS_ERROR" -ne 0 ] && exit 1
if [ "$BASE_REF" = "main" ] || echo "$BASE_REF" | grep -q '^release/'; then
for f in $CHANGESET_FILES; do
BUMPS=$(sed -n '/^---$/,/^---$/p' "$f" | grep -oE '(major|minor|patch)' | sort -u)
if echo "$BUMPS" | grep -q "major"; then
echo "::error::Changeset $f contains a 'major' bump. Only 'patch' bumps are allowed on '$BASE_REF'. PRs with minor/major bumps should target 'next' (auto-retarget may not have run yet)."
exit 1
fi
if echo "$BUMPS" | grep -q "minor"; then
echo "::error::Changeset $f contains a 'minor' bump. Only 'patch' bumps are allowed on '$BASE_REF'. PRs with minor/major bumps should target 'next' (auto-retarget may not have run yet)."
exit 1
fi
done
echo "All changesets are patch-only ($BASE_REF branch policy)"
else
echo "Target is $BASE_REF, all bump types allowed"
fi