166 lines
4.2 KiB
Go
166 lines
4.2 KiB
Go
package platforms
|
|
|
|
import (
|
|
"code-review/services/types"
|
|
"code-review/utils"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// GitlabEvent Gitlab 平台的 webhook 事件
|
|
type GitlabEvent struct {
|
|
apiBase string
|
|
auth *AuthConfig
|
|
Event string
|
|
client *httpClient
|
|
|
|
ObjectKind string `json:"object_kind"` // "push", "merge_request" 等
|
|
Before string `json:"before"`
|
|
After string `json:"after"`
|
|
Ref string `json:"ref"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
} `json:"project"`
|
|
Commits []struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Title string `json:"title"`
|
|
} `json:"commits"`
|
|
}
|
|
|
|
// NewGitlabEvent 创建 GitLab 事件实例
|
|
func NewGitlabEvent(baseURL string, auth *AuthConfig, event string) *GitlabEvent {
|
|
return &GitlabEvent{
|
|
apiBase: baseURL,
|
|
auth: auth,
|
|
Event: event,
|
|
}
|
|
}
|
|
|
|
// 定义 GitLab diff 响应的结构
|
|
type gitlabDiff struct {
|
|
Diff string `json:"diff"`
|
|
NewPath string `json:"new_path"`
|
|
OldPath string `json:"old_path"`
|
|
AMode string `json:"a_mode"`
|
|
BMode string `json:"b_mode"`
|
|
NewFile bool `json:"new_file"`
|
|
RenamedFile bool `json:"renamed_file"`
|
|
DeletedFile bool `json:"deleted_file"`
|
|
}
|
|
|
|
func (e *GitlabEvent) ExtractChanges() (*types.CodeChanges, error) {
|
|
// 检查是否有提交记录
|
|
if len(e.Commits) == 0 {
|
|
log.Printf("没有提交记录,跳过代码审查")
|
|
return nil, nil
|
|
}
|
|
|
|
// 检查是否跳过代码审查
|
|
validCommits := make([]struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Title string `json:"title"`
|
|
}, 0)
|
|
|
|
for _, commit := range e.Commits {
|
|
if strings.Contains(commit.Message, "[skip codereview]") {
|
|
log.Printf("跳过代码审查: commit=%s", commit.ID)
|
|
return nil, nil
|
|
}
|
|
// 过滤合并提交
|
|
if strings.HasPrefix(commit.Message, "Merge remote-tracking branch") ||
|
|
strings.HasPrefix(commit.Message, "Merge branch") {
|
|
log.Printf("跳过合并提交: commit=%s", commit.ID)
|
|
continue
|
|
}
|
|
validCommits = append(validCommits, commit)
|
|
}
|
|
|
|
if len(validCommits) == 0 {
|
|
log.Printf("没有有效的提交记录(所有提交都是合并提交),跳过代码审查")
|
|
return nil, nil
|
|
}
|
|
|
|
if e.client == nil {
|
|
e.client = newHTTPClient(e.apiBase, e.auth)
|
|
log.Printf("初始化 HTTP 客户端: url=%s", e.apiBase)
|
|
}
|
|
|
|
changes := &types.CodeChanges{
|
|
Repository: e.Project.PathWithNamespace,
|
|
Branch: e.Ref,
|
|
CommitID: e.After,
|
|
Files: make([]types.FileChange, 0),
|
|
}
|
|
|
|
for _, commit := range validCommits {
|
|
// 移除 URL 中的 token
|
|
apiPath := fmt.Sprintf("/api/v4/projects/%d/repository/commits/%s/diff",
|
|
e.Project.ID, commit.ID)
|
|
|
|
headers := map[string]string{
|
|
"PRIVATE-TOKEN": e.auth.Token,
|
|
}
|
|
|
|
var diffs []gitlabDiff
|
|
if err := e.client.getWithHeaders(apiPath, &diffs, headers); err != nil {
|
|
log.Printf("获取提交详情失败: commit=%s, error=%v", commit.ID, err)
|
|
continue
|
|
}
|
|
|
|
for _, diff := range diffs {
|
|
status := "modified"
|
|
if diff.NewFile {
|
|
status = "added"
|
|
} else if diff.DeletedFile {
|
|
status = "deleted"
|
|
} else if diff.RenamedFile {
|
|
status = "renamed"
|
|
}
|
|
|
|
changes.Files = append(changes.Files, types.FileChange{
|
|
Path: diff.NewPath,
|
|
Content: diff.Diff,
|
|
Type: utils.ParseFileType(status),
|
|
})
|
|
}
|
|
}
|
|
|
|
return changes, nil
|
|
}
|
|
|
|
func (e *GitlabEvent) PostComments(result *types.ReviewResult) error {
|
|
if e.client == nil {
|
|
e.client = newHTTPClient(e.apiBase, e.auth)
|
|
}
|
|
|
|
// 创建 issue
|
|
path := fmt.Sprintf("/api/v4/projects/%d/issues", e.Project.ID)
|
|
issueData := map[string]interface{}{
|
|
"title": fmt.Sprintf("AI 代码审查 - %s", e.After[:7]),
|
|
"description": utils.FormatReviewResult(result),
|
|
}
|
|
|
|
headers := map[string]string{
|
|
"PRIVATE-TOKEN": e.auth.Token,
|
|
}
|
|
|
|
if err := e.client.postWithHeaders(path, issueData, headers); 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 *GitlabEvent) GetPlatform() string {
|
|
return "gitlab"
|
|
}
|