From 6edfa6bc88ed73fc5a31f1b2fe9f5587c932ada7 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 10 Dec 2020 01:20:13 +0800 Subject: [PATCH] Fix broken migration on webhook (#13911) * Fix broken migration on webhook * Fix lint Co-authored-by: John Olheiser --- models/migrations/migrations.go | 2 ++ models/migrations/v162.go | 59 +++++++++++++++++++++++++++++++++ models/repo_generate.go | 22 ++++++------ models/webhook.go | 10 +++--- modules/convert/convert.go | 4 +-- routers/api/v1/utils/hook.go | 8 ++--- routers/repo/webhook.go | 22 ++++++------ services/webhook/webhook.go | 8 ++--- 8 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 models/migrations/v162.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index d2ad20a36..cac36edf5 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -267,6 +267,8 @@ var migrations = []Migration{ NewMigration("Add block on official review requests branch protection", addBlockOnOfficialReviewRequests), // v161 -> v162 NewMigration("Convert task type from int to string", convertTaskTypeToString), + // v162 -> v163 + NewMigration("Convert webhook task type from int to string", convertWebhookTaskTypeToString), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v162.go b/models/migrations/v162.go new file mode 100644 index 000000000..b65eb4cd9 --- /dev/null +++ b/models/migrations/v162.go @@ -0,0 +1,59 @@ +// Copyright 2020 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 migrations + +import ( + "xorm.io/xorm" +) + +func convertWebhookTaskTypeToString(x *xorm.Engine) error { + const ( + GOGS int = iota + 1 + SLACK + GITEA + DISCORD + DINGTALK + TELEGRAM + MSTEAMS + FEISHU + MATRIX + ) + + var hookTaskTypes = map[int]string{ + GITEA: "gitea", + GOGS: "gogs", + SLACK: "slack", + DISCORD: "discord", + DINGTALK: "dingtalk", + TELEGRAM: "telegram", + MSTEAMS: "msteams", + FEISHU: "feishu", + MATRIX: "matrix", + } + + type Webhook struct { + Type string `xorm:"char(16) index"` + } + if err := x.Sync2(new(Webhook)); err != nil { + return err + } + + for i, s := range hookTaskTypes { + if _, err := x.Exec("UPDATE webhook set type = ? where hook_task_type=?", s, i); err != nil { + return err + } + } + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + if err := dropTableColumns(sess, "webhook", "hook_task_type"); err != nil { + return err + } + + return sess.Commit() +} diff --git a/models/repo_generate.go b/models/repo_generate.go index 0b234d8e3..b0016494c 100644 --- a/models/repo_generate.go +++ b/models/repo_generate.go @@ -117,17 +117,17 @@ func GenerateWebhooks(ctx DBContext, templateRepo, generateRepo *Repository) err for _, templateWebhook := range templateWebhooks { generateWebhook := &Webhook{ - RepoID: generateRepo.ID, - URL: templateWebhook.URL, - HTTPMethod: templateWebhook.HTTPMethod, - ContentType: templateWebhook.ContentType, - Secret: templateWebhook.Secret, - HookEvent: templateWebhook.HookEvent, - IsActive: templateWebhook.IsActive, - HookTaskType: templateWebhook.HookTaskType, - OrgID: templateWebhook.OrgID, - Events: templateWebhook.Events, - Meta: templateWebhook.Meta, + RepoID: generateRepo.ID, + URL: templateWebhook.URL, + HTTPMethod: templateWebhook.HTTPMethod, + ContentType: templateWebhook.ContentType, + Secret: templateWebhook.Secret, + HookEvent: templateWebhook.HookEvent, + IsActive: templateWebhook.IsActive, + Type: templateWebhook.Type, + OrgID: templateWebhook.OrgID, + Events: templateWebhook.Events, + Meta: templateWebhook.Meta, } if err := createWebhook(ctx.e, generateWebhook); err != nil { return err diff --git a/models/webhook.go b/models/webhook.go index 39122808f..dbad2d344 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -110,11 +110,11 @@ type Webhook struct { Secret string `xorm:"TEXT"` Events string `xorm:"TEXT"` *HookEvent `xorm:"-"` - IsSSL bool `xorm:"is_ssl"` - IsActive bool `xorm:"INDEX"` - HookTaskType HookTaskType - Meta string `xorm:"TEXT"` // store hook-specific attributes - LastStatus HookStatus // Last delivery status + IsSSL bool `xorm:"is_ssl"` + IsActive bool `xorm:"INDEX"` + Type HookTaskType `xorm:"char(16) 'type'"` + Meta string `xorm:"TEXT"` // store hook-specific attributes + LastStatus HookStatus // Last delivery status CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` diff --git a/modules/convert/convert.go b/modules/convert/convert.go index 9c90e6ac5..f9f4a641e 100644 --- a/modules/convert/convert.go +++ b/modules/convert/convert.go @@ -227,7 +227,7 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook { "url": w.URL, "content_type": w.ContentType.Name(), } - if w.HookTaskType == models.SLACK { + if w.Type == models.SLACK { s := webhook.GetSlackHook(w) config["channel"] = s.Channel config["username"] = s.Username @@ -237,7 +237,7 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook { return &api.Hook{ ID: w.ID, - Type: string(w.HookTaskType), + Type: string(w.Type), URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), Active: w.IsActive, Config: config, diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 85af6c8e6..c8471184f 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -132,10 +132,10 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID }, BranchFilter: form.BranchFilter, }, - IsActive: form.Active, - HookTaskType: models.HookTaskType(form.Type), + IsActive: form.Active, + Type: models.HookTaskType(form.Type), } - if w.HookTaskType == models.SLACK { + if w.Type == models.SLACK { channel, ok := form.Config["channel"] if !ok { ctx.Error(http.StatusUnprocessableEntity, "", "Missing config option: channel") @@ -219,7 +219,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *models.Webho w.ContentType = models.ToHookContentType(ct) } - if w.HookTaskType == models.SLACK { + if w.Type == models.SLACK { if channel, ok := form.Config["channel"]; ok { meta, err := json.Marshal(&webhook.SlackMeta{ Channel: channel, diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 15d2db88c..49aec8184 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -208,7 +208,7 @@ func GiteaHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { Secret: form.Secret, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.GITEA, + Type: models.GITEA, OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, } @@ -261,7 +261,7 @@ func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind mo Secret: form.Secret, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: kind, + Type: kind, OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, } @@ -311,7 +311,7 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.DISCORD, + Type: models.DISCORD, Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -353,7 +353,7 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.DINGTALK, + Type: models.DINGTALK, Meta: "", OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -404,7 +404,7 @@ func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.TELEGRAM, + Type: models.TELEGRAM, Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -458,7 +458,7 @@ func MatrixHooksNewPost(ctx *context.Context, form auth.NewMatrixHookForm) { HTTPMethod: "PUT", HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.MATRIX, + Type: models.MATRIX, Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -500,7 +500,7 @@ func MSTeamsHooksNewPost(ctx *context.Context, form auth.NewMSTeamsHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.MSTEAMS, + Type: models.MSTEAMS, Meta: "", OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -559,7 +559,7 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.SLACK, + Type: models.SLACK, Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -601,7 +601,7 @@ func FeishuHooksNewPost(ctx *context.Context, form auth.NewFeishuHookForm) { ContentType: models.ContentTypeJSON, HookEvent: ParseHookEvent(form.WebhookForm), IsActive: form.Active, - HookTaskType: models.FEISHU, + Type: models.FEISHU, Meta: "", OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, @@ -647,8 +647,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { return nil, nil } - ctx.Data["HookType"] = w.HookTaskType - switch w.HookTaskType { + ctx.Data["HookType"] = w.Type + switch w.Type { case models.SLACK: ctx.Data["SlackHook"] = webhook.GetSlackHook(w) case models.DISCORD: diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index 104ea3f8b..88dec6bd4 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -128,7 +128,7 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo // Avoid sending "0 new commits" to non-integration relevant webhooks (e.g. slack, discord, etc.). // Integration webhooks (e.g. drone) still receive the required data. if pushEvent, ok := p.(*api.PushPayload); ok && - w.HookTaskType != models.GITEA && w.HookTaskType != models.GOGS && + w.Type != models.GITEA && w.Type != models.GOGS && len(pushEvent.Commits) == 0 { return nil } @@ -144,11 +144,11 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo var payloader api.Payloader var err error - webhook, ok := webhooks[w.HookTaskType] + webhook, ok := webhooks[w.Type] if ok { payloader, err = webhook.payloadCreator(p, event, w.Meta) if err != nil { - return fmt.Errorf("create payload for %s[%s]: %v", w.HookTaskType, event, err) + return fmt.Errorf("create payload for %s[%s]: %v", w.Type, event, err) } } else { p.SetSecret(w.Secret) @@ -172,7 +172,7 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo if err = models.CreateHookTask(&models.HookTask{ RepoID: repo.ID, HookID: w.ID, - Typ: w.HookTaskType, + Typ: w.Type, URL: w.URL, Signature: signature, Payloader: payloader,