mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
203 lines
7.4 KiB
YAML
203 lines
7.4 KiB
YAML
name: Auto Merge
|
|
|
|
on:
|
|
pull_request_review:
|
|
types: [submitted]
|
|
check_suite:
|
|
types: [completed]
|
|
workflow_run:
|
|
workflows: ["CI/CD", "Enterprise Gated CI/CD Pipeline"]
|
|
types: [completed]
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
auto-merge:
|
|
name: Auto Merge PR
|
|
runs-on: ubuntu-latest
|
|
if: >
|
|
${{
|
|
(github.event_name == 'pull_request_review' && github.event.review.state == 'approved') ||
|
|
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
|
|
}}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Check PR status and merge
|
|
uses: actions/github-script@v7
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
// Get PR number from event
|
|
let prNumber;
|
|
|
|
if (context.payload.pull_request) {
|
|
prNumber = context.payload.pull_request.number;
|
|
} else if (context.payload.workflow_run) {
|
|
// Get PR from workflow run
|
|
const { data: prs } = await github.rest.pulls.list({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
state: 'open',
|
|
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`
|
|
});
|
|
if (prs.length === 0) {
|
|
console.log('No open PR found for this branch');
|
|
return;
|
|
}
|
|
prNumber = prs[0].number;
|
|
} else {
|
|
console.log('Could not determine PR number');
|
|
return;
|
|
}
|
|
|
|
console.log(`Checking PR #${prNumber}`);
|
|
|
|
// Get PR details
|
|
const { data: pr } = await github.rest.pulls.get({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber
|
|
});
|
|
|
|
if (pr.state !== 'open') {
|
|
console.log('PR is not open');
|
|
return;
|
|
}
|
|
|
|
if (pr.draft) {
|
|
console.log('PR is still in draft');
|
|
return;
|
|
}
|
|
|
|
// Check if PR is approved
|
|
const { data: reviews } = await github.rest.pulls.listReviews({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber
|
|
});
|
|
|
|
const latestReviews = {};
|
|
for (const review of reviews) {
|
|
latestReviews[review.user.login] = review.state;
|
|
}
|
|
|
|
const hasApproval = Object.values(latestReviews).includes('APPROVED');
|
|
const hasRequestChanges = Object.values(latestReviews).includes('CHANGES_REQUESTED');
|
|
|
|
if (!hasApproval) {
|
|
console.log('PR has not been approved yet');
|
|
return;
|
|
}
|
|
|
|
if (hasRequestChanges) {
|
|
console.log('PR has requested changes');
|
|
return;
|
|
}
|
|
|
|
// Check CI status - support both old and new gated workflows
|
|
const { data: checks } = await github.rest.checks.listForRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: pr.head.sha
|
|
});
|
|
|
|
// Required checks for old CI/CD workflow
|
|
const legacyRequiredChecks = ['Lint Code', 'Build Application', 'E2E Tests'];
|
|
|
|
// Required gate checks for new Enterprise Gated CI/CD Pipeline
|
|
const gatedRequiredChecks = [
|
|
'Gate 1: Code Quality - Passed ✅',
|
|
'Gate 2: Testing - Passed ✅',
|
|
'Gate 3: Build & Package - Passed ✅'
|
|
];
|
|
|
|
const checkStatuses = {};
|
|
|
|
for (const check of checks.check_runs) {
|
|
checkStatuses[check.name] = check.conclusion;
|
|
}
|
|
|
|
console.log('Check statuses:', checkStatuses);
|
|
|
|
// Check if using new gated workflow or old workflow
|
|
const hasGatedChecks = gatedRequiredChecks.some(checkName =>
|
|
checkStatuses[checkName] !== undefined
|
|
);
|
|
|
|
const requiredChecks = hasGatedChecks ? gatedRequiredChecks : legacyRequiredChecks;
|
|
console.log('Using checks:', hasGatedChecks ? 'Enterprise Gated' : 'Legacy');
|
|
|
|
// Wait for all required checks to pass
|
|
const allChecksPassed = requiredChecks.every(checkName =>
|
|
checkStatuses[checkName] === 'success' || checkStatuses[checkName] === 'skipped'
|
|
);
|
|
|
|
if (!allChecksPassed) {
|
|
console.log('Not all required checks have passed');
|
|
|
|
// Check if any checks failed
|
|
const anyChecksFailed = Object.values(checkStatuses).some(status =>
|
|
status === 'failure'
|
|
);
|
|
|
|
if (anyChecksFailed) {
|
|
console.log('Some checks failed, not merging');
|
|
return;
|
|
}
|
|
|
|
console.log('Checks are still running, will retry later');
|
|
return;
|
|
}
|
|
|
|
console.log('All conditions met, merging PR');
|
|
|
|
// Add comment before merging
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body: '✅ All checks passed and PR is approved! Auto-merging and cleaning up branch.'
|
|
});
|
|
|
|
try {
|
|
// Merge the PR
|
|
await github.rest.pulls.merge({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
pull_number: prNumber,
|
|
merge_method: 'squash',
|
|
commit_title: `${pr.title} (#${prNumber})`,
|
|
commit_message: pr.body || ''
|
|
});
|
|
|
|
console.log('PR merged successfully');
|
|
|
|
// Delete the branch
|
|
try {
|
|
await github.rest.git.deleteRef({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
ref: `heads/${pr.head.ref}`
|
|
});
|
|
console.log(`Branch ${pr.head.ref} deleted successfully`);
|
|
} catch (deleteError) {
|
|
console.log('Could not delete branch:', deleteError.message);
|
|
// Don't fail the workflow if branch deletion fails
|
|
}
|
|
|
|
} catch (mergeError) {
|
|
console.error('Failed to merge PR:', mergeError.message);
|
|
|
|
// Post comment about merge failure
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: prNumber,
|
|
body: `❌ Auto-merge failed: ${mergeError.message}\n\nPlease merge manually.`
|
|
});
|
|
}
|