From 22e932e2d5f60665bc4384ed3ce6ba957e596dbb Mon Sep 17 00:00:00 2001 From: Taesu <166604494+bytaesu@users.noreply.github.com> Date: Thu, 10 Sep 2026 17:54:53 +0900 Subject: [PATCH] ci(release): bootstrap v1.6 release workflows (#11239) --- .github/workflows/release-notes-draft.yml | 15 + .github/workflows/release.yml | 457 +--------------------- .github/workflows/verify-changesets.yml | 166 +------- docker-compose.yml | 2 +- 4 files changed, 24 insertions(+), 616 deletions(-) create mode 100644 .github/workflows/release-notes-draft.yml diff --git a/.github/workflows/release-notes-draft.yml b/.github/workflows/release-notes-draft.yml new file mode 100644 index 0000000000..c7eb2357ac --- /dev/null +++ b/.github/workflows/release-notes-draft.yml @@ -0,0 +1,15 @@ +name: Release Notes Draft + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review, edited] + +permissions: {} + +jobs: + draft: + permissions: + pull-requests: write + uses: better-auth/better-auth/.github/workflows/release-notes-draft.yml@0e02187ab45a903c66986fc5e28cddd37185147b + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6395cf3d27..ff4d7998ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,465 +1,20 @@ -# cSpell:words anthropics name: Release on: push: branches: - - main - - next - - release/** + - v1.6.x workflow_dispatch: - inputs: - snapshot: - description: 'Snapshot tag (e.g. "snapshot"). Leave empty for normal release.' - required: false - default: '' - type: string - preview_version: - description: 'Preview release notes for a version (e.g. "1.6.0-beta.0"). Leave empty for normal release.' - required: false - default: '' - type: string - preview_branch: - description: 'Branch to read changeset data from (for preview mode).' - required: false - default: 'next' - type: string permissions: {} -concurrency: - group: ${{ github.workflow }}-${{ github.ref_name }} - cancel-in-progress: false - -env: - BETTER_AUTH_TELEMETRY_ENDPOINT: ${{ vars.BETTER_AUTH_TELEMETRY_ENDPOINT }} - jobs: release: - if: > - (github.event_name != 'workflow_dispatch' || (inputs.snapshot == '' && inputs.preview_version == '')) && - github.repository_owner == 'better-auth' && - (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/next' || startsWith(github.ref, 'refs/heads/release/')) - runs-on: ubuntu-latest - environment: Release - permissions: - contents: write - pull-requests: write - id-token: write - env: - # The release bot's auto-commit must not be gated by the local pre-commit hooks. - LEFTHOOK: "0" - steps: - - name: Generate App Token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - if: vars.RELEASE_APP_ID != '' - with: - app-id: ${{ vars.RELEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - fetch-depth: 0 - persist-credentials: false - token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - - - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version-file: '.nvmrc' - registry-url: 'https://registry.npmjs.org' - package-manager-cache: false - - - run: pnpm install --frozen-lockfile - - - name: Guard next branch pre-release state - id: guard - if: github.ref_name == 'next' - run: | - if [ ! -f .changeset/pre.json ]; then - echo "::warning::next branch is not in pre-release mode (promote in progress). Skipping release." - echo "skip=true" >> "$GITHUB_OUTPUT" - fi - - - name: Determine npm dist-tag - id: npm-tag - run: | - REF="${GITHUB_REF_NAME}" - if [[ "$REF" == "main" ]]; then - echo "tag=latest" >> "$GITHUB_OUTPUT" - elif [[ "$REF" =~ ^release/ ]]; then - # Maintenance branches publish with a version-specific tag (e.g., release-1.5) - TAG="release-${REF#release/}" - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - else - # next and other branches: changesets handles the tag via pre.json - echo "tag=" >> "$GITHUB_OUTPUT" - fi - env: - GITHUB_REF_NAME: ${{ github.ref_name }} - - - name: Create Release Pull Request or Publish - id: changesets - if: steps.guard.outputs.skip != 'true' - uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0 - with: - version: pnpm ci:version - publish: pnpm ci:release - title: "chore: release" - commit: "chore: release" - createGithubReleases: false - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - NPM_CONFIG_TAG: ${{ steps.npm-tag.outputs.tag }} - - - name: Rename release PR with version - if: steps.changesets.outputs.pullRequestNumber - continue-on-error: true - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ steps.changesets.outputs.pullRequestNumber }} - run: | - VERSION=$(jq -r '.version' packages/better-auth/package.json) - gh pr edit "$PR_NUMBER" --title "chore: release v${VERSION}" - - - name: Generate raw release notes - id: raw-notes - if: steps.changesets.outputs.published == 'true' - continue-on-error: true - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} - run: node .github/scripts/release-notes.ts --branch "$GITHUB_REF_NAME" - - - name: Build AI prompt from template - id: ai-prompt - if: steps.raw-notes.outcome == 'success' - continue-on-error: true - env: - RAW_PATH: ${{ steps.raw-notes.outputs.raw_changelog_path }} - CONTEXT_PATH: ${{ steps.raw-notes.outputs.context_path }} - run: | - PROMPT=$(sed \ - -e "s|__RAW_CHANGELOG_PATH__|${RAW_PATH}|g" \ - -e "s|__CONTEXT_PATH__|${CONTEXT_PATH:-none}|g" \ - -e "s|__GITHUB_REPOSITORY__|${GITHUB_REPOSITORY}|g" \ - .github/prompts/release-notes-rewrite.md) - EOF_DELIM="PROMPT_EOF_$(openssl rand -hex 8)" - { - echo "prompt<<${EOF_DELIM}" - echo "$PROMPT" - echo "${EOF_DELIM}" - } >> "$GITHUB_OUTPUT" - - - name: Rewrite release notes with AI - id: ai-notes - if: steps.ai-prompt.outcome == 'success' - continue-on-error: true - uses: anthropics/claude-code-action/base-action@11ba60486e4aec9ddfeafcf4bb3f00b028ac2c16 # v1.0.142 - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - prompt: ${{ steps.ai-prompt.outputs.prompt }} - claude_args: --max-turns 100 --allowedTools "Read Write Bash(gh pr diff*) Bash(gh pr view*)" - - - name: Validate AI output - if: steps.ai-notes.outcome == 'success' - continue-on-error: true - env: - RAW_PATH: ${{ steps.raw-notes.outputs.raw_changelog_path }} - run: | - FINAL="${RAW_PATH}.final" - if [ ! -f "$FINAL" ]; then - echo "AI did not produce output file" - exit 0 - fi - - # Count PR links in both files - RAW_COUNT=$(grep -coP "\\[#\\d+\\]" "$RAW_PATH" 2>/dev/null || true) - RAW_COUNT=${RAW_COUNT:-0} - FINAL_COUNT=$(grep -coP "\\[#\\d+\\]" "$FINAL" 2>/dev/null || true) - FINAL_COUNT=${FINAL_COUNT:-0} - - if [ "$FINAL_COUNT" -lt "$RAW_COUNT" ]; then - echo "::warning::AI output has fewer PR links ($FINAL_COUNT) than raw ($RAW_COUNT). Falling back to raw notes." - rm -f "$FINAL" - exit 0 - fi - - # Verify all package headings from raw are present in final - MISSING=0 - while IFS= read -r heading; do - if ! grep -qF "$heading" "$FINAL"; then - echo "::warning::Missing package heading: $heading" - MISSING=$((MISSING + 1)) - fi - done < <(grep -oP "## \`[^\`]+\`" "$RAW_PATH") - - if [ "$MISSING" -gt 0 ]; then - echo "::warning::AI output is missing $MISSING package heading(s). Falling back to raw notes." - rm -f "$FINAL" - fi - - - name: Create GitHub Release - if: steps.changesets.outputs.published == 'true' - continue-on-error: true - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - VERSION: ${{ steps.raw-notes.outputs.version }} - IS_BETA: ${{ steps.raw-notes.outputs.is_beta }} - RAW_PATH: ${{ steps.raw-notes.outputs.raw_changelog_path }} - PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} - run: | - # Determine version: from raw-notes output, or parse from publishedPackages - if [ -z "$VERSION" ]; then - VERSION=$(echo "$PUBLISHED_PACKAGES" | jq -r '.[0].version // empty') - fi - if [ -z "$VERSION" ]; then - echo "::warning::Could not determine version, skipping release creation" - exit 0 - fi - - TAG="v${VERSION}" - - # Use AI-rewritten notes > raw notes > minimal fallback - if [ -n "$RAW_PATH" ] && [ -f "${RAW_PATH}.final" ]; then - NOTES_FILE="${RAW_PATH}.final" - echo "Using AI-rewritten release notes" - elif [ -n "$RAW_PATH" ] && [ -f "${RAW_PATH}" ]; then - NOTES_FILE="${RAW_PATH}" - echo "Using raw release notes (AI step skipped or failed)" - else - NOTES_FILE=$(mktemp) - echo "Release ${TAG}" > "$NOTES_FILE" - echo "Using minimal fallback (note generation failed)" - fi - - # Tag the exact commit that triggered this workflow run - COMMIT_SHA="${GITHUB_SHA}" - - # Create tag via GitHub API (git push has no credentials with persist-credentials: false) - gh api "repos/${GITHUB_REPOSITORY}/git/refs" \ - -f ref="refs/tags/${TAG}" -f sha="$COMMIT_SHA" 2>/dev/null \ - || echo "Tag $TAG already exists" - - # Create or update release, targeting the exact commit - PRERELEASE_FLAG="" - if [ "$IS_BETA" = "true" ] || echo "$VERSION" | grep -q '-'; then - PRERELEASE_FLAG="--prerelease" - fi - - if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then - gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --notes-file "$NOTES_FILE" $PRERELEASE_FLAG - echo "Updated release $TAG" - else - gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --title "$TAG" --notes-file "$NOTES_FILE" --target "$COMMIT_SHA" $PRERELEASE_FLAG - echo "Created release $TAG" - fi - - - name: Sync main to next via PR - if: github.ref_name == 'main' - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - run: | - git fetch origin next || { echo "next branch does not exist, skipping"; exit 0; } - - AHEAD=$(git rev-list --count origin/next..origin/main) - if [ "$AHEAD" -eq 0 ]; then - echo "No new commits to sync" - exit 0 - fi - echo "Found $AHEAD commit(s) to sync from main to next" - - EXISTING=$(gh pr list --base next --head "${GITHUB_REPOSITORY_OWNER}:main" --state open --repo "$GITHUB_REPOSITORY" --json number --jq '.[0].number // empty') - if [ -n "$EXISTING" ]; then - echo "Sync PR #$EXISTING already exists ($AHEAD commits pending)" - gh pr edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --add-label devops || true - else - SYNC_BODY="Brings stable fixes from main into the next branch." - SYNC_BODY="$SYNC_BODY\n\n**This PR must be merged by a maintainer using 'Create a merge commit'** (not squash, not rebase). This preserves individual fix commits and their verified signatures." - SYNC_BODY="$SYNC_BODY\n\nIf there are conflicts, resolve them by keeping next's versions for \`package.json\` files (next is always ahead of main in version numbers)." - - gh pr create \ - --base next \ - --head main \ - --repo "$GITHUB_REPOSITORY" \ - --title "chore: sync main to next" \ - --label devops \ - --body "$(echo -e "$SYNC_BODY")" || true - - EXISTING=$(gh pr list --base next --head "${GITHUB_REPOSITORY_OWNER}:main" --state open --repo "$GITHUB_REPOSITORY" --json number --jq '.[0].number // empty') - fi - - # Check for merge conflicts (GitHub computes merge state asynchronously) - if [ -n "$EXISTING" ]; then - sleep 10 - for _ in 1 2 3 4 5; do - MERGEABLE=$(gh pr view "$EXISTING" --repo "$GITHUB_REPOSITORY" --json mergeable --jq '.mergeable') - [ "$MERGEABLE" != "UNKNOWN" ] && break - sleep 10 - done - if [ "$MERGEABLE" = "CONFLICTING" ]; then - gh pr edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --add-label "has-conflicts" || true - echo "::warning::Sync PR #$EXISTING has merge conflicts. Resolve by keeping next's versions for package.json files." - elif [ "$MERGEABLE" = "MERGEABLE" ]; then - gh pr edit "$EXISTING" --repo "$GITHUB_REPOSITORY" --remove-label "has-conflicts" 2>/dev/null || true - fi - fi - - snapshot: - if: github.event_name == 'workflow_dispatch' && inputs.snapshot != '' && github.repository_owner == 'better-auth' - runs-on: ubuntu-latest - environment: Release permissions: contents: read id-token: write - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - fetch-depth: 0 - persist-credentials: false - - - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version-file: '.nvmrc' - registry-url: 'https://registry.npmjs.org' - package-manager-cache: false - - - run: pnpm install --frozen-lockfile - - - name: Version snapshot - env: - SNAPSHOT_TAG: ${{ inputs.snapshot }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [ -f .changeset/pre.json ]; then - echo "::error::Snapshots are not supported on branches in pre-release mode." - exit 1 - fi - if echo "$SNAPSHOT_TAG" | grep -qE '^(latest|next|beta|rc)$'; then - echo "::error::Snapshot tag '$SNAPSHOT_TAG' conflicts with a stable dist-tag. Use a descriptive name." - exit 1 - fi - pnpm changeset version --snapshot "$SNAPSHOT_TAG" - - - name: Build - run: pnpm build - - - name: Publish snapshot - env: - SNAPSHOT_TAG: ${{ inputs.snapshot }} - run: pnpm changeset publish --no-git-tag --tag "$SNAPSHOT_TAG" - - preview-notes: - if: github.event_name == 'workflow_dispatch' && inputs.preview_version != '' && github.repository_owner == 'better-auth' - runs-on: ubuntu-latest - environment: Release - permissions: - contents: read - pull-requests: read - steps: - - name: Generate App Token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - if: vars.RELEASE_APP_ID != '' - with: - app-id: ${{ vars.RELEASE_APP_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - - # Always check out main for trusted scripts — the preview_branch - # input controls which ref changeset files are read from (via --branch), - # not which code is executed. - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - ref: main - fetch-depth: 0 - persist-credentials: false - token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version-file: '.nvmrc' - package-manager-cache: false - - - name: Validate inputs - env: - INPUT_VERSION: ${{ inputs.preview_version }} - INPUT_BRANCH: ${{ inputs.preview_branch }} - run: | - git fetch origin "$INPUT_BRANCH" || { echo "::error::Branch '$INPUT_BRANCH' not found"; exit 1; } - if echo "$INPUT_VERSION" | grep -q '-'; then - if ! git show "origin/${INPUT_BRANCH}:.changeset/pre.json" >/dev/null 2>&1; then - echo "::error::Version '$INPUT_VERSION' is a pre-release but branch '$INPUT_BRANCH' has no .changeset/pre.json" - exit 1 - fi - fi - - - name: Generate raw release notes - id: raw-notes - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - INPUT_VERSION: ${{ inputs.preview_version }} - INPUT_BRANCH: ${{ inputs.preview_branch }} - run: | - node .github/scripts/release-notes.ts \ - --version "$INPUT_VERSION" \ - --branch "origin/$INPUT_BRANCH" - - - name: Build AI prompt from template - id: ai-prompt - continue-on-error: true - env: - RAW_PATH: ${{ steps.raw-notes.outputs.raw_changelog_path }} - CONTEXT_PATH: ${{ steps.raw-notes.outputs.context_path }} - run: | - PROMPT=$(sed \ - -e "s|__RAW_CHANGELOG_PATH__|${RAW_PATH}|g" \ - -e "s|__CONTEXT_PATH__|${CONTEXT_PATH:-none}|g" \ - -e "s|__GITHUB_REPOSITORY__|${GITHUB_REPOSITORY}|g" \ - .github/prompts/release-notes-rewrite.md) - EOF_DELIM="PROMPT_EOF_$(openssl rand -hex 8)" - { - echo "prompt<<${EOF_DELIM}" - echo "$PROMPT" - echo "${EOF_DELIM}" - } >> "$GITHUB_OUTPUT" - - - name: Rewrite release notes with AI - id: ai-notes - if: steps.ai-prompt.outcome == 'success' - continue-on-error: true - uses: anthropics/claude-code-action/base-action@11ba60486e4aec9ddfeafcf4bb3f00b028ac2c16 # v1.0.142 - env: - GH_TOKEN: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} - with: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - prompt: ${{ steps.ai-prompt.outputs.prompt }} - claude_args: --max-turns 100 --allowedTools "Read Write Bash(gh pr diff*) Bash(gh pr view*)" - - - name: Post results to job summary - env: - RAW_PATH: ${{ steps.raw-notes.outputs.raw_changelog_path }} - VERSION: ${{ steps.raw-notes.outputs.version }} - run: | - { - echo "# Release Notes Preview: v${VERSION}" - echo "" - if [ -f "${RAW_PATH}.final" ]; then - echo "## AI-Rewritten (final)" - echo "" - cat "${RAW_PATH}.final" - echo "" - echo "---" - echo "" - fi - echo "## Raw (deterministic)" - echo "" - cat "${RAW_PATH}" - } >> "$GITHUB_STEP_SUMMARY" + uses: better-auth/better-auth/.github/workflows/release.yml@0e02187ab45a903c66986fc5e28cddd37185147b + with: + use_shared_tooling: true + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/verify-changesets.yml b/.github/workflows/verify-changesets.yml index bf62dcc69d..7a4384229b 100644 --- a/.github/workflows/verify-changesets.yml +++ b/.github/workflows/verify-changesets.yml @@ -4,176 +4,14 @@ on: pull_request: types: [opened, synchronize, labeled, unlabeled, edited] branches: - - main - - next - - 'release/**' + - v1.6.x merge_group: permissions: {} jobs: verify: - runs-on: ubuntu-latest permissions: contents: read pull-requests: read - steps: - - name: Evaluate exemptions - id: gate - env: - HEAD_REF: ${{ github.head_ref }} - BASE_REF: ${{ github.base_ref }} - HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} - UPSTREAM_REPO: ${{ github.repository }} - run: | - exempt=false - reason="" - - if [ "$GITHUB_EVENT_NAME" = "merge_group" ]; then - exempt=true - reason="merge_group event (verification ran on the source PR)" - elif [ "$HEAD_REPO" = "$UPSTREAM_REPO" ]; then - case "$HEAD_REF" in - changeset-release/*) - exempt=true - reason="release PR from changeset-release/* branch" - ;; - esac - - if [ "$exempt" = "false" ]; then - if [ "$HEAD_REF" = "next" ] && [ "$BASE_REF" = "main" ]; then - exempt=true - reason="next -> main promotion PR" - elif [ "$HEAD_REF" = "main" ] && [ "$BASE_REF" = "next" ]; then - exempt=true - reason="main -> next sync PR" - fi - fi - fi - - { - echo "exempt=$exempt" - echo "reason=$reason" - } >> "$GITHUB_OUTPUT" - - if [ "$exempt" = "true" ]; then - echo "Verification exempt: $reason" - fi - - - name: Checkout - if: steps.gate.outputs.exempt == 'false' - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Block pre.json on main - if: steps.gate.outputs.exempt == 'false' && 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 - if: steps.gate.outputs.exempt == 'false' - 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<> "$GITHUB_OUTPUT" - - - name: Check package changes require changeset - if: steps.gate.outputs.exempt == 'false' && 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 "Changeset not required (skip-changeset label present)" - exit 0 - fi - - PKG_CHANGES=$(git diff --name-only "origin/$BASE_REF"...HEAD -- 'packages/' | grep -c '.' || true) - if [ "$PKG_CHANGES" -eq 0 ]; then - echo "Changeset not required (no package changes)" - 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.gate.outputs.exempt == 'false' && 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 + uses: better-auth/better-auth/.github/workflows/verify-changesets.yml@0e02187ab45a903c66986fc5e28cddd37185147b diff --git a/docker-compose.yml b/docker-compose.yml index b6aa8fd5bf..d18e86b8f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ x-mysql-healthcheck: &mysql-healthcheck services: mongodb: - image: mongo:latest + image: mongo:7.0.34@sha256:c1a84ab5d0c17deed1e0dba1d24bd7c76e5c7b281145fe536911939b1551754c container_name: mongodb ports: - "27017:27017"