feat: add GitHub and GitLab webhook support (#170)
All checks were successful
Check / check (push) Successful in 3m17s
All checks were successful
Check / check (push) Successful in 3m17s
## Summary Adds GitHub and GitLab push webhook support alongside the existing Gitea support. closes #68 ## What Changed ### Auto-detection of webhook source The webhook handler now auto-detects which platform sent the webhook by examining HTTP headers: - **Gitea**: `X-Gitea-Event` - **GitHub**: `X-GitHub-Event` - **GitLab**: `X-Gitlab-Event` Existing Gitea webhooks continue to work unchanged. Unknown sources fall back to Gitea format for backward compatibility. ### Normalized push event All three payload formats are parsed into a unified `PushEvent` struct containing: - Source platform, ref, branch, commit SHA - Repository name, clone URL, HTML URL - Commit URL (with per-platform fallback logic) - Pusher username/name ### New files - **`internal/service/webhook/payloads.go`**: Source-specific payload structs (`GiteaPushPayload`, `GitHubPushPayload`, `GitLabPushPayload`), `ParsePushPayload()` dispatcher, per-platform parsers, branch extraction, and commit URL extraction functions. ### Modified files - **`internal/service/webhook/types.go`**: Added `Source` type (gitea/github/gitlab/unknown), `DetectWebhookSource()`, `DetectEventType()`, and `PushEvent` normalized type. Moved `GiteaPushPayload` to payloads.go. - **`internal/service/webhook/webhook.go`**: `HandleWebhook` now accepts a `Source` parameter and uses `ParsePushPayload()` for unified parsing instead of directly unmarshaling Gitea payloads. - **`internal/handlers/webhook.go`**: Calls `DetectWebhookSource()` and `DetectEventType()` to auto-detect the platform before delegating to the webhook service. - **`internal/service/webhook/webhook_test.go`**: Comprehensive tests for source detection, event type extraction, payload parsing (all 3 platforms), commit URL fallback paths, and integration tests through `HandleWebhook` for GitHub and GitLab sources. - **`README.md`**: Updated description, features, non-goals, and architecture to reflect multi-platform webhook support. ## Test coverage Webhook package: **96.9%** statement coverage. Tests cover: - `DetectWebhookSource` with all header combinations and precedence - `DetectEventType` for each platform - `ParsePushPayload` for Gitea, GitHub, GitLab, unknown source, invalid JSON, empty payloads - Commit URL extraction fallback paths for GitHub and GitLab - Direct struct deserialization for all three payload types - Full `HandleWebhook` integration tests with GitHub and GitLab sources Co-authored-by: user <user@Mac.lan guest wan> Reviewed-on: #170 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
This commit was merged in pull request #170.
This commit is contained in:
@@ -7,12 +7,14 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"sneak.berlin/go/upaas/internal/models"
|
||||
"sneak.berlin/go/upaas/internal/service/webhook"
|
||||
)
|
||||
|
||||
// maxWebhookBodySize is the maximum allowed size of a webhook request body (1MB).
|
||||
const maxWebhookBodySize = 1 << 20
|
||||
|
||||
// HandleWebhook handles incoming Gitea webhooks.
|
||||
// HandleWebhook handles incoming webhooks from Gitea, GitHub, or GitLab.
|
||||
// The webhook source is auto-detected from HTTP headers.
|
||||
func (h *Handlers) HandleWebhook() http.HandlerFunc {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
secret := chi.URLParam(request, "secret")
|
||||
@@ -50,16 +52,17 @@ func (h *Handlers) HandleWebhook() http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// Get event type from header
|
||||
eventType := request.Header.Get("X-Gitea-Event")
|
||||
if eventType == "" {
|
||||
eventType = "push"
|
||||
}
|
||||
// Auto-detect webhook source from headers
|
||||
source := webhook.DetectWebhookSource(request.Header)
|
||||
|
||||
// Extract event type based on detected source
|
||||
eventType := webhook.DetectEventType(request.Header, source)
|
||||
|
||||
// Process webhook
|
||||
webhookErr := h.webhook.HandleWebhook(
|
||||
request.Context(),
|
||||
application,
|
||||
source,
|
||||
eventType,
|
||||
body,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user