@@ -287,372 +287,3 @@ jobs:
287287 } catch (error) {
288288 core.warning(`Failed to delete branch: ${error.message}`);
289289 }
290-
291- update-command :
292- name : Handle Update Command
293- runs-on : ubuntu-latest
294- # Only run on PR comments
295- if : github.event.issue.pull_request
296- steps :
297- - name : Parse command
298- id : command
299- uses : actions/github-script@v8
300- with :
301- script : |
302- const comment = context.payload.comment.body.toLowerCase().trim();
303- const user = context.payload.comment.user.login;
304-
305- core.info(`Comment from ${user}: ${comment}`);
306-
307- // Check for update command (case insensitive)
308- // Supported formats:
309- // - @mergebot update
310- // - @merge-bot update
311- // - /update
312- // - update (if alone)
313- const updatePatterns = [
314- /@merge-?bot\s+update/i,
315- /^\/update$/i,
316- /^update$/i,
317- ];
318-
319- const isUpdateCommand = updatePatterns.some(pattern => pattern.test(comment));
320-
321- if (!isUpdateCommand) {
322- core.info('Not an update command, skipping');
323- return;
324- }
325-
326- core.setOutput('should_update', 'true');
327- core.info('✅ Update command detected');
328-
329- - name : React to comment
330- if : steps.command.outputs.should_update == 'true'
331- uses : actions/github-script@v8
332- with :
333- script : |
334- // Add eyes emoji to show bot is processing
335- await github.rest.reactions.createForIssueComment({
336- owner: context.repo.owner,
337- repo: context.repo.repo,
338- comment_id: context.payload.comment.id,
339- content: 'eyes'
340- });
341-
342- - name : Check permissions
343- if : steps.command.outputs.should_update == 'true'
344- id : check_perms
345- uses : actions/github-script@v8
346- with :
347- script : |
348- const user = context.payload.comment.user.login;
349-
350- // Check if user has write access
351- try {
352- const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
353- owner: context.repo.owner,
354- repo: context.repo.repo,
355- username: user
356- });
357-
358- const hasPermission = ['admin', 'write'].includes(permission.permission);
359-
360- if (!hasPermission) {
361- core.setFailed(`❌ @${user} does not have permission to update PRs (permission: ${permission.permission})`);
362-
363- // Comment on PR
364- await github.rest.issues.createComment({
365- owner: context.repo.owner,
366- repo: context.repo.repo,
367- issue_number: context.payload.issue.number,
368- body: `❌ @${user} you don't have permission to update PRs. Only collaborators with write access can use update commands.`
369- });
370-
371- return;
372- }
373-
374- core.info(`✅ User ${user} has ${permission.permission} access`);
375- core.setOutput('has_permission', 'true');
376- } catch (error) {
377- core.setFailed(`Error checking permissions: ${error.message}`);
378- }
379-
380- - name : Get PR info
381- if : steps.check_perms.outputs.has_permission == 'true'
382- id : pr_info
383- uses : actions/github-script@v8
384- with :
385- script : |
386- const { data: pr } = await github.rest.pulls.get({
387- owner: context.repo.owner,
388- repo: context.repo.repo,
389- pull_number: context.payload.issue.number
390- });
391-
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-
407- // Early exit for fork PRs
408- if (!isSameRepo) {
409- core.info('❌ PR is from fork - update not supported');
410- core.setOutput('is_fork', 'true');
411-
412- const baseBranch = pr.base.ref;
413- const forkMessage = [
414- 'ℹ️ Update commands are not supported for PRs from forks.',
415- '',
416- 'To update your branch, please run these commands locally:',
417- '',
418- '```bash',
419- `git fetch upstream ${baseBranch}`,
420- `git merge upstream/${baseBranch}`,
421- 'git push',
422- '```',
423- '',
424- 'Or create a new PR from the same repository.'
425- ].join('\n');
426-
427- await github.rest.issues.createComment({
428- owner: context.repo.owner,
429- repo: context.repo.repo,
430- issue_number: context.payload.issue.number,
431- body: forkMessage
432- });
433-
434- return;
435- }
436-
437- core.setOutput('base_branch', pr.base.ref);
438- core.setOutput('head_branch', pr.head.ref);
439- core.setOutput('head_repo', pr.head.repo.full_name);
440- core.setOutput('base_repo', pr.base.repo.full_name);
441- core.setOutput('is_same_repo', isSameRepo.toString());
442-
443- - name : Validate branch exists
444- if : steps.check_perms.outputs.has_permission == 'true' && steps.pr_info.outputs.is_fork != 'true'
445- id : validate_branch
446- uses : actions/github-script@v8
447- with :
448- script : |
449- const headBranch = '${{ steps.pr_info.outputs.head_branch }}';
450- const headRepo = '${{ steps.pr_info.outputs.head_repo }}';
451- const isSameRepo = '${{ steps.pr_info.outputs.is_same_repo }}' === 'true';
452-
453- core.info(`Validating branch: ${headBranch} from repo: ${headRepo}`);
454-
455- try {
456- // Check if branch exists
457- const { data: branch } = await github.rest.repos.getBranch({
458- owner: headRepo.split('/')[0],
459- repo: headRepo.split('/')[1],
460- branch: headBranch
461- });
462-
463- core.info(`✅ Branch exists: ${headBranch} (SHA: ${branch.commit.sha})`);
464- core.setOutput('branch_exists', 'true');
465-
466- } catch (error) {
467- if (error.status === 404) {
468- core.setOutput('branch_exists', 'false');
469- core.error(`❌ Branch not found: ${headBranch}`);
470-
471- // Provide helpful error message
472- let errorMessage = `❌ Cannot update branch: Branch \`${headBranch}\` not found.`;
473-
474- if (!isSameRepo) {
475- errorMessage += '\n\nThis appears to be a PR from a fork. Update commands only work for branches in the same repository.';
476- } else {
477- errorMessage += '\n\nThis could mean:\n';
478- errorMessage += '- The branch was deleted after merge\n';
479- errorMessage += '- The branch name changed\n';
480- errorMessage += '- There was a force push that changed the branch reference';
481- }
482-
483- await github.rest.issues.createComment({
484- owner: context.repo.owner,
485- repo: context.repo.repo,
486- issue_number: context.payload.issue.number,
487- body: errorMessage
488- });
489-
490- return;
491- }
492-
493- core.setFailed(`Error checking branch: ${error.message}`);
494- }
495-
496- - name : Check if update is needed
497- if : steps.check_perms.outputs.has_permission == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
498- id : check_update
499- uses : actions/github-script@v8
500- with :
501- script : |
502- const baseBranch = '${{ steps.pr_info.outputs.base_branch }}';
503- const headBranch = '${{ steps.pr_info.outputs.head_branch }}';
504-
505- try {
506- // Get latest commit from base branch
507- const { data: baseBranchData } = await github.rest.repos.getBranch({
508- owner: context.repo.owner,
509- repo: context.repo.repo,
510- branch: baseBranch
511- });
512-
513- const baseSha = baseBranchData.commit.sha;
514-
515- // Check if head branch is behind base (same-repo PRs only at this point)
516- const { data: comparison } = await github.rest.repos.compareCommits({
517- owner: context.repo.owner,
518- repo: context.repo.repo,
519- base: baseSha,
520- head: headBranch
521- });
522-
523- const isBehind = comparison.behind_by > 0;
524- const aheadBy = comparison.ahead_by;
525- const behindBy = comparison.behind_by;
526-
527- core.info(`Branch comparison: ${behindBy} commits behind, ${aheadBy} commits ahead`);
528-
529- if (!isBehind) {
530- core.info('✅ Branch is already up to date');
531- core.setOutput('update_needed', 'false');
532- core.setOutput('already_up_to_date', 'true');
533- } else {
534- core.info(`Update needed: ${behindBy} commits behind`);
535- core.setOutput('update_needed', 'true');
536- core.setOutput('commits_behind', behindBy.toString());
537- }
538-
539- } catch (error) {
540- core.setFailed(`Error checking if update is needed: ${error.message}`);
541- }
542-
543- - name : Handle already up-to-date
544- if : steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.already_up_to_date == 'true'
545- uses : actions/github-script@v8
546- with :
547- script : |
548- await github.rest.issues.createComment({
549- owner: context.repo.owner,
550- repo: context.repo.repo,
551- issue_number: context.payload.issue.number,
552- body: '✅ Branch is already up to date with the latest changes!'
553- });
554-
555- - name : Checkout PR branch
556- if : steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.update_needed == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
557- uses : actions/checkout@v4
558- with :
559- repository : ${{ steps.pr_info.outputs.head_repo }}
560- ref : ${{ steps.pr_info.outputs.head_branch }}
561- fetch-depth : 0
562- token : ${{ secrets.GITHUB_TOKEN }}
563-
564- - name : Update branch
565- if : steps.check_perms.outputs.has_permission == 'true' && steps.check_update.outputs.update_needed == 'true' && steps.validate_branch.outputs.branch_exists == 'true'
566- id : update
567- run : |
568- BASE_BRANCH="${{ steps.pr_info.outputs.base_branch }}"
569- HEAD_BRANCH="${{ steps.pr_info.outputs.head_branch }}"
570- COMMITS_BEHIND="${{ steps.check_update.outputs.commits_behind }}"
571-
572- git config user.name "github-actions[bot]"
573- git config user.email "github-actions[bot]@users.noreply.github.com"
574-
575- echo "Fetching $BASE_BRANCH..."
576- git fetch origin "$BASE_BRANCH"
577-
578- echo "Merging origin/$BASE_BRANCH into $HEAD_BRANCH..."
579- if git merge "origin/$BASE_BRANCH" -m "chore: Update branch with latest changes from $BASE_BRANCH"; then
580- echo "merge_success=true" >> $GITHUB_OUTPUT
581- echo "✅ Branch updated successfully ($COMMITS_BEHIND commits merged)"
582- else
583- echo "merge_success=false" >> $GITHUB_OUTPUT
584- git merge --abort || true
585- echo "❌ Merge failed - conflicts detected"
586- exit 1
587- fi
588-
589- - name : Push changes
590- if : steps.update.outputs.merge_success == 'true'
591- run : |
592- HEAD_BRANCH="${{ steps.pr_info.outputs.head_branch }}"
593- HEAD_REPO="${{ steps.pr_info.outputs.head_repo }}"
594-
595- echo "Pushing changes to $HEAD_BRANCH in $HEAD_REPO..."
596- git push origin "$HEAD_BRANCH"
597-
598- - name : Comment success
599- if : steps.update.outputs.merge_success == 'true'
600- uses : actions/github-script@v8
601- with :
602- script : |
603- const user = context.payload.comment.user.login;
604- const baseBranch = '${{ steps.pr_info.outputs.base_branch }}';
605- const commitsBehind = '${{ steps.check_update.outputs.commits_behind }}';
606-
607- const successMessage = `✅ Branch updated successfully by @${user}!\n\nMerged ${commitsBehind} commit(s) from \`${baseBranch}\`.`;
608-
609- await github.rest.issues.createComment({
610- owner: context.repo.owner,
611- repo: context.repo.repo,
612- issue_number: context.payload.issue.number,
613- body: successMessage
614- });
615-
616- // Add +1 reaction to original comment
617- await github.rest.reactions.createForIssueComment({
618- owner: context.repo.owner,
619- repo: context.repo.repo,
620- comment_id: context.payload.comment.id,
621- content: '+1'
622- });
623-
624- - name : Comment failure
625- if : failure() && steps.check_perms.outputs.has_permission == 'true'
626- uses : actions/github-script@v8
627- with :
628- script : |
629- const baseBranch = '${{ steps.pr_info.outputs.base_branch }}';
630-
631- const failureMessage = [
632- `❌ 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- '```'
643- ].join('\n');
644-
645- await github.rest.issues.createComment({
646- owner: context.repo.owner,
647- repo: context.repo.repo,
648- issue_number: context.payload.issue.number,
649- body: failureMessage
650- });
651-
652- // Add -1 reaction to original comment
653- await github.rest.reactions.createForIssueComment({
654- owner: context.repo.owner,
655- repo: context.repo.repo,
656- comment_id: context.payload.comment.id,
657- content: '-1'
658- });
0 commit comments