This commit is contained in:
ZeroDeng 2025-10-27 00:06:58 +08:00 committed by GitHub
commit c069da32eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 652 additions and 1 deletions

View File

@ -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 != "" {

View File

@ -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

View File

@ -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.

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

View File

@ -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)

View File

@ -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() {

View File

@ -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
View 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)
}

View 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"))
}

View 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}}

View File

@ -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>

View File

@ -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}}

View File

@ -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}}