mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-03 21:12:09 +02:00
Merge 77eeee70a57431023d42e5e5f2b5b37856807cc3 into 6eed75af248ae597d854a3c5e6b8831a5ff76290
This commit is contained in:
commit
e23ef7cd78
@ -372,6 +372,18 @@ func (a *Action) IsIssueEvent() bool {
|
||||
return a.OpType.InActions("comment_issue", "approve_pull_request", "reject_pull_request", "comment_pull", "merge_pull_request")
|
||||
}
|
||||
|
||||
// GetIssueContentBody returns the comment body from the action content.
|
||||
// Unlike GetIssueInfos which splits on "|" into 3 parts, this only splits on
|
||||
// the first "|" to preserve any "|" characters within the comment body
|
||||
// (e.g. Mermaid diagram syntax like "A -->|text| B").
|
||||
func (a *Action) GetIssueContentBody() string {
|
||||
parts := strings.SplitN(a.Content, "|", 2)
|
||||
if len(parts) < 2 {
|
||||
return ""
|
||||
}
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
// GetIssueInfos returns a list of associated information with the action.
|
||||
func (a *Action) GetIssueInfos() []string {
|
||||
// make sure it always returns 3 elements, because there are some access to the a[1] and a[2] without checking the length
|
||||
|
||||
@ -125,6 +125,24 @@ func TestConsistencyUpdateAction(t *testing.T) {
|
||||
unittest.CheckConsistencyFor(t, &activities_model.Action{})
|
||||
}
|
||||
|
||||
func TestGetIssueContentBody(t *testing.T) {
|
||||
tests := []struct {
|
||||
content string
|
||||
expected string
|
||||
}{
|
||||
{content: "1|simple body", expected: "simple body"},
|
||||
{content: "1|A -->|text| B", expected: "A -->|text| B"},
|
||||
{content: "1|first|second|third", expected: "first|second|third"},
|
||||
{content: "1|", expected: ""},
|
||||
{content: "no-delimiter", expected: ""},
|
||||
{content: "", expected: ""},
|
||||
}
|
||||
for _, test := range tests {
|
||||
action := &activities_model.Action{Content: test.content}
|
||||
assert.Equal(t, test.expected, action.GetIssueContentBody(), "content: %q", test.content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteIssueActions(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
||||
@ -25,6 +25,41 @@ type actionNotifier struct {
|
||||
notify_service.NullNotifier
|
||||
}
|
||||
|
||||
// trimUnclosedCodeBlock removes a trailing unclosed fenced code block from a
|
||||
// truncated string. When content is cut at an arbitrary character limit, a
|
||||
// fenced code block (``` ...) may be left open, producing invalid Markdown that
|
||||
// the renderer tries (and fails) to process. This function detects the
|
||||
// situation and strips the partial block.
|
||||
func trimUnclosedCodeBlock(s string) string {
|
||||
inBlock := false
|
||||
lastOpenIdx := -1
|
||||
i := 0
|
||||
for i < len(s) {
|
||||
lineStart := i
|
||||
lineEnd := strings.Index(s[i:], "\n")
|
||||
var line string
|
||||
if lineEnd == -1 {
|
||||
line = s[i:]
|
||||
i = len(s)
|
||||
} else {
|
||||
line = s[i : i+lineEnd]
|
||||
i = i + lineEnd + 1
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimLeft(line, " "), "```") {
|
||||
if !inBlock {
|
||||
lastOpenIdx = lineStart
|
||||
inBlock = true
|
||||
} else {
|
||||
inBlock = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if inBlock && lastOpenIdx >= 0 {
|
||||
return strings.TrimRight(s[:lastOpenIdx], " \t\n")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var _ notify_service.Notifier = &actionNotifier{}
|
||||
|
||||
func Init() error {
|
||||
@ -117,6 +152,9 @@ func (a *actionNotifier) CreateIssueComment(ctx context.Context, doer *user_mode
|
||||
truncatedContent = truncatedContent[:lastSpaceIdx] + "…"
|
||||
}
|
||||
}
|
||||
if truncatedRight != "" {
|
||||
truncatedContent = trimUnclosedCodeBlock(truncatedContent)
|
||||
}
|
||||
act.Content = fmt.Sprintf("%d|%s", issue.Index, truncatedContent)
|
||||
|
||||
if issue.IsPull {
|
||||
|
||||
@ -22,6 +22,55 @@ func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m)
|
||||
}
|
||||
|
||||
func TestTrimUnclosedCodeBlock(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "no code block",
|
||||
input: "hello world",
|
||||
expected: "hello world",
|
||||
},
|
||||
{
|
||||
name: "closed code block",
|
||||
input: "before\n```go\nfmt.Println()\n```\nafter",
|
||||
expected: "before\n```go\nfmt.Println()\n```\nafter",
|
||||
},
|
||||
{
|
||||
name: "unclosed code block",
|
||||
input: "before\n```mermaid\ngraph LR\nA --> B",
|
||||
expected: "before",
|
||||
},
|
||||
{
|
||||
name: "unclosed code block with leading text",
|
||||
input: "some text here\n```\ncode line 1\ncode line 2",
|
||||
expected: "some text here",
|
||||
},
|
||||
{
|
||||
name: "closed then unclosed",
|
||||
input: "```\nblock1\n```\ntext\n```\nunclosed",
|
||||
expected: "```\nblock1\n```\ntext",
|
||||
},
|
||||
{
|
||||
name: "only unclosed fence",
|
||||
input: "```mermaid\ngraph LR",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, trimUnclosedCodeBlock(tt.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenameRepoAction(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
|
||||
@ -107,8 +107,8 @@
|
||||
{{else if .GetOpType.InActions "create_pull_request"}}
|
||||
<span class="tw-inline-block tw-truncate issue title">{{index .GetIssueInfos 1 | ctx.RenderUtils.RenderIssueSimpleTitle}}</span>
|
||||
{{else if .GetOpType.InActions "comment_issue" "approve_pull_request" "reject_pull_request" "comment_pull"}}
|
||||
<a href="{{.GetCommentLink ctx}}" class="tw-inline-block tw-truncate issue title">{{(.GetIssueTitle ctx) | ctx.RenderUtils.RenderIssueSimpleTitle}}</a>
|
||||
{{$comment := index .GetIssueInfos 1}}
|
||||
<a href="{{.GetCommentLink ctx}}" class="text truncate issue title">{{(.GetIssueTitle ctx) | ctx.RenderUtils.RenderIssueSimpleTitle}}</a>
|
||||
{{$comment := .GetIssueContentBody}}
|
||||
{{if $comment}}
|
||||
<div class="render-content markup truncated-markup">{{ctx.RenderUtils.MarkdownToHtml $comment}}</div>
|
||||
{{end}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user