All checks were successful
CI Monitor MIflow / build-image (push) Successful in 2m42s
222 lines
5.9 KiB
TypeScript
222 lines
5.9 KiB
TypeScript
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<MergeRequestNoteSchema[]>} 返回评论列表
|
|
*/
|
|
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<MergeRequestNoteSchema | undefined>} 返回创建的评论
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<MergeRequestNoteSchema | undefined>} 返回修改后的评论
|
|
*/
|
|
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<MergeRequestNoteSchema | undefined>} 返回修改或创建的评论。
|
|
*/
|
|
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<string, string>} summarizedFileMap 文件变更的总结
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async createSummarizedComment(
|
|
summarizedMr: string,
|
|
summarizedFileMap: Map<string, string>
|
|
) {
|
|
// 构建总结评论的内容
|
|
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<void>}
|
|
*/
|
|
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
|