fix(gitea): collapse pull-ref-only heads to pr-N in local branch names

buildForkLocalBranchName still used the raw headRef even when it was
just the pull ref (refs/pull/N/head), which agit prs and deleted head
branches report as their headRefName. that gave local branches literal
names like refs/heads/refs/pull/3/head.
This commit is contained in:
Alexander Adam
2026-10-13 22:23:24 +02:00
committed by paseo-bot[bot]
parent 52bf490fbf
commit 1dbb838af1
2 changed files with 37 additions and 2 deletions
@@ -61,4 +61,29 @@ describe("buildForkLocalBranchName", () => {
it("falls back to the pr number when the owner is not a safe ref segment", () => {
expect(buildForkLocalBranchName({ ...fork, headOwnerLogin: "-zaphod" })).toBe("pr-42/patch-1");
});
// pull-ref-only heads (agit PRs, deleted branches) report headRef as the
// literal pull ref, e.g. refs/pull/42/head, not a real branch name
it("collapses a same-repository pull-ref-only head to pr-<number>", () => {
expect(
buildForkLocalBranchName({
...fork,
isCrossRepository: false,
headOwnerLogin: "arthur",
hasHeadBranch: false,
}),
).toBe("pr-42");
});
it("prefixes pr-<number> with the owner for a fork pull-ref-only head", () => {
expect(
buildForkLocalBranchName({ ...fork, headOwnerLogin: "Arthur", hasHeadBranch: false }),
).toBe("arthur/pr-42");
});
it("does not double the pr number when the fork owner is unknown and there is no head branch", () => {
expect(buildForkLocalBranchName({ ...fork, headOwnerLogin: null, hasHeadBranch: false })).toBe(
"pr-42",
);
});
});
@@ -26,12 +26,22 @@ export interface ForkLocalBranchNameInput {
number: number;
isCrossRepository: boolean;
headOwnerLogin: string | null;
/** false when headRef is a synthetic pull ref, not a real branch name (agit PRs, deleted branches) */
hasHeadBranch?: boolean;
}
export function buildForkLocalBranchName(params: ForkLocalBranchNameInput): string {
const pullRefFallback = `pr-${params.number}`;
// headRef is the literal pull ref (e.g. refs/pull/42/head) when there is no
// real branch to name after, so use the pr number instead
const headSegment = params.hasHeadBranch === false ? pullRefFallback : params.headRef;
if (!params.isCrossRepository) {
return params.headRef;
return headSegment;
}
const owner = normalizeForgeOwnerForBranch(params.headOwnerLogin);
return `${owner ?? `pr-${params.number}`}/${params.headRef}`;
if (!owner) {
// don't double up pr-<n>/pr-<n> when the owner is also unknown
return headSegment === pullRefFallback ? headSegment : `${pullRefFallback}/${headSegment}`;
}
return `${owner}/${headSegment}`;
}