fix: allow re-requesting uncounted review approvals (#38988)

This commit is contained in:
Harsh Sharma
2026-09-08 15:59:06 +00:00
committed by GitHub
parent c9193adb68
commit d93bd06d0c
9 changed files with 160 additions and 33 deletions
+18 -14
View File
@@ -1,6 +1,6 @@
import {env} from 'node:process';
import {expect} from '@playwright/test';
import type {APIRequestContext, Locator, Page} from '@playwright/test';
import type {APIRequestContext, APIResponse, Locator, Page} from '@playwright/test';
/** Generate a random alphanumeric string. */
export function randomString(length: number): string {
@@ -24,11 +24,11 @@ export function apiHeaders() {
return apiAuthHeader(env.GITEA_TEST_E2E_USER, env.GITEA_TEST_E2E_PASSWORD);
}
async function apiRetry(fn: () => Promise<{ok: () => boolean; status: () => number; text: () => Promise<string>}>, label: string) {
async function apiRetry(fn: () => Promise<APIResponse>, label: string): Promise<APIResponse> {
const maxAttempts = 5;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const response = await fn();
if (response.ok()) return;
if (response.ok()) return response;
if ([500, 502, 503].includes(response.status()) && attempt < maxAttempts - 1) {
const jitter = Math.random() * 500;
await new Promise((resolve) => setTimeout(resolve, 1000 * (attempt + 1) + jitter));
@@ -36,6 +36,7 @@ async function apiRetry(fn: () => Promise<{ok: () => boolean; status: () => numb
}
throw new Error(`${label} failed: ${response.status()} ${await response.text()}`);
}
throw new Error(`${label} failed after ${maxAttempts} attempts`);
}
export async function apiCreateRepo(requestContext: APIRequestContext, {name, autoInit = true, headers}: {name: string; autoInit?: boolean; headers?: Record<string, string>}) {
@@ -45,6 +46,13 @@ export async function apiCreateRepo(requestContext: APIRequestContext, {name, au
}), 'apiCreateRepo');
}
export async function apiAddCollaborator(requestContext: APIRequestContext, owner: string, repo: string, collaborator: string, {headers}: {headers?: Record<string, string>} = {}) {
await apiRetry(() => requestContext.put(`${baseUrl()}/api/v1/repos/${owner}/${repo}/collaborators/${collaborator}`, {
headers: headers || apiHeaders(),
data: {permission: 'write'},
}), 'apiAddCollaborator');
}
export async function apiCreateOrg(requestContext: APIRequestContext, name: string, {headers}: {headers?: Record<string, string>} = {}) {
await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/orgs`, {
headers: headers || apiHeaders(),
@@ -91,24 +99,20 @@ export async function apiCloseIssue(requestContext: APIRequestContext, owner: st
/** Create a PR via API. Returns the PR index for subsequent operations. */
export async function apiCreatePR(requestContext: APIRequestContext, owner: string, repo: string, head: string, base: string, title: string, {headers}: {headers?: Record<string, string>} = {}): Promise<number> {
let prIndex = 0;
await apiRetry(async () => {
const response = await requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls`, {
headers: headers || apiHeaders(),
data: {head, base, title},
});
if (response.ok()) prIndex = (await response.json()).number;
return response;
}, 'apiCreatePR');
return prIndex;
const response = await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls`, {
headers: headers || apiHeaders(),
data: {head, base, title},
}), 'apiCreatePR');
return (await response.json()).number;
}
/** Create a review on a PR. `event: "COMMENT"` submits immediately without a pending review. */
export async function apiCreateReview(requestContext: APIRequestContext, owner: string, repo: string, index: number, {event = 'COMMENT', body, comments = [], headers}: {event?: string; body?: string; comments?: Array<{path: string; body: string; new_position?: number; old_position?: number}>; headers?: Record<string, string>} = {}) {
await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls/${index}/reviews`, {
const response = await apiRetry(() => requestContext.post(`${baseUrl()}/api/v1/repos/${owner}/${repo}/pulls/${index}/reviews`, {
headers: headers || apiHeaders(),
data: {event, body, comments},
}), 'apiCreateReview');
return response.json();
}
export async function createProjectColumn(requestContext: APIRequestContext, owner: string, repo: string, projectID: string, title: string) {