Skip to content
Merged
72 changes: 70 additions & 2 deletions apps/server/src/pullRequest/GiteaPullRequestApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2015,8 +2015,8 @@ layer("GiteaPullRequestApi", (it) => {
expect(mockedRequest.mock.calls.map((call) => call[0].path)).toEqual([
"/settings/api",
"/repos/acme/web/issues/7/reactions?page=1&limit=50",
"/repos/acme/web/issues/comments/12/reactions?page=1&limit=50",
"/repos/acme/web/issues/comments/34/reactions?page=1&limit=50",
"/repos/acme/web/issues/comments/12/reactions",
"/repos/acme/web/issues/comments/34/reactions",
]);
}),
);
Expand Down Expand Up @@ -2074,6 +2074,74 @@ layer("GiteaPullRequestApi", (it) => {
}),
);

it.effect.each([50, 200, 201])(
"retains all %i native comment reactions with one unpaginated read",
(count) =>
Effect.gen(function* () {
mockedRequest.mockImplementation((input) => {
if (input.path === "/settings/api") return Effect.succeed(response({ features: [] }));
if (input.path.startsWith("/repos/acme/web/issues/7/reactions?"))
return Effect.succeed(response([]));
if (input.path === "/repos/acme/web/issues/comments/12/reactions")
return Effect.succeed(
response(
Array.from({ length: count }, (_, index) => ({
content: "+1",
user: { login: `reader-${index}` },
})),
),
);
return Effect.die(`unexpected request: ${input.path}`);
});
const api = yield* GiteaPullRequestApi.make;
const reactions = yield* api.listConversationReactions({
host: "forge.example.test",
repository: "acme/web",
number: 7,
viewer: "reader-0",
subjectIds: ["issue:12"],
});

expect(reactions.bySubjectId.get("issue:12")).toEqual([
expect.objectContaining({ content: "thumbs-up", count, viewerHasReacted: true }),
]);
expect(mockedRequest).toHaveBeenCalledTimes(3);
}),
);

it.effect.each([false, true])(
"bounds paginated issue reactions with pagination evidence: %s",
(hasEvidence) =>
Effect.gen(function* () {
mockedRequest.mockImplementation((input) => {
if (input.path === "/settings/api") return Effect.succeed(response({ features: [] }));
const page = Number(
new URL(input.path, "https://forge.example.test").searchParams.get("page"),
);
return Effect.succeed(
response(
Array.from({ length: 50 }, (_, index) => ({
content: "+1",
user: { login: `reader-${page}-${index}` },
})),
hasEvidence ? { "x-total-count": "201" } : {},
),
);
});
const api = yield* GiteaPullRequestApi.make;
const reactions = yield* api.listConversationReactions({
host: "forge.example.test",
repository: "acme/web",
number: 7,
viewer: "reader",
subjectIds: [],
});

expect(reactions.pullRequest).toEqual([]);
expect(mockedRequest).toHaveBeenCalledTimes(hasEvidence ? 5 : 2);
}),
);

it.effect("reports Gitea's missing review-summary reaction route", () =>
Effect.gen(function* () {
mockedRequest.mockReturnValueOnce(Effect.succeed(response({ features: [] })));
Expand Down
51 changes: 25 additions & 26 deletions apps/server/src/pullRequest/GiteaPullRequestApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,8 +1051,8 @@ export const make = Effect.gen(function* () {
repository: string;
path: string;
limit: number;
requirePaginationEvidence?: boolean;
nullAsEmpty?: boolean;
requirePaginationEvidence?: boolean;
}) {
const rows: Array<unknown> = [];
let path = input.path;
Expand Down Expand Up @@ -1781,31 +1781,30 @@ export const make = Effect.gen(function* () {
}
const reactions = yield* Effect.all(
targets.map((entry) =>
readUnknownSlice({
operation: "listConversationReactions",
host: input.host,
repository: input.repository,
path:
entry.target.kind === "pull-request"
? query(`${basePath(input.repository)}/issues/${input.number}/reactions`, {
page: 1,
limit: PAGE_SIZE,
})
: entry.target.kind === "review"
? query(
`${basePath(input.repository)}/pulls/${input.number}/reviews/${entry.target.id}/reactions`,
{ page: 1, limit: PAGE_SIZE },
)
: query(
`${basePath(input.repository)}/issues/comments/${entry.target.id}/reactions`,
{
page: 1,
limit: PAGE_SIZE,
},
),
limit: PAGE_SIZE * MAX_PAGINATION_PAGES,
nullAsEmpty: true,
}).pipe(
(entry.target.kind === "comment"
? // Gitea's comment-reaction handler returns the whole list and ignores pagination.
readUnknownPage({
operation: "listConversationReactions",
host: input.host,
repository: input.repository,
path: `${basePath(input.repository)}/issues/comments/${entry.target.id}/reactions`,
nullAsEmpty: true,
}).pipe(Effect.map(({ rows }) => ({ rows, truncated: false })))
: readUnknownSlice({
operation: "listConversationReactions",
host: input.host,
repository: input.repository,
path: query(
entry.target.kind === "review"
? `${basePath(input.repository)}/pulls/${input.number}/reviews/${entry.target.id}/reactions`
: `${basePath(input.repository)}/issues/${input.number}/reactions`,
{ page: 1, limit: PAGE_SIZE },
),
limit: PAGE_SIZE * CONVERSATION_PAGES,
requirePaginationEvidence: true,
nullAsEmpty: true,
})
).pipe(
Effect.map((result) => ({
subjectId: entry.subjectId,
reactions: result.truncated
Expand Down