import { repoDb } from "../scoped-db";
import { loadPull } from "../pulls";
import type { RepoRow } from "~/lib/types";
import type { WorkflowRunRow } from "../ci/jobs";
import { notifyQuietly, quiet } from "./deliver";
import { repoWatchers } from "./recipients";
const FAILED = new Set(["failure", "timed_out", "startup_failure"]);
/**
* Failure notices go to the actor, the PR author for PR runs and (by the "ci_watching" pref) watchers;
* a success right after a failure on the same workflow and ref sends a "fixed" notice to the same people.
*/
async function notifyRunCompletedUnsafe(repo: RepoRow, runRow: WorkflowRunRow, conclusion: string): Promise<void> {
const failed = FAILED.has(conclusion);
if (!failed && conclusion !== "success") return;
const db = repoDb(repo.id);
const state = await db.first<{ conclusion: string; last_run_id: string | null; previous_conclusion: string | null }>(
"SELECT conclusion, last_run_id, previous_conclusion FROM ci_notify_state WHERE repo_id = ? AND workflow_path = ? AND ref = ?",
repo.id,
runRow.workflow_path,
runRow.ref,
);
const previous = state?.last_run_id === runRow.id ? state.previous_conclusion : (state?.conclusion ?? null);
if (state?.last_run_id !== runRow.id) {
await db.run(
`INSERT INTO ci_notify_state (repo_id, workflow_path, ref, conclusion, last_run_id, previous_conclusion, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (repo_id, workflow_path, ref) DO UPDATE SET conclusion = excluded.conclusion,
last_run_id = excluded.last_run_id, previous_conclusion = excluded.previous_conclusion, updated_at = excluded.updated_at`,
repo.id,
runRow.workflow_path,
runRow.ref,
conclusion,
runRow.id,
previous,
Date.now(),
);
}
const fixed = conclusion === "success" && previous !== null && FAILED.has(previous);