import { repoDb } from "../scoped-db"; import { locate } from "../scoped-db/locators"; import { loadRepoById } from "../repos"; import { notifyQuietly, quiet } from "./deliver"; import { repoAdmins } from "./recipients"; type DeployFailure = { kind: "Sites"; repoId: string; creatorId: string | null; target: string; error: string; settingsPath: "sites"; }; /** Deploy failures go to whoever pushed or requested the deploy plus the repository admins. */ async function notifyDeployFailure(input: DeployFailure): Promise { const repo = await loadRepoById(input.repoId); if (!repo) return; await notifyQuietly({ category: "deploy", repoId: repo.id, accountId: null, access: "read", recipients: [input.creatorId, ...(await repoAdmins(repo.id))], title: `${input.kind} deploy failed for ${repo.owner_name}/${repo.name} (${input.target})`, details: [`Error: ${input.error}`], url: `/${repo.owner_name}/${repo.name}/settings/${input.settingsPath}`, }); } async function notifySiteDeployFailedUnsafe(deploymentId: string, error: string): Promise { const repoId = await locate("site_deployment", deploymentId); if (!repoId) return; const row = await repoDb(repoId).first<{ repo_id: string | null; creator_id: string | null; label: string }>( `SELECT s.repo_id, d.creator_id, d.label FROM site_deployments d JOIN sites s ON s.id = d.site_id WHERE d.id = ? AND d.status = 'failed'`, deploymentId, ); if (!row?.repo_id) return; await notifyDeployFailure({ kind: "Sites", repoId: row.repo_id, creatorId: row.creator_id, target: row.label, error, settingsPath: "sites", }); } export const notifySiteDeployFailed = quiet("notifySiteDeployFailed", notifySiteDeployFailedUnsafe);