diff --git a/README.md b/README.md index f4b6aaf..6d72db2 100644 --- a/README.md +++ b/README.md @@ -55,31 +55,32 @@ When using with the Claude App, you need to set up your API key and URLs directl 11. `get_merge_request_diffs` - Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided) 12. `update_merge_request` - Update a merge request (Either mergeRequestIid or branchName must be provided) 13. `create_note` - Create a new note (comment) to an issue or merge request -14. `mr_discussions` - List discussion items for a merge request -15. `update_merge_request_note` - Modify an existing merge request thread note -16. `list_issues` - List issues in a GitLab project with filtering options -17. `get_issue` - Get details of a specific issue in a GitLab project -18. `update_issue` - Update an issue in a GitLab project -19. `delete_issue` - Delete an issue from a GitLab project -20. `list_issue_links` - List all issue links for a specific issue -21. `get_issue_link` - Get a specific issue link -22. `create_issue_link` - Create an issue link between two issues -23. `delete_issue_link` - Delete an issue link -24. `list_namespaces` - List all namespaces available to the current user -25. `get_namespace` - Get details of a namespace by ID or path -26. `verify_namespace` - Verify if a namespace path exists -27. `get_project` - Get details of a specific project -28. `list_projects` - List projects accessible by the current user -29. `list_labels` - List labels for a project -30. `get_label` - Get a single label from a project -31. `create_label` - Create a new label in a project -32. `update_label` - Update an existing label in a project -33. `delete_label` - Delete a label from a project -34. `list_group_projects` - List projects in a GitLab group with filtering options -35. `list_wiki_pages` - List wiki pages in a GitLab project -36. `get_wiki_page` - Get details of a specific wiki page -37. `create_wiki_page` - Create a new wiki page in a GitLab project -38. `update_wiki_page` - Update an existing wiki page in a GitLab project -39. `delete_wiki_page` - Delete a wiki page from a GitLab project -40. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories) +14. `create_merge_request_thread` - Create a new thread on a merge request +15. `mr_discussions` - List discussion items for a merge request +16. `update_merge_request_note` - Modify an existing merge request thread note +17. `list_issues` - List issues in a GitLab project with filtering options +18. `get_issue` - Get details of a specific issue in a GitLab project +19. `update_issue` - Update an issue in a GitLab project +20. `delete_issue` - Delete an issue from a GitLab project +21. `list_issue_links` - List all issue links for a specific issue +22. `get_issue_link` - Get a specific issue link +23. `create_issue_link` - Create an issue link between two issues +24. `delete_issue_link` - Delete an issue link +25. `list_namespaces` - List all namespaces available to the current user +26. `get_namespace` - Get details of a namespace by ID or path +27. `verify_namespace` - Verify if a namespace path exists +28. `get_project` - Get details of a specific project +29. `list_projects` - List projects accessible by the current user +30. `list_labels` - List labels for a project +31. `get_label` - Get a single label from a project +32. `create_label` - Create a new label in a project +33. `update_label` - Update an existing label in a project +34. `delete_label` - Delete a label from a project +35. `list_group_projects` - List projects in a GitLab group with filtering options +36. `list_wiki_pages` - List wiki pages in a GitLab project +37. `get_wiki_page` - Get details of a specific wiki page +38. `create_wiki_page` - Create a new wiki page in a GitLab project +39. `update_wiki_page` - Update an existing wiki page in a GitLab project +40. `delete_wiki_page` - Delete a wiki page from a GitLab project +41. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories) diff --git a/index.ts b/index.ts index f95d862..c21aab6 100644 --- a/index.ts +++ b/index.ts @@ -75,6 +75,7 @@ import { UpdateLabelSchema, DeleteLabelSchema, CreateNoteSchema, + CreateMergeRequestThreadSchema, ListGroupProjectsSchema, ListWikiPagesSchema, GetWikiPageSchema, @@ -108,6 +109,7 @@ import { // Discussion Types type GitLabDiscussionNote, // Added type GitLabDiscussion, + type MergeRequestThreadPosition, type GetWikiPageOptions, type CreateWikiPageOptions, type UpdateWikiPageOptions, @@ -263,6 +265,11 @@ const allTools = [ description: "Create a new note (comment) to an issue or merge request", inputSchema: zodToJsonSchema(CreateNoteSchema), }, + { + name: "create_merge_request_thread", + description: "Create a new thread on a merge request", + inputSchema: zodToJsonSchema(CreateMergeRequestThreadSchema), + }, { name: "mr_discussions", description: "List discussion items for a merge request", @@ -1520,6 +1527,59 @@ async function createNote( return await response.json(); } +/** + * Create a new thread on a merge request + * ๐Ÿ“ฆ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜: createMergeRequestThread - ๋ณ‘ํ•ฉ ์š”์ฒญ์— ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ(ํ† ๋ก )๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜ + * (New function: createMergeRequestThread - Function to create a new thread (discussion) on a merge request) + * + * This function provides more capabilities than createNote, including the ability to: + * - Create diff notes (comments on specific lines of code) + * - Specify exact positions for comments + * - Set creation timestamps + * + * @param {string} projectId - The ID or URL-encoded path of the project + * @param {number} mergeRequestIid - The internal ID of the merge request + * @param {string} body - The content of the thread + * @param {MergeRequestThreadPosition} [position] - Position information for diff notes + * @param {string} [createdAt] - ISO 8601 formatted creation date + * @returns {Promise} The created discussion thread + */ +async function createMergeRequestThread( + projectId: string, + mergeRequestIid: number, + body: string, + position?: MergeRequestThreadPosition, + createdAt?: string +): Promise { + projectId = decodeURIComponent(projectId); // Decode project ID + const url = new URL( + `${GITLAB_API_URL}/projects/${encodeURIComponent( + projectId + )}/merge_requests/${mergeRequestIid}/discussions` + ); + + const payload: Record = { body }; + + // Add optional parameters if provided + if (position) { + payload.position = position; + } + + if (createdAt) { + payload.created_at = createdAt; + } + + const response = await fetch(url.toString(), { + ...DEFAULT_FETCH_CONFIG, + method: "POST", + body: JSON.stringify(payload), + }); + + await handleGitLabError(response); + const data = await response.json(); + return GitLabDiscussionSchema.parse(data); +} + /** * List all namespaces * ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ชฉ๋ก ์กฐํšŒ @@ -2454,6 +2514,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }; } + case "create_merge_request_thread": { + const args = CreateMergeRequestThreadSchema.parse(request.params.arguments); + const { project_id, merge_request_iid, body, position, created_at } = args; + + const thread = await createMergeRequestThread( + project_id, + merge_request_iid, + body, + position, + created_at + ); + return { + content: [{ type: "text", text: JSON.stringify(thread, null, 2) }], + }; + } + case "list_issues": { const args = ListIssuesSchema.parse(request.params.arguments); const { project_id, ...options } = args; diff --git a/schemas.ts b/schemas.ts index b2dd58a..2e27c00 100644 --- a/schemas.ts +++ b/schemas.ts @@ -1004,6 +1004,30 @@ export const GitLabWikiPageSchema = z.object({ updated_at: z.string().optional(), }); +// Merge Request Thread position schema - used for diff notes +export const MergeRequestThreadPositionSchema = z.object({ + base_sha: z.string().describe("Base commit SHA in the source branch"), + head_sha: z.string().describe("SHA referencing HEAD of the source branch"), + start_sha: z.string().describe("SHA referencing the start commit of the source branch"), + position_type: z.enum(["text", "image", "file"]).describe("Type of position reference"), + new_path: z.string().optional().describe("File path after change"), + old_path: z.string().optional().describe("File path before change"), + new_line: z.number().nullable().optional().describe("Line number after change"), + old_line: z.number().nullable().optional().describe("Line number before change"), + width: z.number().optional().describe("Width of the image (for image diffs)"), + height: z.number().optional().describe("Height of the image (for image diffs)"), + x: z.number().optional().describe("X coordinate on the image (for image diffs)"), + y: z.number().optional().describe("Y coordinate on the image (for image diffs)"), +}); + +// Schema for creating a new merge request thread +export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({ + merge_request_iid: z.number().describe("The IID of a merge request"), + body: z.string().describe("The content of the thread"), + position: MergeRequestThreadPositionSchema.optional().describe("Position when creating a diff note"), + created_at: z.string().optional().describe("Date the thread was created at (ISO 8601 format)"), +}); + // Export types export type GitLabAuthor = z.infer; export type GitLabFork = z.infer; @@ -1053,3 +1077,5 @@ export type DeleteWikiPageOptions = z.infer; export type GitLabWikiPage = z.infer; export type GitLabTreeItem = z.infer; export type GetRepositoryTreeOptions = z.infer; +export type MergeRequestThreadPosition = z.infer; +export type CreateMergeRequestThreadOptions = z.infer;