mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Add tests for webhook and fix some webhook bugs (#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.
This commit is contained in:
		| @@ -116,14 +116,7 @@ var ( | |||||||
| 	_ Payloader = &PackagePayload{} | 	_ Payloader = &PackagePayload{} | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // _________                        __ | // CreatePayload represents a payload information of create event. | ||||||
| // \_   ___ \_______   ____ _____ _/  |_  ____ |  | ||||||
| // /    \  \/\_  __ \_/ __ \\__  \\   __\/ __ \ |  | ||||||
| // \     \____|  | \/\  ___/ / __ \|  | \  ___/ |  | ||||||
| //  \______  /|__|    \___  >____  /__|  \___  > |  | ||||||
| //         \/             \/     \/          \/ |  | ||||||
|  |  | ||||||
| // CreatePayload FIXME |  | ||||||
| type CreatePayload struct { | type CreatePayload struct { | ||||||
| 	Sha     string      `json:"sha"` | 	Sha     string      `json:"sha"` | ||||||
| 	Ref     string      `json:"ref"` | 	Ref     string      `json:"ref"` | ||||||
| @@ -157,13 +150,6 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) { | |||||||
| 	return hook, nil | 	return hook, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // ________         .__          __ |  | ||||||
| // \______ \   ____ |  |   _____/  |_  ____ |  | ||||||
| //  |    |  \_/ __ \|  | _/ __ \   __\/ __ \ |  | ||||||
| //  |    `   \  ___/|  |_\  ___/|  | \  ___/ |  | ||||||
| // /_______  /\___  >____/\___  >__|  \___  > |  | ||||||
| //         \/     \/          \/          \/ |  | ||||||
|  |  | ||||||
| // PusherType define the type to push | // PusherType define the type to push | ||||||
| type PusherType string | type PusherType string | ||||||
|  |  | ||||||
| @@ -186,13 +172,6 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) { | |||||||
| 	return json.MarshalIndent(p, "", "  ") | 	return json.MarshalIndent(p, "", "  ") | ||||||
| } | } | ||||||
|  |  | ||||||
| // ___________           __ |  | ||||||
| // \_   _____/__________|  | __ |  | ||||||
| //  |    __)/  _ \_  __ \  |/ / |  | ||||||
| //  |     \(  <_> )  | \/    < |  | ||||||
| //  \___  / \____/|__|  |__|_ \ |  | ||||||
| //      \/                   \/ |  | ||||||
|  |  | ||||||
| // ForkPayload represents fork payload | // ForkPayload represents fork payload | ||||||
| type ForkPayload struct { | type ForkPayload struct { | ||||||
| 	Forkee *Repository `json:"forkee"` | 	Forkee *Repository `json:"forkee"` | ||||||
| @@ -232,13 +211,6 @@ func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { | |||||||
| 	return json.MarshalIndent(p, "", "  ") | 	return json.MarshalIndent(p, "", "  ") | ||||||
| } | } | ||||||
|  |  | ||||||
| // __________       .__ |  | ||||||
| // \______   \ ____ |  |   ____ _____    ______ ____ |  | ||||||
| //  |       _// __ \|  | _/ __ \\__  \  /  ___// __ \ |  | ||||||
| //  |    |   \  ___/|  |_\  ___/ / __ \_\___ \\  ___/ |  | ||||||
| //  |____|_  /\___  >____/\___  >____  /____  >\___  > |  | ||||||
| //         \/     \/          \/     \/     \/     \/ |  | ||||||
|  |  | ||||||
| // HookReleaseAction defines hook release action type | // HookReleaseAction defines hook release action type | ||||||
| type HookReleaseAction string | type HookReleaseAction string | ||||||
|  |  | ||||||
| @@ -302,13 +274,6 @@ func (p *PushPayload) Branch() string { | |||||||
| 	return strings.ReplaceAll(p.Ref, "refs/heads/", "") | 	return strings.ReplaceAll(p.Ref, "refs/heads/", "") | ||||||
| } | } | ||||||
|  |  | ||||||
| // .___ |  | ||||||
| // |   | ______ ________ __   ____ |  | ||||||
| // |   |/  ___//  ___/  |  \_/ __ \ |  | ||||||
| // |   |\___ \ \___ \|  |  /\  ___/ |  | ||||||
| // |___/____  >____  >____/  \___  > |  | ||||||
| //          \/     \/            \/ |  | ||||||
|  |  | ||||||
| // HookIssueAction FIXME | // HookIssueAction FIXME | ||||||
| type HookIssueAction string | type HookIssueAction string | ||||||
|  |  | ||||||
| @@ -371,13 +336,6 @@ type ChangesPayload struct { | |||||||
| 	Ref   *ChangesFromPayload `json:"ref,omitempty"` | 	Ref   *ChangesFromPayload `json:"ref,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // __________      .__  .__    __________                                     __ |  | ||||||
| // \______   \__ __|  | |  |   \______   \ ____  ________ __   ____   _______/  |_ |  | ||||||
| //  |     ___/  |  \  | |  |    |       _// __ \/ ____/  |  \_/ __ \ /  ___/\   __\ |  | ||||||
| //  |    |   |  |  /  |_|  |__  |    |   \  ___< <_|  |  |  /\  ___/ \___ \  |  | |  | ||||||
| //  |____|   |____/|____/____/  |____|_  /\___  >__   |____/  \___  >____  > |__| |  | ||||||
| //                                     \/     \/   |__|           \/     \/ |  | ||||||
|  |  | ||||||
| // PullRequestPayload represents a payload information of pull request event. | // PullRequestPayload represents a payload information of pull request event. | ||||||
| type PullRequestPayload struct { | type PullRequestPayload struct { | ||||||
| 	Action            HookIssueAction `json:"action"` | 	Action            HookIssueAction `json:"action"` | ||||||
| @@ -402,13 +360,6 @@ type ReviewPayload struct { | |||||||
| 	Content string `json:"content"` | 	Content string `json:"content"` | ||||||
| } | } | ||||||
|  |  | ||||||
| //  __      __.__ __   .__ |  | ||||||
| // /  \    /  \__|  | _|__| |  | ||||||
| // \   \/\/   /  |  |/ /  | |  | ||||||
| //  \        /|  |    <|  | |  | ||||||
| //   \__/\  / |__|__|_ \__| |  | ||||||
| //        \/          \/ |  | ||||||
|  |  | ||||||
| // HookWikiAction an action that happens to a wiki page | // HookWikiAction an action that happens to a wiki page | ||||||
| type HookWikiAction string | type HookWikiAction string | ||||||
|  |  | ||||||
| @@ -435,13 +386,6 @@ func (p *WikiPayload) JSONPayload() ([]byte, error) { | |||||||
| 	return json.MarshalIndent(p, "", " ") | 	return json.MarshalIndent(p, "", " ") | ||||||
| } | } | ||||||
|  |  | ||||||
| //__________                           .__  __ |  | ||||||
| //\______   \ ____ ______   ____  _____|__|/  |_  ___________ ___.__. |  | ||||||
| // |       _// __ \\____ \ /  _ \/  ___/  \   __\/  _ \_  __ <   |  | |  | ||||||
| // |    |   \  ___/|  |_> >  <_> )___ \|  ||  | (  <_> )  | \/\___  | |  | ||||||
| // |____|_  /\___  >   __/ \____/____  >__||__|  \____/|__|   / ____| |  | ||||||
| //        \/     \/|__|              \/                       \/ |  | ||||||
|  |  | ||||||
| // HookRepoAction an action that happens to a repo | // HookRepoAction an action that happens to a repo | ||||||
| type HookRepoAction string | type HookRepoAction string | ||||||
|  |  | ||||||
| @@ -480,7 +424,7 @@ type PackagePayload struct { | |||||||
| 	Action       HookPackageAction `json:"action"` | 	Action       HookPackageAction `json:"action"` | ||||||
| 	Repository   *Repository       `json:"repository"` | 	Repository   *Repository       `json:"repository"` | ||||||
| 	Package      *Package          `json:"package"` | 	Package      *Package          `json:"package"` | ||||||
| 	Organization *User             `json:"organization"` | 	Organization *Organization     `json:"organization"` | ||||||
| 	Sender       *User             `json:"sender"` | 	Sender       *User             `json:"sender"` | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -205,6 +205,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI | |||||||
| 				webhook_module.HookEventWiki:                     util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true), | 				webhook_module.HookEventWiki:                     util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true), | ||||||
| 				webhook_module.HookEventRepository:               util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true), | 				webhook_module.HookEventRepository:               util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true), | ||||||
| 				webhook_module.HookEventRelease:                  util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true), | 				webhook_module.HookEventRelease:                  util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true), | ||||||
|  | 				webhook_module.HookEventPackage:                  util.SliceContainsString(form.Events, string(webhook_module.HookEventPackage), true), | ||||||
| 				webhook_module.HookEventStatus:                   util.SliceContainsString(form.Events, string(webhook_module.HookEventStatus), true), | 				webhook_module.HookEventStatus:                   util.SliceContainsString(form.Events, string(webhook_module.HookEventStatus), true), | ||||||
| 			}, | 			}, | ||||||
| 			BranchFilter: form.BranchFilter, | 			BranchFilter: form.BranchFilter, | ||||||
| @@ -384,6 +385,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh | |||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestAssign] = pullHook(form.Events, string(webhook_module.HookEventPullRequestAssign)) | 	w.HookEvents[webhook_module.HookEventPullRequestAssign] = pullHook(form.Events, string(webhook_module.HookEventPullRequestAssign)) | ||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestLabel] = pullHook(form.Events, string(webhook_module.HookEventPullRequestLabel)) | 	w.HookEvents[webhook_module.HookEventPullRequestLabel] = pullHook(form.Events, string(webhook_module.HookEventPullRequestLabel)) | ||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestMilestone] = pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)) | 	w.HookEvents[webhook_module.HookEventPullRequestMilestone] = pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)) | ||||||
|  | 	w.HookEvents[webhook_module.HookEventPullRequestComment] = pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)) | ||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestReview] = pullHook(form.Events, "pull_request_review") | 	w.HookEvents[webhook_module.HookEventPullRequestReview] = pullHook(form.Events, "pull_request_review") | ||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestReviewRequest] = pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest)) | 	w.HookEvents[webhook_module.HookEventPullRequestReviewRequest] = pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest)) | ||||||
| 	w.HookEvents[webhook_module.HookEventPullRequestSync] = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync)) | 	w.HookEvents[webhook_module.HookEventPullRequestSync] = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync)) | ||||||
|   | |||||||
| @@ -190,3 +190,7 @@ func newDingtalkRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_ | |||||||
| 	var pc payloadConvertor[DingtalkPayload] = dingtalkConvertor{} | 	var pc payloadConvertor[DingtalkPayload] = dingtalkConvertor{} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.DINGTALK, newDingtalkRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -277,6 +277,10 @@ func newDiscordRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m | |||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.DISCORD, newDiscordRequest) | ||||||
|  | } | ||||||
|  |  | ||||||
| func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) { | func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) { | ||||||
| 	switch event { | 	switch event { | ||||||
| 	case webhook_module.HookEventPullRequestReviewApproved: | 	case webhook_module.HookEventPullRequestReviewApproved: | ||||||
|   | |||||||
| @@ -170,3 +170,7 @@ func newFeishuRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mo | |||||||
| 	var pc payloadConvertor[FeishuPayload] = feishuConvertor{} | 	var pc payloadConvertor[FeishuPayload] = feishuConvertor{} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.FEISHU, newFeishuRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -319,8 +319,8 @@ func packageTestPayload() *api.PackagePayload { | |||||||
| 			AvatarURL: "http://localhost:3000/user1/avatar", | 			AvatarURL: "http://localhost:3000/user1/avatar", | ||||||
| 		}, | 		}, | ||||||
| 		Repository: nil, | 		Repository: nil, | ||||||
| 		Organization: &api.User{ | 		Organization: &api.Organization{ | ||||||
| 			UserName:  "org1", | 			Name:      "org1", | ||||||
| 			AvatarURL: "http://localhost:3000/org1/avatar", | 			AvatarURL: "http://localhost:3000/org1/avatar", | ||||||
| 		}, | 		}, | ||||||
| 		Package: &api.Package{ | 		Package: &api.Package{ | ||||||
|   | |||||||
| @@ -24,6 +24,10 @@ import ( | |||||||
| 	webhook_module "code.gitea.io/gitea/modules/webhook" | 	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) { | func newMatrixRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) { | ||||||
| 	meta := &MatrixMeta{} | 	meta := &MatrixMeta{} | ||||||
| 	if err := json.Unmarshal([]byte(w.Meta), meta); err != nil { | 	if err := json.Unmarshal([]byte(w.Meta), meta); err != nil { | ||||||
|   | |||||||
| @@ -349,3 +349,7 @@ func newMSTeamsRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_m | |||||||
| 	var pc payloadConvertor[MSTeamsPayload] = msteamsConvertor{} | 	var pc payloadConvertor[MSTeamsPayload] = msteamsConvertor{} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.MSTEAMS, newMSTeamsRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import ( | |||||||
|  |  | ||||||
| 	git_model "code.gitea.io/gitea/models/git" | 	git_model "code.gitea.io/gitea/models/git" | ||||||
| 	issues_model "code.gitea.io/gitea/models/issues" | 	issues_model "code.gitea.io/gitea/models/issues" | ||||||
|  | 	"code.gitea.io/gitea/models/organization" | ||||||
| 	packages_model "code.gitea.io/gitea/models/packages" | 	packages_model "code.gitea.io/gitea/models/packages" | ||||||
| 	"code.gitea.io/gitea/models/perm" | 	"code.gitea.io/gitea/models/perm" | ||||||
| 	access_model "code.gitea.io/gitea/models/perm/access" | 	access_model "code.gitea.io/gitea/models/perm/access" | ||||||
| @@ -920,10 +921,16 @@ func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_mo | |||||||
| 		return | 		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{ | 	if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{ | ||||||
| 		Action:  action, | 		Action:       action, | ||||||
| 		Package: apiPackage, | 		Package:      apiPackage, | ||||||
| 		Sender:  convert.ToUser(ctx, sender, nil), | 		Organization: org, | ||||||
|  | 		Sender:       convert.ToUser(ctx, sender, nil), | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		log.Error("PrepareWebhooks: %v", err) | 		log.Error("PrepareWebhooks: %v", err) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -120,3 +120,7 @@ func newPackagistRequest(_ context.Context, w *webhook_model.Webhook, t *webhook | |||||||
| 	} | 	} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.PACKAGIST, newPackagistRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -295,6 +295,10 @@ func newSlackRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mod | |||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.SLACK, newSlackRequest) | ||||||
|  | } | ||||||
|  |  | ||||||
| var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`) | var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`) | ||||||
|  |  | ||||||
| // IsValidSlackChannel validates a channel name conforms to what slack expects: | // IsValidSlackChannel validates a channel name conforms to what slack expects: | ||||||
|   | |||||||
| @@ -187,3 +187,7 @@ func newTelegramRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_ | |||||||
| 	var pc payloadConvertor[TelegramPayload] = telegramConvertor{} | 	var pc payloadConvertor[TelegramPayload] = telegramConvertor{} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.TELEGRAM, newTelegramRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -27,16 +27,12 @@ import ( | |||||||
| 	"github.com/gobwas/glob" | 	"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){ | type Requester func(context.Context, *webhook_model.Webhook, *webhook_model.HookTask) (req *http.Request, body []byte, err error) | ||||||
| 	webhook_module.SLACK:      newSlackRequest, |  | ||||||
| 	webhook_module.DISCORD:    newDiscordRequest, | var webhookRequesters = map[webhook_module.HookType]Requester{} | ||||||
| 	webhook_module.DINGTALK:   newDingtalkRequest, |  | ||||||
| 	webhook_module.TELEGRAM:   newTelegramRequest, | func RegisterWebhookRequester(hookType webhook_module.HookType, requester Requester) { | ||||||
| 	webhook_module.MSTEAMS:    newMSTeamsRequest, | 	webhookRequesters[hookType] = requester | ||||||
| 	webhook_module.FEISHU:     newFeishuRequest, |  | ||||||
| 	webhook_module.MATRIX:     newMatrixRequest, |  | ||||||
| 	webhook_module.WECHATWORK: newWechatworkRequest, |  | ||||||
| 	webhook_module.PACKAGIST:  newPackagistRequest, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // IsValidHookTaskType returns true if a webhook registered | // IsValidHookTaskType returns true if a webhook registered | ||||||
|   | |||||||
| @@ -179,3 +179,7 @@ func newWechatworkRequest(_ context.Context, w *webhook_model.Webhook, t *webhoo | |||||||
| 	var pc payloadConvertor[WechatworkPayload] = wechatworkConvertor{} | 	var pc payloadConvertor[WechatworkPayload] = wechatworkConvertor{} | ||||||
| 	return newJSONRequest(pc, w, t, true) | 	return newJSONRequest(pc, w, t, true) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	RegisterWebhookRequester(webhook_module.WECHATWORK, newWechatworkRequest) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -471,6 +471,15 @@ func TestAPIMirrorSyncNonMirrorRepo(t *testing.T) { | |||||||
| 	assert.Equal(t, "Repository is not a mirror", errRespJSON["message"]) | 	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) { | func TestAPIOrgRepoCreate(t *testing.T) { | ||||||
| 	testCases := []struct { | 	testCases := []struct { | ||||||
| 		ctxUserID         int64 | 		ctxUserID         int64 | ||||||
| @@ -488,11 +497,7 @@ func TestAPIOrgRepoCreate(t *testing.T) { | |||||||
| 	for _, testCase := range testCases { | 	for _, testCase := range testCases { | ||||||
| 		user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) | 		user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) | ||||||
| 		session := loginUser(t, user.Name) | 		session := loginUser(t, user.Name) | ||||||
| 		token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization, auth_model.AccessTokenScopeWriteRepository) | 		testAPIOrgCreateRepo(t, session, testCase.orgName, testCase.repoName, testCase.expectedStatus) | ||||||
| 		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) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -172,6 +172,19 @@ func TestAPIListWikiPages(t *testing.T) { | |||||||
| 	assert.Equal(t, dummymeta, meta) | 	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) { | func TestAPINewWikiPage(t *testing.T) { | ||||||
| 	for _, title := range []string{ | 	for _, title := range []string{ | ||||||
| 		"New page", | 		"New page", | ||||||
| @@ -180,16 +193,7 @@ func TestAPINewWikiPage(t *testing.T) { | |||||||
| 		defer tests.PrepareTestEnv(t)() | 		defer tests.PrepareTestEnv(t)() | ||||||
| 		username := "user2" | 		username := "user2" | ||||||
| 		session := loginUser(t, username) | 		session := loginUser(t, username) | ||||||
| 		token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) | 		testAPICreateWikiPage(t, session, username, "repo1", title, http.StatusCreated) | ||||||
|  |  | ||||||
| 		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) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -174,7 +174,7 @@ func testIssueAddComment(t *testing.T, session *TestSession, issueURL, content, | |||||||
|  |  | ||||||
| 	htmlDoc = NewHTMLParser(t, resp.Body) | 	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) | 	assert.Equal(t, content, val) | ||||||
|  |  | ||||||
| 	idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id") | 	idAttr, has := htmlDoc.doc.Find(".comment-list .comment").Eq(commentCount).Attr("id") | ||||||
|   | |||||||
| @@ -4,10 +4,22 @@ | |||||||
| package integration | package integration | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"net/http/httptest" | ||||||
|  | 	"net/url" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"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/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" | 	"code.gitea.io/gitea/tests" | ||||||
|  |  | ||||||
| 	"github.com/PuerkitoBio/goquery" | 	"github.com/PuerkitoBio/goquery" | ||||||
| @@ -39,3 +51,514 @@ 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 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") | ||||||
|  | 		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) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -26,6 +26,9 @@ TYPE = immediate | |||||||
| [queue.push_update] | [queue.push_update] | ||||||
| TYPE = immediate | TYPE = immediate | ||||||
|  |  | ||||||
|  | [queue.webhook_sender] | ||||||
|  | TYPE = immediate | ||||||
|  |  | ||||||
| [repository] | [repository] | ||||||
| ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/gitea-repositories | ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mssql/gitea-repositories | ||||||
|  |  | ||||||
| @@ -111,3 +114,6 @@ ENABLED = true | |||||||
|  |  | ||||||
| [actions] | [actions] | ||||||
| ENABLED = true | ENABLED = true | ||||||
|  |  | ||||||
|  | [webhook] | ||||||
|  | ALLOWED_HOST_LIST = 127.0.0.1 | ||||||
|   | |||||||
| @@ -28,6 +28,9 @@ TYPE = immediate | |||||||
| [queue.push_update] | [queue.push_update] | ||||||
| TYPE = immediate | TYPE = immediate | ||||||
|  |  | ||||||
|  | [queue.webhook_sender] | ||||||
|  | TYPE = immediate | ||||||
|  |  | ||||||
| [repository] | [repository] | ||||||
| ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/gitea-repositories | ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/gitea-repositories | ||||||
|  |  | ||||||
| @@ -118,3 +121,6 @@ REPLY_TO_ADDRESS = incoming+%{token}@localhost | |||||||
|  |  | ||||||
| [actions] | [actions] | ||||||
| ENABLED = true | ENABLED = true | ||||||
|  |  | ||||||
|  | [webhook] | ||||||
|  | ALLOWED_HOST_LIST = 127.0.0.1 | ||||||
|   | |||||||
| @@ -27,6 +27,9 @@ TYPE = immediate | |||||||
| [queue.push_update] | [queue.push_update] | ||||||
| TYPE = immediate | TYPE = immediate | ||||||
|  |  | ||||||
|  | [queue.webhook_sender] | ||||||
|  | TYPE = immediate | ||||||
|  |  | ||||||
| [repository] | [repository] | ||||||
| ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/gitea-repositories | ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/gitea-repositories | ||||||
|  |  | ||||||
| @@ -127,3 +130,6 @@ ENABLED = true | |||||||
|  |  | ||||||
| [actions] | [actions] | ||||||
| ENABLED = true | ENABLED = true | ||||||
|  |  | ||||||
|  | [webhook] | ||||||
|  | ALLOWED_HOST_LIST = 127.0.0.1 | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ TYPE = immediate | |||||||
| [queue.push_update] | [queue.push_update] | ||||||
| TYPE = immediate | TYPE = immediate | ||||||
|  |  | ||||||
|  | [queue.webhook_sender] | ||||||
|  | TYPE = immediate | ||||||
|  |  | ||||||
| [repository] | [repository] | ||||||
| ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea-repositories | ROOT = {{REPO_TEST_DIR}}tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-sqlite/gitea-repositories | ||||||
|  |  | ||||||
| @@ -116,3 +119,6 @@ RENDER_CONTENT_MODE=sanitized | |||||||
|  |  | ||||||
| [actions] | [actions] | ||||||
| ENABLED = true | ENABLED = true | ||||||
|  |  | ||||||
|  | [webhook] | ||||||
|  | ALLOWED_HOST_LIST = 127.0.0.1 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Lunny Xiao
					Lunny Xiao