mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 03:45:46 -06:00
fix(scripts): ignore superseded target dispatch checks (#128704)
This commit is contained in:
committed by
GitHub
parent
41050b2f3b
commit
e45e4ca69f
+32
-8
@@ -32,6 +32,7 @@ const RollupCheckSchema = z.object({
|
||||
workflowRun: optionalNullable(
|
||||
z.object({
|
||||
databaseId: optionalNumber,
|
||||
event: optionalString,
|
||||
workflow: optional(z.object({ databaseId: optionalNumber })),
|
||||
}),
|
||||
),
|
||||
@@ -66,7 +67,7 @@ const RollupResponseSchema = z.object({
|
||||
repository: z.object({ pullRequest: RollupPageSchema.nullish() }).nullish(),
|
||||
}),
|
||||
});
|
||||
const RunListItemSchema = z.object({ id: z.number(), created_at: z.string() });
|
||||
const RunListItemSchema = z.object({ id: z.number(), workflow_id: optionalNumber });
|
||||
const RunListSchema = z
|
||||
.object({ workflow_runs: validArray(RunListItemSchema) })
|
||||
.transform((response) => response.workflow_runs)
|
||||
@@ -89,7 +90,7 @@ const FAILURE_CONCLUSIONS = new Set([
|
||||
"STALE",
|
||||
"TIMED_OUT",
|
||||
]);
|
||||
const ROLLUP_QUERY = `query($owner:String!,$name:String!,$pr:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$pr){state mergeable headRefOid statusCheckRollup{state contexts(first:100,after:$cursor){totalCount pageInfo{hasNextPage endCursor} nodes{kind:__typename ... on CheckRun{name status conclusion databaseId checkSuite{workflowRun{databaseId workflow{databaseId}}}} ... on StatusContext{context state}}}}}}}`;
|
||||
const ROLLUP_QUERY = `query($owner:String!,$name:String!,$pr:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$pr){state mergeable headRefOid statusCheckRollup{state contexts(first:100,after:$cursor){totalCount pageInfo{hasNextPage endCursor} nodes{kind:__typename ... on CheckRun{name status conclusion databaseId checkSuite{workflowRun{databaseId event workflow{databaseId}}}} ... on StatusContext{context state}}}}}}}`;
|
||||
const GH_READ_OPTIONS = {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
timeout: 60_000,
|
||||
@@ -192,7 +193,7 @@ function checkRunIdentity(check: RollupCheck) {
|
||||
const newerJob = (a: JobIdentity, b: JobIdentity) =>
|
||||
a.runId !== b.runId ? a.runId > b.runId : a.checkId > b.checkId;
|
||||
|
||||
export function classifyRollup(rollup: RollupPayload | null | undefined) {
|
||||
export function classifyRollup(rollup: RollupPayload | null | undefined, runs: RunListItem[] = []) {
|
||||
const rawNodes = rollup?.contexts?.nodes ?? [];
|
||||
const hiddenContextCount = Math.max(
|
||||
0,
|
||||
@@ -221,8 +222,8 @@ export function classifyRollup(rollup: RollupPayload | null | undefined) {
|
||||
let supersededCount = 0;
|
||||
// Re-triggers leave every prior run's check runs on the SHA forever and GitHub's aggregate
|
||||
// counts them. A check is superseded when a newer same-workflow check shares its name
|
||||
// (GitHub's latest-name-wins semantics), or when it was cancelled and its workflow has a
|
||||
// newer run (draft->ready cancels the old run before the replacement posts check runs).
|
||||
// (GitHub's latest-name-wins semantics), or when its cancelled workflow has a newer run.
|
||||
// Actions run metadata also proves target-run supersession before a newer run posts jobs.
|
||||
// Older-run checks with unique names stay visible so distinct invocations are not dropped.
|
||||
const nodes = rawNodes.filter((check) => {
|
||||
const identity = checkRunIdentity(check);
|
||||
@@ -236,8 +237,13 @@ export function classifyRollup(rollup: RollupPayload | null | undefined) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const newestRun = newestRunByWorkflow.get(identity.workflowId);
|
||||
if (check.conclusion === "CANCELLED" && newestRun !== undefined && newestRun > identity.runId) {
|
||||
const newestRun = newestRunByWorkflow.get(identity.workflowId) ?? identity.runId;
|
||||
if (
|
||||
check.conclusion === "CANCELLED" &&
|
||||
(newestRun > identity.runId ||
|
||||
(check.checkSuite?.workflowRun?.event === "pull_request_target" &&
|
||||
runs.some((run) => run.workflow_id === identity.workflowId && run.id > identity.runId)))
|
||||
) {
|
||||
supersededCount += 1;
|
||||
return false;
|
||||
}
|
||||
@@ -310,6 +316,13 @@ const findRun = (repo: string, sha: string, after?: number) =>
|
||||
RunListSchema.parse(execGhJson(buildFindRunArgs(repo, sha), GH_READ_OPTIONS)),
|
||||
after,
|
||||
);
|
||||
const findTargetRuns = (repo: string, sha: string) =>
|
||||
RunListSchema.parse(
|
||||
execGhJson(
|
||||
["api", `repos/${repo}/actions/runs?event=pull_request_target&head_sha=${sha}&per_page=100`],
|
||||
GH_READ_OPTIONS,
|
||||
),
|
||||
);
|
||||
const readRun = (repo: string, runId: number) =>
|
||||
RunStatusSchema.parse(
|
||||
execGhJson(
|
||||
@@ -541,7 +554,18 @@ async function main(argv = process.argv.slice(2)) {
|
||||
if (blocked !== null) {
|
||||
return blocked;
|
||||
}
|
||||
const result = classifyRollup(pr.statusCheckRollup);
|
||||
let result = classifyRollup(pr.statusCheckRollup);
|
||||
if (
|
||||
result.verdict === "FAILING" &&
|
||||
pr.statusCheckRollup?.contexts?.nodes?.some(
|
||||
(check) =>
|
||||
check.conclusion === "CANCELLED" &&
|
||||
check.checkSuite?.workflowRun?.event === "pull_request_target" &&
|
||||
checkRunIdentity(check),
|
||||
)
|
||||
) {
|
||||
result = classifyRollup(pr.statusCheckRollup, findTargetRuns(args.repo, args.headSha));
|
||||
}
|
||||
lastState = pr.statusCheckRollup?.state ?? "NONE";
|
||||
lastPending = result.pendingCount;
|
||||
console.log(
|
||||
|
||||
Reference in New Issue
Block a user