mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Use relative links for commits, mentions, and issues in markdown (#29427)
Fixes #29404 Use relative links for - commits - mentions - issues --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
		| @@ -609,7 +609,7 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) { | |||||||
| 		if ok && strings.Contains(mention, "/") { | 		if ok && strings.Contains(mention, "/") { | ||||||
| 			mentionOrgAndTeam := strings.Split(mention, "/") | 			mentionOrgAndTeam := strings.Split(mention, "/") | ||||||
| 			if mentionOrgAndTeam[0][1:] == ctx.Metas["org"] && strings.Contains(teams, ","+strings.ToLower(mentionOrgAndTeam[1])+",") { | 			if mentionOrgAndTeam[0][1:] == ctx.Metas["org"] && strings.Contains(teams, ","+strings.ToLower(mentionOrgAndTeam[1])+",") { | ||||||
| 				replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, "org", ctx.Metas["org"], "teams", mentionOrgAndTeam[1]), mention, "mention")) | 				replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), "org", ctx.Metas["org"], "teams", mentionOrgAndTeam[1]), mention, "mention")) | ||||||
| 				node = node.NextSibling.NextSibling | 				node = node.NextSibling.NextSibling | ||||||
| 				start = 0 | 				start = 0 | ||||||
| 				continue | 				continue | ||||||
| @@ -620,7 +620,7 @@ func mentionProcessor(ctx *RenderContext, node *html.Node) { | |||||||
| 		mentionedUsername := mention[1:] | 		mentionedUsername := mention[1:] | ||||||
|  |  | ||||||
| 		if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) { | 		if DefaultProcessorHelper.IsUsernameMentionable != nil && DefaultProcessorHelper.IsUsernameMentionable(ctx.Ctx, mentionedUsername) { | ||||||
| 			replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(setting.AppURL, mentionedUsername), mention, "mention")) | 			replaceContent(node, loc.Start, loc.End, createLink(util.URLJoin(ctx.Links.Prefix(), mentionedUsername), mention, "mention")) | ||||||
| 			node = node.NextSibling.NextSibling | 			node = node.NextSibling.NextSibling | ||||||
| 		} else { | 		} else { | ||||||
| 			node = node.NextSibling | 			node = node.NextSibling | ||||||
| @@ -898,9 +898,9 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { | |||||||
| 				path = "pulls" | 				path = "pulls" | ||||||
| 			} | 			} | ||||||
| 			if ref.Owner == "" { | 			if ref.Owner == "" { | ||||||
| 				link = createLink(util.URLJoin(setting.AppURL, ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue") | 				link = createLink(util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], path, ref.Issue), reftext, "ref-issue") | ||||||
| 			} else { | 			} else { | ||||||
| 				link = createLink(util.URLJoin(setting.AppURL, ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue") | 				link = createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, path, ref.Issue), reftext, "ref-issue") | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -939,7 +939,7 @@ func commitCrossReferencePatternProcessor(ctx *RenderContext, node *html.Node) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		reftext := ref.Owner + "/" + ref.Name + "@" + base.ShortSha(ref.CommitSha) | 		reftext := ref.Owner + "/" + ref.Name + "@" + base.ShortSha(ref.CommitSha) | ||||||
| 		link := createLink(util.URLJoin(setting.AppSubURL, ref.Owner, ref.Name, "commit", ref.CommitSha), reftext, "commit") | 		link := createLink(util.URLJoin(ctx.Links.Prefix(), ref.Owner, ref.Name, "commit", ref.CommitSha), reftext, "commit") | ||||||
|  |  | ||||||
| 		replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link) | 		replaceContent(node, ref.RefLocation.Start, ref.RefLocation.End, link) | ||||||
| 		node = node.NextSibling.NextSibling | 		node = node.NextSibling.NextSibling | ||||||
| @@ -1166,7 +1166,7 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		link := util.URLJoin(setting.AppURL, ctx.Metas["user"], ctx.Metas["repo"], "commit", hash) | 		link := util.URLJoin(ctx.Links.Prefix(), ctx.Metas["user"], ctx.Metas["repo"], "commit", hash) | ||||||
| 		replaceContent(node, m[2], m[3], createCodeLink(link, base.ShortSha(hash), "commit")) | 		replaceContent(node, m[2], m[3], createCodeLink(link, base.ShortSha(hash), "commit")) | ||||||
| 		start = 0 | 		start = 0 | ||||||
| 		node = node.NextSibling.NextSibling | 		node = node.NextSibling.NextSibling | ||||||
|   | |||||||
| @@ -287,6 +287,7 @@ func TestRender_IssueIndexPattern_Document(t *testing.T) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) { | func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) { | ||||||
|  | 	ctx.Links.AbsolutePrefix = true | ||||||
| 	if ctx.Links.Base == "" { | 	if ctx.Links.Base == "" { | ||||||
| 		ctx.Links.Base = TestRepoURL | 		ctx.Links.Base = TestRepoURL | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -43,7 +43,8 @@ func TestRender_Commits(t *testing.T) { | |||||||
| 			Ctx:          git.DefaultContext, | 			Ctx:          git.DefaultContext, | ||||||
| 			RelativePath: ".md", | 			RelativePath: ".md", | ||||||
| 			Links: markup.Links{ | 			Links: markup.Links{ | ||||||
| 				Base: markup.TestRepoURL, | 				AbsolutePrefix: true, | ||||||
|  | 				Base:           markup.TestRepoURL, | ||||||
| 			}, | 			}, | ||||||
| 			Metas: localMetas, | 			Metas: localMetas, | ||||||
| 		}, input) | 		}, input) | ||||||
| @@ -96,7 +97,8 @@ func TestRender_CrossReferences(t *testing.T) { | |||||||
| 			Ctx:          git.DefaultContext, | 			Ctx:          git.DefaultContext, | ||||||
| 			RelativePath: "a.md", | 			RelativePath: "a.md", | ||||||
| 			Links: markup.Links{ | 			Links: markup.Links{ | ||||||
| 				Base: setting.AppSubURL, | 				AbsolutePrefix: true, | ||||||
|  | 				Base:           setting.AppSubURL, | ||||||
| 			}, | 			}, | ||||||
| 			Metas: localMetas, | 			Metas: localMetas, | ||||||
| 		}, input) | 		}, input) | ||||||
| @@ -588,7 +590,8 @@ func TestPostProcess_RenderDocument(t *testing.T) { | |||||||
| 		err := markup.PostProcess(&markup.RenderContext{ | 		err := markup.PostProcess(&markup.RenderContext{ | ||||||
| 			Ctx: git.DefaultContext, | 			Ctx: git.DefaultContext, | ||||||
| 			Links: markup.Links{ | 			Links: markup.Links{ | ||||||
| 				Base: "https://example.com", | 				AbsolutePrefix: true, | ||||||
|  | 				Base:           "https://example.com", | ||||||
| 			}, | 			}, | ||||||
| 			Metas: localMetas, | 			Metas: localMetas, | ||||||
| 		}, strings.NewReader(input), &res) | 		}, strings.NewReader(input), &res) | ||||||
|   | |||||||
| @@ -130,11 +130,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string { | |||||||
| <li><a href="` + baseURLContent + `/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li> | <li><a href="` + baseURLContent + `/Links" rel="nofollow">Links, Language bindings, Engine bindings</a></li> | ||||||
| <li><a href="` + baseURLContent + `/Tips" rel="nofollow">Tips</a></li> | <li><a href="` + baseURLContent + `/Tips" rel="nofollow">Tips</a></li> | ||||||
| </ul> | </ul> | ||||||
| <p>See commit <a href="http://localhost:3000/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p> | <p>See commit <a href="/gogits/gogs/commit/65f1bf27bc" rel="nofollow"><code>65f1bf27bc</code></a></p> | ||||||
| <p>Ideas and codes</p> | <p>Ideas and codes</p> | ||||||
| <ul> | <ul> | ||||||
| <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" class="ref-issue" rel="nofollow">ocornut/imgui#786</a></li> | <li>Bezier widget (by <a href="/r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/ocornut/imgui/issues/786" class="ref-issue" rel="nofollow">ocornut/imgui#786</a></li> | ||||||
| <li>Bezier widget (by <a href="` + AppURL + `r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" class="ref-issue" rel="nofollow">#786</a></li> | <li>Bezier widget (by <a href="/r-lyeh" rel="nofollow">@r-lyeh</a>) <a href="http://localhost:3000/gogits/gogs/issues/786" class="ref-issue" rel="nofollow">#786</a></li> | ||||||
| <li>Node graph editors <a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">https://github.com/ocornut/imgui/issues/306</a></li> | <li>Node graph editors <a href="https://github.com/ocornut/imgui/issues/306" rel="nofollow">https://github.com/ocornut/imgui/issues/306</a></li> | ||||||
| <li><a href="` + baseURLContent + `/memory_editor_example" rel="nofollow">Memory Editor</a></li> | <li><a href="` + baseURLContent + `/memory_editor_example" rel="nofollow">Memory Editor</a></li> | ||||||
| <li><a href="` + baseURLContent + `/plot_var_example" rel="nofollow">Plot var helper</a></li> | <li><a href="` + baseURLContent + `/plot_var_example" rel="nofollow">Plot var helper</a></li> | ||||||
|   | |||||||
| @@ -82,9 +82,17 @@ type RenderContext struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| type Links struct { | type Links struct { | ||||||
| 	Base       string | 	AbsolutePrefix bool | ||||||
| 	BranchPath string | 	Base           string | ||||||
| 	TreePath   string | 	BranchPath     string | ||||||
|  | 	TreePath       string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *Links) Prefix() string { | ||||||
|  | 	if l.AbsolutePrefix { | ||||||
|  | 		return setting.AppURL | ||||||
|  | 	} | ||||||
|  | 	return setting.AppSubURL | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *Links) HasBranchInfo() bool { | func (l *Links) HasBranchInfo() bool { | ||||||
|   | |||||||
| @@ -117,21 +117,21 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a582 | |||||||
| com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | ||||||
| <span class="emoji" aria-label="thumbs up">👍</span> | <span class="emoji" aria-label="thumbs up">👍</span> | ||||||
| <a href="mailto:mail@domain.com" class="mailto">mail@domain.com</a> | <a href="mailto:mail@domain.com" class="mailto">mail@domain.com</a> | ||||||
| <a href="http://localhost:3000/mention-user" class="mention">@mention-user</a> test | <a href="/mention-user" class="mention">@mention-user</a> test | ||||||
| <a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a> | <a href="/user13/repo11/issues/123" class="ref-issue">#123</a> | ||||||
|   space` |   space` | ||||||
|  |  | ||||||
| 	assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas)) | 	assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas)) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestRenderCommitMessage(t *testing.T) { | func TestRenderCommitMessage(t *testing.T) { | ||||||
| 	expected := `space <a href="http://localhost:3000/mention-user" class="mention">@mention-user</a>  ` | 	expected := `space <a href="/mention-user" class="mention">@mention-user</a>  ` | ||||||
|  |  | ||||||
| 	assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) | 	assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas)) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestRenderCommitMessageLinkSubject(t *testing.T) { | func TestRenderCommitMessageLinkSubject(t *testing.T) { | ||||||
| 	expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="http://localhost:3000/mention-user" class="mention">@mention-user</a>` | 	expected := `<a href="https://example.com/link" class="default-link muted">space </a><a href="/mention-user" class="mention">@mention-user</a>` | ||||||
|  |  | ||||||
| 	assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas)) | 	assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas)) | ||||||
| } | } | ||||||
| @@ -155,14 +155,14 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | |||||||
| <span class="emoji" aria-label="thumbs up">👍</span> | <span class="emoji" aria-label="thumbs up">👍</span> | ||||||
| mail@domain.com | mail@domain.com | ||||||
| @mention-user test | @mention-user test | ||||||
| <a href="http://localhost:3000/user13/repo11/issues/123" class="ref-issue">#123</a> | <a href="/user13/repo11/issues/123" class="ref-issue">#123</a> | ||||||
|   space   |   space   | ||||||
| ` | ` | ||||||
| 	assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas)) | 	assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas)) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestRenderMarkdownToHtml(t *testing.T) { | func TestRenderMarkdownToHtml(t *testing.T) { | ||||||
| 	expected := `<p>space <a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a><br/> | 	expected := `<p>space <a href="/mention-user" rel="nofollow">@mention-user</a><br/> | ||||||
| /just/a/path.bin | /just/a/path.bin | ||||||
| <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a> | <a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a> | ||||||
| <a href="/file.bin" rel="nofollow">local link</a> | <a href="/file.bin" rel="nofollow">local link</a> | ||||||
| @@ -179,7 +179,7 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a582 | |||||||
| com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit | ||||||
| <span class="emoji" aria-label="thumbs up">👍</span> | <span class="emoji" aria-label="thumbs up">👍</span> | ||||||
| <a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a> | <a href="mailto:mail@domain.com" rel="nofollow">mail@domain.com</a> | ||||||
| <a href="http://localhost:3000/mention-user" rel="nofollow">@mention-user</a> test | <a href="/mention-user" rel="nofollow">@mention-user</a> test | ||||||
| #123 | #123 | ||||||
| space</p> | space</p> | ||||||
| ` | ` | ||||||
|   | |||||||
| @@ -34,7 +34,8 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr | |||||||
| 		if err := markdown.RenderRaw(&markup.RenderContext{ | 		if err := markdown.RenderRaw(&markup.RenderContext{ | ||||||
| 			Ctx: ctx, | 			Ctx: ctx, | ||||||
| 			Links: markup.Links{ | 			Links: markup.Links{ | ||||||
| 				Base: urlPrefix, | 				AbsolutePrefix: true, | ||||||
|  | 				Base:           urlPrefix, | ||||||
| 			}, | 			}, | ||||||
| 		}, strings.NewReader(text), ctx.Resp); err != nil { | 		}, strings.NewReader(text), ctx.Resp); err != nil { | ||||||
| 			ctx.Error(http.StatusInternalServerError, err.Error()) | 			ctx.Error(http.StatusInternalServerError, err.Error()) | ||||||
| @@ -79,7 +80,8 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr | |||||||
| 	if err := markup.Render(&markup.RenderContext{ | 	if err := markup.Render(&markup.RenderContext{ | ||||||
| 		Ctx: ctx, | 		Ctx: ctx, | ||||||
| 		Links: markup.Links{ | 		Links: markup.Links{ | ||||||
| 			Base: urlPrefix, | 			AbsolutePrefix: true, | ||||||
|  | 			Base:           urlPrefix, | ||||||
| 		}, | 		}, | ||||||
| 		Metas:        meta, | 		Metas:        meta, | ||||||
| 		IsWiki:       wiki, | 		IsWiki:       wiki, | ||||||
|   | |||||||
| @@ -222,7 +222,8 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient | |||||||
| 	body, err := markdown.RenderString(&markup.RenderContext{ | 	body, err := markdown.RenderString(&markup.RenderContext{ | ||||||
| 		Ctx: ctx, | 		Ctx: ctx, | ||||||
| 		Links: markup.Links{ | 		Links: markup.Links{ | ||||||
| 			Base: ctx.Issue.Repo.HTMLURL(), | 			AbsolutePrefix: true, | ||||||
|  | 			Base:           ctx.Issue.Repo.HTMLURL(), | ||||||
| 		}, | 		}, | ||||||
| 		Metas: ctx.Issue.Repo.ComposeMetas(ctx), | 		Metas: ctx.Issue.Repo.ComposeMetas(ctx), | ||||||
| 	}, ctx.Content) | 	}, ctx.Content) | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"html/template" | 	"html/template" | ||||||
|  | 	"io" | ||||||
|  | 	"mime/quotedprintable" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -19,6 +21,7 @@ import ( | |||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	"code.gitea.io/gitea/models/unittest" | 	"code.gitea.io/gitea/models/unittest" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/markup" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| @@ -67,6 +70,12 @@ func prepareMailerTest(t *testing.T) (doer *user_model.User, repo *repo_model.Re | |||||||
| func TestComposeIssueCommentMessage(t *testing.T) { | func TestComposeIssueCommentMessage(t *testing.T) { | ||||||
| 	doer, _, issue, comment := prepareMailerTest(t) | 	doer, _, issue, comment := prepareMailerTest(t) | ||||||
|  |  | ||||||
|  | 	markup.Init(&markup.ProcessorHelper{ | ||||||
|  | 		IsUsernameMentionable: func(ctx context.Context, username string) bool { | ||||||
|  | 			return username == doer.Name | ||||||
|  | 		}, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
| 	setting.IncomingEmail.Enabled = true | 	setting.IncomingEmail.Enabled = true | ||||||
| 	defer func() { setting.IncomingEmail.Enabled = false }() | 	defer func() { setting.IncomingEmail.Enabled = false }() | ||||||
|  |  | ||||||
| @@ -77,7 +86,8 @@ func TestComposeIssueCommentMessage(t *testing.T) { | |||||||
| 	msgs, err := composeIssueCommentMessages(&mailCommentContext{ | 	msgs, err := composeIssueCommentMessages(&mailCommentContext{ | ||||||
| 		Context: context.TODO(), // TODO: use a correct context | 		Context: context.TODO(), // TODO: use a correct context | ||||||
| 		Issue:   issue, Doer: doer, ActionType: activities_model.ActionCommentIssue, | 		Issue:   issue, Doer: doer, ActionType: activities_model.ActionCommentIssue, | ||||||
| 		Content: "test body", Comment: comment, | 		Content: fmt.Sprintf("test @%s %s#%d body", doer.Name, issue.Repo.FullName(), issue.Index), | ||||||
|  | 		Comment: comment, | ||||||
| 	}, "en-US", recipients, false, "issue comment") | 	}, "en-US", recipients, false, "issue comment") | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Len(t, msgs, 2) | 	assert.Len(t, msgs, 2) | ||||||
| @@ -96,6 +106,20 @@ func TestComposeIssueCommentMessage(t *testing.T) { | |||||||
| 	assert.Equal(t, "<user2/repo1/issues/1/comment/2@localhost>", gomailMsg.GetHeader("Message-ID")[0], "Message-ID header doesn't match") | 	assert.Equal(t, "<user2/repo1/issues/1/comment/2@localhost>", gomailMsg.GetHeader("Message-ID")[0], "Message-ID header doesn't match") | ||||||
| 	assert.Equal(t, "<mailto:"+replyTo+">", gomailMsg.GetHeader("List-Post")[0]) | 	assert.Equal(t, "<mailto:"+replyTo+">", gomailMsg.GetHeader("List-Post")[0]) | ||||||
| 	assert.Len(t, gomailMsg.GetHeader("List-Unsubscribe"), 2) // url + mailto | 	assert.Len(t, gomailMsg.GetHeader("List-Unsubscribe"), 2) // url + mailto | ||||||
|  |  | ||||||
|  | 	var buf bytes.Buffer | ||||||
|  | 	gomailMsg.WriteTo(&buf) | ||||||
|  |  | ||||||
|  | 	b, err := io.ReadAll(quotedprintable.NewReader(&buf)) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  |  | ||||||
|  | 	// text/plain | ||||||
|  | 	assert.Contains(t, string(b), fmt.Sprintf(`( %s )`, doer.HTMLURL())) | ||||||
|  | 	assert.Contains(t, string(b), fmt.Sprintf(`( %s )`, issue.HTMLURL())) | ||||||
|  |  | ||||||
|  | 	// text/html | ||||||
|  | 	assert.Contains(t, string(b), fmt.Sprintf(`href="%s"`, doer.HTMLURL())) | ||||||
|  | 	assert.Contains(t, string(b), fmt.Sprintf(`href="%s"`, issue.HTMLURL())) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestComposeIssueMessage(t *testing.T) { | func TestComposeIssueMessage(t *testing.T) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 KN4CK3R
					KN4CK3R