Skip to content

Record upstream Mike backlog classifications (#49) #9

Record upstream Mike backlog classifications (#49)

Record upstream Mike backlog classifications (#49) #9

name: Dispatch unverified agent heads
on:
schedule:
- cron: "*/5 * * * *"
workflow_dispatch:
push:
branches: [main]
permissions:
actions: write
contents: read
issues: write
pull-requests: read
concurrency:
group: dispatch-unverified-agent-heads
cancel-in-progress: false
jobs:
dispatch:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Dispatch Baseline for unverified exact heads
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
script: |
const { owner, repo } = context.repo;
const trustedAssociations = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
const { data: workflow } = await github.rest.actions.getWorkflow({
owner,
repo,
workflow_id: "baseline.yml",
});
const reportFailure = async (pr, run) => {
const marker = `<!-- ross-baseline-run:${run.id} -->`;
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: pr.number,
per_page: 100,
});
if (comments.some((comment) => comment.body?.includes(marker))) return;
const jobs = await github.paginate(
github.rest.actions.listJobsForWorkflowRun,
{
owner,
repo,
run_id: run.id,
per_page: 100,
},
);
const failures = jobs
.filter((job) => job.conclusion && job.conclusion !== "success" && job.conclusion !== "skipped")
.map((job) => {
const steps = (job.steps || [])
.filter((step) => step.conclusion === "failure")
.map((step) => step.name);
return `- **${job.name}** (${job.conclusion})${steps.length ? ` — ${steps.join(", ")}` : ""}`;
});
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body: [
marker,
`Baseline failed for exact head \`${pr.head.sha}\`.`,
"",
failures.length ? failures.join("\n") : `- Workflow conclusion: **${run.conclusion}**`,
"",
`[Open workflow run](${run.html_url})`,
"",
"Bounded automatic repair runs only for eligible low-risk paths. Protected workflow, dependency, migration, deployment, security, legal, governance, or release changes require focused review.",
].join("\n"),
});
};
const pullRequests = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
base: "main",
per_page: 100,
});
for (const pr of pullRequests) {
const markedSyncBot =
pr.user?.login === "github-actions[bot]" &&
pr.head.ref.startsWith("agent/upstream-sync-") &&
pr.body?.includes("Automated-Upstream-Mike-Sync: true");
const eligible =
!pr.draft &&
pr.head.repo?.full_name === `${owner}/${repo}` &&
pr.head.ref.startsWith("agent/") &&
(trustedAssociations.has(pr.author_association) || markedSyncBot);
if (!eligible) continue;
const runs = await github.paginate(
github.rest.actions.listWorkflowRuns,
{
owner,
repo,
workflow_id: workflow.id,
branch: pr.head.ref,
per_page: 100,
},
);
const exactHeadRun = runs.find((run) => run.head_sha === pr.head.sha);
if (exactHeadRun) {
core.info(
`PR #${pr.number} already has Baseline run ${exactHeadRun.id} for ${pr.head.sha} (${exactHeadRun.status}/${exactHeadRun.conclusion || "none"}).`,
);
if (
exactHeadRun.status === "completed" &&
exactHeadRun.conclusion &&
exactHeadRun.conclusion !== "success" &&
exactHeadRun.conclusion !== "skipped" &&
exactHeadRun.conclusion !== "neutral"
) {
await reportFailure(pr, exactHeadRun);
}
continue;
}
await github.rest.actions.createWorkflowDispatch({
owner,
repo,
workflow_id: workflow.id,
ref: pr.head.ref,
});
core.notice(
`Dispatched Baseline for PR #${pr.number} exact head ${pr.head.sha}.`,
);
}