mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-03 14:27:36 +01:00
Add support for Bark webhook integration
This commit introduces the Bark notification integration, allowing users to configure Bark webhooks in repositories. It includes form models, templates, routing changes, and test cases to handle Bark webhook functionality.
This commit is contained in:
parent
b2ee5be52e
commit
e72d74244e
@ -35,7 +35,7 @@ func loadWebhookFrom(rootCfg ConfigProvider) {
|
||||
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", "packagist"}
|
||||
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork", "packagist", "bark"}
|
||||
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
|
||||
Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("")
|
||||
if Webhook.ProxyURL != "" {
|
||||
|
||||
@ -114,6 +114,7 @@ const (
|
||||
MATRIX HookType = "matrix"
|
||||
WECHATWORK HookType = "wechatwork"
|
||||
PACKAGIST HookType = "packagist"
|
||||
BARK HookType = "bark"
|
||||
)
|
||||
|
||||
// HookStatus is the status of a web hook
|
||||
|
||||
@ -2467,9 +2467,14 @@ settings.web_hook_name_feishu = Feishu
|
||||
settings.web_hook_name_larksuite = Lark Suite
|
||||
settings.web_hook_name_wechatwork = WeCom (Wechat Work)
|
||||
settings.web_hook_name_packagist = Packagist
|
||||
settings.web_hook_name_bark = Bark
|
||||
settings.packagist_username = Packagist username
|
||||
settings.packagist_api_token = API token
|
||||
settings.packagist_package_url = Packagist package URL
|
||||
settings.bark_url = Bark URL
|
||||
settings.bark_url_help = Full Bark URL including device key (e.g., https://api.day.app/your_device_key/)
|
||||
settings.bark_sound = Sound (optional)
|
||||
settings.bark_group = Group (optional)
|
||||
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.
|
||||
|
||||
@ -2465,9 +2465,14 @@ settings.web_hook_name_feishu=飞书
|
||||
settings.web_hook_name_larksuite=Lark Suite
|
||||
settings.web_hook_name_wechatwork=企业微信
|
||||
settings.web_hook_name_packagist=Packagist
|
||||
settings.web_hook_name_bark=Bark
|
||||
settings.packagist_username=Packagist 用户名
|
||||
settings.packagist_api_token=API 令牌
|
||||
settings.packagist_package_url=Packagist 软件包 URL
|
||||
settings.bark_url=Bark URL
|
||||
settings.bark_url_help=完整的 Bark URL,包含设备密钥(例如:https://api.day.app/your_device_key/)
|
||||
settings.bark_sound=提示音(可选)
|
||||
settings.bark_group=分组(可选)
|
||||
settings.deploy_keys=部署密钥
|
||||
settings.add_deploy_key=添加部署密钥
|
||||
settings.deploy_key_desc=部署密钥具有对仓库的只读拉取权限。
|
||||
|
||||
BIN
public/assets/img/bark.png
Normal file
BIN
public/assets/img/bark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 870 B |
@ -581,6 +581,32 @@ func packagistHookParams(ctx *context.Context) webhookParams {
|
||||
}
|
||||
}
|
||||
|
||||
// BarkHooksNewPost response for creating Bark webhook
|
||||
func BarkHooksNewPost(ctx *context.Context) {
|
||||
createWebhook(ctx, barkHookParams(ctx))
|
||||
}
|
||||
|
||||
// BarkHooksEditPost response for editing Bark webhook
|
||||
func BarkHooksEditPost(ctx *context.Context) {
|
||||
editWebhook(ctx, barkHookParams(ctx))
|
||||
}
|
||||
|
||||
func barkHookParams(ctx *context.Context) webhookParams {
|
||||
form := web.GetForm(ctx).(*forms.NewBarkHookForm)
|
||||
|
||||
return webhookParams{
|
||||
Type: webhook_module.BARK,
|
||||
URL: form.PayloadURL,
|
||||
ContentType: webhook.ContentTypeJSON,
|
||||
HTTPMethod: http.MethodPost,
|
||||
WebhookForm: form.WebhookForm,
|
||||
Meta: &webhook_service.BarkMeta{
|
||||
Sound: form.Sound,
|
||||
Group: form.Group,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
|
||||
orCtx, err := getOwnerRepoCtx(ctx)
|
||||
if err != nil {
|
||||
@ -619,6 +645,8 @@ func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
|
||||
ctx.Data["MatrixHook"] = webhook_service.GetMatrixHook(w)
|
||||
case webhook_module.PACKAGIST:
|
||||
ctx.Data["PackagistHook"] = webhook_service.GetPackagistHook(w)
|
||||
case webhook_module.BARK:
|
||||
ctx.Data["BarkHook"] = webhook_service.GetBarkHook(w)
|
||||
}
|
||||
|
||||
ctx.Data["History"], err = w.History(ctx, 1)
|
||||
|
||||
@ -434,6 +434,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo_setting.FeishuHooksNewPost)
|
||||
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo_setting.WechatworkHooksNewPost)
|
||||
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksNewPost)
|
||||
m.Post("/bark/new", web.Bind(forms.NewBarkHookForm{}), repo_setting.BarkHooksNewPost)
|
||||
}
|
||||
|
||||
addWebhookEditRoutes := func() {
|
||||
@ -448,6 +449,7 @@ func registerWebRoutes(m *web.Router) {
|
||||
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo_setting.FeishuHooksEditPost)
|
||||
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo_setting.WechatworkHooksEditPost)
|
||||
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksEditPost)
|
||||
m.Post("/bark/{id}", web.Bind(forms.NewBarkHookForm{}), repo_setting.BarkHooksEditPost)
|
||||
}
|
||||
|
||||
addSettingsVariablesRoutes := func() {
|
||||
|
||||
@ -410,6 +410,20 @@ func (f *NewPackagistHookForm) Validate(req *http.Request, errs binding.Errors)
|
||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// NewBarkHookForm form for creating Bark hook
|
||||
type NewBarkHookForm struct {
|
||||
PayloadURL string `binding:"Required;ValidUrl" form:"payload_url"`
|
||||
Sound string `form:"sound"`
|
||||
Group string `form:"group"`
|
||||
WebhookForm
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
func (f *NewBarkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
|
||||
ctx := context.GetValidateContext(req)
|
||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// .___
|
||||
// | | ______ ________ __ ____
|
||||
// | |/ ___// ___/ | \_/ __ \
|
||||
|
||||
349
services/webhook/bark.go
Normal file
349
services/webhook/bark.go
Normal file
@ -0,0 +1,349 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
webhook_model "code.gitea.io/gitea/models/webhook"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
)
|
||||
|
||||
type (
|
||||
// BarkPayload represents the payload for Bark notifications
|
||||
BarkPayload struct {
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
Sound string `json:"sound,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
// BarkMeta contains the metadata for the webhook
|
||||
BarkMeta struct {
|
||||
Sound string `json:"sound"`
|
||||
Group string `json:"group"`
|
||||
}
|
||||
|
||||
barkConvertor struct {
|
||||
Sound string
|
||||
Group string
|
||||
}
|
||||
)
|
||||
|
||||
// GetBarkHook returns bark metadata
|
||||
func GetBarkHook(w *webhook_model.Webhook) *BarkMeta {
|
||||
s := &BarkMeta{}
|
||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||
log.Error("webhook.GetBarkHook(%d): %v", w.ID, err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (bc barkConvertor) getGroup(defaultGroup string) string {
|
||||
if bc.Group != "" {
|
||||
return bc.Group
|
||||
}
|
||||
return defaultGroup
|
||||
}
|
||||
|
||||
// Create implements PayloadConvertor Create method
|
||||
func (bc barkConvertor) Create(p *api.CreatePayload) (BarkPayload, error) {
|
||||
refName := git.RefName(p.Ref).ShortName()
|
||||
title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
|
||||
body := fmt.Sprintf("%s created %s %s", p.Sender.UserName, p.RefType, refName)
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(refName),
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Delete implements PayloadConvertor Delete method
|
||||
func (bc barkConvertor) Delete(p *api.DeletePayload) (BarkPayload, error) {
|
||||
refName := git.RefName(p.Ref).ShortName()
|
||||
title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
|
||||
body := fmt.Sprintf("%s deleted %s %s", p.Sender.UserName, p.RefType, refName)
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Repo.HTMLURL,
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Fork implements PayloadConvertor Fork method
|
||||
func (bc barkConvertor) Fork(p *api.ForkPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Repository forked", p.Forkee.FullName)
|
||||
body := fmt.Sprintf("%s forked %s to %s", p.Sender.UserName, p.Forkee.FullName, p.Repo.FullName)
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Repo.HTMLURL,
|
||||
Group: bc.getGroup(p.Forkee.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Push implements PayloadConvertor Push method
|
||||
func (bc barkConvertor) Push(p *api.PushPayload) (BarkPayload, error) {
|
||||
branchName := git.RefName(p.Ref).ShortName()
|
||||
|
||||
var titleLink string
|
||||
if p.TotalCommits == 1 {
|
||||
titleLink = p.Commits[0].URL
|
||||
} else {
|
||||
titleLink = p.CompareURL
|
||||
}
|
||||
if titleLink == "" {
|
||||
titleLink = p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(branchName)
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("[%s:%s] %d new commit(s)", p.Repo.FullName, branchName, p.TotalCommits)
|
||||
|
||||
var body strings.Builder
|
||||
body.WriteString(fmt.Sprintf("%s pushed to %s\n", p.Pusher.UserName, branchName))
|
||||
for i, commit := range p.Commits {
|
||||
body.WriteString(fmt.Sprintf("%s: %s", commit.ID[:7], strings.TrimRight(commit.Message, "\r\n")))
|
||||
if commit.Author != nil {
|
||||
body.WriteString(fmt.Sprintf(" - %s", commit.Author.Name))
|
||||
}
|
||||
if i < len(p.Commits)-1 {
|
||||
body.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body.String(),
|
||||
URL: titleLink,
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Issue implements PayloadConvertor Issue method
|
||||
func (bc barkConvertor) Issue(p *api.IssuePayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Issue #%d: %s", p.Repository.FullName, p.Index, p.Action)
|
||||
body := fmt.Sprintf("%s %s issue #%d: %s", p.Sender.UserName, p.Action, p.Index, p.Issue.Title)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Issue.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Wiki implements PayloadConvertor Wiki method
|
||||
func (bc barkConvertor) Wiki(p *api.WikiPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Wiki %s", p.Repository.FullName, p.Action)
|
||||
body := fmt.Sprintf("%s %s wiki page: %s", p.Sender.UserName, p.Action, p.Page)
|
||||
wikiURL := p.Repository.HTMLURL + "/wiki/" + url.PathEscape(p.Page)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: wikiURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IssueComment implements PayloadConvertor IssueComment method
|
||||
func (bc barkConvertor) IssueComment(p *api.IssueCommentPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] New comment on #%d", p.Repository.FullName, p.Issue.Index)
|
||||
body := fmt.Sprintf("%s commented on issue #%d: %s\n%s",
|
||||
p.Sender.UserName, p.Issue.Index, p.Issue.Title,
|
||||
truncateString(p.Comment.Body, 100))
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Comment.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PullRequest implements PayloadConvertor PullRequest method
|
||||
func (bc barkConvertor) PullRequest(p *api.PullRequestPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] PR #%d: %s", p.Repository.FullName, p.Index, p.Action)
|
||||
body := fmt.Sprintf("%s %s pull request #%d: %s",
|
||||
p.Sender.UserName, p.Action, p.Index, p.PullRequest.Title)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.PullRequest.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Review implements PayloadConvertor Review method
|
||||
func (bc barkConvertor) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (BarkPayload, error) {
|
||||
var action string
|
||||
switch p.Action {
|
||||
case api.HookIssueReviewed:
|
||||
var err error
|
||||
action, err = parseHookPullRequestEventType(event)
|
||||
if err != nil {
|
||||
return BarkPayload{}, err
|
||||
}
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("[%s] PR #%d review %s", p.Repository.FullName, p.Index, action)
|
||||
body := fmt.Sprintf("PR #%d: %s", p.Index, p.PullRequest.Title)
|
||||
if p.Review != nil && p.Review.Content != "" {
|
||||
body += "\n" + truncateString(p.Review.Content, 100)
|
||||
}
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.PullRequest.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Repository implements PayloadConvertor Repository method
|
||||
func (bc barkConvertor) Repository(p *api.RepositoryPayload) (BarkPayload, error) {
|
||||
var title, body string
|
||||
switch p.Action {
|
||||
case api.HookRepoCreated:
|
||||
title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
|
||||
body = fmt.Sprintf("%s created repository", p.Sender.UserName)
|
||||
case api.HookRepoDeleted:
|
||||
title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
|
||||
body = fmt.Sprintf("%s deleted repository", p.Sender.UserName)
|
||||
default:
|
||||
return BarkPayload{}, nil
|
||||
}
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Repository.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Release implements PayloadConvertor Release method
|
||||
func (bc barkConvertor) Release(p *api.ReleasePayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Release %s", p.Repository.FullName, p.Action)
|
||||
body := fmt.Sprintf("%s %s release %s", p.Sender.UserName, p.Action, p.Release.TagName)
|
||||
if p.Release.Title != "" {
|
||||
body += ": " + p.Release.Title
|
||||
}
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Release.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Package implements PayloadConvertor Package method
|
||||
func (bc barkConvertor) Package(p *api.PackagePayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Package %s", p.Repository.FullName, p.Action)
|
||||
body := fmt.Sprintf("%s %s package %s:%s",
|
||||
p.Sender.UserName, p.Action, p.Package.Name, p.Package.Version)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.Package.HTMLURL,
|
||||
Group: bc.getGroup(p.Repository.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Status implements PayloadConvertor Status method
|
||||
func (bc barkConvertor) Status(p *api.CommitStatusPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Commit status: %s", p.Repo.FullName, p.State)
|
||||
body := fmt.Sprintf("Commit %s: %s", base.ShortSha(p.SHA), p.Description)
|
||||
if p.Context != "" {
|
||||
body = fmt.Sprintf("%s (%s)", body, p.Context)
|
||||
}
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.TargetURL,
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WorkflowRun implements PayloadConvertor WorkflowRun method
|
||||
func (bc barkConvertor) WorkflowRun(p *api.WorkflowRunPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Workflow %s", p.Repo.FullName, p.WorkflowRun.Status)
|
||||
body := fmt.Sprintf("Workflow '%s' %s", p.WorkflowRun.DisplayTitle, p.WorkflowRun.Status)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.WorkflowRun.HTMLURL,
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WorkflowJob implements PayloadConvertor WorkflowJob method
|
||||
func (bc barkConvertor) WorkflowJob(p *api.WorkflowJobPayload) (BarkPayload, error) {
|
||||
title := fmt.Sprintf("[%s] Job %s", p.Repo.FullName, p.WorkflowJob.Status)
|
||||
body := fmt.Sprintf("Job '%s' %s", p.WorkflowJob.Name, p.WorkflowJob.Status)
|
||||
|
||||
return BarkPayload{
|
||||
Title: title,
|
||||
Body: body,
|
||||
URL: p.WorkflowJob.HTMLURL,
|
||||
Group: bc.getGroup(p.Repo.FullName),
|
||||
Sound: bc.Sound,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// truncateString truncates a string to the specified length
|
||||
func truncateString(s string, maxLen int) string {
|
||||
if len(s) <= maxLen {
|
||||
return s
|
||||
}
|
||||
return s[:maxLen] + "..."
|
||||
}
|
||||
|
||||
func newBarkRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) {
|
||||
meta := &BarkMeta{}
|
||||
if err := json.Unmarshal([]byte(w.Meta), meta); err != nil {
|
||||
return nil, nil, fmt.Errorf("newBarkRequest meta json: %w", err)
|
||||
}
|
||||
var pc payloadConvertor[BarkPayload] = barkConvertor{
|
||||
Sound: meta.Sound,
|
||||
Group: meta.Group,
|
||||
}
|
||||
return newJSONRequest(pc, w, t, true)
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterWebhookRequester(webhook_module.BARK, newBarkRequest)
|
||||
}
|
||||
214
services/webhook/bark_test.go
Normal file
214
services/webhook/bark_test.go
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
webhook_model "code.gitea.io/gitea/models/webhook"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBarkPayload(t *testing.T) {
|
||||
bc := barkConvertor{}
|
||||
|
||||
t.Run("Create", func(t *testing.T) {
|
||||
p := createTestPayload()
|
||||
|
||||
pl, err := bc.Create(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] branch test created", pl.Title)
|
||||
assert.Equal(t, "user1 created branch test", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
p := deleteTestPayload()
|
||||
|
||||
pl, err := bc.Delete(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] branch test deleted", pl.Title)
|
||||
assert.Equal(t, "user1 deleted branch test", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Fork", func(t *testing.T) {
|
||||
p := forkTestPayload()
|
||||
|
||||
pl, err := bc.Fork(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo2] Repository forked", pl.Title)
|
||||
assert.Equal(t, "user1 forked test/repo2 to test/repo", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo", pl.URL)
|
||||
assert.Equal(t, "test/repo2", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Push", func(t *testing.T) {
|
||||
p := pushTestPayload()
|
||||
|
||||
pl, err := bc.Push(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo:test] 2 new commit(s)", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 pushed to test")
|
||||
assert.Contains(t, pl.Body, "2020558: commit message - user1")
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Issue", func(t *testing.T) {
|
||||
p := issueTestPayload()
|
||||
|
||||
p.Action = api.HookIssueOpened
|
||||
pl, err := bc.Issue(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Issue #2: opened", pl.Title)
|
||||
assert.Equal(t, "user1 opened issue #2: crash", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
|
||||
p.Action = api.HookIssueClosed
|
||||
pl, err = bc.Issue(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Issue #2: closed", pl.Title)
|
||||
assert.Equal(t, "user1 closed issue #2: crash", pl.Body)
|
||||
})
|
||||
|
||||
t.Run("IssueComment", func(t *testing.T) {
|
||||
p := issueCommentTestPayload()
|
||||
|
||||
pl, err := bc.IssueComment(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] New comment on #2", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 commented on issue #2: crash")
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/issues/2#issuecomment-4", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("PullRequest", func(t *testing.T) {
|
||||
p := pullRequestTestPayload()
|
||||
|
||||
pl, err := bc.PullRequest(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] PR #12: opened", pl.Title)
|
||||
assert.Equal(t, "user1 opened pull request #12: Fix bug", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("PullRequestComment", func(t *testing.T) {
|
||||
p := pullRequestCommentTestPayload()
|
||||
|
||||
pl, err := bc.IssueComment(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] New comment on #12", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 commented")
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Review", func(t *testing.T) {
|
||||
p := pullRequestTestPayload()
|
||||
p.Action = api.HookIssueReviewed
|
||||
|
||||
pl, err := bc.Review(p, webhook_module.HookEventPullRequestReviewApproved)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] PR #12 review approved", pl.Title)
|
||||
assert.Equal(t, "PR #12: Fix bug", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Repository", func(t *testing.T) {
|
||||
p := repositoryTestPayload()
|
||||
|
||||
pl, err := bc.Repository(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Repository created", pl.Title)
|
||||
assert.Equal(t, "user1 created repository", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Package", func(t *testing.T) {
|
||||
p := packageTestPayload()
|
||||
|
||||
pl, err := bc.Package(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Package published", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 published package")
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Wiki", func(t *testing.T) {
|
||||
p := wikiTestPayload()
|
||||
|
||||
p.Action = api.HookWikiCreated
|
||||
pl, err := bc.Wiki(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Wiki created", pl.Title)
|
||||
assert.Equal(t, "user1 created wiki page: index", pl.Body)
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
|
||||
t.Run("Release", func(t *testing.T) {
|
||||
p := pullReleaseTestPayload()
|
||||
|
||||
pl, err := bc.Release(p)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "[test/repo] Release published", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 published release v1.0")
|
||||
assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.URL)
|
||||
assert.Equal(t, "test/repo", pl.Group)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBarkJSONPayload(t *testing.T) {
|
||||
p := pushTestPayload()
|
||||
data, err := p.JSONPayload()
|
||||
require.NoError(t, err)
|
||||
|
||||
hook := &webhook_model.Webhook{
|
||||
RepoID: 3,
|
||||
IsActive: true,
|
||||
Type: webhook_module.BARK,
|
||||
URL: "https://api.day.app/devicekey/",
|
||||
Meta: `{}`,
|
||||
HTTPMethod: "POST",
|
||||
}
|
||||
task := &webhook_model.HookTask{
|
||||
HookID: hook.ID,
|
||||
EventType: webhook_module.HookEventPush,
|
||||
PayloadContent: string(data),
|
||||
PayloadVersion: 2,
|
||||
}
|
||||
|
||||
req, reqBody, err := newBarkRequest(t.Context(), hook, task)
|
||||
require.NotNil(t, req)
|
||||
require.NotNil(t, reqBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "POST", req.Method)
|
||||
assert.Equal(t, "https://api.day.app/devicekey/", req.URL.String())
|
||||
assert.Equal(t, "application/json", req.Header.Get("Content-Type"))
|
||||
}
|
||||
20
templates/repo/settings/webhook/bark.tmpl
Normal file
20
templates/repo/settings/webhook/bark.tmpl
Normal file
@ -0,0 +1,20 @@
|
||||
{{if eq .HookType "bark"}}
|
||||
<p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://github.com/Finb/Bark" (ctx.Locale.Tr "repo.settings.web_hook_name_bark")}}</p>
|
||||
<form class="ui form" action="{{.BaseLink}}/bark/{{or .Webhook.ID "new"}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="required field {{if .Err_PayloadURL}}error{{end}}">
|
||||
<label for="payload_url">{{ctx.Locale.Tr "repo.settings.bark_url"}}</label>
|
||||
<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" placeholder="https://api.day.app/your_device_key/" autofocus required>
|
||||
<p class="help">{{ctx.Locale.Tr "repo.settings.bark_url_help"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="sound">{{ctx.Locale.Tr "repo.settings.bark_sound"}}</label>
|
||||
<input id="sound" name="sound" value="{{.BarkHook.Sound}}" placeholder="bell">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="group">{{ctx.Locale.Tr "repo.settings.bark_group"}}</label>
|
||||
<input id="group" name="group" value="{{.BarkHook.Group}}" placeholder="Gitea">
|
||||
</div>
|
||||
{{template "repo/settings/webhook/settings" dict "BaseLink" .BaseLink "Webhook" .Webhook "UseAuthorizationHeader" false}}
|
||||
</form>
|
||||
{{end}}
|
||||
@ -47,4 +47,8 @@
|
||||
{{template "shared/webhook/icon" (dict "HookType" "packagist" "Size" $size)}}
|
||||
{{ctx.Locale.Tr "repo.settings.web_hook_name_packagist"}}
|
||||
</a>
|
||||
<a class="item" href="{{.BaseLinkNew}}/bark/new">
|
||||
{{template "shared/webhook/icon" (dict "HookType" "bark" "Size" $size)}}
|
||||
{{ctx.Locale.Tr "repo.settings.web_hook_name_bark"}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -24,4 +24,6 @@
|
||||
<img alt width="{{$size}}" height="{{$size}}" src="{{AssetUrlPrefix}}/img/wechatwork.png">
|
||||
{{else if eq .HookType "packagist"}}
|
||||
<img alt width="{{$size}}" height="{{$size}}" src="{{AssetUrlPrefix}}/img/packagist.png">
|
||||
{{else if eq .HookType "bark"}}
|
||||
<img alt width="{{$size}}" height="{{$size}}" src="{{AssetUrlPrefix}}/img/bark.png">
|
||||
{{end}}
|
||||
|
||||
@ -21,5 +21,6 @@
|
||||
{{template "repo/settings/webhook/matrix" .ctxData}}
|
||||
{{template "repo/settings/webhook/wechatwork" .ctxData}}
|
||||
{{template "repo/settings/webhook/packagist" .ctxData}}
|
||||
{{template "repo/settings/webhook/bark" .ctxData}}
|
||||
</div>
|
||||
{{template "repo/settings/webhook/history" .ctxData}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user