Files
SpacetimeDB/.github/workflows/pr_approval_check.yml
T
Zeke Foppa 154287c52f CI - Simplify PR approval check (#4578)
# Description of Changes

The previous version ended up incurring two different entries on the PR
(one for the `pull_request` event and one for the `pull_request_review`
event). Both versions were marked "required", so PRs could end up in an
unmergeable state if one check had succeeded but the other had failed
(e.g. if you submitted a PR approval, the previous `pull_request`
version of the check would still be failed since it didn't refresh).

See the entries at top and bottom here:
<img width="481" height="225" alt="image"
src="https://github.com/user-attachments/assets/5b7a4302-6bc2-47e9-93c8-812cb9ece60b"
/>

This PR fixes it by only allowing the `pull_request_review` events. I
_think_ this covers all the cases, but I'm not sure.

# API and ABI breaking changes

None.

# Expected complexity level and risk

1

# Testing

I don't know how to test it really 🤷

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
2026-03-07 03:12:49 +00:00

107 lines
3.7 KiB
YAML

name: Review Checks
on:
pull_request:
types: [opened, synchronize, reopened]
pull_request_review:
types: [submitted, dismissed]
merge_group:
permissions:
contents: read
pull-requests: read
statuses: write
concurrency:
group: pr-approval-check-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
publish-approval-status:
name: Set approval status
runs-on: ubuntu-latest
steps:
- name: Evaluate and publish approval status
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const contextName = "PR approval check";
let targetSha;
let state;
let description;
if (context.eventName === "merge_group") {
targetSha = process.env.GITHUB_SHA;
state = "success";
description = "Merge group entry; approvals already satisfied";
} else {
const pr = context.payload.pull_request;
targetSha = pr.head.sha;
if (pr.user.login !== "clockwork-labs-bot") {
state = "success";
description = "PR author is not clockwork-labs-bot";
} else {
const result = await github.graphql(
`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
latestOpinionatedReviews(first: 100, writersOnly: true) {
nodes {
state
author {
login
}
}
}
}
}
}
`,
{
owner: context.repo.owner,
repo: context.repo.repo,
number: pr.number,
}
);
const effectiveApprovers =
result.repository.pullRequest.latestOpinionatedReviews.nodes
.filter((review) => review.state === "APPROVED")
.map((review) => review.author?.login)
.filter(Boolean);
core.info(
`Latest effective approvers (${effectiveApprovers.length}): ${effectiveApprovers.join(", ")}`
);
if (effectiveApprovers.length < 2) {
state = "failure";
description = "PRs from clockwork-labs-bot require at least 2 approvals";
} else {
state = "success";
description = "PR has the required number of approvals";
}
}
}
core.info(`Publishing status ${state} for ${targetSha}: ${description}`);
// We need to set a separate commit status for this, because it runs on both
// pull_request and pull_request_review events. If we don't set an explicit context,
// what happens is that there are sometimes two separate statuses on the same commit -
// one from each event type. This leads to weird cases where one copy of the check is failed,
// and the other is successful, and the failed one blocks the PR from merging.
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: targetSha,
state,
context: contextName,
description,
});