97 lines · 3.3 KB
import { repoDb } from "./scoped-db";
import { randomId } from "./crypto";
import { assertBelowCap, CAPS } from "./limits";
import { toProtection } from "./protection";
import type { BranchProtection, BranchProtectionRow } from "./protection";

export type ProtectionInput = {
  pattern: string;
  requirePullRequest: boolean;
  requiredApprovals: number;
  requiredChecks: string[];
  dismissStaleReviews: boolean;
  allowDeletions: boolean;
  allowForcePushes: boolean;
  enforceAdmins: boolean;
};

/** Callers must have checked admin access on the repo. */
export async function listProtectionRules(repoId: string): Promise<BranchProtection[]> {
  const rows = await repoDb(repoId).all<BranchProtectionRow>(
    "SELECT * FROM branch_protections WHERE repo_id = ? ORDER BY pattern",
    repoId,
  );
  return rows.map(toProtection);
}

export async function loadProtectionRule(repoId: string, id: string): Promise<BranchProtection | null> {
  const row = await repoDb(repoId).first<BranchProtectionRow>(
    "SELECT * FROM branch_protections WHERE id = ? AND repo_id = ?",
    id,
    repoId,
  );
  return row ? toProtection(row) : null;
}

/** Creates (id null) or updates a rule; returns the rule id. Callers must have checked admin access. */
export async function saveProtectionRule(repoId: string, id: string | null, input: ProtectionInput): Promise<string> {
  if (!id)
    assertBelowCap(
      (