From c8fd32a8a935e15f72984bc65d2629d4d5bfff02 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Wed, 24 Dec 2025 20:05:32 +0800 Subject: [PATCH] ci: remove auto cherry pick (#6976) --- .../workflows/auto-cherry-pick-to-main.yml | 337 ------------------ .github/workflows/cherry-pick-to-main.yml | 325 ----------------- 2 files changed, 662 deletions(-) delete mode 100644 .github/workflows/auto-cherry-pick-to-main.yml delete mode 100644 .github/workflows/cherry-pick-to-main.yml diff --git a/.github/workflows/auto-cherry-pick-to-main.yml b/.github/workflows/auto-cherry-pick-to-main.yml deleted file mode 100644 index 7a234f2a4b..0000000000 --- a/.github/workflows/auto-cherry-pick-to-main.yml +++ /dev/null @@ -1,337 +0,0 @@ -name: Auto Cherry-pick to Main - -on: - push: - branches: - - canary - schedule: - # Run every hour to catch any missed commits - - cron: '0 * * * *' - workflow_dispatch: - -jobs: - auto-cherry-pick: - runs-on: ubuntu-latest - if: github.repository == 'better-auth/better-auth' - - permissions: - contents: write - pull-requests: write - issues: write - - steps: - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - with: - fetch-depth: 0 - token: ${{ secrets.PAT_TOKEN }} - - - name: Configure Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Find commits to cherry-pick - id: find-commits - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - // Get all merged PRs targeting canary branch - const prs = await github.rest.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'closed', - base: 'canary', - per_page: 100, - sort: 'updated', - direction: 'desc' - }); - - // Filter for merged PRs without breaking change labels - const prsToProcess = prs.data.filter(pr => { - if (!pr.merged_at) return false; - - // Skip if PR has breaking change label - const hasBreakingChange = pr.labels.some(label => - label.name === 'breaking-change' || - label.name === 'breaking' || - label.name === 'major' - ); - - if (hasBreakingChange) { - console.log(`Skipping PR #${pr.number}: has breaking change label`); - return false; - } - - // Skip if PR has merge-to-main or merge-to-main-failure label (handled by other workflow) - const hasManualLabel = pr.labels.some(label => - label.name === 'merge-to-main' || - label.name === 'merge-to-main-failure' - ); - - if (hasManualLabel) { - console.log(`Skipping PR #${pr.number}: handled by manual cherry-pick workflow`); - return false; - } - - // Skip if PR has skip-cherry-pick label - const hasSkipLabel = pr.labels.some(label => - label.name === 'skip-cherry-pick' || - label.name === 'canary-only' - ); - - if (hasSkipLabel) { - console.log(`Skipping PR #${pr.number}: has skip label`); - return false; - } - - // Skip if PR has already been auto-cherry-picked (prevents duplicates) - const hasAutoPickedLabel = pr.labels.some(label => - label.name === 'auto-cherry-picked' - ); - - if (hasAutoPickedLabel) { - console.log(`Skipping PR #${pr.number}: already auto-cherry-picked`); - return false; - } - - return true; - }); - - console.log(`Found ${prsToProcess.length} PRs eligible for auto cherry-pick`); - - if (prsToProcess.length === 0) { - console.log('No PRs to process'); - core.setOutput('has_prs', 'false'); - return; - } - - core.setOutput('has_prs', 'true'); - core.setOutput('prs_to_process', JSON.stringify(prsToProcess.map(pr => ({ - number: pr.number, - merge_commit_sha: pr.merge_commit_sha, - title: pr.title - })))); - - - name: Cherry-pick to main - id: cherry-pick - if: steps.find-commits.outputs.has_prs == 'true' - env: - GH_TOKEN: ${{ secrets.PAT_TOKEN }} - PRS_JSON: ${{ steps.find-commits.outputs.prs_to_process }} - run: | - # Fetch all branches - git fetch origin main - git fetch origin canary - - # Checkout main branch - git checkout -B main origin/main - - set +e # Don't exit on error - - echo "Processing PRs for auto cherry-pick..." - echo "$PRS_JSON" > prs.json - - success_prs="" - conflict_prs="" - skipped_prs="" - success_count=0 - conflict_count=0 - skipped_count=0 - - for row in $(jq -r '.[] | @base64' prs.json); do - _jq() { - echo ${row} | base64 --decode | jq -r ${1} - } - - PR_NUM=$(_jq '.number') - MERGE_COMMIT=$(_jq '.merge_commit_sha') - PR_TITLE=$(_jq '.title') - - echo "----------------------------------------" - echo "Processing PR #$PR_NUM: $PR_TITLE" - echo "Merge commit: $MERGE_COMMIT" - - # Attempt cherry-pick - if git cherry-pick -m 1 "$MERGE_COMMIT"; then - echo "✅ Successfully cherry-picked PR #$PR_NUM" - success_prs="$success_prs $PR_NUM" - success_count=$((success_count + 1)) - else - # Check if it's an empty commit (already applied) - if git diff-index --quiet HEAD; then - echo "⏭️ PR #$PR_NUM changes already in main (empty commit)" - git cherry-pick --abort - skipped_prs="$skipped_prs $PR_NUM" - skipped_count=$((skipped_count + 1)) - else - echo "❌ Conflict in PR #$PR_NUM" - conflict_prs="$conflict_prs $PR_NUM" - git cherry-pick --abort - conflict_count=$((conflict_count + 1)) - fi - fi - done - - set -e # Re-enable exit on error - - echo "----------------------------------------" - echo "Summary:" - echo " Success: $success_count" - echo " Conflicts: $conflict_count" - echo " Already in main: $skipped_count" - - # Push all successful cherry-picks - if [ $success_count -gt 0 ]; then - git push origin main - echo "✅ Pushed $success_count cherry-pick(s) to main" - fi - - # Save results for next steps - echo "success_prs=$success_prs" >> $GITHUB_OUTPUT - echo "conflict_prs=$conflict_prs" >> $GITHUB_OUTPUT - echo "skipped_prs=$skipped_prs" >> $GITHUB_OUTPUT - echo "success_count=$success_count" >> $GITHUB_OUTPUT - echo "conflict_count=$conflict_count" >> $GITHUB_OUTPUT - echo "skipped_count=$skipped_count" >> $GITHUB_OUTPUT - - - name: Label and comment on successful PRs - if: always() && steps.cherry-pick.outputs.success_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const successPrs = '${{ steps.cherry-pick.outputs.success_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of successPrs) { - console.log(`Processing successful PR #${prNumber}`); - - // Add auto-cherry-picked label to prevent re-processing - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['auto-cherry-picked'] - }); - console.log(`✅ Added auto-cherry-picked label to PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not add label to PR #${prNumber}: ${error.message}`); - } - - // Check if we've already commented about success - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - }); - - const hasSuccessComment = comments.data.some(comment => - comment.body.includes('Automatically cherry-picked to `main` branch') - ); - - if (hasSuccessComment) { - console.log(`⏭️ Skipping comment on PR #${prNumber} - success comment already exists`); - continue; - } - - // Add success comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: '✅ Automatically cherry-picked to `main` branch!' - }); - } - - - name: Label skipped PRs - if: always() && steps.cherry-pick.outputs.skipped_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const skippedPrs = '${{ steps.cherry-pick.outputs.skipped_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of skippedPrs) { - console.log(`Marking skipped PR #${prNumber} as auto-cherry-picked`); - - // Add auto-cherry-picked label to prevent re-processing - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['auto-cherry-picked'] - }); - console.log(`✅ Added auto-cherry-picked label to PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not add label to PR #${prNumber}: ${error.message}`); - } - } - - - name: Handle PRs with conflicts - if: always() && steps.cherry-pick.outputs.conflict_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const conflictPrs = '${{ steps.cherry-pick.outputs.conflict_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of conflictPrs) { - console.log(`Checking PR #${prNumber} for existing conflict comment`); - - // Check if we've already commented about conflicts - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - }); - - const hasConflictComment = comments.data.some(comment => - comment.body.includes('Auto cherry-pick to `main` failed due to conflicts') - ); - - if (hasConflictComment) { - console.log(`⏭️ Skipping PR #${prNumber} - conflict comment already exists`); - continue; - } - - console.log(`Adding conflict comment and label to PR #${prNumber}`); - - // Add skip-cherry-pick label to prevent retry attempts - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['skip-cherry-pick'] - }); - console.log(`✅ Added skip-cherry-pick label to PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not add label to PR #${prNumber}: ${error.message}`); - } - - // Add conflict comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `⚠️ **Auto cherry-pick to \`main\` failed due to conflicts!**\n\nThis PR could not be automatically cherry-picked to the \`main\` branch. Please either:\n\n1. Manually cherry-pick and resolve conflicts, or\n2. Add the \`merge-to-main\` label to retry the cherry-pick\n\nThe \`skip-cherry-pick\` label has been added to prevent automatic retry attempts.` - }); - } - - - name: Workflow Summary - if: always() && steps.find-commits.outputs.has_prs == 'true' - run: | - echo "### Auto Cherry-pick Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Success: ${{ steps.cherry-pick.outputs.success_count }}" >> $GITHUB_STEP_SUMMARY - echo "- ⚠️ Conflicts: ${{ steps.cherry-pick.outputs.conflict_count }}" >> $GITHUB_STEP_SUMMARY - echo "- ℹ️ Already in main: ${{ steps.cherry-pick.outputs.skipped_count }}" >> $GITHUB_STEP_SUMMARY - - if [ -n "${{ steps.cherry-pick.outputs.success_prs }}" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Successful PRs:** ${{ steps.cherry-pick.outputs.success_prs }}" >> $GITHUB_STEP_SUMMARY - fi - - if [ -n "${{ steps.cherry-pick.outputs.conflict_prs }}" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "**PRs with conflicts:** ${{ steps.cherry-pick.outputs.conflict_prs }}" >> $GITHUB_STEP_SUMMARY - fi diff --git a/.github/workflows/cherry-pick-to-main.yml b/.github/workflows/cherry-pick-to-main.yml deleted file mode 100644 index cd86dc4b06..0000000000 --- a/.github/workflows/cherry-pick-to-main.yml +++ /dev/null @@ -1,325 +0,0 @@ -name: Cherry-pick to Main - -on: - schedule: - # Run every 5 minutes - - cron: '*/5 * * * *' - workflow_dispatch: - -jobs: - cherry-pick: - runs-on: ubuntu-latest - if: github.repository == 'better-auth/better-auth' - - permissions: - contents: write - pull-requests: write - issues: write - - steps: - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - with: - fetch-depth: 0 - token: ${{ secrets.PAT_TOKEN }} - - - name: Configure Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Find PRs with merge-to-main label - id: find-prs - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - // Get all closed PRs targeting canary branch - const prs = await github.rest.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'closed', - base: 'canary', - per_page: 100, - sort: 'updated', - direction: 'desc' - }); - - // Filter for merged PRs with merge-to-main label - const prsToProcess = prs.data.filter(pr => - pr.merged_at && - pr.labels.some(label => label.name === 'merge-to-main') - ); - - console.log(`Found ${prsToProcess.length} PRs with merge-to-main label`); - - if (prsToProcess.length === 0) { - console.log('No PRs to process'); - core.setOutput('has_prs', 'false'); - return; - } - - core.setOutput('has_prs', 'true'); - core.setOutput('prs_to_process', JSON.stringify(prsToProcess.map(pr => ({ - number: pr.number, - merge_commit_sha: pr.merge_commit_sha, - title: pr.title - })))); - - - name: Cherry-pick to main - id: cherry-pick - if: steps.find-prs.outputs.has_prs == 'true' - env: - GH_TOKEN: ${{ secrets.PAT_TOKEN }} - run: | - # Fetch all branches - git fetch origin main - git fetch origin canary - - # Checkout main branch - git checkout -B main origin/main - - set +e # Don't exit on error - - echo "Processing PRs with merge-to-main label..." - echo '${{ steps.find-prs.outputs.prs_to_process }}' > prs.json - - success_prs="" - conflict_prs="" - skipped_prs="" - success_count=0 - conflict_count=0 - skipped_count=0 - - for row in $(jq -r '.[] | @base64' prs.json); do - _jq() { - echo ${row} | base64 --decode | jq -r ${1} - } - - PR_NUM=$(_jq '.number') - MERGE_COMMIT=$(_jq '.merge_commit_sha') - PR_TITLE=$(_jq '.title') - - echo "----------------------------------------" - echo "Processing PR #$PR_NUM: $PR_TITLE" - echo "Merge commit: $MERGE_COMMIT" - - # Check if commit already exists in main - if git branch -r --contains "$MERGE_COMMIT" | grep -q "origin/main"; then - echo "✓ PR #$PR_NUM already in main, will remove label" - skipped_prs="$skipped_prs $PR_NUM" - skipped_count=$((skipped_count + 1)) - continue - fi - - # Attempt cherry-pick - if git cherry-pick -m 1 "$MERGE_COMMIT"; then - echo "✅ Successfully cherry-picked PR #$PR_NUM" - success_prs="$success_prs $PR_NUM" - success_count=$((success_count + 1)) - else - echo "❌ Conflict in PR #$PR_NUM" - conflict_prs="$conflict_prs $PR_NUM" - git cherry-pick --abort - conflict_count=$((conflict_count + 1)) - fi - done - - set -e # Re-enable exit on error - - echo "----------------------------------------" - echo "Summary:" - echo " Success: $success_count" - echo " Conflicts: $conflict_count" - echo " Already in main: $skipped_count" - - # Push all successful cherry-picks - if [ $success_count -gt 0 ]; then - git push origin main - echo "✅ Pushed $success_count cherry-pick(s) to main" - fi - - # Save results for next steps - echo "success_prs=$success_prs" >> $GITHUB_OUTPUT - echo "conflict_prs=$conflict_prs" >> $GITHUB_OUTPUT - echo "skipped_prs=$skipped_prs" >> $GITHUB_OUTPUT - echo "success_count=$success_count" >> $GITHUB_OUTPUT - echo "conflict_count=$conflict_count" >> $GITHUB_OUTPUT - echo "skipped_count=$skipped_count" >> $GITHUB_OUTPUT - - - name: Remove label and comment on successful PRs - if: always() && steps.cherry-pick.outputs.success_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const successPrs = '${{ steps.cherry-pick.outputs.success_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of successPrs) { - console.log(`Processing successful PR #${prNumber}`); - - // Remove merge-to-main label - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - name: 'merge-to-main' - }); - console.log(`✅ Removed merge-to-main label from PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not remove merge-to-main label from PR #${prNumber}: ${error.message}`); - } - - // Remove merge-to-main-failure label if it exists - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - name: 'merge-to-main-failure' - }); - console.log(`✅ Removed merge-to-main-failure label from PR #${prNumber}`); - } catch (error) { - // Ignore if label doesn't exist - if (error.status !== 404) { - console.log(`⚠️ Could not remove merge-to-main-failure label from PR #${prNumber}: ${error.message}`); - } - } - - // Add success comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: '✅ Successfully cherry-picked to `main` branch!' - }); - } - - - name: Remove label from skipped PRs - if: always() && steps.cherry-pick.outputs.skipped_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const skippedPrs = '${{ steps.cherry-pick.outputs.skipped_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of skippedPrs) { - console.log(`Processing skipped PR #${prNumber}`); - - // Remove merge-to-main label - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - name: 'merge-to-main' - }); - console.log(`✅ Removed merge-to-main label from PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not remove merge-to-main label from PR #${prNumber}: ${error.message}`); - } - - // Remove merge-to-main-failure label if it exists - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - name: 'merge-to-main-failure' - }); - console.log(`✅ Removed merge-to-main-failure label from PR #${prNumber}`); - } catch (error) { - // Ignore if label doesn't exist - if (error.status !== 404) { - console.log(`⚠️ Could not remove merge-to-main-failure label from PR #${prNumber}: ${error.message}`); - } - } - - // Add info comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: 'ℹ️ This commit already exists in the `main` branch. Removed `merge-to-main` label.' - }); - } - - - name: Comment on PRs with conflicts - if: always() && steps.cherry-pick.outputs.conflict_prs != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - const conflictPrs = '${{ steps.cherry-pick.outputs.conflict_prs }}'.trim().split(' ').filter(Boolean); - - for (const prNumber of conflictPrs) { - console.log(`Checking PR #${prNumber} for existing conflict comment`); - - // Check if we've already commented about conflicts - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - }); - - const hasConflictComment = comments.data.some(comment => - comment.body.includes('Cherry-pick to `main` failed due to conflicts') - ); - - if (hasConflictComment) { - console.log(`⏭️ Skipping PR #${prNumber} - conflict comment already exists`); - continue; - } - - console.log(`Adding conflict comment and label to PR #${prNumber}`); - - // Add merge-to-main-failure label - try { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - labels: ['merge-to-main-failure'] - }); - console.log(`✅ Added merge-to-main-failure label to PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not add label to PR #${prNumber}: ${error.message}`); - } - - // Remove merge-to-main label to stop retry attempts - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - name: 'merge-to-main' - }); - console.log(`✅ Removed merge-to-main label from PR #${prNumber}`); - } catch (error) { - console.log(`⚠️ Could not remove label from PR #${prNumber}: ${error.message}`); - } - - // Add conflict comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, - body: `⚠️ **Cherry-pick to \`main\` failed due to conflicts!**\n\nPlease manually cherry-pick this commit to the \`main\` branch and resolve the conflicts.` - }); - } - - - name: Workflow Summary - if: always() && steps.find-prs.outputs.has_prs == 'true' - run: | - echo "### Cherry-pick Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- ✅ Success: ${{ steps.cherry-pick.outputs.success_count }}" >> $GITHUB_STEP_SUMMARY - echo "- ⚠️ Conflicts: ${{ steps.cherry-pick.outputs.conflict_count }}" >> $GITHUB_STEP_SUMMARY - echo "- ℹ️ Already in main: ${{ steps.cherry-pick.outputs.skipped_count }}" >> $GITHUB_STEP_SUMMARY - - if [ -n "${{ steps.cherry-pick.outputs.success_prs }}" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "**Successful PRs:** ${{ steps.cherry-pick.outputs.success_prs }}" >> $GITHUB_STEP_SUMMARY - fi - - if [ -n "${{ steps.cherry-pick.outputs.conflict_prs }}" ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "**PRs with conflicts:** ${{ steps.cherry-pick.outputs.conflict_prs }}" >> $GITHUB_STEP_SUMMARY - fi