feat(industrial-embodied-ai): bind controller execution receipts #22
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Require maintainer approval | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| branches: [main] | |
| # Re-evaluate the gate when a review is submitted or dismissed so an | |
| # approval clears the failing status without waiting for a new push. | |
| # Note: pull_request_review does not support a branches filter, so the | |
| # base-branch check lives in the job-level `if` below. | |
| pull_request_review: | |
| types: [submitted, dismissed] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| statuses: write | |
| jobs: | |
| gate: | |
| runs-on: ubuntu-latest | |
| if: github.event.pull_request.base.ref == 'main' | |
| steps: | |
| - name: Check for maintainer approval | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const MAINTAINERS = ['imran-siddique']; | |
| const author = context.payload.pull_request.user.login; | |
| if (MAINTAINERS.includes(author)) { | |
| core.info(`Author ${author} is a maintainer, skipping gate`); | |
| return; | |
| } | |
| const association = context.payload.pull_request.author_association; | |
| if (association === 'MEMBER' || association === 'OWNER') { | |
| core.info(`Author is ${association}, skipping gate`); | |
| return; | |
| } | |
| // Both pull_request_target and pull_request_review payloads | |
| // carry the PR at context.payload.pull_request. | |
| const prNumber = context.payload.pull_request.number; | |
| // Re-fetch the PR so we compare against the head SHA at | |
| // evaluation time, not a possibly stale SHA from the payload. | |
| const { data: pr } = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| }); | |
| const headSha = pr.head.sha; | |
| // Paginate: listReviews otherwise returns only the first 30. | |
| const reviews = await github.paginate(github.rest.pulls.listReviews, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| }); | |
| // Only a maintainer's most recent non-comment review counts, | |
| // and it must approve the current head commit. An approval of | |
| // an older commit does not clear the gate after a later push | |
| // (prevents approve-then-swap). | |
| const latestByMaintainer = new Map(); | |
| for (const review of reviews) { | |
| if ( | |
| review.user && | |
| review.user.type === 'User' && | |
| MAINTAINERS.includes(review.user.login) && | |
| review.state !== 'COMMENTED' | |
| ) { | |
| latestByMaintainer.set(review.user.login, review); | |
| } | |
| } | |
| const approved = [...latestByMaintainer.values()].some( | |
| (r) => r.state === 'APPROVED' && r.commit_id === headSha | |
| ); | |
| if (!approved) { | |
| core.setFailed('Waiting for maintainer approval of the current head commit before merging.'); | |
| } |