diff options
author | Michael B. <153499594+mbollmann-v@users.noreply.github.com> | 2025-01-13 18:17:39 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-13 17:17:39 +0000 |
commit | a90af22003308e54dd4b0604b26f99c9325e37ab (patch) | |
tree | 4a9d0986fb3da9d91715349762560a612526dd8c | |
parent | 348b7074c8bbbd6d11231ba658cd1cec774a3fa4 (diff) | |
download | gitea-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.yml | 21 | ||||
-rw-r--r-- | models/webhook/webhook_system.go | 13 | ||||
-rw-r--r-- | models/webhook/webhook_system_test.go | 37 | ||||
-rw-r--r-- | routers/api/v1/admin/hooks.go | 21 | ||||
-rw-r--r-- | templates/swagger/v1_json.tmpl | 12 |
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": { |