52 lines · 2.1 KB
import { repoDb } from "../scoped-db";
import { notFoundError } from "../errors";
import { assertBelowCap, CAPS } from "../limits";
import { cancelActiveJob, completeJob } 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 repoDb(repoId).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 db = repoDb(runRow.repo_id);
  const jobs = await db.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 cancelActiveJob(job, "cancelled by user");
    else await completeJob(job.id, "cancelled");
  }
  if (runRow.approval_required === 1 && runRow.status === "queued") {
    await db.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 db = repoDb(repoId);