52 lines · 1.7 KB
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<void> {
  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<void> {
  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;