From 23971a77a00d4970b7c209545c9f65db6351d509 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 1 Feb 2025 22:44:50 -0800 Subject: [PATCH] Add tests for webhook and fix some webhook bugs (#33396) (#33442) This PR created a mock webhook server in the tests and added integration tests for generic webhooks. It also fixes bugs in package webhooks and pull request comment webhooks. This also corrected an error on the package webhook. The previous implementation uses a `User` struct as an organization, now it has been corrected but it will not be consistent with the previous implementation, some fields which not belong to the organization have been removed. Backport #33396 Backport part of #33337 --- models/webhook/webhook.go | 6 + models/webhook/webhook_test.go | 2 +- modules/structs/hook.go | 60 +-- modules/webhook/structs.go | 1 + modules/webhook/type.go | 17 +- routers/api/v1/utils/hook.go | 2 + services/webhook/dingtalk.go | 4 + services/webhook/discord.go | 4 + services/webhook/feishu.go | 4 + services/webhook/general_test.go | 4 +- services/webhook/matrix.go | 4 + services/webhook/msteams.go | 4 + services/webhook/notifier.go | 13 +- services/webhook/packagist.go | 4 + services/webhook/slack.go | 4 + services/webhook/telegram.go | 4 + services/webhook/webhook.go | 16 +- services/webhook/wechatwork.go | 4 + tests/integration/api_repo_test.go | 15 +- tests/integration/api_wiki_test.go | 24 +- tests/integration/issue_test.go | 2 +- tests/integration/repo_webhook_test.go | 565 +++++++++++++++++++++++++ tests/mssql.ini.tmpl | 6 + tests/mysql.ini.tmpl | 6 + tests/pgsql.ini.tmpl | 6 + tests/sqlite.ini.tmpl | 6 + 26 files changed, 682 insertions(+), 105 deletions(-) diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 894357e36a..a17582c0c9 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -299,6 +299,11 @@ func (w *Webhook) HasPackageEvent() bool { (w.ChooseEvents && w.HookEvents.Package) } +func (w *Webhook) HasStatusEvent() bool { + return w.SendEverything || + (w.ChooseEvents && w.HookEvents.Status) +} + // HasPullRequestReviewRequestEvent returns true if hook enabled pull request review request event. func (w *Webhook) HasPullRequestReviewRequestEvent() bool { return w.SendEverything || @@ -337,6 +342,7 @@ func (w *Webhook) EventCheckers() []struct { {w.HasReleaseEvent, webhook_module.HookEventRelease}, {w.HasPackageEvent, webhook_module.HookEventPackage}, {w.HasPullRequestReviewRequestEvent, webhook_module.HookEventPullRequestReviewRequest}, + {w.HasStatusEvent, webhook_module.HookEventStatus}, } } diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index c6c3f40d46..5e135369e6 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -74,7 +74,7 @@ func TestWebhook_EventsArray(t *testing.T) { "pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone", "pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected", "pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release", - "package", "pull_request_review_request", + "package", "pull_request_review_request", "status", }, (&Webhook{ HookEvent: &webhook_module.HookEvent{SendEverything: true}, diff --git a/modules/structs/hook.go b/modules/structs/hook.go index ce5742e5c7..cef2dbd712 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -116,14 +116,7 @@ var ( _ Payloader = &PackagePayload{} ) -// _________ __ -// \_ ___ \_______ ____ _____ _/ |_ ____ -// / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \ -// \ \____| | \/\ ___/ / __ \| | \ ___/ -// \______ /|__| \___ >____ /__| \___ > -// \/ \/ \/ \/ - -// CreatePayload FIXME +// CreatePayload represents a payload information of create event. type CreatePayload struct { Sha string `json:"sha"` Ref string `json:"ref"` @@ -157,13 +150,6 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) { return hook, nil } -// ________ .__ __ -// \______ \ ____ | | _____/ |_ ____ -// | | \_/ __ \| | _/ __ \ __\/ __ \ -// | ` \ ___/| |_\ ___/| | \ ___/ -// /_______ /\___ >____/\___ >__| \___ > -// \/ \/ \/ \/ - // PusherType define the type to push type PusherType string @@ -186,13 +172,6 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } -// ___________ __ -// \_ _____/__________| | __ -// | __)/ _ \_ __ \ |/ / -// | \( <_> ) | \/ < -// \___ / \____/|__| |__|_ \ -// \/ \/ - // ForkPayload represents fork payload type ForkPayload struct { Forkee *Repository `json:"forkee"` @@ -232,13 +211,6 @@ func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } -// __________ .__ -// \______ \ ____ | | ____ _____ ______ ____ -// | _// __ \| | _/ __ \\__ \ / ___// __ \ -// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/ -// |____|_ /\___ >____/\___ >____ /____ >\___ > -// \/ \/ \/ \/ \/ \/ - // HookReleaseAction defines hook release action type type HookReleaseAction string @@ -302,13 +274,6 @@ func (p *PushPayload) Branch() string { return strings.ReplaceAll(p.Ref, "refs/heads/", "") } -// .___ -// | | ______ ________ __ ____ -// | |/ ___// ___/ | \_/ __ \ -// | |\___ \ \___ \| | /\ ___/ -// |___/____ >____ >____/ \___ > -// \/ \/ \/ - // HookIssueAction FIXME type HookIssueAction string @@ -371,13 +336,6 @@ type ChangesPayload struct { Ref *ChangesFromPayload `json:"ref,omitempty"` } -// __________ .__ .__ __________ __ -// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_ -// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ -// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | | -// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__| -// \/ \/ |__| \/ \/ - // PullRequestPayload represents a payload information of pull request event. type PullRequestPayload struct { Action HookIssueAction `json:"action"` @@ -402,13 +360,6 @@ type ReviewPayload struct { Content string `json:"content"` } -// __ __.__ __ .__ -// / \ / \__| | _|__| -// \ \/\/ / | |/ / | -// \ /| | <| | -// \__/\ / |__|__|_ \__| -// \/ \/ - // HookWikiAction an action that happens to a wiki page type HookWikiAction string @@ -435,13 +386,6 @@ func (p *WikiPayload) JSONPayload() ([]byte, error) { return json.MarshalIndent(p, "", " ") } -//__________ .__ __ -//\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. -// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | -// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ | -// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____| -// \/ \/|__| \/ \/ - // HookRepoAction an action that happens to a repo type HookRepoAction string @@ -480,7 +424,7 @@ type PackagePayload struct { Action HookPackageAction `json:"action"` Repository *Repository `json:"repository"` Package *Package `json:"package"` - Organization *User `json:"organization"` + Organization *Organization `json:"organization"` Sender *User `json:"sender"` } diff --git a/modules/webhook/structs.go b/modules/webhook/structs.go index 927a91a74c..a9f8e33ae2 100644 --- a/modules/webhook/structs.go +++ b/modules/webhook/structs.go @@ -26,6 +26,7 @@ type HookEvents struct { Repository bool `json:"repository"` Release bool `json:"release"` Package bool `json:"package"` + Status bool `json:"status"` } // HookEvent represents events that will delivery hook. diff --git a/modules/webhook/type.go b/modules/webhook/type.go index fbec889272..281f7e653b 100644 --- a/modules/webhook/type.go +++ b/modules/webhook/type.go @@ -38,14 +38,6 @@ const ( // Event returns the HookEventType as an event string func (h HookEventType) Event() string { switch h { - case HookEventCreate: - return "create" - case HookEventDelete: - return "delete" - case HookEventFork: - return "fork" - case HookEventPush: - return "push" case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone: return "issues" case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone, @@ -59,14 +51,9 @@ func (h HookEventType) Event() string { return "pull_request_rejected" case HookEventPullRequestReviewComment: return "pull_request_comment" - case HookEventWiki: - return "wiki" - case HookEventRepository: - return "repository" - case HookEventRelease: - return "release" + default: + return string(h) } - return "" } // HookType is the type of a webhook diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 4328878e19..8e91c2e0ef 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -205,6 +205,8 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI Wiki: util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true), Repository: util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true), Release: util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true), + Package: util.SliceContainsString(form.Events, string(webhook_module.HookEventPackage), true), + Status: util.SliceContainsString(form.Events, string(webhook_module.HookEventStatus), true), }, BranchFilter: form.BranchFilter, }, diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index e382f5a9df..992b8c566f 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -190,3 +190,7 @@ func newDingtalkRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_ var pc payloadConvertor[DingtalkPayload] = dingtalkConvertor{} return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.DINGTALK, newDingtalkRequest) +} diff --git a/services/webhook/discord.go b/services/webhook/discord.go index c562d98168..30d930062e 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -277,6 +277,10 @@ func newDiscordRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m return newJSONRequest(pc, w, t, true) } +func init() { + RegisterWebhookRequester(webhook_module.DISCORD, newDiscordRequest) +} + func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) { switch event { case webhook_module.HookEventPullRequestReviewApproved: diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index 7ca7d1cf5f..4e6aebc39d 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -170,3 +170,7 @@ func newFeishuRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mo var pc payloadConvertor[FeishuPayload] = feishuConvertor{} return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.FEISHU, newFeishuRequest) +} diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index ef1ec7f324..ec735d785a 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -319,8 +319,8 @@ func packageTestPayload() *api.PackagePayload { AvatarURL: "http://localhost:3000/user1/avatar", }, Repository: nil, - Organization: &api.User{ - UserName: "org1", + Organization: &api.Organization{ + Name: "org1", AvatarURL: "http://localhost:3000/org1/avatar", }, Package: &api.Package{ diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index 5e9f808d8b..96dfa139ac 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -24,6 +24,10 @@ import ( webhook_module "code.gitea.io/gitea/modules/webhook" ) +func init() { + RegisterWebhookRequester(webhook_module.MATRIX, newMatrixRequest) +} + func newMatrixRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) { meta := &MatrixMeta{} if err := json.Unmarshal([]byte(w.Meta), meta); err != nil { diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 7ef96ffa27..1ae7c4f931 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -349,3 +349,7 @@ func newMSTeamsRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m var pc payloadConvertor[MSTeamsPayload] = msteamsConvertor{} return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.MSTEAMS, newMSTeamsRequest) +} diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index a3d5cb34b1..52a69d53b6 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -8,6 +8,7 @@ import ( git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/models/organization" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" @@ -924,10 +925,16 @@ func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_mo return } + var org *api.Organization + if pd.Owner.IsOrganization() { + org = convert.ToOrganization(ctx, organization.OrgFromUser(pd.Owner)) + } + if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{ - Action: action, - Package: apiPackage, - Sender: convert.ToUser(ctx, sender, nil), + Action: action, + Package: apiPackage, + Organization: org, + Sender: convert.ToUser(ctx, sender, nil), }); err != nil { log.Error("PrepareWebhooks: %v", err) } diff --git a/services/webhook/packagist.go b/services/webhook/packagist.go index 4d809ab3a6..e66895832b 100644 --- a/services/webhook/packagist.go +++ b/services/webhook/packagist.go @@ -120,3 +120,7 @@ func newPackagistRequest(_ context.Context, w *webhook_model.Webhook, t *webhook } return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.PACKAGIST, newPackagistRequest) +} diff --git a/services/webhook/slack.go b/services/webhook/slack.go index c905e7a89f..e0e938d53d 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -295,6 +295,10 @@ func newSlackRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mod return newJSONRequest(pc, w, t, true) } +func init() { + RegisterWebhookRequester(webhook_module.SLACK, newSlackRequest) +} + var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`) // IsValidSlackChannel validates a channel name conforms to what slack expects: diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index e54d6f2947..6fbf995801 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -187,3 +187,7 @@ func newTelegramRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_ var pc payloadConvertor[TelegramPayload] = telegramConvertor{} return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.TELEGRAM, newTelegramRequest) +} diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index e0e8fa2fc1..b5e0864f15 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -27,16 +27,12 @@ import ( "github.com/gobwas/glob" ) -var webhookRequesters = map[webhook_module.HookType]func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error){ - webhook_module.SLACK: newSlackRequest, - webhook_module.DISCORD: newDiscordRequest, - webhook_module.DINGTALK: newDingtalkRequest, - webhook_module.TELEGRAM: newTelegramRequest, - webhook_module.MSTEAMS: newMSTeamsRequest, - webhook_module.FEISHU: newFeishuRequest, - webhook_module.MATRIX: newMatrixRequest, - webhook_module.WECHATWORK: newWechatworkRequest, - webhook_module.PACKAGIST: newPackagistRequest, +type Requester func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error) + +var webhookRequesters = map[webhook_module.HookType]Requester{} + +func RegisterWebhookRequester(hookType webhook_module.HookType, requester Requester) { + webhookRequesters[hookType] = requester } // IsValidHookTaskType returns true if a webhook registered diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index 1d8c1d7dac..44e0ff7de5 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -179,3 +179,7 @@ func newWechatworkRequest(_ context.Context, w *webhook_model.Webhook, t *webhoo var pc payloadConvertor[WechatworkPayload] = wechatworkConvertor{} return newJSONRequest(pc, w, t, true) } + +func init() { + RegisterWebhookRequester(webhook_module.WECHATWORK, newWechatworkRequest) +} diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index 122afbfa08..aae038d51e 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -471,6 +471,15 @@ func TestAPIMirrorSyncNonMirrorRepo(t *testing.T) { assert.Equal(t, "Repository is not a mirror", errRespJSON["message"]) } +func testAPIOrgCreateRepo(t *testing.T, session *TestSession, orgName, repoName string, status int) { + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository) + + req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", orgName), &api.CreateRepoOption{ + Name: repoName, + }).AddTokenAuth(token) + MakeRequest(t, req, status) +} + func TestAPIOrgRepoCreate(t *testing.T) { testCases := []struct { ctxUserID int64 @@ -488,11 +497,7 @@ func TestAPIOrgRepoCreate(t *testing.T) { for _, testCase := range testCases { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) session := loginUser(t, user.Name) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository) - req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", testCase.orgName), &api.CreateRepoOption{ - Name: testCase.repoName, - }).AddTokenAuth(token) - MakeRequest(t, req, testCase.expectedStatus) + testAPIOrgCreateRepo(t, session, testCase.orgName, testCase.repoName, testCase.expectedStatus) } } diff --git a/tests/integration/api_wiki_test.go b/tests/integration/api_wiki_test.go index 05d90fc4e3..8e5f67e282 100644 --- a/tests/integration/api_wiki_test.go +++ b/tests/integration/api_wiki_test.go @@ -172,6 +172,19 @@ func TestAPIListWikiPages(t *testing.T) { assert.Equal(t, dummymeta, meta) } +func testAPICreateWikiPage(t *testing.T, session *TestSession, userName, repoName, title string, status int) { + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", userName, repoName) + + req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{ + Title: title, + ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")), + Message: "", + }).AddTokenAuth(token) + MakeRequest(t, req, status) +} + func TestAPINewWikiPage(t *testing.T) { for _, title := range []string{ "New page", @@ -180,16 +193,7 @@ func TestAPINewWikiPage(t *testing.T) { defer tests.PrepareTestEnv(t)() username := "user2" session := loginUser(t, username) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - - urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", username, "repo1") - - req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{ - Title: title, - ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")), - Message: "", - }).AddTokenAuth(token) - MakeRequest(t, req, http.StatusCreated) + testAPICreateWikiPage(t, session, username, "repo1", title, http.StatusCreated) } } diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 4617c5f89a..bd0cedd300 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -174,7 +174,7 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, htmlDoc = NewHTMLParser(t, resp.Body) - val := htmlDoc.doc.Find(".comment-list .comment .render-content p").Eq(commentCount).Text() + val := strings.TrimSpace(htmlDoc.doc.Find(".comment-list .comment .render-content").Eq(commentCount).Text()) assert.Equal(t, content, val) idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id") diff --git a/tests/integration/repo_webhook_test.go b/tests/integration/repo_webhook_test.go index ef44a9e2d0..5a50d7d491 100644 --- a/tests/integration/repo_webhook_test.go +++ b/tests/integration/repo_webhook_test.go @@ -4,10 +4,23 @@ package integration import ( + "context" + "fmt" + "io" "net/http" + "net/http/httptest" + "net/url" "strings" "testing" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/json" + api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/tests" "github.com/PuerkitoBio/goquery" @@ -39,3 +52,555 @@ func TestNewWebHookLink(t *testing.T) { }) } } + +func testAPICreateWebhookForRepo(t *testing.T, session *TestSession, userName, repoName, url, event string) { + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) + req := NewRequestWithJSON(t, "POST", "/api/v1/repos/"+userName+"/"+repoName+"/hooks", api.CreateHookOption{ + Type: "gitea", + Config: api.CreateHookOptionConfig{ + "content_type": "json", + "url": url, + }, + Events: []string{event}, + Active: true, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) +} + +func testCreateWebhookForRepo(t *testing.T, session *TestSession, webhookType, userName, repoName, url, eventKind string) { + csrf := GetUserCSRFToken(t, session) + req := NewRequestWithValues(t, "POST", "/"+userName+"/"+repoName+"/settings/hooks/"+webhookType+"/new", map[string]string{ + "_csrf": csrf, + "payload_url": url, + "events": eventKind, + "active": "true", + "content_type": fmt.Sprintf("%d", webhook.ContentTypeJSON), + "http_method": "POST", + }) + session.MakeRequest(t, req, http.StatusSeeOther) +} + +func testAPICreateWebhookForOrg(t *testing.T, session *TestSession, userName, url, event string) { + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) + req := NewRequestWithJSON(t, "POST", "/api/v1/orgs/"+userName+"/hooks", api.CreateHookOption{ + Type: "gitea", + Config: api.CreateHookOptionConfig{ + "content_type": "json", + "url": url, + }, + Events: []string{event}, + Active: true, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) +} + +type mockWebhookProvider struct { + server *httptest.Server +} + +func newMockWebhookProvider(callback func(r *http.Request), status int) *mockWebhookProvider { + m := &mockWebhookProvider{} + m.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + callback(r) + w.WriteHeader(status) + })) + return m +} + +func (m *mockWebhookProvider) URL() string { + if m.server == nil { + return "" + } + return m.server.URL +} + +// Close closes the mock webhook http server +func (m *mockWebhookProvider) Close() { + if m.server != nil { + m.server.Close() + m.server = nil + } +} + +func Test_WebhookCreate(t *testing.T) { + var payloads []api.CreatePayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.CreatePayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = string(webhook_module.HookEventCreate) + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "create") + + // 2. trigger the webhook + testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + + // 3. validate the webhook is triggered + assert.Len(t, payloads, 1) + assert.EqualValues(t, string(webhook_module.HookEventCreate), triggeredEvent) + assert.EqualValues(t, "repo1", payloads[0].Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repo.FullName) + assert.EqualValues(t, "master2", payloads[0].Ref) + assert.EqualValues(t, "branch", payloads[0].RefType) + }) +} + +func Test_WebhookDelete(t *testing.T) { + var payloads []api.DeletePayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.DeletePayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "delete" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "delete") + + // 2. trigger the webhook + testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + testAPIDeleteBranch(t, "master2", http.StatusNoContent) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "delete", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "repo1", payloads[0].Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repo.FullName) + assert.EqualValues(t, "master2", payloads[0].Ref) + assert.EqualValues(t, "branch", payloads[0].RefType) + }) +} + +func Test_WebhookFork(t *testing.T) { + var payloads []api.ForkPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.ForkPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "fork" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user1") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "fork") + + // 2. trigger the webhook + testRepoFork(t, session, "user2", "repo1", "user1", "repo1-fork", "master") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "fork", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "repo1-fork", payloads[0].Repo.Name) + assert.EqualValues(t, "user1/repo1-fork", payloads[0].Repo.FullName) + assert.EqualValues(t, "repo1", payloads[0].Forkee.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Forkee.FullName) + }) +} + +func Test_WebhookIssueComment(t *testing.T) { + var payloads []api.IssueCommentPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.IssueCommentPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "issue_comment" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issue_comment") + + // 2. trigger the webhook + issueURL := testNewIssue(t, session, "user2", "repo1", "Title2", "Description2") + testIssueAddComment(t, session, issueURL, "issue title2 comment1", "") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "issue_comment", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "created", payloads[0].Action) + assert.EqualValues(t, "repo1", payloads[0].Issue.Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Issue.Repo.FullName) + assert.EqualValues(t, "Title2", payloads[0].Issue.Title) + assert.EqualValues(t, "Description2", payloads[0].Issue.Body) + assert.EqualValues(t, "issue title2 comment1", payloads[0].Comment.Body) + }) +} + +func Test_WebhookRelease(t *testing.T) { + var payloads []api.ReleasePayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.ReleasePayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "release" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "release") + + // 2. trigger the webhook + createNewRelease(t, session, "/user2/repo1", "v0.0.99", "v0.0.99", false, false) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "release", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "repo1", payloads[0].Repository.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repository.FullName) + assert.EqualValues(t, "v0.0.99", payloads[0].Release.TagName) + assert.False(t, payloads[0].Release.IsDraft) + assert.False(t, payloads[0].Release.IsPrerelease) + }) +} + +func Test_WebhookPush(t *testing.T) { + var payloads []api.PushPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.PushPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "push" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "push") + + // 2. trigger the webhook + testCreateFile(t, session, "user2", "repo1", "master", "test_webhook_push.md", "# a test file for webhook push") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "push", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "repo1", payloads[0].Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repo.FullName) + assert.Len(t, payloads[0].Commits, 1) + assert.EqualValues(t, []string{"test_webhook_push.md"}, payloads[0].Commits[0].Added) + }) +} + +func Test_WebhookIssue(t *testing.T) { + var payloads []api.IssuePayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.IssuePayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "issues" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "issues") + + // 2. trigger the webhook + testNewIssue(t, session, "user2", "repo1", "Title1", "Description1") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "issues", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "opened", payloads[0].Action) + assert.EqualValues(t, "repo1", payloads[0].Issue.Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Issue.Repo.FullName) + assert.EqualValues(t, "Title1", payloads[0].Issue.Title) + assert.EqualValues(t, "Description1", payloads[0].Issue.Body) + }) +} + +func Test_WebhookPullRequest(t *testing.T) { + var payloads []api.PullRequestPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.PullRequestPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "pull_request" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request") + + testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + // 2. trigger the webhook + repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) + testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "pull_request", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "repo1", payloads[0].PullRequest.Base.Repository.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].PullRequest.Base.Repository.FullName) + assert.EqualValues(t, "repo1", payloads[0].PullRequest.Head.Repository.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].PullRequest.Head.Repository.FullName) + assert.EqualValues(t, 0, payloads[0].PullRequest.Additions) + }) +} + +func Test_WebhookPullRequestComment(t *testing.T) { + var payloads []api.IssueCommentPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.IssueCommentPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "pull_request_comment" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request_comment") + + // 2. trigger the webhook + testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) + prID := testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request") + + testIssueAddComment(t, session, "/user2/repo1/pulls/"+prID, "pull title2 comment1", "") + + // 3. validate the webhook is triggered + assert.EqualValues(t, "pull_request_comment", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "created", payloads[0].Action) + assert.EqualValues(t, "repo1", payloads[0].Issue.Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Issue.Repo.FullName) + assert.EqualValues(t, "first pull request", payloads[0].Issue.Title) + assert.EqualValues(t, "", payloads[0].Issue.Body) + assert.EqualValues(t, "pull title2 comment1", payloads[0].Comment.Body) + }) +} + +func Test_WebhookWiki(t *testing.T) { + var payloads []api.WikiPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.WikiPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "wiki" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "wiki") + + // 2. trigger the webhook + testAPICreateWikiPage(t, session, "user2", "repo1", "Test Wiki Page", http.StatusCreated) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "wiki", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "created", payloads[0].Action) + assert.EqualValues(t, "repo1", payloads[0].Repository.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repository.FullName) + assert.EqualValues(t, "Test-Wiki-Page", payloads[0].Page) + }) +} + +func Test_WebhookRepository(t *testing.T) { + var payloads []api.RepositoryPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.RepositoryPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "repository" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user1") + + testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "repository") + + // 2. trigger the webhook + testAPIOrgCreateRepo(t, session, "org3", "repo_new", http.StatusCreated) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "repository", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "created", payloads[0].Action) + assert.EqualValues(t, "org3", payloads[0].Organization.UserName) + assert.EqualValues(t, "repo_new", payloads[0].Repository.Name) + assert.EqualValues(t, "org3/repo_new", payloads[0].Repository.FullName) + }) +} + +func Test_WebhookPackage(t *testing.T) { + var payloads []api.PackagePayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + content, _ := io.ReadAll(r.Body) + var payload api.PackagePayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "package" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user1") + + testAPICreateWebhookForOrg(t, session, "org3", provider.URL(), "package") + + // 2. trigger the webhook + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) + url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", "org3", "gitea", "v1.24.0") + req := NewRequestWithBody(t, "PUT", url+"/gitea", strings.NewReader("This is a dummy file")). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "package", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, "created", payloads[0].Action) + assert.EqualValues(t, "gitea", payloads[0].Package.Name) + assert.EqualValues(t, "generic", payloads[0].Package.Type) + assert.EqualValues(t, "org3", payloads[0].Organization.UserName) + assert.EqualValues(t, "v1.24.0", payloads[0].Package.Version) + }) +} + +func Test_WebhookStatus(t *testing.T) { + var payloads []api.CommitStatusPayload + var triggeredEvent string + provider := newMockWebhookProvider(func(r *http.Request) { + assert.Contains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should contain status") + assert.Contains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should contain status") + assert.Contains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should contain status") + assert.Contains(t, r.Header["X-Github-Event"], "status", "X-GitHub-Event should contain status") + assert.Contains(t, r.Header["X-Gitea-Event"], "status", "X-Gitea-Event should contain status") + assert.Contains(t, r.Header["X-Gogs-Event"], "status", "X-Gogs-Event should contain status") + content, _ := io.ReadAll(r.Body) + var payload api.CommitStatusPayload + err := json.Unmarshal(content, &payload) + assert.NoError(t, err) + payloads = append(payloads, payload) + triggeredEvent = "status" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "status") + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1}) + + gitRepo1, err := gitrepo.OpenRepository(context.Background(), repo1) + assert.NoError(t, err) + commitID, err := gitRepo1.GetBranchCommitID(repo1.DefaultBranch) + assert.NoError(t, err) + + // 2. trigger the webhook + testCtx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeAll) + + // update a status for a commit via API + doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{ + State: api.CommitStatusSuccess, + TargetURL: "http://test.ci/", + Description: "", + Context: "testci", + })(t) + + // 3. validate the webhook is triggered + assert.EqualValues(t, "status", triggeredEvent) + assert.Len(t, payloads, 1) + assert.EqualValues(t, commitID, payloads[0].Commit.ID) + assert.EqualValues(t, "repo1", payloads[0].Repo.Name) + assert.EqualValues(t, "user2/repo1", payloads[0].Repo.FullName) + assert.EqualValues(t, "testci", payloads[0].Context) + assert.EqualValues(t, commitID, payloads[0].SHA) + }) +} + +func Test_WebhookStatus_NoWrongTrigger(t *testing.T) { + var trigger string + provider := newMockWebhookProvider(func(r *http.Request) { + assert.NotContains(t, r.Header["X-Github-Event-Type"], "status", "X-GitHub-Event-Type should not contain status") + assert.NotContains(t, r.Header["X-Gitea-Event-Type"], "status", "X-Gitea-Event-Type should not contain status") + assert.NotContains(t, r.Header["X-Gogs-Event-Type"], "status", "X-Gogs-Event-Type should not contain status") + trigger = "push" + }, http.StatusOK) + defer provider.Close() + + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + // 1. create a new webhook with special webhook for repo1 + session := loginUser(t, "user2") + + // create a push_only webhook from web UI + testCreateWebhookForRepo(t, session, "gitea", "user2", "repo1", provider.URL(), "push_only") + + // 2. trigger the webhook with a push action + testCreateFile(t, session, "user2", "repo1", "master", "test_webhook_push.md", "# a test file for webhook push") + + // 3. validate the webhook is triggered with right event + assert.EqualValues(t, "push", trigger) + }) +} diff --git a/tests/mssql.ini.tmpl b/tests/mssql.ini.tmpl index 77c969e813..8b1593a396 100644 --- a/tests/mssql.ini.tmpl +++ b/tests/mssql.ini.tmpl @@ -26,6 +26,9 @@ TYPE = immediate [queue.push_update] TYPE = immediate +[queue.webhook_sender] +TYPE = immediate + [repository] ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/gitea-repositories @@ -112,3 +115,6 @@ ENABLED = true [actions] ENABLED = true + +[webhook] +ALLOWED_HOST_LIST = 127.0.0.1 diff --git a/tests/mysql.ini.tmpl b/tests/mysql.ini.tmpl index 0fddde46de..8cafba9591 100644 --- a/tests/mysql.ini.tmpl +++ b/tests/mysql.ini.tmpl @@ -28,6 +28,9 @@ TYPE = immediate [queue.push_update] TYPE = immediate +[queue.webhook_sender] +TYPE = immediate + [repository] ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/gitea-repositories @@ -119,3 +122,6 @@ REPLY_TO_ADDRESS = incoming+%{token}@localhost [actions] ENABLED = true + +[webhook] +ALLOWED_HOST_LIST = 127.0.0.1 diff --git a/tests/pgsql.ini.tmpl b/tests/pgsql.ini.tmpl index 695662c2e9..fb881d411c 100644 --- a/tests/pgsql.ini.tmpl +++ b/tests/pgsql.ini.tmpl @@ -27,6 +27,9 @@ TYPE = immediate [queue.push_update] TYPE = immediate +[queue.webhook_sender] +TYPE = immediate + [repository] ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/gitea-repositories @@ -128,3 +131,6 @@ ENABLED = true [actions] ENABLED = true + +[webhook] +ALLOWED_HOST_LIST = 127.0.0.1 diff --git a/tests/sqlite.ini.tmpl b/tests/sqlite.ini.tmpl index 1cbcd8b2e5..c0b3e1c859 100644 --- a/tests/sqlite.ini.tmpl +++ b/tests/sqlite.ini.tmpl @@ -22,6 +22,9 @@ TYPE = immediate [queue.push_update] TYPE = immediate +[queue.webhook_sender] +TYPE = immediate + [repository] ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea-repositories @@ -117,3 +120,6 @@ RENDER_CONTENT_MODE=sanitized [actions] ENABLED = true + +[webhook] +ALLOWED_HOST_LIST = 127.0.0.1