mirror of
https://github.com/go-gitea/gitea.git
synced 2025-10-27 05:55:21 +08:00
Merge 2ffa0e296a into bc50431e8b
This commit is contained in:
commit
c069da32eb
@ -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)
|
||||
}
|
||||
|
||||
// .___
|
||||
// | | ______ ________ __ ____
|
||||
// | |/ ___// ___/ | \_/ __ \
|
||||
|
||||
354
services/webhook/bark.go
Normal file
354
services/webhook/bark.go
Normal file
@ -0,0 +1,354 @@
|
||||
// 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(" - " + 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 = p.Sender.UserName + " created repository"
|
||||
case api.HookRepoDeleted:
|
||||
title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
|
||||
body = p.Sender.UserName + " deleted repository"
|
||||
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) {
|
||||
repoFullName := ""
|
||||
if p.Repository != nil {
|
||||
repoFullName = p.Repository.FullName
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("[%s] Package %s", repoFullName, 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(repoFullName),
|
||||
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)
|
||||
}
|
||||
215
services/webhook/bark_test.go
Normal file
215
services/webhook/bark_test.go
Normal file
@ -0,0 +1,215 @@
|
||||
// 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
|
||||
p.Review = nil // Remove review content for clean test
|
||||
|
||||
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, "[] Package created", pl.Title)
|
||||
assert.Contains(t, pl.Body, "user1 created package")
|
||||
assert.Empty(t, 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…
Reference in New Issue
Block a user