Skip to content

Commit a3aab25

Browse files
committed
Add tests for webhook and fix some webhook bugs (go-gitea#33396)
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.
1 parent b6fd874 commit a3aab25

23 files changed

+631
-89
lines changed

modules/structs/hook.go

+2-58
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,7 @@ var (
116116
_ Payloader = &PackagePayload{}
117117
)
118118

119-
// _________ __
120-
// \_ ___ \_______ ____ _____ _/ |_ ____
121-
// / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
122-
// \ \____| | \/\ ___/ / __ \| | \ ___/
123-
// \______ /|__| \___ >____ /__| \___ >
124-
// \/ \/ \/ \/
125-
126-
// CreatePayload FIXME
119+
// CreatePayload represents a payload information of create event.
127120
type CreatePayload struct {
128121
Sha string `json:"sha"`
129122
Ref string `json:"ref"`
@@ -157,13 +150,6 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) {
157150
return hook, nil
158151
}
159152

160-
// ________ .__ __
161-
// \______ \ ____ | | _____/ |_ ____
162-
// | | \_/ __ \| | _/ __ \ __\/ __ \
163-
// | ` \ ___/| |_\ ___/| | \ ___/
164-
// /_______ /\___ >____/\___ >__| \___ >
165-
// \/ \/ \/ \/
166-
167153
// PusherType define the type to push
168154
type PusherType string
169155

@@ -186,13 +172,6 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) {
186172
return json.MarshalIndent(p, "", " ")
187173
}
188174

189-
// ___________ __
190-
// \_ _____/__________| | __
191-
// | __)/ _ \_ __ \ |/ /
192-
// | \( <_> ) | \/ <
193-
// \___ / \____/|__| |__|_ \
194-
// \/ \/
195-
196175
// ForkPayload represents fork payload
197176
type ForkPayload struct {
198177
Forkee *Repository `json:"forkee"`
@@ -232,13 +211,6 @@ func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
232211
return json.MarshalIndent(p, "", " ")
233212
}
234213

235-
// __________ .__
236-
// \______ \ ____ | | ____ _____ ______ ____
237-
// | _// __ \| | _/ __ \\__ \ / ___// __ \
238-
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
239-
// |____|_ /\___ >____/\___ >____ /____ >\___ >
240-
// \/ \/ \/ \/ \/ \/
241-
242214
// HookReleaseAction defines hook release action type
243215
type HookReleaseAction string
244216

@@ -302,13 +274,6 @@ func (p *PushPayload) Branch() string {
302274
return strings.ReplaceAll(p.Ref, "refs/heads/", "")
303275
}
304276

305-
// .___
306-
// | | ______ ________ __ ____
307-
// | |/ ___// ___/ | \_/ __ \
308-
// | |\___ \ \___ \| | /\ ___/
309-
// |___/____ >____ >____/ \___ >
310-
// \/ \/ \/
311-
312277
// HookIssueAction FIXME
313278
type HookIssueAction string
314279

@@ -371,13 +336,6 @@ type ChangesPayload struct {
371336
Ref *ChangesFromPayload `json:"ref,omitempty"`
372337
}
373338

374-
// __________ .__ .__ __________ __
375-
// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
376-
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
377-
// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
378-
// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
379-
// \/ \/ |__| \/ \/
380-
381339
// PullRequestPayload represents a payload information of pull request event.
382340
type PullRequestPayload struct {
383341
Action HookIssueAction `json:"action"`
@@ -402,13 +360,6 @@ type ReviewPayload struct {
402360
Content string `json:"content"`
403361
}
404362

405-
// __ __.__ __ .__
406-
// / \ / \__| | _|__|
407-
// \ \/\/ / | |/ / |
408-
// \ /| | <| |
409-
// \__/\ / |__|__|_ \__|
410-
// \/ \/
411-
412363
// HookWikiAction an action that happens to a wiki page
413364
type HookWikiAction string
414365

@@ -435,13 +386,6 @@ func (p *WikiPayload) JSONPayload() ([]byte, error) {
435386
return json.MarshalIndent(p, "", " ")
436387
}
437388

438-
//__________ .__ __
439-
//\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
440-
// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |
441-
// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ |
442-
// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
443-
// \/ \/|__| \/ \/
444-
445389
// HookRepoAction an action that happens to a repo
446390
type HookRepoAction string
447391

@@ -480,7 +424,7 @@ type PackagePayload struct {
480424
Action HookPackageAction `json:"action"`
481425
Repository *Repository `json:"repository"`
482426
Package *Package `json:"package"`
483-
Organization *User `json:"organization"`
427+
Organization *Organization `json:"organization"`
484428
Sender *User `json:"sender"`
485429
}
486430

modules/webhook/structs.go

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type HookEvents struct {
2626
Repository bool `json:"repository"`
2727
Release bool `json:"release"`
2828
Package bool `json:"package"`
29+
Status bool `json:"status"`
2930
}
3031

3132
// HookEvent represents events that will delivery hook.

routers/api/v1/utils/hook.go

+2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
205205
Wiki: util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true),
206206
Repository: util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true),
207207
Release: util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true),
208+
Package: util.SliceContainsString(form.Events, string(webhook_module.HookEventPackage), true),
209+
Status: util.SliceContainsString(form.Events, string(webhook_module.HookEventStatus), true),
208210
},
209211
BranchFilter: form.BranchFilter,
210212
},

services/webhook/dingtalk.go

+4
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,7 @@ func newDingtalkRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_
190190
var pc payloadConvertor[DingtalkPayload] = dingtalkConvertor{}
191191
return newJSONRequest(pc, w, t, true)
192192
}
193+
194+
func init() {
195+
RegisterWebhookRequester(webhook_module.DINGTALK, newDingtalkRequest)
196+
}

services/webhook/discord.go

+4
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ func newDiscordRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m
277277
return newJSONRequest(pc, w, t, true)
278278
}
279279

280+
func init() {
281+
RegisterWebhookRequester(webhook_module.DISCORD, newDiscordRequest)
282+
}
283+
280284
func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) {
281285
switch event {
282286
case webhook_module.HookEventPullRequestReviewApproved:

services/webhook/feishu.go

+4
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,7 @@ func newFeishuRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mo
170170
var pc payloadConvertor[FeishuPayload] = feishuConvertor{}
171171
return newJSONRequest(pc, w, t, true)
172172
}
173+
174+
func init() {
175+
RegisterWebhookRequester(webhook_module.FEISHU, newFeishuRequest)
176+
}

services/webhook/general_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ func packageTestPayload() *api.PackagePayload {
319319
AvatarURL: "http://localhost:3000/user1/avatar",
320320
},
321321
Repository: nil,
322-
Organization: &api.User{
323-
UserName: "org1",
322+
Organization: &api.Organization{
323+
Name: "org1",
324324
AvatarURL: "http://localhost:3000/org1/avatar",
325325
},
326326
Package: &api.Package{

services/webhook/matrix.go

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import (
2424
webhook_module "code.gitea.io/gitea/modules/webhook"
2525
)
2626

27+
func init() {
28+
RegisterWebhookRequester(webhook_module.MATRIX, newMatrixRequest)
29+
}
30+
2731
func newMatrixRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) {
2832
meta := &MatrixMeta{}
2933
if err := json.Unmarshal([]byte(w.Meta), meta); err != nil {

services/webhook/msteams.go

+4
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,7 @@ func newMSTeamsRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m
349349
var pc payloadConvertor[MSTeamsPayload] = msteamsConvertor{}
350350
return newJSONRequest(pc, w, t, true)
351351
}
352+
353+
func init() {
354+
RegisterWebhookRequester(webhook_module.MSTEAMS, newMSTeamsRequest)
355+
}

services/webhook/notifier.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
git_model "code.gitea.io/gitea/models/git"
1010
issues_model "code.gitea.io/gitea/models/issues"
11+
"code.gitea.io/gitea/models/organization"
1112
packages_model "code.gitea.io/gitea/models/packages"
1213
"code.gitea.io/gitea/models/perm"
1314
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
924925
return
925926
}
926927

928+
var org *api.Organization
929+
if pd.Owner.IsOrganization() {
930+
org = convert.ToOrganization(ctx, organization.OrgFromUser(pd.Owner))
931+
}
932+
927933
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{
928-
Action: action,
929-
Package: apiPackage,
930-
Sender: convert.ToUser(ctx, sender, nil),
934+
Action: action,
935+
Package: apiPackage,
936+
Organization: org,
937+
Sender: convert.ToUser(ctx, sender, nil),
931938
}); err != nil {
932939
log.Error("PrepareWebhooks: %v", err)
933940
}

services/webhook/packagist.go

+4
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,7 @@ func newPackagistRequest(_ context.Context, w *webhook_model.Webhook, t *webhook
120120
}
121121
return newJSONRequest(pc, w, t, true)
122122
}
123+
124+
func init() {
125+
RegisterWebhookRequester(webhook_module.PACKAGIST, newPackagistRequest)
126+
}

services/webhook/slack.go

+4
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,10 @@ func newSlackRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mod
295295
return newJSONRequest(pc, w, t, true)
296296
}
297297

298+
func init() {
299+
RegisterWebhookRequester(webhook_module.SLACK, newSlackRequest)
300+
}
301+
298302
var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`)
299303

300304
// IsValidSlackChannel validates a channel name conforms to what slack expects:

services/webhook/telegram.go

+4
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,7 @@ func newTelegramRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_
187187
var pc payloadConvertor[TelegramPayload] = telegramConvertor{}
188188
return newJSONRequest(pc, w, t, true)
189189
}
190+
191+
func init() {
192+
RegisterWebhookRequester(webhook_module.TELEGRAM, newTelegramRequest)
193+
}

services/webhook/webhook.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,12 @@ import (
2727
"github.com/gobwas/glob"
2828
)
2929

30-
var webhookRequesters = map[webhook_module.HookType]func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error){
31-
webhook_module.SLACK: newSlackRequest,
32-
webhook_module.DISCORD: newDiscordRequest,
33-
webhook_module.DINGTALK: newDingtalkRequest,
34-
webhook_module.TELEGRAM: newTelegramRequest,
35-
webhook_module.MSTEAMS: newMSTeamsRequest,
36-
webhook_module.FEISHU: newFeishuRequest,
37-
webhook_module.MATRIX: newMatrixRequest,
38-
webhook_module.WECHATWORK: newWechatworkRequest,
39-
webhook_module.PACKAGIST: newPackagistRequest,
30+
type Requester func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error)
31+
32+
var webhookRequesters = map[webhook_module.HookType]Requester{}
33+
34+
func RegisterWebhookRequester(hookType webhook_module.HookType, requester Requester) {
35+
webhookRequesters[hookType] = requester
4036
}
4137

4238
// IsValidHookTaskType returns true if a webhook registered

services/webhook/wechatwork.go

+4
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,7 @@ func newWechatworkRequest(_ context.Context, w *webhook_model.Webhook, t *webhoo
179179
var pc payloadConvertor[WechatworkPayload] = wechatworkConvertor{}
180180
return newJSONRequest(pc, w, t, true)
181181
}
182+
183+
func init() {
184+
RegisterWebhookRequester(webhook_module.WECHATWORK, newWechatworkRequest)
185+
}

tests/integration/api_repo_test.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,15 @@ func TestAPIMirrorSyncNonMirrorRepo(t *testing.T) {
471471
assert.Equal(t, "Repository is not a mirror", errRespJSON["message"])
472472
}
473473

474+
func testAPIOrgCreateRepo(t *testing.T, session *TestSession, orgName, repoName string, status int) {
475+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
476+
477+
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", orgName), &api.CreateRepoOption{
478+
Name: repoName,
479+
}).AddTokenAuth(token)
480+
MakeRequest(t, req, status)
481+
}
482+
474483
func TestAPIOrgRepoCreate(t *testing.T) {
475484
testCases := []struct {
476485
ctxUserID int64
@@ -488,11 +497,7 @@ func TestAPIOrgRepoCreate(t *testing.T) {
488497
for _, testCase := range testCases {
489498
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID})
490499
session := loginUser(t, user.Name)
491-
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository)
492-
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos", testCase.orgName), &api.CreateRepoOption{
493-
Name: testCase.repoName,
494-
}).AddTokenAuth(token)
495-
MakeRequest(t, req, testCase.expectedStatus)
500+
testAPIOrgCreateRepo(t, session, testCase.orgName, testCase.repoName, testCase.expectedStatus)
496501
}
497502
}
498503

tests/integration/api_wiki_test.go

+14-10
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,19 @@ func TestAPIListWikiPages(t *testing.T) {
172172
assert.Equal(t, dummymeta, meta)
173173
}
174174

175+
func testAPICreateWikiPage(t *testing.T, session *TestSession, userName, repoName, title string, status int) {
176+
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
177+
178+
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", userName, repoName)
179+
180+
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
181+
Title: title,
182+
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
183+
Message: "",
184+
}).AddTokenAuth(token)
185+
MakeRequest(t, req, status)
186+
}
187+
175188
func TestAPINewWikiPage(t *testing.T) {
176189
for _, title := range []string{
177190
"New page",
@@ -180,16 +193,7 @@ func TestAPINewWikiPage(t *testing.T) {
180193
defer tests.PrepareTestEnv(t)()
181194
username := "user2"
182195
session := loginUser(t, username)
183-
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
184-
185-
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", username, "repo1")
186-
187-
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
188-
Title: title,
189-
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
190-
Message: "",
191-
}).AddTokenAuth(token)
192-
MakeRequest(t, req, http.StatusCreated)
196+
testAPICreateWikiPage(t, session, username, "repo1", title, http.StatusCreated)
193197
}
194198
}
195199

tests/integration/issue_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content,
174174

175175
htmlDoc = NewHTMLParser(t, resp.Body)
176176

177-
val := htmlDoc.doc.Find(".comment-list .comment .render-content p").Eq(commentCount).Text()
177+
val := strings.TrimSpace(htmlDoc.doc.Find(".comment-list .comment .render-content").Eq(commentCount).Text())
178178
assert.Equal(t, content, val)
179179

180180
idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id")

0 commit comments

Comments
 (0)