Skip to content

Commit afe9a1a

Browse files
committed
Add pagination to merge request discussions, similar to issue discussions
1 parent 547b05c commit afe9a1a

File tree

2 files changed

+120
-104
lines changed

2 files changed

+120
-104
lines changed

index.ts

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ import {
100100
// Discussion Schemas
101101
GitLabDiscussionNoteSchema, // Added
102102
GitLabDiscussionSchema,
103+
PaginatedDiscussionsResponseSchema,
103104
UpdateMergeRequestNoteSchema, // Added
104105
CreateMergeRequestNoteSchema, // Added
105106
ListMergeRequestDiscussionsSchema,
@@ -142,8 +143,10 @@ import {
142143
type PromoteProjectMilestoneOptions,
143144
type GetMilestoneBurndownEventsOptions,
144145
// Discussion Types
145-
type GitLabDiscussionNote, // Added
146+
type GitLabDiscussionNote,
146147
type GitLabDiscussion,
148+
type PaginatedDiscussionsResponse,
149+
type PaginationOptions,
147150
type MergeRequestThreadPosition,
148151
type GetWikiPageOptions,
149152
type CreateWikiPageOptions,
@@ -1209,80 +1212,90 @@ async function createMergeRequest(
12091212
}
12101213

12111214
/**
1212-
* List merge request discussion items
1213-
* 병합 요청 토론 목록 조회
1215+
* Shared helper function for listing discussions
1216+
* 토론 목록 조회를 위한 공유 헬퍼 함수
12141217
*
12151218
* @param {string} projectId - The ID or URL-encoded path of the project
1216-
* @param {number} mergeRequestIid - The IID of a merge request
1217-
* @returns {Promise<GitLabDiscussion[]>} List of discussions
1219+
* @param {"issues" | "merge_requests"} resourceType - The type of resource (issues or merge_requests)
1220+
* @param {number} resourceIid - The IID of the issue or merge request
1221+
* @param {PaginationOptions} options - Pagination and sorting options
1222+
* @returns {Promise<PaginatedDiscussionsResponse>} Paginated list of discussions
12181223
*/
1219-
async function listMergeRequestDiscussions(
1224+
async function listDiscussions(
12201225
projectId: string,
1221-
mergeRequestIid: number
1222-
): Promise<GitLabDiscussion[]> {
1226+
resourceType: "issues" | "merge_requests",
1227+
resourceIid: number,
1228+
options: PaginationOptions = {}
1229+
): Promise<PaginatedDiscussionsResponse> {
12231230
projectId = decodeURIComponent(projectId); // Decode project ID
12241231
const url = new URL(
12251232
`${GITLAB_API_URL}/projects/${encodeURIComponent(
12261233
projectId
1227-
)}/merge_requests/${mergeRequestIid}/discussions`
1234+
)}/${resourceType}/${resourceIid}/discussions`
12281235
);
12291236

1237+
// Add query parameters for pagination and sorting
1238+
if (options.page) {
1239+
url.searchParams.append("page", options.page.toString());
1240+
}
1241+
if (options.per_page) {
1242+
url.searchParams.append("per_page", options.per_page.toString());
1243+
}
1244+
12301245
const response = await fetch(url.toString(), {
12311246
...DEFAULT_FETCH_CONFIG,
12321247
});
12331248

12341249
await handleGitLabError(response);
1235-
const data = await response.json();
1236-
// Ensure the response is parsed as an array of discussions
1237-
return z.array(GitLabDiscussionSchema).parse(data);
1250+
const discussions = await response.json();
1251+
1252+
// Extract pagination headers
1253+
const pagination = {
1254+
x_next_page: response.headers.get("x-next-page") ? parseInt(response.headers.get("x-next-page")!) : null,
1255+
x_page: response.headers.get("x-page") ? parseInt(response.headers.get("x-page")!) : undefined,
1256+
x_per_page: response.headers.get("x-per-page") ? parseInt(response.headers.get("x-per-page")!) : undefined,
1257+
x_prev_page: response.headers.get("x-prev-page") ? parseInt(response.headers.get("x-prev-page")!) : null,
1258+
x_total: response.headers.get("x-total") ? parseInt(response.headers.get("x-total")!) : null,
1259+
x_total_pages: response.headers.get("x-total-pages") ? parseInt(response.headers.get("x-total-pages")!) : null,
1260+
};
1261+
1262+
return PaginatedDiscussionsResponseSchema.parse({
1263+
items: discussions,
1264+
pagination: pagination,
1265+
});
1266+
}
1267+
1268+
/**
1269+
* List merge request discussion items
1270+
* 병합 요청 토론 목록 조회
1271+
*
1272+
* @param {string} projectId - The ID or URL-encoded path of the project
1273+
* @param {number} mergeRequestIid - The IID of a merge request
1274+
* @param {DiscussionPaginationOptions} options - Pagination and sorting options
1275+
* @returns {Promise<GitLabDiscussion[]>} List of discussions
1276+
*/
1277+
async function listMergeRequestDiscussions(
1278+
projectId: string,
1279+
mergeRequestIid: number,
1280+
options: PaginationOptions = {}
1281+
): Promise<PaginatedDiscussionsResponse> {
1282+
return listDiscussions(projectId, "merge_requests", mergeRequestIid, options);
12381283
}
12391284

12401285
/**
12411286
* List discussions for an issue
12421287
*
12431288
* @param {string} projectId - The ID or URL-encoded path of the project
12441289
* @param {number} issueIid - The internal ID of the project issue
1245-
* @param {Object} options - Pagination and sorting options
1290+
* @param {DiscussionPaginationOptions} options - Pagination and sorting options
12461291
* @returns {Promise<GitLabDiscussion[]>} List of issue discussions
12471292
*/
12481293
async function listIssueDiscussions(
12491294
projectId: string,
12501295
issueIid: number,
1251-
options: {
1252-
page?: number;
1253-
per_page?: number;
1254-
sort?: "asc" | "desc";
1255-
order_by?: "created_at" | "updated_at";
1256-
} = {}
1257-
): Promise<GitLabDiscussion[]> {
1258-
projectId = decodeURIComponent(projectId); // Decode project ID
1259-
const url = new URL(
1260-
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/issues/${issueIid}/discussions`
1261-
);
1262-
1263-
// Add query parameters for pagination and sorting
1264-
if (options.page) {
1265-
url.searchParams.append("page", options.page.toString());
1266-
}
1267-
if (options.per_page) {
1268-
url.searchParams.append("per_page", options.per_page.toString());
1269-
}
1270-
if (options.sort) {
1271-
url.searchParams.append("sort", options.sort);
1272-
}
1273-
if (options.order_by) {
1274-
url.searchParams.append("order_by", options.order_by);
1275-
}
1276-
1277-
const response = await fetch(url.toString(), {
1278-
...DEFAULT_FETCH_CONFIG,
1279-
});
1280-
1281-
await handleGitLabError(response);
1282-
const data = await response.json();
1283-
1284-
// Parse the response as an array of discussions
1285-
return z.array(GitLabDiscussionSchema).parse(data);
1296+
options: PaginationOptions = {}
1297+
): Promise<PaginatedDiscussionsResponse> {
1298+
return listDiscussions(projectId, "issues", issueIid, options);
12861299
}
12871300

12881301
/**
@@ -3284,9 +3297,11 @@ server.setRequestHandler(CallToolRequestSchema, async request => {
32843297

32853298
case "mr_discussions": {
32863299
const args = ListMergeRequestDiscussionsSchema.parse(request.params.arguments);
3300+
const { project_id, merge_request_iid, ...options } = args;
32873301
const discussions = await listMergeRequestDiscussions(
3288-
args.project_id,
3289-
args.merge_request_iid
3302+
project_id,
3303+
merge_request_iid,
3304+
options
32903305
);
32913306
return {
32923307
content: [{ type: "text", text: JSON.stringify(discussions, null, 2) }],

0 commit comments

Comments
 (0)