Skip to main content
Glama

Git Stuff Server

by skurekjakub
adoPrCommentService.ts6.02 kB
// src/tools/adoPrComment/adoPrCommentService.ts import * as GitInterfaces from "azure-devops-node-api/interfaces/GitInterfaces.js"; import { getAdoConfig } from "../../utils/configManager.js"; import { AdoPrCommentRequest, AdoPrCommentResponse, AdoPrSingleCommentItem, IndividualAdoPrCommentResult } from "./adoPrCommentSchema.js"; import fetch from 'node-fetch'; import { getAzureCliAccessToken } from "../../utils/azureCliAuth.js"; const ADO_API_VERSION = "7.1-preview.1"; // Or your desired API version async function postSingleAdoPrComment( config: any, // Consider defining a type for config pullRequestId: number, commentItem: AdoPrSingleCommentItem, ): Promise<IndividualAdoPrCommentResult> { const { comment, filePath, lineNumber, threadId } = commentItem; // threadId is now from commentItem let formattedComment = comment; if (filePath) { formattedComment = filePath ? `**File: ${filePath}` : ''; formattedComment += lineNumber ? ` (Line: ${lineNumber})**\n\n` : '**\n\n'; formattedComment += comment; } // Construct the API URL const apiUrl = threadId ? `https://dev.azure.com/${config.organization}/${config.project}/_apis/git/repositories/${config.repository}/pullRequests/${pullRequestId}/threads/${threadId}/comments?api-version=${ADO_API_VERSION}` : `https://dev.azure.com/${config.organization}/${config.project}/_apis/git/repositories/${config.repository}/pullRequests/${pullRequestId}/threads?api-version=${ADO_API_VERSION}`; const requestBody = threadId ? { // Body for replying to a comment content: formattedComment, commentType: 1, // 1 for text } : { // Body for creating a new thread with a comment comments: [ { parentCommentId: 0, content: formattedComment, commentType: 1, // 1 for text }, ], status: 1, // 1 for Active. }; if (!threadId && filePath) { (requestBody as any).threadContext = { filePath: filePath, rightFileEnd: lineNumber ? { line: lineNumber, offset: 1 } : undefined, rightFileStart: lineNumber ? { line: lineNumber, offset: 1 } : undefined, }; } console.error(`[ADO Comment] Posting to: ${apiUrl}`); console.error(`[ADO Comment] Request body: ${JSON.stringify(requestBody, null, 2)}`); try { // Get access token from Azure CLI const accessToken = await getAzureCliAccessToken(config.organization); const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}`, }, body: JSON.stringify(requestBody), }); if (!response.ok) { const errorText = await response.text(); console.error(`[ADO Comment] API Error ${response.status}: ${errorText}`); return { success: false, message: `Azure DevOps API request failed with status ${response.status}.`, error: errorText, originalCommentContent: comment, originalFilePath: filePath, originalThreadId: threadId, // Pass back original threadId }; } const responseData: any = await response.json(); console.error(`[ADO Comment] API Success: ${JSON.stringify(responseData, null, 2)}`); return { success: true, message: threadId ? "Successfully replied to comment." : "Successfully posted new comment thread.", commentId: threadId ? responseData.id : responseData.comments[0]?.id, threadId: threadId ? threadId : responseData.id, originalCommentContent: comment, originalFilePath: filePath, originalThreadId: threadId, // Pass back original threadId }; } catch (error: any) { console.error(`[ADO Comment] Error in postSingleAdoPrComment: ${error.message}`, error); return { success: false, message: "Failed to post comment due to an internal error during API call.", error: error.message, originalCommentContent: comment, originalFilePath: filePath, originalThreadId: threadId, // Pass back original threadId }; } } /** * Posts one or more comments to an Azure DevOps Pull Request. */ export async function postAdoPrComment( request: AdoPrCommentRequest ): Promise<AdoPrCommentResponse> { const { organizationId, pullRequestId, commentsToPost } = request; try { const config = await getAdoConfig(organizationId); if (!config.organization) { return { success: false, message: "Azure DevOps organization not configured.", batchResults: [] }; } if (!config.project) { return { success: false, message: "Azure DevOps project not configured.", batchResults: [] }; } if (!config.repository) { return { success: false, message: "Azure DevOps repository not configured.", batchResults: [] }; } // Always handle batch comments as commentsToPost is now mandatory and validated to be non-empty const batchResults: IndividualAdoPrCommentResult[] = []; for (const singleCommentItem of commentsToPost) { const result = await postSingleAdoPrComment(config, pullRequestId, singleCommentItem); batchResults.push(result); } const allSuccessful = batchResults.every(r => r.success); return { success: allSuccessful, message: allSuccessful ? "All comments posted successfully." : "Some comments failed to post.", batchResults: batchResults, }; } catch (error: any) { console.error(`[ADO Comment Service] Error: ${error.message}`, error); return { success: false, message: "Failed to process comment request due to an internal error.", batchResults: commentsToPost ? commentsToPost.map(item => ({ success: false, message: "Failed due to a service-level internal error.", error: error.message, originalCommentContent: item.comment, originalFilePath: item.filePath, originalThreadId: item.threadId, })) : [], }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/skurekjakub/GitStuffServer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server