aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael B. <153499594+mbollmann-v@users.noreply.github.com>2025-01-13 18:17:39 +0100
committerGitHub <noreply@github.com>2025-01-13 17:17:39 +0000
commita90af22003308e54dd4b0604b26f99c9325e37ab (patch)
tree4a9d0986fb3da9d91715349762560a612526dd8c
parent348b7074c8bbbd6d11231ba658cd1cec774a3fa4 (diff)
downloadgitea-a90af22003308e54dd4b0604b26f99c9325e37ab.tar.gz
gitea-a90af22003308e54dd4b0604b26f99c9325e37ab.zip
Let API create and edit system webhooks, attempt 2 (#33180)
This PR fixes inconsistencies between system and default webhooks in the Gitea API. (See also #26418) - A system webhook is a webhook that captures events for all repositories. - A default webhook is copied to a new repository when it is created. Before this PR `POST /api/v1/admin/hooks/` creates default webhooks (if not configured otherwise) and `GET /api/v1/admin/hooks/` returns system webhooks. The PR introduces an optional query parameter to `GET /api/v1/admin/hooks/` to enable selecting if either default, system or both kind of webhooks should be retrieved. By default the flag is set to return system webhooks keep current behaviour. ## Examples ### System Webhooks #### Create ``` POST /api/v1/admin/hooks/ { "type": "gitea", "active": false, "branch_filter": "*", "events": [ "create", "..." ], "config": { "url": "http://...", "content_type": "json", "secret": "secret", "is_system_webhook": true // <-- controls hook type } } ``` #### List ``` GET/api/v1/admin/hooks?type=system //type argument is optional here since it's the default ``` #### Others The other relevant endpoints work as expected by referencing the hook by id ``` GET /api/v1/admin/hooks/:id PATCH /api/v1/admin/hooks/:id DELETE /api/v1/admin/hooks/:id ``` ### Default Webhooks #### Create ``` POST /api/v1/admin/hooks/ { "type": "gitea", "active": false, "branch_filter": "*", "events": [ "create", "..." ], "config": { "url": "http://...", "content_type": "json", "secret": "secret", "is_system_webhook": false // optional, as false is the default value } } ``` #### List ``` GET/api/v1/admin/hooks?type=default ``` #### Others The other relevant endpoints work as expected by referencing the hook by id ``` GET /api/v1/admin/hooks/:id PATCH /api/v1/admin/hooks/:id DELETE /api/v1/admin/hooks/:id ```
-rw-r--r--models/fixtures/webhook.yml21
-rw-r--r--models/webhook/webhook_system.go13
-rw-r--r--models/webhook/webhook_system_test.go37
-rw-r--r--routers/api/v1/admin/hooks.go21
-rw-r--r--templates/swagger/v1_json.tmpl12
5 files changed, 103 insertions, 1 deletions
diff --git a/models/fixtures/webhook.yml b/models/fixtures/webhook.yml
index f62bae1f31..ebc4062b60 100644
--- a/models/fixtures/webhook.yml
+++ b/models/fixtures/webhook.yml
@@ -22,6 +22,7 @@
content_type: 1 # json
events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}'
is_active: true
+
-
id: 4
repo_id: 2
@@ -29,3 +30,23 @@
content_type: 1 # json
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
is_active: true
+
+-
+ id: 5
+ repo_id: 0
+ owner_id: 0
+ url: www.example.com/url5
+ content_type: 1 # json
+ events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
+ is_active: true
+ is_system_webhook: true
+
+-
+ id: 6
+ repo_id: 0
+ owner_id: 0
+ url: www.example.com/url6
+ content_type: 1 # json
+ events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
+ is_active: true
+ is_system_webhook: false
diff --git a/models/webhook/webhook_system.go b/models/webhook/webhook_system.go
index a2a9ee321a..58d9d4a5c1 100644
--- a/models/webhook/webhook_system.go
+++ b/models/webhook/webhook_system.go
@@ -11,6 +11,19 @@ import (
"code.gitea.io/gitea/modules/optional"
)
+// GetSystemOrDefaultWebhooks returns webhooks by given argument or all if argument is missing.
+func GetSystemOrDefaultWebhooks(ctx context.Context, isSystemWebhook optional.Option[bool]) ([]*Webhook, error) {
+ webhooks := make([]*Webhook, 0, 5)
+ if !isSystemWebhook.Has() {
+ return webhooks, db.GetEngine(ctx).Where("repo_id=? AND owner_id=?", 0, 0).
+ Find(&webhooks)
+ }
+
+ return webhooks, db.GetEngine(ctx).
+ Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, isSystemWebhook.Value()).
+ Find(&webhooks)
+}
+
// GetDefaultWebhooks returns all admin-default webhooks.
func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
diff --git a/models/webhook/webhook_system_test.go b/models/webhook/webhook_system_test.go
new file mode 100644
index 0000000000..96157ed9c9
--- /dev/null
+++ b/models/webhook/webhook_system_test.go
@@ -0,0 +1,37 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package webhook
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/optional"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGetSystemOrDefaultWebhooks(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ hooks, err := GetSystemOrDefaultWebhooks(db.DefaultContext, optional.None[bool]())
+ assert.NoError(t, err)
+ if assert.Len(t, hooks, 2) {
+ assert.Equal(t, int64(5), hooks[0].ID)
+ assert.Equal(t, int64(6), hooks[1].ID)
+ }
+
+ hooks, err = GetSystemOrDefaultWebhooks(db.DefaultContext, optional.Some(true))
+ assert.NoError(t, err)
+ if assert.Len(t, hooks, 1) {
+ assert.Equal(t, int64(5), hooks[0].ID)
+ }
+
+ hooks, err = GetSystemOrDefaultWebhooks(db.DefaultContext, optional.Some(false))
+ assert.NoError(t, err)
+ if assert.Len(t, hooks, 1) {
+ assert.Equal(t, int64(6), hooks[0].ID)
+ }
+}
diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go
index 6b4689047b..c812ca182d 100644
--- a/routers/api/v1/admin/hooks.go
+++ b/routers/api/v1/admin/hooks.go
@@ -34,11 +34,30 @@ func ListHooks(ctx *context.APIContext) {
// in: query
// description: page size of results
// type: integer
+ // - type: string
+ // enum:
+ // - system
+ // - default
+ // - all
+ // description: system, default or both kinds of webhooks
+ // name: type
+ // default: system
+ // in: query
+ //
// responses:
// "200":
// "$ref": "#/responses/HookList"
- sysHooks, err := webhook.GetSystemWebhooks(ctx, optional.None[bool]())
+ // for compatibility the default value is true
+ isSystemWebhook := optional.Some(true)
+ typeValue := ctx.FormString("type")
+ if typeValue == "default" {
+ isSystemWebhook = optional.Some(false)
+ } else if typeValue == "all" {
+ isSystemWebhook = optional.None[bool]()
+ }
+
+ sysHooks, err := webhook.GetSystemOrDefaultWebhooks(ctx, isSystemWebhook)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetSystemWebhooks", err)
return
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index fb37d45ce8..8082fc594a 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -234,6 +234,18 @@
"description": "page size of results",
"name": "limit",
"in": "query"
+ },
+ {
+ "enum": [
+ "system",
+ "default",
+ "all"
+ ],
+ "type": "string",
+ "default": "system",
+ "description": "system, default or both kinds of webhooks",
+ "name": "type",
+ "in": "query"
}
],
"responses": {