Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 86 additions & 8 deletions .github/workflows/automated-review-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ on:

permissions: {}

# Coalesce replaceable state reconciliations before they allocate a runner.
# Source updates and merge-group checks keep unique run IDs so none are lost.
concurrency:
group: >-
${{
github.event_name == 'workflow_run' &&
format('{0}-wakeup-{1}', github.workflow, github.event.workflow_run.display_title) ||
github.event_name == 'issue_comment' && github.event.issue.pull_request &&
format('{0}-comment-pr-{1}', github.workflow, github.event.issue.number) ||
format('{0}-run-{1}', github.workflow, github.run_id)
}}
cancel-in-progress: false

jobs:
target:
name: resolve automated review target
Expand Down Expand Up @@ -55,7 +68,7 @@ jobs:
const match = /^(?:refs\/heads\/)?gh-readonly-queue\/.+\/pr-([1-9]\d*)-([0-9a-f]{40})$/i.exec(headRef);
const pullNumber = match ? Number(match[1]) : undefined;
return Number.isSafeInteger(pullNumber)
? { pullNumber, sourceHeadSha: match[2].toLowerCase() }
? { pullNumber, baseSha: match[2].toLowerCase() }
: undefined;
};
const parseReviewWakeupIdentity = (run) => {
Expand Down Expand Up @@ -102,6 +115,13 @@ jobs:
core.setOutput("key", `run-${context.runId}`);
return;
}
const mergeGroupBaseSha =
context.payload.merge_group?.base_sha?.toLowerCase();
if (queueEntry.baseSha !== mergeGroupBaseSha) {
core.setFailed("Merge queue ref does not match its base commit");
core.setOutput("key", `run-${context.runId}`);
return;
}
}
const pullNumber = queueEntry?.pullNumber ??
context.payload.pull_request?.number ??
Expand All @@ -113,8 +133,8 @@ jobs:
core.setOutput("key", `run-${context.runId}`);
return;
}
let headSha = queueEntry?.sourceHeadSha;
if (!headSha) {
let headSha;
{
try {
const response = await github.rest.git.getRef({
owner: context.repo.owner,
Expand Down Expand Up @@ -611,19 +631,75 @@ jobs:
{
owner: context.repo.owner,
repo: context.repo.repo,
ref: `heads/gh-readonly-queue/${baseRef}/pr-${pullNumber}-${headSha}`,
ref: `heads/gh-readonly-queue/${baseRef}/pr-${pullNumber}-`,
},
"merge queue refs",
);
let queueEntryIdentity;
if (refs.length > 0) {
const queueResponse = await github.graphql(
`query ResolveIndependentQueueSource(
$owner: String!
$repo: String!
$pullNumber: Int!
) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pullNumber) {
number
headRefOid
mergeQueueEntry {
baseCommit { oid }
headCommit { oid }
pullRequest { number headRefOid }
}
}
}
}`,
{ owner: context.repo.owner, repo: context.repo.repo, pullNumber },
);
const queuePull = queueResponse?.repository?.pullRequest;
const queueEntry = queuePull?.mergeQueueEntry;
const queueSourceHead = queueEntry?.pullRequest?.headRefOid;
const queueBaseSha = queueEntry?.baseCommit?.oid;
const queueMergeGroupSha = queueEntry?.headCommit?.oid;
if (
queuePull?.number !== pullNumber ||
queueEntry?.pullRequest?.number !== pullNumber ||
!fullSha.test(queueSourceHead ?? "") ||
!fullSha.test(queueBaseSha ?? "") ||
!fullSha.test(queueMergeGroupSha ?? "") ||
queuePull?.headRefOid?.toLowerCase() !==
queueSourceHead.toLowerCase()
) throw new Error("Merge queue entry is malformed");
if (queueSourceHead.toLowerCase() !== headSha.toLowerCase()) {
return { headSha, queueFailures: 0, skipped: false };
}
queueEntryIdentity = {
baseSha: queueBaseSha.toLowerCase(),
mergeGroupSha: queueMergeGroupSha.toLowerCase(),
};
}
const seen = new Set();
const expectedQueueRef =
`refs/heads/gh-readonly-queue/${baseRef}/pr-${pullNumber}-${headSha}`;
const queueRefPrefix =
`refs/heads/gh-readonly-queue/${baseRef}/pr-${pullNumber}-`;
for (const queueRef of refs) {
if (queueRef?.ref !== expectedQueueRef) continue;
if (
typeof queueRef?.ref !== "string" ||
!queueRef.ref.startsWith(queueRefPrefix)
) continue;
const queueBaseSha = queueRef.ref.slice(queueRefPrefix.length);
if (!fullSha.test(queueBaseSha)) {
throw new Error("Merge queue ref has a malformed base commit");
}
const mergeGroupSha = queueRef?.object?.sha;
if (!fullSha.test(mergeGroupSha ?? "")) {
throw new Error("Merge queue ref has a malformed commit");
}
if (
queueBaseSha.toLowerCase() !== queueEntryIdentity?.baseSha ||
mergeGroupSha.toLowerCase() !==
queueEntryIdentity?.mergeGroupSha
) continue;
if (seen.has(mergeGroupSha.toLowerCase())) continue;
seen.add(mergeGroupSha.toLowerCase());
await github.rest.repos.createCommitStatus({
Expand Down Expand Up @@ -742,7 +818,8 @@ jobs:
if (
!Number.isSafeInteger(pullNumber) ||
pullNumber !== queueEntry.pullNumber ||
sourceHeadSha !== queueEntry.sourceHeadSha
queueEntry.baseSha !==
context.payload.merge_group.base_sha?.toLowerCase()
) {
core.setFailed("Merge queue source does not match its serialized lock");
return;
Expand All @@ -753,6 +830,7 @@ jobs:
repo: context.repo.repo,
pullNumber,
sourceHeadSha,
baseSha: queueEntry.baseSha,
mergeGroupSha: context.payload.merge_group.head_sha,
});
if (result.state === "success") {
Expand Down
Loading
Loading