Files
forgebot/internal/apiserver/handlers/webhook.go
T
unkinben c13b2ae999 Fix UUID cast in task creation, add kind test manifests
- Fix parent_task_id NULLIF cast to UUID type in INSERT query
- Fix itoa helper to use strconv.Itoa
- Handle AddReaction errors gracefully in webhook handler
- Add hack/kind/ manifests for local testing with kind cluster
2026-06-10 22:22:57 +10:00

94 lines
2.2 KiB
Go

package handlers
import (
"io"
"log/slog"
"net/http"
"strings"
"git.unkin.net/unkin/forgebot/internal/database"
"git.unkin.net/unkin/forgebot/internal/provider/gitea"
"git.unkin.net/unkin/forgebot/pkg/models"
)
type WebhookHandler struct {
db *database.DB
provider *gitea.Client
webhookSecret string
}
func NewWebhookHandler(db *database.DB, provider *gitea.Client, secret string) *WebhookHandler {
return &WebhookHandler{
db: db,
provider: provider,
webhookSecret: secret,
}
}
func (h *WebhookHandler) HandleGitea(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "failed to read body", http.StatusBadRequest)
return
}
signature := r.Header.Get("X-Gitea-Signature")
if !gitea.VerifySignature(body, h.webhookSecret, signature) {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
event, err := h.provider.ParseWebhook(body, h.webhookSecret)
if err != nil {
slog.Error("failed to parse webhook", "error", err)
http.Error(w, "failed to parse webhook", http.StatusBadRequest)
return
}
if event == nil {
w.WriteHeader(http.StatusOK)
return
}
commands := models.ParseCommands(event.Body)
if len(commands) == 0 {
w.WriteHeader(http.StatusOK)
return
}
parts := strings.SplitN(event.Repository, "/", 2)
if len(parts) != 2 {
http.Error(w, "invalid repository format", http.StatusBadRequest)
return
}
for _, cmd := range commands {
task, err := h.db.CreateTask(r.Context(), models.CreateTaskRequest{
Command: cmd.Name,
Repository: event.Repository,
Ref: event.Ref,
IssueNumber: event.IssueNum,
PRNumber: event.PRNum,
CommentID: event.CommentID,
Body: cmd.Args,
Author: event.Author,
})
if err != nil {
slog.Error("failed to create task", "error", err, "command", cmd.Name)
continue
}
slog.Info("task created from webhook",
"id", task.ID,
"command", cmd.Name,
"repository", event.Repository,
"author", event.Author,
)
if err := h.provider.AddReaction(parts[0], parts[1], event.CommentID, "eyes"); err != nil {
slog.Warn("failed to add reaction", "error", err)
}
}
w.WriteHeader(http.StatusAccepted)
}