Skip to content

Commit 5104c88

Browse files
authored
Modify the content format of the Feishu webhook (#25106)
close #24368 ## what my pull request does Since the official documentation states that custom bots do not support hyperlink functionality, simply adding it without making some formatting changes would result in an unappealing output. Therefore, I have modified the formatting of the output. Currently, it is only used for Feishu. --- [docs](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/im-v1/message/create_json#%E8%B6%85%E9%93%BE%E6%8E%A5%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E) <img width="641" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/360e1c81-ab64-4ef6-851e-aa450d6e85a4"> - Issue <img width="423" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/519f6fae-81ab-4ec8-89b8-f6a73ff93783"> - Issue Comment <img width="548" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/749c0d1c-3657-431e-b787-8bf4c23cce83"> - Assign <img width="431" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/066f99e5-eabb-455d-91fb-a8359cc26dc7"> <img width="457" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/c6c10f99-db83-46ef-a775-4c91979fa68f"> - Merge <img width="408" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/e627bf43-5954-45aa-acf6-261ee046802f"> - PullRequest <img width="425" alt="image" src="https://github.com/go-gitea/gitea/assets/75628309/72cfa714-d3fa-4fb9-abdd-e8508d756056">
1 parent f67f57a commit 5104c88

File tree

4 files changed

+111
-15
lines changed

4 files changed

+111
-15
lines changed

services/webhook/feishu.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,40 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
9797

9898
// Issue implements PayloadConvertor Issue method
9999
func (f *FeishuPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
100-
text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true)
101-
102-
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
100+
title, link, by, operator, result, assignees := getIssuesInfo(p)
101+
var res api.Payloader
102+
if assignees != "" {
103+
if p.Action == api.HookIssueAssigned || p.Action == api.HookIssueUnassigned || p.Action == api.HookIssueMilestoned {
104+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, result, assignees, p.Issue.Body))
105+
} else {
106+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, assignees, p.Issue.Body))
107+
}
108+
} else {
109+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, p.Issue.Body))
110+
}
111+
return res, nil
103112
}
104113

105114
// IssueComment implements PayloadConvertor IssueComment method
106115
func (f *FeishuPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
107-
text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
108-
109-
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + p.Comment.Body), nil
116+
title, link, by, operator := getIssuesCommentInfo(p)
117+
return newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, p.Comment.Body)), nil
110118
}
111119

112120
// PullRequest implements PayloadConvertor PullRequest method
113121
func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
114-
text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
115-
116-
return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
122+
title, link, by, operator, result, assignees := getPullRequestInfo(p)
123+
var res api.Payloader
124+
if assignees != "" {
125+
if p.Action == api.HookIssueAssigned || p.Action == api.HookIssueUnassigned || p.Action == api.HookIssueMilestoned {
126+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, result, assignees, p.PullRequest.Body))
127+
} else {
128+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, assignees, p.PullRequest.Body))
129+
}
130+
} else {
131+
res = newFeishuTextPayload(fmt.Sprintf("%s\n%s\n%s\n%s\n\n%s", title, link, by, operator, p.PullRequest.Body))
132+
}
133+
return res, nil
117134
}
118135

119136
// Review implements PayloadConvertor Review method

services/webhook/feishu_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,15 @@ func TestFeishuPayload(t *testing.T) {
7272
require.NotNil(t, pl)
7373
require.IsType(t, &FeishuPayload{}, pl)
7474

75-
assert.Equal(t, "#2 crash\r\n[test/repo] Issue opened: #2 crash by user1\r\n\r\nissue body", pl.(*FeishuPayload).Content.Text)
75+
assert.Equal(t, "[Issue-test/repo #2]: opened\ncrash\nhttp://localhost:3000/test/repo/issues/2\nIssue by user1\nOperator: user1\nAssignees: user1\n\nissue body", pl.(*FeishuPayload).Content.Text)
7676

7777
p.Action = api.HookIssueClosed
7878
pl, err = d.Issue(p)
7979
require.NoError(t, err)
8080
require.NotNil(t, pl)
8181
require.IsType(t, &FeishuPayload{}, pl)
8282

83-
assert.Equal(t, "#2 crash\r\n[test/repo] Issue closed: #2 crash by user1", pl.(*FeishuPayload).Content.Text)
83+
assert.Equal(t, "[Issue-test/repo #2]: closed\ncrash\nhttp://localhost:3000/test/repo/issues/2\nIssue by user1\nOperator: user1\nAssignees: user1\n\nissue body", pl.(*FeishuPayload).Content.Text)
8484
})
8585

8686
t.Run("IssueComment", func(t *testing.T) {
@@ -92,7 +92,7 @@ func TestFeishuPayload(t *testing.T) {
9292
require.NotNil(t, pl)
9393
require.IsType(t, &FeishuPayload{}, pl)
9494

95-
assert.Equal(t, "#2 crash\r\n[test/repo] New comment on issue #2 crash by user1\r\n\r\nmore info needed", pl.(*FeishuPayload).Content.Text)
95+
assert.Equal(t, "[Comment-test/repo #2]: created\ncrash\nhttp://localhost:3000/test/repo/issues/2\nIssue by user1\nOperator: user1\n\nmore info needed", pl.(*FeishuPayload).Content.Text)
9696
})
9797

9898
t.Run("PullRequest", func(t *testing.T) {
@@ -104,7 +104,7 @@ func TestFeishuPayload(t *testing.T) {
104104
require.NotNil(t, pl)
105105
require.IsType(t, &FeishuPayload{}, pl)
106106

107-
assert.Equal(t, "#12 Fix bug\r\n[test/repo] Pull request opened: #12 Fix bug by user1\r\n\r\nfixes bug #2", pl.(*FeishuPayload).Content.Text)
107+
assert.Equal(t, "[PullRequest-test/repo #12]: opened\nFix bug\nhttp://localhost:3000/test/repo/pulls/12\nPullRequest by user1\nOperator: user1\nAssignees: user1\n\nfixes bug #2", pl.(*FeishuPayload).Content.Text)
108108
})
109109

110110
t.Run("PullRequestComment", func(t *testing.T) {
@@ -116,7 +116,7 @@ func TestFeishuPayload(t *testing.T) {
116116
require.NotNil(t, pl)
117117
require.IsType(t, &FeishuPayload{}, pl)
118118

119-
assert.Equal(t, "#12 Fix bug\r\n[test/repo] New comment on pull request #12 Fix bug by user1\r\n\r\nchanges requested", pl.(*FeishuPayload).Content.Text)
119+
assert.Equal(t, "[Comment-test/repo #12]: created\nFix bug\nhttp://localhost:3000/test/repo/pulls/12\nPullRequest by user1\nOperator: user1\n\nchanges requested", pl.(*FeishuPayload).Content.Text)
120120
})
121121

122122
t.Run("Review", func(t *testing.T) {

services/webhook/general.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,69 @@ func htmlLinkFormatter(url, text string) string {
2828
return fmt.Sprintf(`<a href="%s">%s</a>`, html.EscapeString(url), html.EscapeString(text))
2929
}
3030

31+
// getPullRequestInfo gets the information for a pull request
32+
func getPullRequestInfo(p *api.PullRequestPayload) (title, link, by, operator, operateResult, assignees string) {
33+
title = fmt.Sprintf("[PullRequest-%s #%d]: %s\n%s", p.Repository.FullName, p.PullRequest.Index, p.Action, p.PullRequest.Title)
34+
assignList := p.PullRequest.Assignees
35+
assignStringList := make([]string, len(assignList))
36+
37+
for i, user := range assignList {
38+
assignStringList[i] = user.UserName
39+
}
40+
if p.Action == api.HookIssueAssigned {
41+
operateResult = fmt.Sprintf("%s assign this to %s", p.Sender.UserName, assignList[len(assignList)-1].UserName)
42+
} else if p.Action == api.HookIssueUnassigned {
43+
operateResult = fmt.Sprintf("%s unassigned this for someone", p.Sender.UserName)
44+
} else if p.Action == api.HookIssueMilestoned {
45+
operateResult = fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.PullRequest.Milestone.ID)
46+
}
47+
link = p.PullRequest.HTMLURL
48+
by = fmt.Sprintf("PullRequest by %s", p.PullRequest.Poster.UserName)
49+
if len(assignStringList) > 0 {
50+
assignees = fmt.Sprintf("Assignees: %s", strings.Join(assignStringList, ", "))
51+
}
52+
operator = fmt.Sprintf("Operator: %s", p.Sender.UserName)
53+
return title, link, by, operator, operateResult, assignees
54+
}
55+
56+
// getIssuesInfo gets the information for an issue
57+
func getIssuesInfo(p *api.IssuePayload) (issueTitle, link, by, operator, operateResult, assignees string) {
58+
issueTitle = fmt.Sprintf("[Issue-%s #%d]: %s\n%s", p.Repository.FullName, p.Issue.Index, p.Action, p.Issue.Title)
59+
assignList := p.Issue.Assignees
60+
assignStringList := make([]string, len(assignList))
61+
62+
for i, user := range assignList {
63+
assignStringList[i] = user.UserName
64+
}
65+
if p.Action == api.HookIssueAssigned {
66+
operateResult = fmt.Sprintf("%s assign this to %s", p.Sender.UserName, assignList[len(assignList)-1].UserName)
67+
} else if p.Action == api.HookIssueUnassigned {
68+
operateResult = fmt.Sprintf("%s unassigned this for someone", p.Sender.UserName)
69+
} else if p.Action == api.HookIssueMilestoned {
70+
operateResult = fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.Issue.Milestone.ID)
71+
}
72+
link = p.Issue.HTMLURL
73+
by = fmt.Sprintf("Issue by %s", p.Issue.Poster.UserName)
74+
if len(assignStringList) > 0 {
75+
assignees = fmt.Sprintf("Assignees: %s", strings.Join(assignStringList, ", "))
76+
}
77+
operator = fmt.Sprintf("Operator: %s", p.Sender.UserName)
78+
return issueTitle, link, by, operator, operateResult, assignees
79+
}
80+
81+
// getIssuesCommentInfo gets the information for a comment
82+
func getIssuesCommentInfo(p *api.IssueCommentPayload) (title, link, by, operator string) {
83+
title = fmt.Sprintf("[Comment-%s #%d]: %s\n%s", p.Repository.FullName, p.Issue.Index, p.Action, p.Issue.Title)
84+
link = p.Issue.HTMLURL
85+
if p.IsPull {
86+
by = fmt.Sprintf("PullRequest by %s", p.Issue.Poster.UserName)
87+
} else {
88+
by = fmt.Sprintf("Issue by %s", p.Issue.Poster.UserName)
89+
}
90+
operator = fmt.Sprintf("Operator: %s", p.Sender.UserName)
91+
return title, link, by, operator
92+
}
93+
3194
func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, withSender bool) (string, string, string, int) {
3295
repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName)
3396
issueTitle := fmt.Sprintf("#%d %s", p.Index, p.Issue.Title)

services/webhook/general_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ func issueTestPayload() *api.IssuePayload {
123123
HTMLURL: "http://localhost:3000/test/repo/issues/2",
124124
Title: "crash",
125125
Body: "issue body",
126+
Poster: &api.User{
127+
UserName: "user1",
128+
AvatarURL: "http://localhost:3000/user1/avatar",
129+
},
126130
Assignees: []*api.User{
127131
{
128132
UserName: "user1",
@@ -161,7 +165,11 @@ func issueCommentTestPayload() *api.IssueCommentPayload {
161165
URL: "http://localhost:3000/api/v1/repos/test/repo/issues/2",
162166
HTMLURL: "http://localhost:3000/test/repo/issues/2",
163167
Title: "crash",
164-
Body: "this happened",
168+
Poster: &api.User{
169+
UserName: "user1",
170+
AvatarURL: "http://localhost:3000/user1/avatar",
171+
},
172+
Body: "this happened",
165173
},
166174
}
167175
}
@@ -190,6 +198,10 @@ func pullRequestCommentTestPayload() *api.IssueCommentPayload {
190198
HTMLURL: "http://localhost:3000/test/repo/pulls/12",
191199
Title: "Fix bug",
192200
Body: "fixes bug #2",
201+
Poster: &api.User{
202+
UserName: "user1",
203+
AvatarURL: "http://localhost:3000/user1/avatar",
204+
},
193205
},
194206
IsPull: true,
195207
}
@@ -254,6 +266,10 @@ func pullRequestTestPayload() *api.PullRequestPayload {
254266
Title: "Fix bug",
255267
Body: "fixes bug #2",
256268
Mergeable: true,
269+
Poster: &api.User{
270+
UserName: "user1",
271+
AvatarURL: "http://localhost:3000/user1/avatar",
272+
},
257273
Assignees: []*api.User{
258274
{
259275
UserName: "user1",

0 commit comments

Comments
 (0)