feat: add branch comparison functionality and update related schemas

This commit is contained in:
Martim Pimentel
2025-05-22 12:02:03 +01:00
parent 005b46a1a6
commit c834ebc135
2 changed files with 105 additions and 15 deletions

View File

@ -53,7 +53,7 @@ import {
CreateMergeRequestSchema,
ForkRepositorySchema,
CreateBranchSchema,
GitLabMergeRequestDiffSchema,
GitLabDiffSchema,
GetMergeRequestSchema,
GetMergeRequestDiffsSchema,
UpdateMergeRequestSchema,
@ -126,6 +126,9 @@ import {
GetRepositoryTreeSchema,
type GitLabTreeItem,
type GetRepositoryTreeOptions,
GitLabCompareResult,
GitLabCompareResultSchema,
GetBranchDiffsSchema,
} from "./schemas.js";
/**
@ -261,6 +264,12 @@ const allTools = [
"Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)",
inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
},
{
name: "get_branch_diffs",
description:
"Get the changes/diffs between two branches or commits in a GitLab project",
inputSchema: zodToJsonSchema(GetBranchDiffsSchema),
},
{
name: "update_merge_request",
description:
@ -436,6 +445,7 @@ const readOnlyTools = [
"get_file_contents",
"get_merge_request",
"get_merge_request_diffs",
"get_branch_diffs",
"mr_discussions",
"list_issues",
"get_issue",
@ -1552,7 +1562,50 @@ async function getMergeRequestDiffs(
await handleGitLabError(response);
const data = (await response.json()) as { changes: unknown };
return z.array(GitLabMergeRequestDiffSchema).parse(data.changes);
return z.array(GitLabDiffSchema).parse(data.changes);
}
/**
* Get branch comparison diffs
*
* @param {string} projectId - The ID or URL-encoded path of the project
* @param {string} from - The branch name or commit SHA to compare from
* @param {string} to - The branch name or commit SHA to compare to
* @param {boolean} [straight] - Comparison method: false for '...' (default), true for '--'
* @returns {Promise<GitLabCompareResult>} Branch comparison results
*/
async function getBranchDiffs(
projectId: string,
from: string,
to: string,
straight?: boolean
): Promise<GitLabCompareResult> {
projectId = decodeURIComponent(projectId); // Decode project ID
const url = new URL(
`${GITLAB_API_URL}/projects/${encodeURIComponent(projectId)}/repository/compare`
);
url.searchParams.append("from", from);
url.searchParams.append("to", to);
if (straight !== undefined) {
url.searchParams.append("straight", straight.toString());
}
const response = await fetch(url.toString(), {
...DEFAULT_FETCH_CONFIG,
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(
`GitLab API error: ${response.status} ${response.statusText}\n${errorBody}`
);
}
const data = await response.json();
return GitLabCompareResultSchema.parse(data);
}
/**
@ -2414,6 +2467,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
};
}
case "get_branch_diffs": {
const args = GetBranchDiffsSchema.parse(request.params.arguments);
const diffs = await getBranchDiffs(
args.project_id,
args.from,
args.to,
args.straight
);
return {
content: [{ type: "text", text: JSON.stringify(diffs, null, 2) }],
};
}
case "search_repositories": {
const args = SearchRepositoriesSchema.parse(request.params.arguments);
const results = await searchProjects(

View File

@ -271,9 +271,15 @@ export const CreateMergeRequestOptionsSchema = z.object({
draft: z.boolean().optional(),
});
export const CreateBranchOptionsSchema = z.object({
name: z.string(), // Changed from ref to match GitLab API
ref: z.string(), // The source branch/commit for the new branch
export const GitLabDiffSchema = z.object({
old_path: z.string(),
new_path: z.string(),
a_mode: z.string(),
b_mode: z.string(),
diff: z.string(),
new_file: z.boolean(),
renamed_file: z.boolean(),
deleted_file: z.boolean(),
});
// Response schemas for operations
@ -291,6 +297,27 @@ export const GitLabSearchResponseSchema = z.object({
items: z.array(GitLabRepositorySchema),
});
// create branch schemas
export const CreateBranchOptionsSchema = z.object({
name: z.string(), // Changed from ref to match GitLab API
ref: z.string(), // The source branch/commit for the new branch
});
export const GitLabCompareResultSchema = z.object({
commit: z.object({
id: z.string().optional(),
short_id: z.string().optional(),
title: z.string().optional(),
author_name: z.string().optional(),
author_email: z.string().optional(),
created_at: z.string().optional(),
}).optional(),
commits: z.array(GitLabCommitSchema),
diffs: z.array(GitLabDiffSchema),
compare_timeout: z.boolean().optional(),
compare_same_ref: z.boolean().optional(),
});
// Issue related schemas
export const GitLabLabelSchema = z.object({
id: z.number(),
@ -596,20 +623,16 @@ export const ForkRepositorySchema = ProjectParamsSchema.extend({
namespace: z.string().optional().describe("Namespace to fork to (full path)"),
});
// Branch related schemas
export const CreateBranchSchema = ProjectParamsSchema.extend({
branch: z.string().describe("Name for the new branch"),
ref: z.string().optional().describe("Source branch/commit for new branch"),
});
export const GitLabMergeRequestDiffSchema = z.object({
old_path: z.string(),
new_path: z.string(),
a_mode: z.string(),
b_mode: z.string(),
diff: z.string(),
new_file: z.boolean(),
renamed_file: z.boolean(),
deleted_file: z.boolean(),
export const GetBranchDiffsSchema = ProjectParamsSchema.extend({
from: z.string().describe("The base branch or commit SHA to compare from"),
to: z.string().describe("The target branch or commit SHA to compare to"),
straight: z.boolean().optional().describe("Comparison method: false for '...' (default), true for '--'"),
});
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
@ -1082,6 +1105,7 @@ export type GitLabDirectoryContent = z.infer<
export type GitLabContent = z.infer<typeof GitLabContentSchema>;
export type FileOperation = z.infer<typeof FileOperationSchema>;
export type GitLabTree = z.infer<typeof GitLabTreeSchema>;
export type GitLabCompareResult = z.infer<typeof GitLabCompareResultSchema>;
export type GitLabCommit = z.infer<typeof GitLabCommitSchema>;
export type GitLabReference = z.infer<typeof GitLabReferenceSchema>;
export type CreateRepositoryOptions = z.infer<
@ -1097,7 +1121,7 @@ export type GitLabCreateUpdateFileResponse = z.infer<
>;
export type GitLabSearchResponse = z.infer<typeof GitLabSearchResponseSchema>;
export type GitLabMergeRequestDiff = z.infer<
typeof GitLabMergeRequestDiffSchema
typeof GitLabDiffSchema
>;
export type CreateNoteOptions = z.infer<typeof CreateNoteSchema>;
export type GitLabIssueLink = z.infer<typeof GitLabIssueLinkSchema>;