88 lines
2.3 KiB
Go
88 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// GitLabPayload 简化版的 GitLab Push Webhook 数据结构
|
|
type GitLabPayload struct {
|
|
Ref string `json:"ref"`
|
|
After string `json:"after"`
|
|
Project struct {
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
} `json:"project"`
|
|
}
|
|
|
|
func handleWebhook(c *gin.Context) {
|
|
// 1. 校验 GitLab Secret Token Header
|
|
clientToken := c.GetHeader("X-Gitlab-Token")
|
|
if globalConfig.SecretToken != "" && clientToken != globalConfig.SecretToken {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Secret Token"})
|
|
return
|
|
}
|
|
|
|
// 2. 校验 Event 类型
|
|
eventType := c.GetHeader("X-Gitlab-Event")
|
|
if eventType != "Push Hook" {
|
|
c.JSON(http.StatusOK, gin.H{"status": "ignored", "reason": "Only Push Hook is handled"})
|
|
return
|
|
}
|
|
|
|
// 3. 解析 Body JSON
|
|
var payload GitLabPayload
|
|
if err := c.ShouldBindJSON(&payload); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON Payload"})
|
|
return
|
|
}
|
|
|
|
repoName := payload.Project.PathWithNamespace
|
|
ref := payload.Ref
|
|
commitID := payload.After
|
|
|
|
if repoName == "" || ref == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Missing repo or ref in payload"})
|
|
return
|
|
}
|
|
|
|
// 4. 匹配脚本路径
|
|
repoConfig, exists := globalConfig.Projects[repoName]
|
|
if !exists {
|
|
c.JSON(http.StatusOK, gin.H{"status": "ignored", "message": "No script config for repository " + repoName})
|
|
return
|
|
}
|
|
|
|
scriptPath, exists := repoConfig[ref]
|
|
if !exists {
|
|
c.JSON(http.StatusOK, gin.H{"status": "ignored", "message": fmt.Sprintf("No script config for %s on %s", repoName, ref)})
|
|
return
|
|
}
|
|
|
|
// 5. 校验脚本文件是否存在
|
|
if _, err := os.Stat(scriptPath); os.IsNotExist(err) {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Script file not found: " + scriptPath})
|
|
return
|
|
}
|
|
|
|
// 6. 入队等待 worker 按队列顺序消费
|
|
enqueueBuildTask(buildTask{
|
|
scriptPath: scriptPath,
|
|
repoName: repoName,
|
|
ref: ref,
|
|
commitID: commitID,
|
|
})
|
|
|
|
log.Printf("[QUEUED] 收到 push 入队 [%s] (仓库: %s, 分支: %s, commit: %s)\n",
|
|
scriptPath, repoName, ref, shortCommit(commitID))
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": "queued",
|
|
"repository": repoName,
|
|
"ref": ref,
|
|
"script": scriptPath,
|
|
})
|
|
}
|