Files
ai-code-review/services/platforms/gitea.go
2025-02-18 16:53:34 +08:00

190 lines
4.8 KiB
Go

package platforms
import (
"code-review/services/types"
"code-review/utils"
"fmt"
"log"
"strings"
)
type GiteaEvent struct {
apiBase string
token string
Event string
client *httpClient
Ref string `json:"ref"`
Before string `json:"before"`
After string `json:"after"`
CompareURL string `json:"compare_url"`
Commits []struct {
ID string `json:"id"`
Message string `json:"message"`
URL string `json:"url"`
Author Author `json:"author"`
Committer Author `json:"committer"`
Timestamp string `json:"timestamp"`
} `json:"commits"`
Repository struct {
ID int `json:"id"`
Name string `json:"name"`
FullName string `json:"full_name"`
HTMLURL string `json:"html_url"`
Private bool `json:"private"`
} `json:"repository"`
}
// NewGiteaEvent 创建 Gitea 事件
func NewGiteaEvent(apiBase, token string, event string) *GiteaEvent {
return &GiteaEvent{
apiBase: apiBase,
token: token,
Event: event,
}
}
func (e *GiteaEvent) ExtractChanges() (*types.CodeChanges, error) {
// 检查是否有提交记录
if len(e.Commits) == 0 {
log.Printf("没有提交记录,跳过代码审查")
return nil, nil
}
// 检查是否跳过代码审查
for _, commit := range e.Commits {
if strings.Contains(commit.Message, "[skip codereview]") {
log.Printf("跳过代码审查: commit=%s", commit.ID)
return nil, nil
}
}
if e.client == nil {
e.client = newHTTPClient(e.apiBase, e.token)
log.Printf("初始化 HTTP 客户端: url=%s", e.apiBase)
}
changes := &types.CodeChanges{
Repository: e.Repository.FullName,
Branch: e.Ref,
CommitID: e.After,
Files: make([]types.FileChange, 0),
}
for _, commit := range e.Commits {
// 直接获取 diff 内容
apiPath := fmt.Sprintf("/api/v1/repos/%s/git/commits/%s.diff?access_token=%s", e.Repository.FullName, commit.ID, e.token)
var diffContent string
if err := e.client.get(apiPath, &diffContent); err != nil {
log.Printf("获取提交详情失败: commit=%s, error=%v", commit.ID, err)
continue
}
// 去除首尾空白
diffContent = strings.TrimSpace(diffContent)
if diffContent == "" {
log.Printf("提交没有变更内容: commit=%s", commit.ID)
continue
}
// 解析 diff 内容
diffBlocks := strings.Split(diffContent, "diff --git ")
// 去除空块
for _, block := range diffBlocks {
if strings.TrimSpace(block) == "" {
continue
}
// 移除 'diff --git ' 前缀
block = strings.TrimPrefix(block, "diff --git ")
// 解析文件名和变更类型
lines := strings.Split(block, "\n")
if len(lines) < 2 {
continue
}
// 获取文件名
filename := ""
status := "modified"
for _, line := range lines {
if strings.HasPrefix(line, "--- a/") {
filename = strings.TrimPrefix(line, "--- a/")
break
} else if strings.HasPrefix(line, "+++ b/") {
filename = strings.TrimPrefix(line, "+++ b/")
break
}
}
// 如果没有找到文件名,跳过
if filename == "" {
continue
}
// 确定变更类型
if strings.Contains(block, "new file mode") {
status = "added"
} else if strings.Contains(block, "deleted file mode") {
status = "deleted"
} else if strings.Contains(block, "rename from") {
status = "renamed"
}
var content strings.Builder
content.WriteString(fmt.Sprintf("### 变更说明\n"))
content.WriteString(fmt.Sprintf("提交信息: %s\n\n", commit.Message))
switch status {
case "added":
content.WriteString(fmt.Sprintf("新增文件: %s\n\n", filename))
case "modified":
content.WriteString(fmt.Sprintf("修改文件: %s\n\n", filename))
case "deleted":
content.WriteString(fmt.Sprintf("删除文件: %s\n\n", filename))
case "renamed":
content.WriteString(fmt.Sprintf("重命名文件: %s\n\n", filename))
}
content.WriteString("### 变更内容\n")
content.WriteString("```diff\n")
content.WriteString(block)
content.WriteString("\n```\n")
changes.Files = append(changes.Files, types.FileChange{
Path: filename,
Content: content.String(),
Type: parseFileType(status),
})
}
}
return changes, nil
}
func (e *GiteaEvent) PostComments(result *types.ReviewResult) error {
if e.client == nil {
e.client = newHTTPClient(e.apiBase, e.token)
}
// 创建 issue
path := fmt.Sprintf("/api/v1/repos/%s/issues", e.Repository.FullName)
issueData := map[string]interface{}{
"title": fmt.Sprintf("AI 代码审查 - %s", e.After[:7]),
"body": utils.FormatReviewResult(result),
}
if err := e.client.post(path, issueData); err != nil {
log.Printf("创建 issue 失败: path=%s, error=%v", path, err)
return fmt.Errorf("创建 issue 失败: %w", err)
}
log.Printf("成功创建 issue: path=%s, commitID=%s", path, e.After[:7])
return nil
}
func (e *GiteaEvent) GetPlatform() string {
return "gitea"
}