pr_01m47d24b0e6n91zwymwxg0vpx/apps/web/app/lib/provenance.server.ts

37 lines1,640 bytesCodeBlame
1import type { Pull, RepoPath, Viewer } from "@g1t/contracts";
2
3import { repos, work } from "./services.server";
4
5/** How far back the default branch is read to place a commit. */
6const HISTORY_READ = 300;
7
8/**
9 * The merged pull request a commit arrived in: the one whose head it is,
10 * or else the one whose stretch of the default branch's history holds it,
11 * from its head back to where it started. One read of pull requests and at
12 * most one of history, however many pull requests there are.
13 */
14export async function pullForCommit(path: RepoPath, viewer: Viewer, hash: string): Promise<Pull | null> {
15 const closed = await work.listPulls(path, viewer, "closed");
16 if (!closed.ok) return null;
17 const merged = closed.value.filter((pull) => pull.status === "merged" && pull.headCommit);
18 const direct = merged.find((pull) => pull.headCommit === hash);
19 if (direct) return direct;
20
21 const log = await repos.log(path, viewer, null, HISTORY_READ);
22 if (!log.ok) return null;
23 const position = new Map(log.value.map((commit, index) => [commit.hash, index]));
24 const at = position.get(hash);
25 if (at == null) return null;
26 // Newest first: a pull request's commits sit at or after its head and
27 // before the commit it started from.
28 let best: { pull: Pull; head: number } | null = null;
29 for (const pull of merged) {
30 const head = position.get(pull.headCommit!);
31 if (head == null || head > at) continue;
32 const base = pull.mergeBase ? position.get(pull.mergeBase) : undefined;
33 if (base != null && base <= at) continue;
34 if (!best || head > best.head) best = { pull, head };
35 }
36 return best?.pull ?? null;
37}