diff --git a/packages/@emulators/github/src/__tests__/contents-commits.test.ts b/packages/@emulators/github/src/__tests__/contents-commits.test.ts index e3fd4380..a7f4c93d 100644 --- a/packages/@emulators/github/src/__tests__/contents-commits.test.ts +++ b/packages/@emulators/github/src/__tests__/contents-commits.test.ts @@ -1678,6 +1678,30 @@ describe("GitHub commits routes", () => { expect(res.status).toBe(409); }); + it("409s on a branch ref lookup in an empty repository, like GitHub", async () => { + const res = await app.request(`${base}/repos/octocat/empty-repo/git/ref/heads/main`, { headers: authHeaders() }); + expect(res.status).toBe(409); + expect(((await res.json()) as { message: string }).message).toBe("Git Repository is empty."); + }); + + it("still 404s on a missing branch ref in a populated repository", async () => { + const res = await app.request(`${base}/repos/octocat/hello-world/git/ref/heads/no-such-branch`, { + headers: authHeaders(), + }); + expect(res.status).toBe(404); + }); + + it("serves the branch ref once an empty repository receives its first commit", async () => { + const created = await app.request(`${base}/repos/octocat/empty-repo/contents/README.md`, { + method: "PUT", + headers: jsonHeaders(), + body: JSON.stringify({ message: "first", content: Buffer.from("hi\n").toString("base64") }), + }); + expect(created.status).toBe(201); + const res = await app.request(`${base}/repos/octocat/empty-repo/git/ref/heads/main`, { headers: authHeaders() }); + expect(res.status).toBe(200); + }); + it("returns a single commit with files and stats", async () => { const created = await putFile(app, "notes.txt", "one\ntwo\n"); const createdBody = (await created.json()) as { commit: { sha: string } }; diff --git a/packages/@emulators/github/src/routes/branches.ts b/packages/@emulators/github/src/routes/branches.ts index df3b3a51..7d5ed6da 100644 --- a/packages/@emulators/github/src/routes/branches.ts +++ b/packages/@emulators/github/src/routes/branches.ts @@ -687,6 +687,11 @@ export function branchesAndGitRoutes({ app, store, webhooks, baseUrl }: RouteCon const repo = lookupRepo(gh, owner, repoName); if (!repo) throw notFoundResponse(); assertRepoContentsRead(gh, c.get("authUser"), repo); + // GitHub answers a ref lookup in a repository with no commits with 409, + // not 404, so clients can tell "empty" from "missing branch". + if (gh.commits.findBy("repo_id", repo.id).length === 0) { + throw new ApiError(409, "Git Repository is empty."); + } const fullRef = fullRefFromParam(refParam); const r = gh.refs.findBy("repo_id", repo.id).find((x) => x.ref === fullRef); if (!r) throw notFoundResponse();