import { waitUntil } from "cloudflare:workers";
import { hasPermission, loadRepoById, repoPermission } from "./repos";
import { loadUserById, toViewer } from "./auth";
import type { RepoRow } from "~/lib/types";
import { checkMergeability, loadPullByIssueId } from "./pulls";
import { scheduleWorkflows } from "./ci/scheduler";
import { requestCodeOwnerReviews } from "./review-requests";
import { emitWebhook, publicUrl } from "./events/emit";
import type { Viewer } from "~/lib/types";
/**
* Pull requests from forks run untrusted code on our containers, so (like GitHub) runs from actors
* without write access to the base repository wait for a maintainer to approve them.
*/
export async function forkRunNeedsApproval(
baseRepo: RepoRow,
headRepo: RepoRow,
actorId: string | null,
): Promise<boolean> {
if (baseRepo.id === headRepo.id) return false;
const actor = actorId ? await loadUserById(actorId) : null;
return !hasPermission(await repoPermission(baseRepo, actor ? toViewer(actor) : null), "write");
}
/**
* The code that runs belongs to the pull request's author and the head repository's owner, not to whoever
* triggered the event, so a maintainer reopening or editing a fork PR does not implicitly approve its code.
*/
export async function forkPullNeedsApproval(baseRepo: RepoRow, headRepo: RepoRow, authorId: string): Promise<boolean> {
if (baseRepo.id === headRepo.id) return false;
if (await forkRunNeedsApproval(baseRepo, headRepo, authorId)) return true;
return forkRunNeedsApproval(baseRepo, headRepo, headRepo.owner_id);
}
/**
* Kicks off CI and mergeability checks for a pull request lifecycle event without blocking the request.
* `expectedHeadSha` is the head the actor saw; if it moved before the background task ran, nothing is scheduled.
*/
export function afterPullChange(
target: { repo_id: string; issue_id: string },