( token: string, owner: string, repo: string )
| 632 | for (let attempt = 0; attempt < maxRetries; attempt++) { |
| 633 | try { |
| 634 | const res = await ghFetch(`/repos/${owner}/${repo}/pulls/${pullNumber}/merge`, token, { |
| 635 | method: 'PUT', |
| 636 | body: JSON.stringify({ merge_method: mergeMethod }), |
| 637 | headers: { 'Content-Type': 'application/json' }, |
| 638 | }); |
| 639 | |
| 640 | if (res.ok) { |
| 641 | const data = await res.json(); |
| 642 | return { merged: true, sha: data.sha, message: data.message }; |
| 643 | } |
| 644 | |
| 645 | const err = await res.json().catch(() => ({ message: res.statusText })); |
| 646 | |
| 647 | if (res.status === 405) { |
| 648 | if (attempt < maxRetries - 1) { await sleep(3000); continue; } |
| 649 | throw new Error(`Cannot merge PR #${pullNumber}: ${err.message || 'Method not allowed. Check branch protection rules.'}`); |
| 650 | } |
| 651 | if (res.status === 409) { |
| 652 | if (attempt < maxRetries - 1) { await sleep(1500); continue; } |
| 653 | throw new Error(`Merge conflict on PR #${pullNumber}: ${err.message}`); |
| 654 | } |
| 655 | if (res.status === 403) { |
| 656 | if (err.message?.includes('Resource not accessible')) |
| 657 | throw new Error(`PERMISSION_DENIED: ${err.message}`); |
| 658 | if (err.message?.includes('rate limit') || err.message?.includes('abuse')) |
| 659 | throw new Error(`RATE_LIMITED: ${err.message}`); |
| 660 | throw new Error(`Forbidden: ${err.message}`); |
| 661 | } |
| 662 | if (res.status === 401) { |
| 663 | throw new Error(`PERMISSION_DENIED: Token expired or invalid (401 Unauthorized)`); |
| 664 | } |
| 665 | throw new Error(`Merge failed (HTTP ${res.status}): ${err.message || res.statusText}`); |
| 666 | } catch (err) { |
| 667 | lastError = err instanceof Error ? err : new Error(String(err)); |
| 668 | if (lastError.message.includes('PERMISSION_DENIED') || lastError.message.includes('RATE_LIMITED')) { |
| 669 | throw lastError; |
| 670 | } |
| 671 | if (attempt < maxRetries - 1) { await sleep(1500); } |
| 672 | } |
| 673 | } |
| 674 | throw lastError || new Error(`Failed to merge PR #${pullNumber} after ${maxRetries} attempts`); |
| 675 | } |
| 676 | |
| 677 | /** |
| 678 | * Delete a branch after merge (cleanup). |
| 679 | */ |
| 680 | export async function deleteBranch( |
| 681 | token: string, |
| 682 | owner: string, |
nothing calls this directly
no test coverage detected