operations/codeup/changeRequests.ts (187 lines of code) (raw):

import { z } from "zod"; import { yunxiaoRequest, buildUrl, handleRepositoryIdEncoding, floatToIntString } from "../../common/utils.js"; import { ChangeRequestSchema, PatchSetSchema, GetChangeRequestSchema, GetChangeRequestOptions, ListChangeRequestsSchema, ListChangeRequestsOptions, ListChangeRequestPatchSetsSchema, ListChangeRequestPatchSetsOptions, CreateChangeRequestSchema, CreateChangeRequestOptions } from "../../common/types.js"; // 通过API获取仓库的数字ID async function getRepositoryNumericId(organizationId: string, repositoryId: string): Promise<string> { const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${repositoryId}`; const response = await yunxiaoRequest(url, { method: "GET", }); if (!response || typeof response !== 'object' || !('id' in response)) { throw new Error("Failed to get repository ID"); } const repoId = response.id; if (!repoId) { throw new Error("Could not get repository ID"); } return repoId.toString(); } /** * 查询合并请求 * @param organizationId * @param repositoryId * @param localId */ export async function getChangeRequestFunc( organizationId: string, repositoryId: string, localId: string ): Promise<z.infer<typeof ChangeRequestSchema>> { const encodedRepoId = handleRepositoryIdEncoding(repositoryId); const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests/${localId}`; const response = await yunxiaoRequest(url, { method: "GET", }); return ChangeRequestSchema.parse(response); } /** * 查询合并请求列表 * @param organizationId * @param page * @param perPage * @param projectIds * @param authorIds * @param reviewerIds * @param state * @param search * @param orderBy * @param sort * @param createdBefore * @param createdAfter */ export async function listChangeRequestsFunc( organizationId: string, page?: number, perPage?: number, projectIds?: string, authorIds?: string, reviewerIds?: string, state?: string, // Possible values: opened, merged, closed search?: string, orderBy?: string, // Possible values: created_at, updated_at sort?: string, // Possible values: asc, desc createdBefore?: string, createdAfter?: string ): Promise<z.infer<typeof ChangeRequestSchema>[]> { const baseUrl = `/oapi/v1/codeup/organizations/${organizationId}/changeRequests`; // 构建查询参数 const queryParams: Record<string, string | number | undefined> = {}; if (page !== undefined) { queryParams.page = page; } if (perPage !== undefined) { queryParams.perPage = perPage; } if (projectIds !== undefined) { queryParams.projectIds = projectIds; } if (authorIds !== undefined) { queryParams.authorIds = authorIds; } if (reviewerIds !== undefined) { queryParams.reviewerIds = reviewerIds; } if (state !== undefined) { queryParams.state = state; } if (search !== undefined) { queryParams.search = search; } if (orderBy !== undefined) { queryParams.orderBy = orderBy; } if (sort !== undefined) { queryParams.sort = sort; } if (createdBefore !== undefined) { queryParams.createdBefore = createdBefore; } if (createdAfter !== undefined) { queryParams.createdAfter = createdAfter; } // 使用buildUrl函数构建包含查询参数的URL const url = buildUrl(baseUrl, queryParams); const response = await yunxiaoRequest(url, { method: "GET", }); // 确保响应是数组 if (!Array.isArray(response)) { return []; } // 解析每个变更请求对象 return response.map(changeRequest => ChangeRequestSchema.parse(changeRequest)); } /** * 查询合并请求的版本列表 * @param organizationId * @param repositoryId * @param localId */ export async function listChangeRequestPatchSetsFunc( organizationId: string, repositoryId: string, localId: string ): Promise<z.infer<typeof PatchSetSchema>[]> { const encodedRepoId = handleRepositoryIdEncoding(repositoryId); const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests/${localId}/diffs/patches`; const response = await yunxiaoRequest(url, { method: "GET", }); // 确保响应是数组 if (!Array.isArray(response)) { return []; } // 解析每个版本对象 return response.map(patchSet => PatchSetSchema.parse(patchSet)); } /** * 创建合并请求 * @param organizationId * @param repositoryId * @param title * @param sourceBranch * @param targetBranch * @param description * @param sourceProjectId * @param targetProjectId * @param reviewerUserIds * @param workItemIds * @param createFrom */ export async function createChangeRequestFunc( organizationId: string, repositoryId: string, title: string, sourceBranch: string, targetBranch: string, description?: string, sourceProjectId?: number, targetProjectId?: number, reviewerUserIds?: string[], workItemIds?: string[], createFrom: string = "WEB" // Possible values: WEB, COMMAND_LINE ): Promise<z.infer<typeof ChangeRequestSchema>> { const encodedRepoId = handleRepositoryIdEncoding(repositoryId); // 检查和获取sourceProjectId和targetProjectId let sourceIdString: string | undefined; let targetIdString: string | undefined; if (sourceProjectId !== undefined) { sourceIdString = floatToIntString(sourceProjectId); } if (targetProjectId !== undefined) { targetIdString = floatToIntString(targetProjectId); } // 如果repositoryId是纯数字,且sourceProjectId或targetProjectId未提供,直接使用repositoryId的值 if (!isNaN(Number(repositoryId))) { // 是数字ID,可以直接使用 if (sourceIdString === undefined) { sourceIdString = repositoryId; } if (targetIdString === undefined) { targetIdString = repositoryId; } } else if (repositoryId.includes("%2F") || repositoryId.includes("/")) { // 如果是组织ID与仓库名称的组合,调用API获取数字ID if (sourceIdString === undefined || targetIdString === undefined) { try { const numericId = await getRepositoryNumericId(organizationId, encodedRepoId); if (sourceIdString === undefined) { sourceIdString = numericId; } if (targetIdString === undefined) { targetIdString = numericId; } } catch (error) { throw new Error(`When using 'organizationId%2Frepo-name' format, you must first get the numeric ID of the repository and use it for sourceProjectId and targetProjectId parameters. Please use get_repository tool to get the numeric ID of '${repositoryId}' and then use that ID as the value for sourceProjectId and targetProjectId.`); } } } // 确保sourceProjectId和targetProjectId已设置 if (sourceIdString === undefined) { throw new Error("Could not get sourceProjectId, please provide this parameter manually"); } if (targetIdString === undefined) { throw new Error("Could not get targetProjectId, please provide this parameter manually"); } const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests`; // 准备payload const payload: Record<string, any> = { title: title, sourceBranch: sourceBranch, targetBranch: targetBranch, sourceProjectId: sourceIdString, targetProjectId: targetIdString, createFrom: createFrom, }; // 添加可选参数 if (description !== undefined) { payload.description = description; } if (reviewerUserIds !== undefined) { payload.reviewerUserIds = reviewerUserIds; } if (workItemIds !== undefined) { payload.workItemIds = workItemIds; } const response = await yunxiaoRequest(url, { method: "POST", body: payload, }); return ChangeRequestSchema.parse(response); }