import { z } from "zod";
import { assertNotArchived, loadRepoById, requireRepoAccess } from "./repos";
import { loadPull } from "./pulls";
import { notFoundError } from "./errors";
import { publicUrl } from "./events/emit";
import { repoRef } from "~/lib/validation";
import type { RepoRow, Viewer } from "~/lib/types";
export const pullInput = repoRef.extend({ number: z.number().int().positive() });
export async function requirePull(
owner: string,
repoName: string,
number: number,
viewer: Viewer | null,
needed: "read" | "write",
{ mutation = false }: { mutation?: boolean } = {},
) {
const access = await requireRepoAccess(owner, repoName, viewer, needed);
// Site admins can read a hidden pull request; mutations and write access never load it.
const includeHidden = !mutation && needed === "read" && Boolean(viewer?.isAdmin);
const pull = await loadPull(access.repo.id, number, { includeHidden });
if (!pull) throw notFoundError("Pull request not found");
const headRepo = pull.head_repo_id === access.repo.id ? access.repo : await loadRepoById(pull.head_repo_id);
if (!headRepo) throw notFoundError("Head repository was deleted");
return { ...access, pull, headRepo };
}
export function pullUrl(repo: RepoRow, number: number): string {
return publicUrl(`/${repo.owner_name}/${repo.name}/pull/${number}`);
}
/** `requirePull` for a mutation: additionally rejects archived base repositories. */
export async function requirePullMutation(
owner: string,
repoName: string,
number: number,
viewer: Viewer | null,
needed: "read" | "write",
) {