import { all, first, run } from "../db";
import { notFoundError } from "../errors";
import { assertBelowCap, CAPS } from "../limits";
import { completeJob, runnerStub } from "./jobs";
import type { WorkflowJobRow, WorkflowRunRow } from "./jobs";
import { startRun } from "./scheduler";
export async function loadRunByNumber(repoId: string, number: number): Promise<WorkflowRunRow> {
const row = await first<WorkflowRunRow>(
"SELECT * FROM workflow_runs WHERE repo_id = ? AND run_number = ?",
repoId,
number,
);
if (!row) throw notFoundError("Run not found");
return row;
}
/** Cancels every unfinished job of a run; running jobs are stopped through their runner. */
export async function cancelRunRow(runRow: WorkflowRunRow): Promise<void> {
const jobs = await all<WorkflowJobRow>(
"SELECT * FROM workflow_jobs WHERE run_id = ? AND status != 'completed'",
runRow.id,
);
for (const job of jobs) {
if (job.status === "in_progress") await runnerStub(job.id, job.runs_on).cancel("cancelled by user");
else await completeJob(job.id, "cancelled");
}
if (runRow.approval_required === 1 && runRow.status === "queued") {
await run(
"UPDATE workflow_runs SET status = 'completed', conclusion = 'cancelled', completed_at = ? WHERE id = ?",
Date.now(),
runRow.id,
);
}
}
/** Approves a fork run awaiting a maintainer and starts it, within the per-repo active run cap. */
export async function approveRunRow(repoId: string, runRow: WorkflowRunRow): Promise<void> {
const active = await first<{ count: number }>(
"SELECT COUNT(*) AS count FROM workflow_runs WHERE repo_id = ? AND status != 'completed' AND approval_required = 0",