diff --git a/packages/spike/src/gitea/test/helpers.ts b/packages/spike/src/gitea/test/helpers.ts index 44805fa..098fbb0 100644 --- a/packages/spike/src/gitea/test/helpers.ts +++ b/packages/spike/src/gitea/test/helpers.ts @@ -228,10 +228,30 @@ export async function commentOnPR(repo: string, prNumber: number, body: string, } export async function mergePR(repo: string, prNumber: number, user: User) { - return giteaFetch(`/repos/${repo}/pulls/${prNumber}/merge`, user, { - method: "POST", - body: JSON.stringify({ Do: "merge", merge_message_field: "Test merge" }), - }) + // Gitea returns 404/405 while computing mergeability after PR creation + const path = `/repos/${repo}/pulls/${prNumber}/merge` + + for (let attempt = 0; attempt < 10; attempt++) { + const response = await fetch(`${giteaUrl}/api/v1${path}`, { + method: "POST", + headers: { + Authorization: `token ${user.token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ Do: "merge" }), + }) + + if (response.ok) return + if (response.status === 404 || response.status === 405) { + await Bun.sleep(1000) + continue + } + + const body = await response.text().catch(() => "") + throw new Error(`Gitea ${response.status}: POST ${path}\n${body}`) + } + + throw new Error(`Gitea merge failed after 10 retries for ${path}`) } export async function createReview(repo: string, prNumber: number, user: User, filePath: string) { diff --git a/packages/spike/src/gitea/test/webhooks.test.ts b/packages/spike/src/gitea/test/webhooks.test.ts index 419c4ec..6d31975 100644 --- a/packages/spike/src/gitea/test/webhooks.test.ts +++ b/packages/spike/src/gitea/test/webhooks.test.ts @@ -4,7 +4,6 @@ setDefaultTimeout(30_000) import { ensure } from "@workshop/shared/utils" import { type User, - type TestPR, setupWebhooks, expectPullRequestWebhook, expectIssueCommentWebhook, @@ -15,6 +14,10 @@ import { mergePR, } from "./helpers" +function testBranch(label: string) { + return `test-${crypto.randomUUID().slice(0, 8)}-${label}` +} + function getEnv(name: string): string { const value = process.env[name] ensure(value, `Missing env var: ${name}. See .env.example`) @@ -37,20 +40,19 @@ afterAll(() => teardown()) // --- Tests for Corey's repo (Spike opens PR, Corey comments/reviews/merges) --- describe(`${coreyRepo}`, () => { - let pr: TestPR - const branch = `test-${Date.now()}-corey` - test("opening a PR sends pull_request webhook with correct author and repo", async () => { - pr = await expectPullRequestWebhook({ action: "opened", branch }, async (webhook) => { - const result = await openTestPR(coreyRepo, spike, branch) + const branch = testBranch("open") + await expectPullRequestWebhook({ action: "opened", branch }, async (webhook) => { + await openTestPR(coreyRepo, spike, branch) const payload = await webhook expect(payload.pull_request.user.login).toBe(spike.username) expect(payload.repository.full_name).toBe(coreyRepo) - return result }) }) test("commenting sends issue_comment webhook with correct user", async () => { + const branch = testBranch("comment") + const pr = await openTestPR(coreyRepo, spike, branch) await expectIssueCommentWebhook({ action: "created", username: corey.username, prNumber: pr.number }, async (webhook) => { await commentOnPR(coreyRepo, pr.number, "Looks good!", corey) const payload = await webhook @@ -59,6 +61,8 @@ describe(`${coreyRepo}`, () => { }) test("review with line comment sends pull_request_comment webhook", async () => { + const branch = testBranch("review") + const pr = await openTestPR(coreyRepo, spike, branch) await expectPullRequestCommentWebhook({ action: "reviewed", branch }, async (webhook) => { await createReview(coreyRepo, pr.number, corey, pr.filename) const payload = await webhook @@ -68,6 +72,8 @@ describe(`${coreyRepo}`, () => { }) test("merging sends pull_request closed webhook", async () => { + const branch = testBranch("merge") + const pr = await openTestPR(coreyRepo, spike, branch) await expectPullRequestWebhook({ action: "closed", branch }, async (webhook) => { await mergePR(coreyRepo, pr.number, corey) const payload = await webhook @@ -79,20 +85,19 @@ describe(`${coreyRepo}`, () => { // --- Tests for Spike's repo (Corey opens PR, Spike comments/reviews/merges) --- describe(`${spikeRepo}`, () => { - let pr: TestPR - const branch = `test-${Date.now()}-spike` - test("opening a PR sends pull_request webhook with correct author and repo", async () => { - pr = await expectPullRequestWebhook({ action: "opened", branch }, async (webhook) => { - const result = await openTestPR(spikeRepo, corey, branch) + const branch = testBranch("open") + await expectPullRequestWebhook({ action: "opened", branch }, async (webhook) => { + await openTestPR(spikeRepo, corey, branch) const payload = await webhook expect(payload.pull_request.user.login).toBe(corey.username) expect(payload.repository.full_name).toBe(spikeRepo) - return result }) }) test("commenting sends issue_comment webhook with correct user", async () => { + const branch = testBranch("comment") + const pr = await openTestPR(spikeRepo, corey, branch) await expectIssueCommentWebhook({ action: "created", username: spike.username, prNumber: pr.number }, async (webhook) => { await commentOnPR(spikeRepo, pr.number, "On it!", spike) const payload = await webhook @@ -101,6 +106,8 @@ describe(`${spikeRepo}`, () => { }) test("review with line comment sends pull_request_comment webhook", async () => { + const branch = testBranch("review") + const pr = await openTestPR(spikeRepo, corey, branch) await expectPullRequestCommentWebhook({ action: "reviewed", branch }, async (webhook) => { await createReview(spikeRepo, pr.number, spike, pr.filename) const payload = await webhook @@ -110,6 +117,8 @@ describe(`${spikeRepo}`, () => { }) test("merging sends pull_request closed webhook", async () => { + const branch = testBranch("merge") + const pr = await openTestPR(spikeRepo, corey, branch) await expectPullRequestWebhook({ action: "closed", branch }, async (webhook) => { await mergePR(spikeRepo, pr.number, spike) const payload = await webhook