diff --git a/.github/workflows/check-main-status.yml b/.github/workflows/check-main-status.yml new file mode 100644 index 00000000..634ab22a --- /dev/null +++ b/.github/workflows/check-main-status.yml @@ -0,0 +1,53 @@ +name: Check Main Branch Status +on: + pull_request: + merge_group: + workflow_dispatch: + inputs: + pr_number: + description: "Pull Request number" + required: true + +jobs: + check-main-status: + runs-on: ubuntu-24.04 + env: + PR_NUMBER: ${{ github.event.number || github.event.inputs.pr_number }} + steps: + - uses: actions/checkout@v3 + with: + sparse-checkout: | + .github/workflows/lib/ + - run: pwd + - run: ls -lap + - run: ls -lap .github/workflows/lib/ + - uses: actions/github-script@v7 + name: Check if PR has 'fix-ci' label + id: has_fix_ci_label + with: + retries: 3 + script: | + const checkMain = require('./.github/workflows/lib/checkMain.js'); + + const result = checkMain.hasFixCiLabel(github, context.owner, context.repo, process.env.PR_NUMBER); + console.log(`Has 'fix-ci' label: ${result}`); + + return result; + + - uses: actions/github-script@v7 + name: Ensure Main Branch Check Runs Are Successful + if: ${{ steps.has_fix_ci_label.outputs.result == 'false' }} + with: + retries: 3 + script: | + const checkMain = require('./.github/workflows/lib/checkMain.js'); + + function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + try { + await checkMain.ensureChecksRunsSuccessful(delay, github, context.owner, context.repo); + } catch (error) { + core.setFailed(error.message); + } diff --git a/.github/workflows/dfu_check.yml b/.github/workflows/dfu_check.yml index 18e415fa..864656f7 100644 --- a/.github/workflows/dfu_check.yml +++ b/.github/workflows/dfu_check.yml @@ -2,6 +2,7 @@ name: DFU image compatibility check on: workflow_call: + merge_group: push: branches: - main diff --git a/.github/workflows/lib/checkMain.mjs b/.github/workflows/lib/checkMain.mjs new file mode 100644 index 00000000..1b5ffbb2 --- /dev/null +++ b/.github/workflows/lib/checkMain.mjs @@ -0,0 +1,59 @@ +module.exports = { + async hasFixCiLabel(octokit, owner, repo, prNumber) { + const labels = await octokit.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: prNumber, + }); + + return labels.data.map(label => label.name).includes('fix-ci'); + }, + + async ensureChecksRunsSuccessful(delay, octokit, owner, repo) { + let retryPending = 12; // Retry for up to 1 hour (12 retries with 5 minutes interval) + + while (retryPending > 0) { + const mainRef = await octokit.git.getRef({ + owner, + repo, + ref: 'heads/main', + }); + + const mainSha = mainRef.data.object.sha; + console.log(`Main branch SHA: ${mainSha}`); + + let checkRuns = await octokit.checks.listForRef({ + owner, + repo, + ref: mainSha, + }); + + console.log(`Check runs (${checkRuns.data.total_count}):`); + for (let run of checkRuns.data.check_runs) { + console.log(`- ${run.name}`); + console.log(`\tstatus: ${run.status}`); + console.log(`\tconclusion: ${run.conclusion}`); + } + + const failedChecks = checkRuns.data.check_runs.filter(run => run.conclusion !== null && run.conclusion !== 'success'); + const pendingChecks = checkRuns.data.check_runs.filter(run => run.status !== 'completed'); + + if (failedChecks.length > 0) { + throw new Error('Cannot merge: The main branch has failing checks.'); + } else if (pendingChecks.length === 0) { + console.log('Main branch is healthy.'); + break; + } else { + console.log('Checks are still pending.'); + + retryPending--; + if (retryPending === 0) { + throw new Error('Timeout waiting for pending checks on main branch.'); + } + + console.log('Waiting for 5 minutes before retrying...'); + await delay(5 * 60 * 1000); // Wait for 5 minutes + } + } + }, +};