import { MergeRequestNoteSchema } from "@gitbeaker/rest" import { Logger } from "winston" import service from "../../../service" import { CreateRangeDiscussionPosition } from "../../../service/gitlab/discussions" import { shortenPath } from "../../../utils/pathTools" /** * Gitlab评论控制器 */ export class Commenter { private base_sha: string private head_sha: string private start_sha: string private project_id: number private merge_request_iid: number private loadingComment: MergeRequestNoteSchema | null = null private comments: MergeRequestNoteSchema[] = [] private logger: Logger constructor( base_sha: string, head_sha: string, start_sha: string, project_id: number, merge_request_iid: number, logger: Logger ) { this.base_sha = base_sha this.head_sha = head_sha this.start_sha = start_sha this.project_id = project_id this.merge_request_iid = merge_request_iid this.logger = logger } /** * 获取所有评论 * @returns {Promise} 返回评论列表 */ async getComments() { // 如果评论列表已经存在,直接返回 if (this.comments.length > 0) { return this.comments } const commentList: MergeRequestNoteSchema[] = [] let page = 1 const per_page = 100 while (true) { // 从 GitLab 服务获取评论 const comments = await service.gitlab.mr.getComments( this.project_id, this.merge_request_iid, page, per_page ) commentList.push(...comments) page++ // 如果获取的评论数量少于每页数量,说明已经获取完毕,退出循环 if (comments.length < per_page) { break } } this.comments = commentList return commentList } /** * 创建评论 * @param {string} body 评论内容 * @returns {Promise} 返回创建的评论 */ async createComment(body: string) { // 调用 GitLab 服务创建评论 const res = await service.gitlab.note.create2Mr( this.project_id, this.merge_request_iid, body ) if (!res) { this.logger.error("Failed to create comment") } return res } /** * 创建加载中的评论 * @returns {Promise} */ async createLoadingComment() { const body = "小煎蛋正在处理您的合并请求,请稍等片刻。" // 调用 GitLab 服务创建加载中的评论 const res = await service.gitlab.note.create2Mr( this.project_id, this.merge_request_iid, body ) if (!res) { this.logger.error("Failed to create loading comment") } this.loadingComment = res } /** * 修改加载中的评论 * @param {string} body 新的评论内容 * @returns {Promise} 返回修改后的评论 */ async modifyLoadingComment(body: string) { if (!this.loadingComment) { this.logger.error("No loading comment to modify") return } // 调用 GitLab 服务修改加载中的评论 const res = await service.gitlab.note.modify2Mr( this.project_id, this.merge_request_iid, this.loadingComment.id, body ) if (!res) { this.logger.error("Failed to modify loading comment") } return res } /** * 修改加载中的评论,如果失败则创建新的评论。 * @param {string} body - 评论内容。 * @returns {Promise} 返回修改或创建的评论。 */ async modifyLoadingOrCreateComment(body: string) { if (this.loadingComment) { const res = await this.modifyLoadingComment(body) if (res) return res } return this.createComment(body) } /** * 创建总结评论 * @param {string} summarizedMr 合并请求的总结 * @param {Map} summarizedFileMap 文件变更的总结 * @returns {Promise} */ async createSummarizedComment( summarizedMr: string, summarizedFileMap: Map ) { // 构建总结评论的内容 const summarizedComment = ` # 整体摘要: ${summarizedMr} # 文件变更: | 文件路径 | 变更摘要 | | --- | --- | ${[...summarizedFileMap] .map(([path, summary]) => `| \`${shortenPath(path)}\` | ${summary} |`) .join("\n")} ` this.logger.debug(`Summarized comment: ${summarizedComment}`) // 尝试修改加载中的评论,如果失败则创建新的评论 const res = await this.modifyLoadingOrCreateComment(summarizedComment) if (!res) { this.logger.error("Failed to create summarized comment") } } /** * 创建审查评论 * @param {string} new_path 新文件路径 * @param {string} old_path 旧文件路径 * @param {number} start_line 开始行 * @param {number} end_line 结束行 * @param {string} content 评论内容 * @returns {Promise} */ async createReviewComment( new_path: string, old_path: string, start_line: number, end_line: number, content: string ) { // 计算文件路径的 SHA1 哈希值 const hasher = new Bun.CryptoHasher("sha1") hasher.update(new_path) const fileSha = hasher.digest("hex") // 构建评论的位置对象 const position: CreateRangeDiscussionPosition = { base_sha: this.base_sha, start_sha: this.start_sha, head_sha: this.head_sha, new_path, old_path, position_type: "text", new_line: end_line, line_range: { start: { line_code: `${fileSha}_0_${end_line}`, }, end: { line_code: `${fileSha}_0_${end_line}`, }, }, } // 调用 GitLab 服务创建审查评论 const res = await service.gitlab.discussions.create2Mr( this.project_id, this.merge_request_iid, content, position ) if (!res) { this.logger.error("Failed to create review comment") } } } export default Commenter