适配gitea 取消gogs(没有对应接口支持)
This commit is contained in:
@ -10,40 +10,191 @@ import (
|
||||
|
||||
type GiteaEvent struct {
|
||||
apiBase string
|
||||
token string
|
||||
auth *AuthConfig
|
||||
Event string
|
||||
client *httpClient
|
||||
|
||||
Secret string `json:"secret"`
|
||||
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"`
|
||||
ID string `json:"sha"`
|
||||
Message string `json:"commit.message"`
|
||||
URL string `json:"url"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
Created string `json:"created"`
|
||||
Author struct {
|
||||
Active bool `json:"active"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Created string `json:"created"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
FollowersCount int `json:"followers_count"`
|
||||
FollowingCount int `json:"following_count"`
|
||||
FullName string `json:"full_name"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
ID int `json:"id"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
Language string `json:"language"`
|
||||
LastLogin string `json:"last_login"`
|
||||
Location string `json:"location"`
|
||||
Login string `json:"login"`
|
||||
LoginName string `json:"login_name"`
|
||||
ProhibitLogin bool `json:"prohibit_login"`
|
||||
Restricted bool `json:"restricted"`
|
||||
SourceID int `json:"source_id"`
|
||||
Visibility string `json:"visibility"`
|
||||
Website string `json:"website"`
|
||||
} `json:"author"`
|
||||
Committer struct {
|
||||
Active bool `json:"active"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Created string `json:"created"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
FollowersCount int `json:"followers_count"`
|
||||
FollowingCount int `json:"following_count"`
|
||||
FullName string `json:"full_name"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
ID int `json:"id"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
Language string `json:"language"`
|
||||
LastLogin string `json:"last_login"`
|
||||
Location string `json:"location"`
|
||||
Login string `json:"login"`
|
||||
LoginName string `json:"login_name"`
|
||||
ProhibitLogin bool `json:"prohibit_login"`
|
||||
Restricted bool `json:"restricted"`
|
||||
SourceID int `json:"source_id"`
|
||||
Visibility string `json:"visibility"`
|
||||
Website string `json:"website"`
|
||||
} `json:"committer"`
|
||||
Commit struct {
|
||||
Author struct {
|
||||
Date string `json:"date"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
} `json:"author"`
|
||||
Committer struct {
|
||||
Date string `json:"date"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
} `json:"committer"`
|
||||
Message string `json:"message"`
|
||||
Tree struct {
|
||||
Created string `json:"created"`
|
||||
SHA string `json:"sha"`
|
||||
URL string `json:"url"`
|
||||
} `json:"tree"`
|
||||
URL string `json:"url"`
|
||||
Verification struct {
|
||||
Payload string `json:"payload"`
|
||||
Reason string `json:"reason"`
|
||||
Signature string `json:"signature"`
|
||||
Signer struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
} `json:"signer"`
|
||||
Verified bool `json:"verified"`
|
||||
} `json:"verification"`
|
||||
} `json:"commit"`
|
||||
Files []struct {
|
||||
Filename string `json:"filename"`
|
||||
Status string `json:"status"`
|
||||
} `json:"files"`
|
||||
Parents []struct {
|
||||
Created string `json:"created"`
|
||||
SHA string `json:"sha"`
|
||||
URL string `json:"url"`
|
||||
} `json:"parents"`
|
||||
Stats struct {
|
||||
Additions int `json:"additions"`
|
||||
Deletions int `json:"deletions"`
|
||||
Total int `json:"total"`
|
||||
} `json:"stats"`
|
||||
} `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"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
FullName string `json:"full_name"`
|
||||
Description string `json:"description"`
|
||||
Private bool `json:"private"`
|
||||
Fork bool `json:"fork"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
SSHURL string `json:"ssh_url"`
|
||||
CloneURL string `json:"clone_url"`
|
||||
Website string `json:"website"`
|
||||
StarsCount int `json:"stars_count"`
|
||||
ForksCount int `json:"forks_count"`
|
||||
WatchersCount int `json:"watchers_count"`
|
||||
OpenIssuesCount int `json:"open_issues_count"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Owner struct {
|
||||
ID int `json:"id"`
|
||||
Login string `json:"login"`
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Username string `json:"username"`
|
||||
} `json:"owner"`
|
||||
} `json:"repository"`
|
||||
Pusher struct {
|
||||
ID int `json:"id"`
|
||||
Login string `json:"login"`
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Username string `json:"username"`
|
||||
} `json:"pusher"`
|
||||
Sender struct {
|
||||
ID int `json:"id"`
|
||||
Login string `json:"login"`
|
||||
FullName string `json:"full_name"`
|
||||
Email string `json:"email"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
Username string `json:"username"`
|
||||
} `json:"sender"`
|
||||
}
|
||||
|
||||
// NewGiteaEvent 创建 Gitea 事件
|
||||
func NewGiteaEvent(apiBase, token string, event string) *GiteaEvent {
|
||||
func NewGiteaEvent(apiBase string, auth *AuthConfig, event string) *GiteaEvent {
|
||||
return &GiteaEvent{
|
||||
apiBase: apiBase,
|
||||
token: token,
|
||||
auth: auth,
|
||||
Event: event,
|
||||
}
|
||||
}
|
||||
|
||||
// 定义 Gitea commit 响应的结构
|
||||
type giteaCommitResponse struct {
|
||||
Commit struct {
|
||||
Message string `json:"message"`
|
||||
Author struct {
|
||||
Date string `json:"date"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
} `json:"author"`
|
||||
Committer struct {
|
||||
Date string `json:"date"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
} `json:"committer"`
|
||||
} `json:"commit"`
|
||||
Files []struct {
|
||||
Filename string `json:"filename"`
|
||||
Status string `json:"status"`
|
||||
Additions int `json:"additions"`
|
||||
Deletions int `json:"deletions"`
|
||||
Changes int `json:"changes"`
|
||||
Content string `json:"content"`
|
||||
} `json:"files"`
|
||||
}
|
||||
|
||||
func (e *GiteaEvent) ExtractChanges() (*types.CodeChanges, error) {
|
||||
// 检查是否有提交记录
|
||||
if len(e.Commits) == 0 {
|
||||
@ -53,14 +204,14 @@ func (e *GiteaEvent) ExtractChanges() (*types.CodeChanges, error) {
|
||||
|
||||
// 检查是否跳过代码审查
|
||||
for _, commit := range e.Commits {
|
||||
if strings.Contains(commit.Message, "[skip codereview]") {
|
||||
if strings.Contains(commit.Commit.Message, "[skip codereview]") {
|
||||
log.Printf("跳过代码审查: commit=%s", commit.ID)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if e.client == nil {
|
||||
e.client = newHTTPClient(e.apiBase, e.token)
|
||||
e.client = newHTTPClient(e.apiBase, e.auth)
|
||||
log.Printf("初始化 HTTP 客户端: url=%s", e.apiBase)
|
||||
}
|
||||
|
||||
@ -73,89 +224,46 @@ func (e *GiteaEvent) ExtractChanges() (*types.CodeChanges, error) {
|
||||
|
||||
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
|
||||
apiPath := fmt.Sprintf("/api/v1/repos/%s/%s/git/commits/%s", e.Repository.Owner.Login, e.Repository.Name, e.After)
|
||||
var diffContent giteaCommitResponse
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
// 处理每个文件的变更
|
||||
for _, file := range diffContent.Files {
|
||||
var content strings.Builder
|
||||
content.WriteString(fmt.Sprintf("### 变更说明\n"))
|
||||
content.WriteString(fmt.Sprintf("提交信息: %s\n\n", commit.Message))
|
||||
content.WriteString(fmt.Sprintf("提交信息: %s\n\n", diffContent.Commit.Message))
|
||||
|
||||
switch status {
|
||||
status := "modified"
|
||||
switch file.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))
|
||||
status = "added"
|
||||
content.WriteString(fmt.Sprintf("新增文件: %s\n\n", file.Filename))
|
||||
case "removed":
|
||||
status = "deleted"
|
||||
content.WriteString(fmt.Sprintf("删除文件: %s\n\n", file.Filename))
|
||||
case "renamed":
|
||||
content.WriteString(fmt.Sprintf("重命名文件: %s\n\n", filename))
|
||||
status = "renamed"
|
||||
content.WriteString(fmt.Sprintf("重命名文件: %s\n\n", file.Filename))
|
||||
default:
|
||||
content.WriteString(fmt.Sprintf("修改文件: %s\n\n", file.Filename))
|
||||
}
|
||||
|
||||
content.WriteString("### 变更内容\n")
|
||||
content.WriteString("```diff\n")
|
||||
content.WriteString(block)
|
||||
content.WriteString("\n```\n")
|
||||
if file.Content != "" {
|
||||
content.WriteString("### 变更内容\n")
|
||||
content.WriteString("```diff\n")
|
||||
content.WriteString(file.Content)
|
||||
content.WriteString("\n```\n")
|
||||
}
|
||||
|
||||
changes.Files = append(changes.Files, types.FileChange{
|
||||
Path: filename,
|
||||
Path: file.Filename,
|
||||
Content: content.String(),
|
||||
Type: parseFileType(status),
|
||||
Type: utils.ParseFileType(status),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -165,11 +273,11 @@ func (e *GiteaEvent) ExtractChanges() (*types.CodeChanges, error) {
|
||||
|
||||
func (e *GiteaEvent) PostComments(result *types.ReviewResult) error {
|
||||
if e.client == nil {
|
||||
e.client = newHTTPClient(e.apiBase, e.token)
|
||||
e.client = newHTTPClient(e.apiBase, e.auth)
|
||||
}
|
||||
|
||||
// 创建 issue
|
||||
path := fmt.Sprintf("/api/v1/repos/%s/issues", e.Repository.FullName)
|
||||
path := fmt.Sprintf("/api/v1/repos/%s/%s/issues", e.Repository.Owner.Login, e.Repository.Name)
|
||||
issueData := map[string]interface{}{
|
||||
"title": fmt.Sprintf("AI 代码审查 - %s", e.After[:7]),
|
||||
"body": utils.FormatReviewResult(result),
|
||||
|
Reference in New Issue
Block a user