Changes
20 changed files (+416/-3)
-
-
@@ -28,6 +28,7 @@ All event pushes are POST requests. The methods currently supported are:- Microsoft Teams - Feishu - Wechatwork - Packagist ### Event information
-
-
-
@@ -27,5 +27,6 @@ Gitea 的存储 webhook。这可以有存储库管路设定页 `/:username/:repo- Microsoft Teams - Feishu - Wechatwork - Packagist ## TBD
-
-
-
@@ -27,6 +27,7 @@ Gitea 的儲存庫事件支援 web hook。這可以有儲存庫管理員在設- Microsoft Teams - Feishu - Wechatwork - Packagist ### 事件資訊
-
-
-
@@ -161,6 +161,7 @@ const (FEISHU HookType = "feishu" MATRIX HookType = "matrix" WECHATWORK HookType = "wechatwork" PACKAGIST HookType = "packagist" ) // HookStatus is the status of a web hook
-
-
-
@@ -36,7 +36,7 @@ func newWebhookService() {Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() Webhook.AllowedHostList = sec.Key("ALLOWED_HOST_LIST").MustString("") Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork"} Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork", "packagist"} Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("") if Webhook.ProxyURL != "" {
-
-
-
@@ -40,7 +40,7 @@ type CreateHookOptionConfig map[string]string// CreateHookOption options when create a hook type CreateHookOption struct { // required: true // enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork // enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork,packagist Type string `json:"type" binding:"Required"` // required: true Config CreateHookOptionConfig `json:"config" binding:"Required"`
-
-
-
@@ -1947,6 +1947,10 @@ settings.add_matrix_hook_desc = Integrate <a href="%s">Matrix</a> into your reposettings.add_msteams_hook_desc = Integrate <a href="%s">Microsoft Teams</a> into your repository. settings.add_feishu_hook_desc = Integrate <a href="%s">Feishu</a> into your repository. settings.add_Wechat_hook_desc = Integrate <a href="%s">Wechatwork</a> into your repository. settings.add_packagist_hook_desc = Integrate <a href="%s">Packagist</a> into your repository. settings.packagist_username = Packagist username settings.packagist_api_token = API token settings.packagist_package_url = Packagist package URL settings.deploy_keys = Deploy Keys settings.add_deploy_key = Add Deploy Key settings.deploy_key_desc = Deploy keys have read-only pull access to the repository.
-
-
public/img/packagist.png (new)
-
-
@@ -682,6 +682,59 @@ func WechatworkHooksNewPost(ctx *context.Context) {ctx.Redirect(orCtx.Link) } // PackagistHooksNewPost response for creating packagist hook func PackagistHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewPackagistHookForm) ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} ctx.Data["HookType"] = webhook.PACKAGIST orCtx, err := getOrgRepoCtx(ctx) if err != nil { ctx.ServerError("getOrgRepoCtx", err) return } if ctx.HasError() { ctx.HTML(http.StatusOK, orCtx.NewTemplate) return } meta, err := json.Marshal(&webhook_service.PackagistMeta{ Username: form.Username, APIToken: form.APIToken, PackageURL: form.PackageURL, }) if err != nil { ctx.ServerError("Marshal", err) return } w := &webhook.Webhook{ RepoID: orCtx.RepoID, URL: fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)), ContentType: webhook.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, Type: webhook.PACKAGIST, Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) return } else if err := webhook.CreateWebhook(db.DefaultContext, w); err != nil { ctx.ServerError("CreateWebhook", err) return } ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) ctx.Redirect(orCtx.Link) } func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) { ctx.Data["RequireHighlightJS"] = true
-
@@ -719,6 +772,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) {ctx.Data["TelegramHook"] = webhook_service.GetTelegramHook(w) case webhook.MATRIX: ctx.Data["MatrixHook"] = webhook_service.GetMatrixHook(w) case webhook.PACKAGIST: ctx.Data["PackagistHook"] = webhook_service.GetPackagistHook(w) } ctx.Data["History"], err = w.History(1)
-
@@ -1137,6 +1192,50 @@ func WechatworkHooksEditPost(ctx *context.Context) {ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) } // PackagistHooksEditPost response for editing packagist hook func PackagistHooksEditPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewPackagistHookForm) ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksEdit"] = true orCtx, w := checkWebhook(ctx) if ctx.Written() { return } ctx.Data["Webhook"] = w if ctx.HasError() { ctx.HTML(http.StatusOK, orCtx.NewTemplate) return } meta, err := json.Marshal(&webhook_service.PackagistMeta{ Username: form.Username, APIToken: form.APIToken, PackageURL: form.PackageURL, }) if err != nil { ctx.ServerError("Marshal", err) return } w.Meta = string(meta) w.URL = fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)) w.HookEvent = ParseHookEvent(form.WebhookForm) w.IsActive = form.Active if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) return } else if err := webhook.UpdateWebhook(w); err != nil { ctx.ServerError("UpdateWebhook", err) return } ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) } // TestWebhook test if web hook is work fine func TestWebhook(ctx *context.Context) { hookID := ctx.ParamsInt64(":id")
-
-
-
@@ -448,6 +448,7 @@ func RegisterRoutes(m *web.Route) {m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) }, webhooksEnabled) m.Group("/{configType:default-hooks|system-hooks}", func() {
-
@@ -462,6 +463,7 @@ func RegisterRoutes(m *web.Route) {m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) }) m.Group("/auths", func() {
-
@@ -657,6 +659,7 @@ func RegisterRoutes(m *web.Route) {m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) m.Group("/{id}", func() { m.Get("", repo.WebHooksEdit) m.Post("/test", repo.TestWebhook)
-
@@ -672,6 +675,7 @@ func RegisterRoutes(m *web.Route) {m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) }, webhooksEnabled) m.Group("/keys", func() {
-
-
-
@@ -396,6 +396,20 @@ func (f *NewWechatWorkHookForm) Validate(req *http.Request, errs binding.Errors)return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } // NewPackagistHookForm form for creating packagist hook type NewPackagistHookForm struct { Username string `binding:"Required"` APIToken string `binding:"Required"` PackageURL string `binding:"Required;ValidUrl"` WebhookForm } // Validate validates the fields func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { ctx := context.GetContext(req) return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } // .___ // | | ______ ________ __ ____ // | |/ ___// ___/ | \_/ __ \
-
-
-
@@ -0,0 +1,112 @@// Copyright 2022 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package webhook import ( "errors" webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" ) type ( // PackagistPayload represents PackagistPayload struct { PackagistRepository struct { URL string `json:"url"` } `json:"repository"` } // PackagistMeta contains the meta data for the webhook PackagistMeta struct { Username string `json:"username"` APIToken string `json:"api_token"` PackageURL string `json:"package_url"` } ) // GetPackagistHook returns packagist metadata func GetPackagistHook(w *webhook_model.Webhook) *PackagistMeta { s := &PackagistMeta{} if err := json.Unmarshal([]byte(w.Meta), s); err != nil { log.Error("webhook.GetPackagistHook(%d): %v", w.ID, err) } return s } // JSONPayload Marshals the PackagistPayload to json func (f *PackagistPayload) JSONPayload() ([]byte, error) { data, err := json.MarshalIndent(f, "", " ") if err != nil { return []byte{}, err } return data, nil } var _ PayloadConvertor = &PackagistPayload{} // Create implements PayloadConvertor Create method func (f *PackagistPayload) Create(p *api.CreatePayload) (api.Payloader, error) { return nil, nil } // Delete implements PayloadConvertor Delete method func (f *PackagistPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { return nil, nil } // Fork implements PayloadConvertor Fork method func (f *PackagistPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { return nil, nil } // Push implements PayloadConvertor Push method func (f *PackagistPayload) Push(p *api.PushPayload) (api.Payloader, error) { return f, nil } // Issue implements PayloadConvertor Issue method func (f *PackagistPayload) Issue(p *api.IssuePayload) (api.Payloader, error) { return nil, nil } // IssueComment implements PayloadConvertor IssueComment method func (f *PackagistPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) { return nil, nil } // PullRequest implements PayloadConvertor PullRequest method func (f *PackagistPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) { return nil, nil } // Review implements PayloadConvertor Review method func (f *PackagistPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { return nil, nil } // Repository implements PayloadConvertor Repository method func (f *PackagistPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) { return nil, nil } // Release implements PayloadConvertor Release method func (f *PackagistPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { return nil, nil } // GetPackagistPayload converts a packagist webhook into a PackagistPayload func GetPackagistPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { s := new(PackagistPayload) packagist := &PackagistMeta{} if err := json.Unmarshal([]byte(meta), &packagist); err != nil { return s, errors.New("GetPackagistPayload meta json:" + err.Error()) } s.PackagistRepository.URL = packagist.PackageURL return convertPayloader(s, p, event) }
-
-
-
@@ -0,0 +1,140 @@// Copyright 2022 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package webhook import ( "testing" webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestPackagistPayload(t *testing.T) { t.Run("Create", func(t *testing.T) { p := createTestPayload() d := new(PackagistPayload) pl, err := d.Create(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Delete", func(t *testing.T) { p := deleteTestPayload() d := new(PackagistPayload) pl, err := d.Delete(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Fork", func(t *testing.T) { p := forkTestPayload() d := new(PackagistPayload) pl, err := d.Fork(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Push", func(t *testing.T) { p := pushTestPayload() d := new(PackagistPayload) d.PackagistRepository.URL = "https://packagist.org/api/update-package?username=THEUSERNAME&apiToken=TOPSECRETAPITOKEN" pl, err := d.Push(p) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &PackagistPayload{}, pl) assert.Equal(t, "https://packagist.org/api/update-package?username=THEUSERNAME&apiToken=TOPSECRETAPITOKEN", pl.(*PackagistPayload).PackagistRepository.URL) }) t.Run("Issue", func(t *testing.T) { p := issueTestPayload() d := new(PackagistPayload) p.Action = api.HookIssueOpened pl, err := d.Issue(p) require.NoError(t, err) require.Nil(t, pl) p.Action = api.HookIssueClosed pl, err = d.Issue(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("IssueComment", func(t *testing.T) { p := issueCommentTestPayload() d := new(PackagistPayload) pl, err := d.IssueComment(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("PullRequest", func(t *testing.T) { p := pullRequestTestPayload() d := new(PackagistPayload) pl, err := d.PullRequest(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("PullRequestComment", func(t *testing.T) { p := pullRequestCommentTestPayload() d := new(PackagistPayload) pl, err := d.IssueComment(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Review", func(t *testing.T) { p := pullRequestTestPayload() p.Action = api.HookIssueReviewed d := new(PackagistPayload) pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Repository", func(t *testing.T) { p := repositoryTestPayload() d := new(PackagistPayload) pl, err := d.Repository(p) require.NoError(t, err) require.Nil(t, pl) }) t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() d := new(PackagistPayload) pl, err := d.Release(p) require.NoError(t, err) require.Nil(t, pl) }) } func TestPackagistJSONPayload(t *testing.T) { p := pushTestPayload() pl, err := new(PackagistPayload).Push(p) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &PackagistPayload{}, pl) json, err := pl.JSONPayload() require.NoError(t, err) assert.NotEmpty(t, json) }
-
-
-
@@ -58,6 +58,10 @@ var webhooks = map[webhook_model.HookType]*webhook{name: webhook_model.WECHATWORK, payloadCreator: GetWechatworkPayload, }, webhook_model.PACKAGIST: { name: webhook_model.PACKAGIST, payloadCreator: GetPackagistPayload, }, } // RegisterWebhook registers a webhook
-
-
-
@@ -34,6 +34,8 @@<img width="26" height="26" src="{{AssetUrlPrefix}}/img/matrix.svg"> {{else if eq .HookType "wechatwork"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/wechatwork.png"> {{else if eq .HookType "packagist"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/packagist.png"> {{end}} </div> </h4>
-
@@ -48,6 +50,7 @@{{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} {{template "repo/settings/webhook/packagist" .}} </div> {{template "repo/settings/webhook/history" .}}
-
-
-
@@ -29,6 +29,8 @@<img width="26" height="26" src="{{AssetUrlPrefix}}/img/matrix.svg"> {{else if eq .HookType "wechatwork"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/wechatwork.png"> {{else if eq .HookType "packagist"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/packagist.png"> {{end}} </div> </h4>
-
@@ -43,6 +45,7 @@{{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} {{template "repo/settings/webhook/packagist" .}} </div> {{template "repo/settings/webhook/history" .}}
-
-
-
@@ -34,6 +34,9 @@<a class="item" href="{{.BaseLinkNew}}/wechatwork/new"> <img width="20" height="20" src="{{AssetUrlPrefix}}/img/wechatwork.png">Wechatwork </a> <a class="item" href="{{.BaseLinkNew}}/packagist/new"> <img width="20" height="20" src="{{AssetUrlPrefix}}/img/packagist.png">Packagist </a> </div> </div> </div>
-
-
-
@@ -27,6 +27,8 @@<img width="26" height="26" src="{{AssetUrlPrefix}}/img/matrix.svg"> {{else if eq .HookType "wechatwork"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/wechatwork.png"> {{else if eq .HookType "packagist"}} <img width="26" height="26" src="{{AssetUrlPrefix}}/img/packagist.png"> {{end}} </div> </h4>
-
@@ -41,6 +43,7 @@{{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} {{template "repo/settings/webhook/packagist" .}} </div> {{template "repo/settings/webhook/history" .}}
-
-
-
@@ -0,0 +1,19 @@{{if eq .HookType "packagist"}} <p>{{.i18n.Tr "repo.settings.add_packagist_hook_desc" "https://packagist.org" | Str2html}}</p> <form class="ui form" action="{{.BaseLink}}/packagist/{{or .Webhook.ID "new"}}" method="post"> {{.CsrfTokenHtml}} <div class="required field {{if .Err_Username}}error{{end}}"> <label for="username">{{.i18n.Tr "repo.settings.packagist_username"}}</label> <input id="username" name="username" value="{{.PackagistHook.Username}}" placeholder="e.g. Gitea" autofocus required> </div> <div class="required field {{if .Err_APIToken}}error{{end}}"> <label for="api_token">{{.i18n.Tr "repo.settings.packagist_api_token"}}</label> <input id="api_token" name="api_token" value="{{.PackagistHook.APIToken}}" placeholder="e.g. X5F_tZ-Wj3c1vqaU2Rky" required> </div> <div class="required field {{if .Err_PackageURL}}error{{end}}"> <label for="package_url">{{.i18n.Tr "repo.settings.packagist_package_url"}}</label> <input id="package_url" name="package_url" value="{{.PackagistHook.PackageURL}}" placeholder="e.g. https://packagist.org/packages/laravel/framework" required> </div> {{template "repo/settings/webhook/settings" .}} </form> {{end}}
-
-
-
@@ -13517,7 +13517,8 @@"slack", "telegram", "feishu", "wechatwork" "wechatwork", "packagist" ], "x-go-name": "Type" }
-