Skip to content

Commit 8dac887

Browse files
fix: improve mergebot update command with better error handling
- Add branch existence validation before attempting checkout - Add proper handling for PRs from forks - Add detailed error messages for different failure scenarios - Add branch comparison logic to check if update is actually needed - Add debug logging for troubleshooting - Handle cases where branch was deleted after merge - Provide helpful instructions for manual updates when automation fails
1 parent 2d89e1b commit 8dac887

File tree

1 file changed

+177
-11
lines changed

1 file changed

+177
-11
lines changed

.github/workflows/merge-bot.yml

Lines changed: 177 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -389,31 +389,184 @@ jobs:
389389
pull_number: context.payload.issue.number
390390
});
391391
392+
// Debug information
393+
core.info(`PR #${pr.number}: ${pr.title}`);
394+
core.info(`- Base: ${pr.base.ref} (repo: ${pr.base.repo.full_name})`);
395+
core.info(`- Head: ${pr.head.ref} (repo: ${pr.head.repo.full_name})`);
396+
core.info(`- Same repo: ${pr.head.repo.full_name === pr.base.repo.full_name}`);
397+
398+
// Validate branch information
399+
if (!pr.head.ref || !pr.base.ref) {
400+
core.setFailed('Invalid PR branch information');
401+
return;
402+
}
403+
404+
// Check if it's from the same repository
405+
const isSameRepo = pr.head.repo.full_name === pr.base.repo.full_name;
406+
392407
core.setOutput('base_branch', pr.base.ref);
393408
core.setOutput('head_branch', pr.head.ref);
394409
core.setOutput('head_repo', pr.head.repo.full_name);
395410
core.setOutput('base_repo', pr.base.repo.full_name);
411+
core.setOutput('is_same_repo', isSameRepo.toString());
396412
397-
core.info(`PR #${pr.number}: ${pr.title}`);
398-
core.info(`- Base: ${pr.base.ref}`);
399-
core.info(`- Head: ${pr.head.ref}`);
400-
core.info(`- Same repo: ${pr.head.repo.full_name === pr.base.repo.full_name}`);
413+
- name: Validate branch exists
414+
if: steps.check_perms.outputs.has_permission == 'true'
415+
id: validate_branch
416+
uses: actions/github-script@v8
417+
with:
418+
script: |
419+
const headBranch = '${{ steps.pr_info.outputs.head_branch }}';
420+
const headRepo = '${{ steps.pr_info.outputs.head_repo }}';
421+
const isSameRepo = '${{ steps.pr_info.outputs.is_same_repo }}' === 'true';
422+
423+
core.info(`Validating branch: ${headBranch} from repo: ${headRepo}`);
424+
425+
try {
426+
// Check if branch exists
427+
const { data: branch } = await github.rest.repos.getBranch({
428+
owner: headRepo.split('/')[0],
429+
repo: headRepo.split('/')[1],
430+
branch: headBranch
431+
});
432+
433+
core.info(`✅ Branch exists: ${headBranch} (SHA: ${branch.commit.sha})`);
434+
core.setOutput('branch_exists', 'true');
435+
436+
} catch (error) {
437+
if (error.status === 404) {
438+
core.setOutput('branch_exists', 'false');
439+
core.error(`❌ Branch not found: ${headBranch}`);
440+
441+
// Provide helpful error message
442+
let errorMessage = `❌ Cannot update branch: Branch \`${headBranch}\` not found.`;
443+
444+
if (!isSameRepo) {
445+
errorMessage += '\n\nThis appears to be a PR from a fork. Update commands only work for branches in the same repository.';
446+
} else {
447+
errorMessage += '\n\nThis could mean:\n';
448+
errorMessage += '- The branch was deleted after merge\n';
449+
errorMessage += '- The branch name changed\n';
450+
errorMessage += '- There was a force push that changed the branch reference';
451+
}
452+
453+
await github.rest.issues.createComment({
454+
owner: context.repo.owner,
455+
repo: context.repo.repo,
456+
issue_number: context.payload.issue.number,
457+
body: errorMessage
458+
});
459+
460+
return;
461+
}
462+
463+
core.setFailed(`Error checking branch: ${error.message}`);
464+
}
465+
466+
- name: Check if update is needed
467+
if: steps.check_perms.outputs.has_permission == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
468+
id: check_update
469+
uses: actions/github-script@v8
470+
with:
471+
script: |
472+
const baseBranch = '${{ steps.pr_info.outputs.base_branch }}';
473+
const headBranch = '${{ steps.pr_info.outputs.head_branch }}';
474+
const isSameRepo = '${{ steps.pr_info.outputs.is_same_repo }}' === 'true';
475+
476+
if (!isSameRepo) {
477+
core.info('PR is from fork - update not supported');
478+
core.setOutput('update_needed', 'false');
479+
core.setOutput('is_fork', 'true');
480+
return;
481+
}
482+
483+
try {
484+
// Get latest commit from base branch
485+
const { data: baseBranchData } = await github.rest.repos.getBranch({
486+
owner: context.repo.owner,
487+
repo: context.repo.repo,
488+
branch: baseBranch
489+
});
490+
491+
const baseSha = baseBranchData.commit.sha;
492+
493+
// Check if head branch is behind base
494+
const { data: comparison } = await github.rest.repos.compareCommits({
495+
owner: context.repo.owner,
496+
repo: context.repo.repo,
497+
base: baseSha,
498+
head: `${context.repo.owner}/${context.repo.repo}:${headBranch}`
499+
});
500+
501+
const isBehind = comparison.behind_by > 0;
502+
const aheadBy = comparison.ahead_by;
503+
const behindBy = comparison.behind_by;
504+
505+
core.info(`Branch comparison: ${behindBy} commits behind, ${aheadBy} commits ahead`);
506+
507+
if (!isBehind) {
508+
core.info('✅ Branch is already up to date');
509+
core.setOutput('update_needed', 'false');
510+
core.setOutput('already_up_to_date', 'true');
511+
} else {
512+
core.info(`Update needed: ${behindBy} commits behind`);
513+
core.setOutput('update_needed', 'true');
514+
core.setOutput('commits_behind', behindBy.toString());
515+
}
516+
517+
} catch (error) {
518+
core.setFailed(`Error checking if update is needed: ${error.message}`);
519+
}
520+
521+
- name: Handle already up-to-date
522+
if: steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.already_up_to_date == 'true'
523+
uses: actions/github-script@v8
524+
with:
525+
script: |
526+
await github.rest.issues.createComment({
527+
owner: context.repo.owner,
528+
repo: context.repo.repo,
529+
issue_number: context.payload.issue.number,
530+
body: '✅ Branch is already up to date with the latest changes!'
531+
});
532+
533+
- name: Handle fork PR
534+
if: steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.is_fork == 'true'
535+
uses: actions/github-script@v8
536+
with:
537+
script: |
538+
await github.rest.issues.createComment({
539+
owner: context.repo.owner,
540+
repo: context.repo.repo,
541+
issue_number: context.payload.issue.number,
542+
body: 'ℹ️ Update commands are not supported for PRs from forks.
543+
544+
To update your branch, please run these commands locally:
545+
546+
```bash
547+
git fetch upstream main
548+
git merge upstream/main
549+
git push
550+
```
551+
552+
Or create a new PR from the same repository.'
553+
});
401554

402555
- name: Checkout PR branch
403-
if: steps.check_perms.outputs.has_permission == 'true'
556+
if: steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.update_needed == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
404557
uses: actions/checkout@v4
405558
with:
406-
repository: ${{ steps.pr_info.outputs.head_repo }}
407559
ref: ${{ steps.pr_info.outputs.head_branch }}
408560
fetch-depth: 0
409561
token: ${{ secrets.GITHUB_TOKEN }}
410562

411563
- name: Update branch
412-
if: steps.check_perms.outputs.has_permission == 'true'
564+
if: steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.update_needed == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
413565
id: update
414566
run: |
415567
BASE_BRANCH="${{ steps.pr_info.outputs.base_branch }}"
416568
HEAD_BRANCH="${{ steps.pr_info.outputs.head_branch }}"
569+
COMMITS_BEHIND="${{ steps.check_update.outputs.commits_behind }}"
417570
418571
git config user.name "github-actions[bot]"
419572
git config user.email "github-actions[bot]@users.noreply.github.com"
@@ -424,7 +577,7 @@ jobs:
424577
echo "Merging origin/$BASE_BRANCH into $HEAD_BRANCH..."
425578
if git merge "origin/$BASE_BRANCH" -m "chore: Update branch with latest changes from $BASE_BRANCH"; then
426579
echo "merge_success=true" >> $GITHUB_OUTPUT
427-
echo "✅ Branch updated successfully"
580+
echo "✅ Branch updated successfully ($COMMITS_BEHIND commits merged)"
428581
else
429582
echo "merge_success=false" >> $GITHUB_OUTPUT
430583
git merge --abort || true
@@ -446,12 +599,15 @@ jobs:
446599
script: |
447600
const user = context.payload.comment.user.login;
448601
const baseBranch = '${{ steps.pr_info.outputs.base_branch }}';
602+
const commitsBehind = '${{ steps.check_update.outputs.commits_behind }}';
449603
450604
await github.rest.issues.createComment({
451605
owner: context.repo.owner,
452606
repo: context.repo.repo,
453607
issue_number: context.payload.issue.number,
454-
body: `✅ Branch updated successfully by @${user}!\n\nMerged latest changes from \`${baseBranch}\`.`
608+
body: `✅ Branch updated successfully by @${user}!
609+
610+
Merged ${commitsBehind} commit(s) from \`${baseBranch}\`.`
455611
});
456612

457613
// Add +1 reaction to original comment
@@ -473,7 +629,17 @@ jobs:
473629
owner: context.repo.owner,
474630
repo: context.repo.repo,
475631
issue_number: context.payload.issue.number,
476-
body: `❌ Failed to update branch with latest changes from \`${baseBranch}\`.\n\nThis usually means there are merge conflicts that need to be resolved manually.\n\nPlease update your branch locally:\n\`\`\`bash\ngit fetch origin ${baseBranch}\ngit merge origin/${baseBranch}\n# Resolve conflicts\ngit push\n\`\`\``
632+
body: `❌ Failed to update branch with latest changes from \`${baseBranch}\`.
633+
634+
This usually means there are merge conflicts that need to be resolved manually.
635+
636+
Please update your branch locally:
637+
\`\`\`bash
638+
git fetch origin ${baseBranch}
639+
git merge origin/${baseBranch}
640+
# Resolve conflicts
641+
git push
642+
\`\`\``
477643
});
478644

479645
// Add -1 reaction to original comment
@@ -482,4 +648,4 @@ jobs:
482648
repo: context.repo.repo,
483649
comment_id: context.payload.comment.id,
484650
content: '-1'
485-
});
651+
});

0 commit comments

Comments
 (0)