Skip to content

Add Gitea Webhook #1755

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

Merged
merged 3 commits into from
May 29, 2017
Merged
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
9 changes: 8 additions & 1 deletion models/webhook.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2017 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.

Expand Down Expand Up @@ -312,9 +313,11 @@ type HookTaskType int
const (
GOGS HookTaskType = iota + 1
SLACK
GITEA
)

var hookTaskTypes = map[string]HookTaskType{
"gitea": GITEA,
"gogs": GOGS,
"slack": SLACK,
}
Expand All @@ -327,6 +330,8 @@ func ToHookTaskType(name string) HookTaskType {
// Name returns the name of an hook task type
func (t HookTaskType) Name() string {
switch t {
case GITEA:
return "gitea"
case GOGS:
return "gogs"
case SLACK:
Expand Down Expand Up @@ -503,7 +508,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
}
}

// Use separate objects so modifications won't be made on payload on non-Gogs type hooks.
// Use separate objects so modifications won't be made on payload on non-Gogs/Gitea type hooks.
switch w.HookTaskType {
case SLACK:
payloader, err = GetSlackPayload(p, event, w.Meta)
Expand Down Expand Up @@ -536,6 +541,8 @@ func (t *HookTask) deliver() {

timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
req := httplib.Post(t.URL).SetTimeout(timeout, timeout).
Header("X-Gitea-Delivery", t.UUID).
Header("X-Gitea-Event", string(t.EventType)).
Header("X-Gogs-Delivery", t.UUID).
Header("X-Gogs-Event", string(t.EventType)).
Header("X-GitHub-Delivery", t.UUID).
Expand Down
5 changes: 4 additions & 1 deletion models/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,19 @@ func TestDeleteWebhookByOrgID(t *testing.T) {
func TestToHookTaskType(t *testing.T) {
assert.Equal(t, GOGS, ToHookTaskType("gogs"))
assert.Equal(t, SLACK, ToHookTaskType("slack"))
assert.Equal(t, GITEA, ToHookTaskType("gitea"))
}

func TestHookTaskType_Name(t *testing.T) {
assert.Equal(t, "gogs", GOGS.Name())
assert.Equal(t, "slack", SLACK.Name())
assert.Equal(t, "gitea", GITEA.Name())
}

func TestIsValidHookTaskType(t *testing.T) {
assert.True(t, IsValidHookTaskType("gogs"))
assert.True(t, IsValidHookTaskType("slack"))
assert.True(t, IsValidHookTaskType("gitea"))
assert.False(t, IsValidHookTaskType("invalid"))
}

Expand All @@ -221,7 +224,7 @@ func TestCreateHookTask(t *testing.T) {
hookTask := &HookTask{
RepoID: 3,
HookID: 3,
Type: GOGS,
Type: GITEA,
URL: "http://www.example.com/unit_test",
Payloader: &api.PushPayload{},
}
Expand Down
14 changes: 14 additions & 0 deletions modules/auth/repo_form.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2017 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.

Expand Down Expand Up @@ -154,6 +155,19 @@ func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
return validate(errs, ctx.Data, f, ctx.Locale)
}

// NewGogshookForm form for creating gogs hook
type NewGogshookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
ContentType int `binding:"Required"`
Secret string
WebhookForm
}

// Validate validates the fields
func (f *NewGogshookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}

// NewSlackHookForm form for creating slack hook
type NewSlackHookForm struct {
PayloadURL string `binding:"Required;ValidUrl"`
Expand Down
3 changes: 2 additions & 1 deletion modules/setting/setting.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2017 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.

Expand Down Expand Up @@ -1324,7 +1325,7 @@ func newWebhookService() {
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{"gogs", "slack"}
Webhook.Types = []string{"gitea", "gogs", "slack"}
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
}

Expand Down
Binary file added public/img/gogs.ico
Binary file not shown.
93 changes: 91 additions & 2 deletions routers/repo/webhook.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2017 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.

Expand Down Expand Up @@ -120,6 +121,53 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {

// WebHooksNewPost response for creating webhook
func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
ctx.Data["HookType"] = "gitea"

orCtx, err := getOrgRepoCtx(ctx)
if err != nil {
ctx.Handle(500, "getOrgRepoCtx", err)
return
}
ctx.Data["BaseLink"] = orCtx.Link

if ctx.HasError() {
ctx.HTML(200, orCtx.NewTemplate)
return
}

contentType := models.ContentTypeJSON
if models.HookContentType(form.ContentType) == models.ContentTypeForm {
contentType = models.ContentTypeForm
}

w := &models.Webhook{
RepoID: orCtx.RepoID,
URL: form.PayloadURL,
ContentType: contentType,
Secret: form.Secret,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
HookTaskType: models.GITEA,
OrgID: orCtx.OrgID,
}
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
} else if err := models.CreateWebhook(w); err != nil {
ctx.Handle(500, "CreateWebhook", err)
return
}

ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
ctx.Redirect(orCtx.Link + "/settings/hooks")
}

// GogsHooksNewPost response for creating webhook
func GogsHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
Expand Down Expand Up @@ -150,7 +198,7 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
Secret: form.Secret,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
HookTaskType: models.GOGS,
HookTaskType: models.GITEA,
OrgID: orCtx.OrgID,
}
if err := w.UpdateEvent(); err != nil {
Expand Down Expand Up @@ -245,8 +293,10 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
case models.SLACK:
ctx.Data["SlackHook"] = w.GetSlackHook()
ctx.Data["HookType"] = "slack"
default:
case models.GOGS:
ctx.Data["HookType"] = "gogs"
default:
ctx.Data["HookType"] = "gitea"
}

ctx.Data["History"], err = w.History(1)
Expand Down Expand Up @@ -310,6 +360,45 @@ func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
}

// GogsHooksEditPost response for editing gogs hook
func GogsHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
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(200, orCtx.NewTemplate)
return
}

contentType := models.ContentTypeJSON
if models.HookContentType(form.ContentType) == models.ContentTypeForm {
contentType = models.ContentTypeForm
}

w.URL = form.PayloadURL
w.ContentType = contentType
w.Secret = form.Secret
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
} else if err := models.UpdateWebhook(w); err != nil {
ctx.Handle(500, "GogsHooksEditPost", err)
return
}

ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
}

// SlackHooksEditPost response for editing slack hook
func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
Expand Down
12 changes: 8 additions & 4 deletions routers/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", org.Webhooks)
m.Post("/delete", org.DeleteWebhook)
m.Get("/:type/new", repo.WebhooksNew)
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
})

Expand Down Expand Up @@ -423,11 +425,13 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook)
m.Get("/:type/new", repo.WebhooksNew)
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/:id/test", repo.TestWebhook)
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)

m.Group("/git", func() {
Expand Down
5 changes: 4 additions & 1 deletion templates/org/settings/hook_new.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
<h4 class="ui top attached header">
{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}
<div class="ui right">
{{if eq .HookType "gogs"}}
{{if eq .HookType "gitea"}}
<img class="img-13" src="{{AppSubUrl}}/img/favicon.png">
{{else if eq .HookType "gogs"}}
<img class="img-13" src="{{AppSubUrl}}/img/gogs.ico">
{{else if eq .HookType "slack"}}
<img class="img-13" src="{{AppSubUrl}}/img/slack.png">
{{end}}
</div>
</h4>
<div class="ui attached segment">
{{template "repo/settings/hook_gitea" .}}
{{template "repo/settings/hook_gogs" .}}
{{template "repo/settings/hook_slack" .}}
</div>
Expand Down
28 changes: 28 additions & 0 deletions templates/repo/settings/hook_gitea.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{if eq .HookType "gitea"}}
<p>{{.i18n.Tr "repo.settings.add_webhook_desc" "https://docs.gitea.io/features/webhook.html" | Str2html}}</p>
<form class="ui form" action="{{.BaseLink}}/settings/hooks/gitea/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.ID}}{{end}}" method="post">
{{.CsrfTokenHtml}}
<div class="required field {{if .Err_PayloadURL}}error{{end}}">
<label for="payload_url">{{.i18n.Tr "repo.settings.payload_url"}}</label>
<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" autofocus required>
</div>
<div class="field">
<label>{{.i18n.Tr "repo.settings.content_type"}}</label>
<div class="ui selection dropdown">
<input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}application/json{{end}}">
<div class="default text"></div>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" data-value="1">application/json</div>
<div class="item" data-value="2">application/x-www-form-urlencoded</div>
</div>
</div>
</div>
<input class="fake" type="password">
<div class="field {{if .Err_Secret}}error{{end}}">
<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label>
<input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off">
</div>
{{template "repo/settings/hook_settings" .}}
</form>
{{end}}
5 changes: 4 additions & 1 deletion templates/repo/settings/hook_list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
<div class="ui floating1 jump dropdown">
<div class="ui blue tiny button">{{.i18n.Tr "repo.settings.add_webhook"}}</div>
<div class="menu">
<a class="item" href="{{.BaseLink}}/settings/hooks/gogs/new">
<a class="item" href="{{.BaseLink}}/settings/hooks/gitea/new">
<img class="img-10" src="{{AppSubUrl}}/img/favicon.png">Gitea
</a>
<a class="item" href="{{.BaseLink}}/settings/hooks/gogs/new">
<img class="img-10" src="{{AppSubUrl}}/img/gogs.ico">Gogs
</a>
<a class="item" href="{{.BaseLink}}/settings/hooks/slack/new">
<img class="img-10" src="{{AppSubUrl}}/img/slack.png">Slack
</a>
Expand Down
5 changes: 4 additions & 1 deletion templates/repo/settings/hook_new.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
<h4 class="ui top attached header">
{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}
<div class="ui right">
{{if eq .HookType "gogs"}}
{{if eq .HookType "gitea"}}
<img class="img-13" src="{{AppSubUrl}}/img/favicon.png">
{{else if eq .HookType "gogs"}}
<img class="img-13" src="{{AppSubUrl}}/img/gogs.ico">
{{else if eq .HookType "slack"}}
<img class="img-13" src="{{AppSubUrl}}/img/slack.png">
{{end}}
</div>
</h4>
<div class="ui attached segment">
{{template "repo/settings/hook_gitea" .}}
{{template "repo/settings/hook_gogs" .}}
{{template "repo/settings/hook_slack" .}}
</div>
Expand Down