fork: resolve Gitea branch refs via the branches endpoint
Gitea's /repos/{o}/{r}/commits/{ref} only resolves 40-hex SHAs —
a branch name like "main" returns 404 even when the branch exists.
GitHub's API is more lenient and resolves branch names server-side.
resolveGiteaPinnedRef was calling /commits/{ref} and 404ing on
branch refs, so the entire import path failed before it could
read the tree. updateStatus already used the branches endpoint
correctly; this aligns resolveGiteaPinnedRef with it.
resolveGiteaCommitSha is now a SHA-only helper that refuses to
make the API call for non-SHA refs (matches Gitea's contract).
Test mocks updated to return the branch response shape.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -186,12 +186,12 @@ describe("resolveGiteaPinnedRef", () => {
|
||||
expect(result).toEqual({ pinnedRef: sha, trackingRef: sha });
|
||||
});
|
||||
|
||||
it("resolves a branch ref to its commit SHA via the commits endpoint", async () => {
|
||||
it("resolves a branch ref to its commit SHA via the branches endpoint", async () => {
|
||||
const branchSha = "fedcba9876543210fedcba9876543210fedcba98";
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(jsonResponse({ default_branch: "main" }))
|
||||
.mockResolvedValueOnce(jsonResponse({ sha: branchSha }));
|
||||
.mockResolvedValueOnce(jsonResponse({ name: "main", commit: { id: branchSha } }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
const result = await resolveGiteaPinnedRef(
|
||||
parseGiteaSourceUrl("https://git.example.com/acme/skills"),
|
||||
@@ -202,13 +202,23 @@ describe("resolveGiteaPinnedRef", () => {
|
||||
});
|
||||
|
||||
describe("resolveGiteaCommitSha", () => {
|
||||
it("returns the sha from a commit response", async () => {
|
||||
it("returns the sha from a commit response when given a 40-hex ref", async () => {
|
||||
const sha = "abc123abc123abc123abc123abc123abc123abcd";
|
||||
vi.stubGlobal(
|
||||
"fetch",
|
||||
vi.fn().mockResolvedValue(jsonResponse({ sha: "abc123abc123abc123abc123abc123abc123abcd" })),
|
||||
vi.fn().mockResolvedValue(jsonResponse({ sha })),
|
||||
);
|
||||
const sha = await resolveGiteaCommitSha("acme", "skills", "main", giteaApiBase("git.example.com"));
|
||||
expect(sha).toBe("abc123abc123abc123abc123abc123abc123abcd");
|
||||
const result = await resolveGiteaCommitSha("acme", "skills", sha, giteaApiBase("git.example.com"));
|
||||
expect(result).toBe(sha);
|
||||
});
|
||||
|
||||
it("refuses to call the API for a non-SHA ref", async () => {
|
||||
const fetchMock = vi.fn();
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
await expect(
|
||||
resolveGiteaCommitSha("acme", "skills", "main", giteaApiBase("git.example.com")),
|
||||
).rejects.toMatchObject({ status: 422 });
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -162,6 +162,11 @@ export async function resolveGiteaCommitSha(
|
||||
ref: string,
|
||||
apiBase: string,
|
||||
): Promise<string> {
|
||||
if (!/^[0-9a-f]{40}$/i.test(ref.trim())) {
|
||||
throw unprocessable(
|
||||
`Gitea /commits endpoint only resolves SHAs; got "${ref}". Use fetchGiteaBranch for branch names.`,
|
||||
);
|
||||
}
|
||||
const response = await fetchGiteaJson<GiteaCommitResponse>(
|
||||
`${apiBase}/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`,
|
||||
);
|
||||
@@ -191,7 +196,13 @@ export async function resolveGiteaPinnedRef(parsed: GiteaSourceUrl): Promise<{
|
||||
const trackingRef = parsed.explicitRef
|
||||
? parsed.ref
|
||||
: await resolveGiteaDefaultBranch(parsed.owner, parsed.repo, apiBase);
|
||||
const pinnedRef = await resolveGiteaCommitSha(parsed.owner, parsed.repo, trackingRef, apiBase);
|
||||
// Gitea's /repos/{o}/{r}/commits/{ref} endpoint only resolves SHAs — a branch
|
||||
// name returns 404. The branches endpoint accepts both branch names and tags.
|
||||
const branch = await fetchGiteaBranch(apiBase, parsed.owner, parsed.repo, trackingRef);
|
||||
const pinnedRef = asString(branch.commit?.id);
|
||||
if (!pinnedRef) {
|
||||
throw unprocessable(`Failed to resolve Gitea ref ${trackingRef}`);
|
||||
}
|
||||
return { pinnedRef, trackingRef };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user