From 3349fd8f7901d9a04769dff71d86fb67374e9395 Mon Sep 17 00:00:00 2001 From: "Dr. Tobias Quathamer" Date: Sun, 23 Jan 2022 14:46:30 +0100 Subject: [PATCH] Add packagist webhook (#18224) Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang --- docs/content/doc/features/webhooks.en-us.md | 1 + docs/content/doc/features/webhooks.zh-cn.md | 1 + docs/content/doc/features/webhooks.zh-tw.md | 1 + models/webhook/webhook.go | 1 + modules/setting/webhook.go | 2 +- modules/structs/hook.go | 2 +- options/locale/locale_en-US.ini | 4 + public/img/packagist.png | Bin 0 -> 4573 bytes routers/web/repo/webhook.go | 99 +++++++++++++ routers/web/web.go | 4 + services/forms/repo_form.go | 14 ++ services/webhook/packagist.go | 112 ++++++++++++++ services/webhook/packagist_test.go | 140 ++++++++++++++++++ services/webhook/webhook.go | 4 + templates/admin/hook_new.tmpl | 3 + templates/org/settings/hook_new.tmpl | 3 + .../repo/settings/webhook/base_list.tmpl | 3 + templates/repo/settings/webhook/new.tmpl | 3 + .../repo/settings/webhook/packagist.tmpl | 19 +++ templates/swagger/v1_json.tmpl | 3 +- 20 files changed, 416 insertions(+), 3 deletions(-) create mode 100644 public/img/packagist.png create mode 100644 services/webhook/packagist.go create mode 100644 services/webhook/packagist_test.go create mode 100644 templates/repo/settings/webhook/packagist.tmpl diff --git a/docs/content/doc/features/webhooks.en-us.md b/docs/content/doc/features/webhooks.en-us.md index 5ded4512c3..2dba7b7f83 100644 --- a/docs/content/doc/features/webhooks.en-us.md +++ b/docs/content/doc/features/webhooks.en-us.md @@ -28,6 +28,7 @@ All event pushes are POST requests. The methods currently supported are: - Microsoft Teams - Feishu - Wechatwork +- Packagist ### Event information diff --git a/docs/content/doc/features/webhooks.zh-cn.md b/docs/content/doc/features/webhooks.zh-cn.md index f3a312eee2..76139460c0 100644 --- a/docs/content/doc/features/webhooks.zh-cn.md +++ b/docs/content/doc/features/webhooks.zh-cn.md @@ -27,5 +27,6 @@ Gitea 的存储 webhook。这可以有存储库管路设定页 `/:username/:repo - Microsoft Teams - Feishu - Wechatwork +- Packagist ## TBD diff --git a/docs/content/doc/features/webhooks.zh-tw.md b/docs/content/doc/features/webhooks.zh-tw.md index 697b413916..20fec3d62d 100644 --- a/docs/content/doc/features/webhooks.zh-tw.md +++ b/docs/content/doc/features/webhooks.zh-tw.md @@ -27,6 +27,7 @@ Gitea 的儲存庫事件支援 web hook。這可以有儲存庫管理員在設 - Microsoft Teams - Feishu - Wechatwork +- Packagist ### 事件資訊 diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 21c01d9289..ffc9b72b64 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -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 diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index b576f9573b..0bfd7dcb4d 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -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 != "" { diff --git a/modules/structs/hook.go b/modules/structs/hook.go index bb62483cda..e4d7652c72 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -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"` diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8ee7347c0d..de0d26d647 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1947,6 +1947,10 @@ settings.add_matrix_hook_desc = Integrate Matrix into your repo settings.add_msteams_hook_desc = Integrate Microsoft Teams into your repository. settings.add_feishu_hook_desc = Integrate Feishu into your repository. settings.add_Wechat_hook_desc = Integrate Wechatwork into your repository. +settings.add_packagist_hook_desc = Integrate Packagist 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. diff --git a/public/img/packagist.png b/public/img/packagist.png new file mode 100644 index 0000000000000000000000000000000000000000..76c0e62a20d7ca8f50ce24b1e5acb8b4af2b932f GIT binary patch literal 4573 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 literal 0 HcmV?d00001 diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index 2ec2e8911f..fb984de7f5 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -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") diff --git a/routers/web/web.go b/routers/web/web.go index 4c50229906..545194aabd 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -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() { diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 19b5a37664..e6bd088da4 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -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) +} + // .___ // | | ______ ________ __ ____ // | |/ ___// ___/ | \_/ __ \ diff --git a/services/webhook/packagist.go b/services/webhook/packagist.go new file mode 100644 index 0000000000..ace93b13ff --- /dev/null +++ b/services/webhook/packagist.go @@ -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) +} diff --git a/services/webhook/packagist_test.go b/services/webhook/packagist_test.go new file mode 100644 index 0000000000..08912924d2 --- /dev/null +++ b/services/webhook/packagist_test.go @@ -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) +} diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index bb7a9692d1..607fac9634 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -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 diff --git a/templates/admin/hook_new.tmpl b/templates/admin/hook_new.tmpl index 2cd3fc826c..049e54ef83 100644 --- a/templates/admin/hook_new.tmpl +++ b/templates/admin/hook_new.tmpl @@ -34,6 +34,8 @@ {{else if eq .HookType "wechatwork"}} + {{else if eq .HookType "packagist"}} + {{end}} @@ -48,6 +50,7 @@ {{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} + {{template "repo/settings/webhook/packagist" .}} {{template "repo/settings/webhook/history" .}} diff --git a/templates/org/settings/hook_new.tmpl b/templates/org/settings/hook_new.tmpl index 43351d0ceb..5e8ebb51e9 100644 --- a/templates/org/settings/hook_new.tmpl +++ b/templates/org/settings/hook_new.tmpl @@ -29,6 +29,8 @@ {{else if eq .HookType "wechatwork"}} + {{else if eq .HookType "packagist"}} + {{end}} @@ -43,6 +45,7 @@ {{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} + {{template "repo/settings/webhook/packagist" .}} {{template "repo/settings/webhook/history" .}} diff --git a/templates/repo/settings/webhook/base_list.tmpl b/templates/repo/settings/webhook/base_list.tmpl index e96d086039..f16c43bad6 100644 --- a/templates/repo/settings/webhook/base_list.tmpl +++ b/templates/repo/settings/webhook/base_list.tmpl @@ -34,6 +34,9 @@ Wechatwork + + Packagist + diff --git a/templates/repo/settings/webhook/new.tmpl b/templates/repo/settings/webhook/new.tmpl index 6df128f40a..a438a4c71a 100644 --- a/templates/repo/settings/webhook/new.tmpl +++ b/templates/repo/settings/webhook/new.tmpl @@ -27,6 +27,8 @@ {{else if eq .HookType "wechatwork"}} + {{else if eq .HookType "packagist"}} + {{end}} @@ -41,6 +43,7 @@ {{template "repo/settings/webhook/feishu" .}} {{template "repo/settings/webhook/matrix" .}} {{template "repo/settings/webhook/wechatwork" .}} + {{template "repo/settings/webhook/packagist" .}} {{template "repo/settings/webhook/history" .}} diff --git a/templates/repo/settings/webhook/packagist.tmpl b/templates/repo/settings/webhook/packagist.tmpl new file mode 100644 index 0000000000..04161dc40f --- /dev/null +++ b/templates/repo/settings/webhook/packagist.tmpl @@ -0,0 +1,19 @@ +{{if eq .HookType "packagist"}} +

{{.i18n.Tr "repo.settings.add_packagist_hook_desc" "https://packagist.org" | Str2html}}

+
+ {{.CsrfTokenHtml}} +
+ + +
+
+ + +
+
+ + +
+ {{template "repo/settings/webhook/settings" .}} +
+{{end}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index bba728363a..768c4c69ee 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -13517,7 +13517,8 @@ "slack", "telegram", "feishu", - "wechatwork" + "wechatwork", + "packagist" ], "x-go-name": "Type" }