Skip to content

Commit dc6cc59

Browse files
author
Sven Groot
committed
feat: add support for creating and updating issue notes
- Added create_issue_note to add a new note to an existing issue thread - Added update_issue_note to modify an existing issue thread note - Similar to existing merge request note functions but for issues
1 parent 5924fd3 commit dc6cc59

File tree

3 files changed

+165
-26
lines changed

3 files changed

+165
-26
lines changed

README.md

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -93,30 +93,32 @@ When using with the Claude App, you need to set up your API key and URLs directl
9393
15. `mr_discussions` - List discussion items for a merge request
9494
16. `update_merge_request_note` - Modify an existing merge request thread note
9595
17. `create_merge_request_note` - Add a new note to an existing merge request thread
96-
18. `list_issues` - List issues in a GitLab project with filtering options
97-
19. `get_issue` - Get details of a specific issue in a GitLab project
98-
20. `update_issue` - Update an issue in a GitLab project
99-
21. `delete_issue` - Delete an issue from a GitLab project
100-
22. `list_issue_links` - List all issue links for a specific issue
101-
23. `list_issue_discussions` - List discussions for an issue in a GitLab project
102-
24. `get_issue_link` - Get a specific issue link
103-
25. `create_issue_link` - Create an issue link between two issues
104-
26. `delete_issue_link` - Delete an issue link
105-
27. `list_namespaces` - List all namespaces available to the current user
106-
28. `get_namespace` - Get details of a namespace by ID or path
107-
29. `verify_namespace` - Verify if a namespace path exists
108-
30. `get_project` - Get details of a specific project
109-
31. `list_projects` - List projects accessible by the current user
110-
32. `list_labels` - List labels for a project
111-
33. `get_label` - Get a single label from a project
112-
34. `create_label` - Create a new label in a project
113-
35. `update_label` - Update an existing label in a project
114-
36. `delete_label` - Delete a label from a project
115-
37. `list_group_projects` - List projects in a GitLab group with filtering options
116-
38. `list_wiki_pages` - List wiki pages in a GitLab project
117-
39. `get_wiki_page` - Get details of a specific wiki page
118-
40. `create_wiki_page` - Create a new wiki page in a GitLab project
119-
41. `update_wiki_page` - Update an existing wiki page in a GitLab project
120-
42. `delete_wiki_page` - Delete a wiki page from a GitLab project
121-
43. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
96+
18. `update_issue_note` - Update the content of an existing issue note
97+
19. `create_issue_note` - Add a new note to an existing issue thread
98+
20. `list_issues` - List issues in a GitLab project with filtering options
99+
21. `get_issue` - Get details of a specific issue in a GitLab project
100+
22. `update_issue` - Update an issue in a GitLab project
101+
23. `delete_issue` - Delete an issue from a GitLab project
102+
24. `list_issue_links` - List all issue links for a specific issue
103+
25. `list_issue_discussions` - List discussions for an issue in a GitLab project
104+
26. `get_issue_link` - Get a specific issue link
105+
27. `create_issue_link` - Create an issue link between two issues
106+
28. `delete_issue_link` - Delete an issue link
107+
29. `list_namespaces` - List all namespaces available to the current user
108+
30. `get_namespace` - Get details of a namespace by ID or path
109+
31. `verify_namespace` - Verify if a namespace path exists
110+
32. `get_project` - Get details of a specific project
111+
33. `list_projects` - List projects accessible by the current user
112+
34. `list_labels` - List labels for a project
113+
35. `get_label` - Get a single label from a project
114+
36. `create_label` - Create a new label in a project
115+
37. `update_label` - Update an existing label in a project
116+
38. `delete_label` - Delete a label from a project
117+
39. `list_group_projects` - List projects in a GitLab group with filtering options
118+
40. `list_wiki_pages` - List wiki pages in a GitLab project
119+
41. `get_wiki_page` - Get details of a specific wiki page
120+
42. `create_wiki_page` - Create a new wiki page in a GitLab project
121+
43. `update_wiki_page` - Update an existing wiki page in a GitLab project
122+
44. `delete_wiki_page` - Delete a wiki page from a GitLab project
123+
45. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
122124
<!-- TOOLS-END -->

index.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ import {
121121
GetRepositoryTreeSchema,
122122
type GitLabTreeItem,
123123
type GetRepositoryTreeOptions,
124+
UpdateIssueNoteSchema,
125+
CreateIssueNoteSchema,
124126
} from "./schemas.js";
125127

126128
/**
@@ -287,6 +289,16 @@ const allTools = [
287289
description: "Add a new note to an existing merge request thread",
288290
inputSchema: zodToJsonSchema(CreateMergeRequestNoteSchema),
289291
},
292+
{
293+
name: "update_issue_note",
294+
description: "Modify an existing issue thread note",
295+
inputSchema: zodToJsonSchema(UpdateIssueNoteSchema),
296+
},
297+
{
298+
name: "create_issue_note",
299+
description: "Add a new note to an existing issue thread",
300+
inputSchema: zodToJsonSchema(CreateIssueNoteSchema),
301+
},
290302
{
291303
name: "list_issues",
292304
description: "List issues in a GitLab project with filtering options",
@@ -1126,6 +1138,81 @@ async function updateMergeRequestNote(
11261138
return GitLabDiscussionNoteSchema.parse(data);
11271139
}
11281140

1141+
/**
1142+
* Update an issue discussion note
1143+
* @param {string} projectId - The ID or URL-encoded path of the project
1144+
* @param {number} issueIid - The IID of an issue
1145+
* @param {string} discussionId - The ID of a thread
1146+
* @param {number} noteId - The ID of a thread note
1147+
* @param {string} body - The new content of the note
1148+
* @returns {Promise<GitLabDiscussionNote>} The updated note
1149+
*/
1150+
async function updateIssueNote(
1151+
projectId: string,
1152+
issueIid: number,
1153+
discussionId: string,
1154+
noteId: number,
1155+
body: string
1156+
): Promise<GitLabDiscussionNote> {
1157+
projectId = decodeURIComponent(projectId); // Decode project ID
1158+
const url = new URL(
1159+
`${GITLAB_API_URL}/projects/${encodeURIComponent(
1160+
projectId
1161+
)}/issues/${issueIid}/discussions/${discussionId}/notes/${noteId}`
1162+
);
1163+
1164+
const payload = { body };
1165+
1166+
const response = await fetch(url.toString(), {
1167+
...DEFAULT_FETCH_CONFIG,
1168+
method: "PUT",
1169+
body: JSON.stringify(payload),
1170+
});
1171+
1172+
await handleGitLabError(response);
1173+
const data = await response.json();
1174+
return GitLabDiscussionNoteSchema.parse(data);
1175+
}
1176+
1177+
/**
1178+
* Create a note in an issue discussion
1179+
* @param {string} projectId - The ID or URL-encoded path of the project
1180+
* @param {number} issueIid - The IID of an issue
1181+
* @param {string} discussionId - The ID of a thread
1182+
* @param {string} body - The content of the new note
1183+
* @param {string} [createdAt] - The creation date of the note (ISO 8601 format)
1184+
* @returns {Promise<GitLabDiscussionNote>} The created note
1185+
*/
1186+
async function createIssueNote(
1187+
projectId: string,
1188+
issueIid: number,
1189+
discussionId: string,
1190+
body: string,
1191+
createdAt?: string
1192+
): Promise<GitLabDiscussionNote> {
1193+
projectId = decodeURIComponent(projectId); // Decode project ID
1194+
const url = new URL(
1195+
`${GITLAB_API_URL}/projects/${encodeURIComponent(
1196+
projectId
1197+
)}/issues/${issueIid}/discussions/${discussionId}/notes`
1198+
);
1199+
1200+
const payload: { body: string; created_at?: string } = { body };
1201+
if (createdAt) {
1202+
payload.created_at = createdAt;
1203+
}
1204+
1205+
const response = await fetch(url.toString(), {
1206+
...DEFAULT_FETCH_CONFIG,
1207+
method: "POST",
1208+
body: JSON.stringify(payload),
1209+
});
1210+
1211+
await handleGitLabError(response);
1212+
const data = await response.json();
1213+
return GitLabDiscussionNoteSchema.parse(data);
1214+
}
1215+
11291216
/**
11301217
* Add a new note to an existing merge request thread
11311218
* 기존 병합 요청 스레드에 새 노트 추가
@@ -2461,6 +2548,38 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
24612548
};
24622549
}
24632550

2551+
case "update_issue_note": {
2552+
const args = UpdateIssueNoteSchema.parse(
2553+
request.params.arguments
2554+
);
2555+
const note = await updateIssueNote(
2556+
args.project_id,
2557+
args.issue_iid,
2558+
args.discussion_id,
2559+
args.note_id,
2560+
args.body
2561+
);
2562+
return {
2563+
content: [{ type: "text", text: JSON.stringify(note, null, 2) }],
2564+
};
2565+
}
2566+
2567+
case "create_issue_note": {
2568+
const args = CreateIssueNoteSchema.parse(
2569+
request.params.arguments
2570+
);
2571+
const note = await createIssueNote(
2572+
args.project_id,
2573+
args.issue_iid,
2574+
args.discussion_id,
2575+
args.body,
2576+
args.created_at
2577+
);
2578+
return {
2579+
content: [{ type: "text", text: JSON.stringify(note, null, 2) }],
2580+
};
2581+
}
2582+
24642583
case "get_merge_request": {
24652584
const args = GetMergeRequestSchema.parse(request.params.arguments);
24662585
const mergeRequest = await getMergeRequest(

schemas.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,22 @@ export const CreateMergeRequestNoteSchema = ProjectParamsSchema.extend({
491491
created_at: z.string().optional().describe("Date the note was created at (ISO 8601 format)"),
492492
});
493493

494+
// Input schema for updating an issue discussion note
495+
export const UpdateIssueNoteSchema = ProjectParamsSchema.extend({
496+
issue_iid: z.number().describe("The IID of an issue"),
497+
discussion_id: z.string().describe("The ID of a thread"),
498+
note_id: z.number().describe("The ID of a thread note"),
499+
body: z.string().describe("The content of the note or reply"),
500+
});
501+
502+
// Input schema for adding a note to an existing issue discussion
503+
export const CreateIssueNoteSchema = ProjectParamsSchema.extend({
504+
issue_iid: z.number().describe("The IID of an issue"),
505+
discussion_id: z.string().describe("The ID of a thread"),
506+
body: z.string().describe("The content of the note or reply"),
507+
created_at: z.string().optional().describe("Date the note was created at (ISO 8601 format)"),
508+
});
509+
494510
// API Operation Parameter Schemas
495511

496512
export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
@@ -1085,6 +1101,8 @@ export type GitLabMergeRequestDiff = z.infer<
10851101
export type CreateNoteOptions = z.infer<typeof CreateNoteSchema>;
10861102
export type GitLabIssueLink = z.infer<typeof GitLabIssueLinkSchema>;
10871103
export type ListIssueDiscussionsOptions = z.infer<typeof ListIssueDiscussionsSchema>;
1104+
export type UpdateIssueNoteOptions = z.infer<typeof UpdateIssueNoteSchema>;
1105+
export type CreateIssueNoteOptions = z.infer<typeof CreateIssueNoteSchema>;
10881106
export type GitLabNamespace = z.infer<typeof GitLabNamespaceSchema>;
10891107
export type GitLabNamespaceExistsResponse = z.infer<
10901108
typeof GitLabNamespaceExistsResponseSchema

0 commit comments

Comments
 (0)