Skip to content

WIP: Refactor webhooks #8963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions custom/conf/app.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ AUTO_WATCH_NEW_REPOS = true
AUTO_WATCH_ON_CHANGES = false

[webhook]
; Supported webhook types
SUPPORTED_TYPES = gitea, gogs, slack, discord, dingtalk, telegram, msteams
; Hook task queue length, increase if webhook shooting starts hanging
QUEUE_LENGTH = 1000
; Deliver timeout in seconds
Expand Down
1 change: 1 addition & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ relation to port exhaustion.

## Webhook (`webhook`)

- `SUPPORTED_TYPES`: **gitea, gogs, slack, discord, dingtalk, telegram, msteams** Supported webhook types.
- `QUEUE_LENGTH`: **1000**: Hook task queue length. Use caution when editing this value.
- `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks.
- `SKIP_TLS_VERIFY`: **false**: Allow insecure certification.
Expand Down
1 change: 1 addition & 0 deletions docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ menu:

## Webhook (`webhook`)

- `SUPPORTED_TYPES`: **gitea, gogs, slack, discord, dingtalk, telegram, msteams** 支持的 webhook 类型。
- `QUEUE_LENGTH`: 说明: Hook 任务队列长度。
- `DELIVER_TIMEOUT`: 请求webhooks的超时时间,单位秒。
- `SKIP_TLS_VERIFY`: 是否允许不安全的证书。
Expand Down
8 changes: 7 additions & 1 deletion modules/setting/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var (
QueueLength: 1000,
DeliverTimeout: 5,
SkipTLSVerify: false,
Types: []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams"},
PagingNum: 10,
ProxyURL: "",
ProxyHosts: []string{},
Expand All @@ -33,10 +34,15 @@ var (

func newWebhookService() {
sec := Cfg.Section("webhook")

Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams"}
defaults := Webhook.Types
Webhook.Types = sec.Key("SUPPORTED_TYPES").Strings(",")
if len(Webhook.Types) == 0 {
Webhook.Types = defaults
}
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("")
if Webhook.ProxyURL != "" {
Expand Down
4 changes: 2 additions & 2 deletions modules/webhook/deliver.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ func webhookProxy() func(req *http.Request) (*url.URL, error) {
}
}

// InitDeliverHooks starts the hooks delivery thread
func InitDeliverHooks() {
// initDeliverHooks starts the hooks delivery thread
func initDeliverHooks() {
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second

webhookHTTPClient = &http.Client{
Expand Down
13 changes: 11 additions & 2 deletions modules/webhook/dingtalk.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,17 @@ func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error)
return nil, nil
}

// GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
func GetDingtalkPayload(p api.Payloader, event models.HookEventType, meta string) (*DingtalkPayload, error) {
type DingtalkWebhookType struct {
}

var _ WebhookType = &DingtalkWebhookType{}

func (dingtalkType *DingtalkWebhookType) Name() string {
return "dingtalk"
}

// GetPayload converts a ding talk webhook into a DingtalkPayload
func (dingtalkType *DingtalkWebhookType) GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
s := new(DingtalkPayload)

switch event {
Expand Down
13 changes: 11 additions & 2 deletions modules/webhook/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,17 @@ func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*Discor
}, nil
}

// GetDiscordPayload converts a discord webhook into a DiscordPayload
func GetDiscordPayload(p api.Payloader, event models.HookEventType, meta string) (*DiscordPayload, error) {
type DiscordWebhookType struct {
}

var _ WebhookType = &DiscordWebhookType{}

func (discordType *DiscordWebhookType) Name() string {
return "discord"
}

// GetPayload converts a discord webhook into a DiscordPayload
func (discordType *DiscordWebhookType) GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
s := new(DiscordPayload)

discord := &DiscordMeta{}
Expand Down
13 changes: 11 additions & 2 deletions modules/webhook/msteams.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,8 +699,17 @@ func getMSTeamsReleasePayload(p *api.ReleasePayload) (*MSTeamsPayload, error) {
}, nil
}

// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
func GetMSTeamsPayload(p api.Payloader, event models.HookEventType, meta string) (*MSTeamsPayload, error) {
type MSTeamsWebhookType struct {
}

var _ WebhookType = &MSTeamsWebhookType{}

func (msteamsType *MSTeamsWebhookType) Name() string {
return "msteams"
}

// GetPayload converts a MSTeams webhook into a MSTeamsPayload
func (msteamsType *MSTeamsWebhookType) GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
s := new(MSTeamsPayload)

switch event {
Expand Down
13 changes: 11 additions & 2 deletions modules/webhook/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,17 @@ func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*Sla
}, nil
}

// GetSlackPayload converts a slack webhook into a SlackPayload
func GetSlackPayload(p api.Payloader, event models.HookEventType, meta string) (*SlackPayload, error) {
type SlackWebhookType struct {
}

var _ WebhookType = &SlackWebhookType{}

func (slackType *SlackWebhookType) Name() string {
return "slack"
}

// GetPayload converts a slack webhook into a SlackPayload
func (slackType *SlackWebhookType) GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
s := new(SlackPayload)

slack := &SlackMeta{}
Expand Down
13 changes: 11 additions & 2 deletions modules/webhook/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,17 @@ func getTelegramReleasePayload(p *api.ReleasePayload) (*TelegramPayload, error)
return nil, nil
}

// GetTelegramPayload converts a telegram webhook into a TelegramPayload
func GetTelegramPayload(p api.Payloader, event models.HookEventType, meta string) (*TelegramPayload, error) {
type TelegramWebhookType struct {
}

var _ WebhookType = &TelegramWebhookType{}

func (telegramType *TelegramWebhookType) Name() string {
return "telegram"
}

// GetPayload converts a telegram webhook into a TelegramPayload
func (telegramType *TelegramWebhookType) GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
s := new(TelegramPayload)

switch event {
Expand Down
45 changes: 20 additions & 25 deletions modules/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,33 +88,13 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo
var payloader api.Payloader
var err error
// Use separate objects so modifications won't be made on payload on non-Gogs/Gitea type hooks.
switch w.HookTaskType {
case models.SLACK:
payloader, err = GetSlackPayload(p, event, w.Meta)
webhookType, ok := webhookTypes[w.HookTaskType.Name()]
if ok {
payloader, err = webhookType.GetPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetSlackPayload: %v", err)
return fmt.Errorf("GetPayload: %v", err)
}
case models.DISCORD:
payloader, err = GetDiscordPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetDiscordPayload: %v", err)
}
case models.DINGTALK:
payloader, err = GetDingtalkPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetDingtalkPayload: %v", err)
}
case models.TELEGRAM:
payloader, err = GetTelegramPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetTelegramPayload: %v", err)
}
case models.MSTEAMS:
payloader, err = GetMSTeamsPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetMSTeamsPayload: %v", err)
}
default:
} else {
p.SetSecret(w.Secret)
payloader = p
}
Expand Down Expand Up @@ -187,3 +167,18 @@ func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api.
}
return nil
}

// Init initlize
func Init() error {
for _, tp := range setting.Webhook.Types {
for _, wt := range defaultWebhookTypes {
if strings.EqualFold(wt.Name(), tp) {
RegisterWebhookType(wt)
break
}
}
}

initDeliverHooks()
return nil
}
36 changes: 36 additions & 0 deletions modules/webhook/webhook_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2019 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 (
"code.gitea.io/gitea/models"
api "code.gitea.io/gitea/modules/structs"
)

// WebhookType represents a webhook type, all webhook types should implement this interface
type WebhookType interface {
Name() string
GetPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error)
}

var (
webhookTypes map[string]WebhookType
defaultWebhookTypes = []WebhookType{
&SlackWebhookType{},
&TelegramWebhookType{},
&DingtalkWebhookType{},
&DiscordWebhookType{},
&MSTeamsWebhookType{},
}
)

func init() {
webhookTypes = make(map[string]WebhookType)
}

// RegisterWebhookType register a webhook type
func RegisterWebhookType(t WebhookType) {
webhookTypes[t.Name()] = t
}
4 changes: 3 additions & 1 deletion routers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ func GlobalInit() {
issue_indexer.InitIssueIndexer(false)
models.InitRepoIndexer()
mirror_service.InitSyncMirrors()
webhook.InitDeliverHooks()
if err := webhook.Init(); err != nil {
log.Fatal("Failed to initialize webhook: %v", err)
}
models.InitTestPullRequests()
if err := task.Init(); err != nil {
log.Fatal("Failed to initialize task scheduler: %v", err)
Expand Down