[v14.0/forgejo] fix(ui): improve rendering of commit links (#10613)

**Backport:** https://codeberg.org/forgejo/forgejo/pulls/10530

This commit changes the commit link rendering (link to a single commit,
a diff, a PR, etc):

1. If it is a link to something on the local instance:
  1.1. If it is to the same org and repo, the link is just e.g. the
  commit hash
  1.2. If it is to another repo, the link is the org/repo/commit hash
2. If the link is to another instance:
  The link is the domain/optional sub path/org/repo/commit hash

This change is made to keep the link as short as possible, while not
hiding that the link may go to an external instance.

Followup to !9146

Closes #10241

Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10613
Reviewed-by: Beowulf <beowulf@beocode.eu>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
This commit is contained in:
forgejo-backport-action 2026-01-07 13:51:34 +01:00 committed by Beowulf
commit 440f38913e
3 changed files with 120 additions and 81 deletions

View file

@ -46,6 +46,9 @@ var (
// valid chars in encoded path and parameter: [-+~_%.a-zA-Z0-9/]
// httpSchemePattern matches https:// or http://
httpSchemePattern = regexp.MustCompile(`^https?://`)
// hashCurrentPattern matches string that represents a commit SHA, e.g. d8a994ef243349f321568f9e36d5c3f444b99cae
// Although SHA1 hashes are 40 chars long, SHA256 are 64, the regex matches the hash from 7 to 64 chars in length
// so that abbreviated hash links can be used as well. This matches git and GitHub usability.
@ -72,7 +75,7 @@ var (
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")
// Fediverse handle regex (same as emailRegex but with additonal @ or !
// Fediverse handle regex (same as emailRegex but with additional @ or !
// at start)
fediRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([@!]([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+)@([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+))(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")
@ -826,10 +829,7 @@ func pullReviewCommitPatternProcessor(ctx *RenderContext, node *html.Node) {
text := "!" + id + " (commit "
baseURLEnd := strings.Index(urlFull, repoSlug) + len(repoSlug)
if len(ctx.Links.Base) > 0 && !strings.HasPrefix(ctx.Links.Base, urlFull[:baseURLEnd]) {
text = repoSlug + "@" + text
}
optionalRepoSlugAndInstancePath(ctx, &text, urlFull, repoSlug)
aNode.AppendChild(&html.Node{
Type: html.TextNode,
@ -1083,10 +1083,7 @@ func fullHashPatternProcessor(ctx *RenderContext, node *html.Node) {
// We need to figure out the base of the provided URL, which is up to and including the
// `<owner>/<repo>` slug.
// With that we can determine if it matches the current repo, or if the slug should be shown.
baseURLEnd := strings.Index(urlFull, repoSlug) + len(repoSlug)
if len(ctx.Links.Base) > 0 && !strings.HasPrefix(ctx.Links.Base, urlFull[:baseURLEnd]) {
text = repoSlug + "@" + text
}
optionalRepoSlugAndInstancePath(ctx, &text, urlFull, repoSlug)
// 3rd capture group matches an optional file path after the SHA
filePath := ""
@ -1191,10 +1188,7 @@ func comparePatternProcessor(ctx *RenderContext, node *html.Node) {
text := text1 + textDots + text2
baseURLEnd := strings.Index(urlFull, repoSlug) + len(repoSlug)
if len(ctx.Links.Base) > 0 && !strings.HasPrefix(ctx.Links.Base, urlFull[:baseURLEnd]) {
text = repoSlug + "@" + text
}
optionalRepoSlugAndInstancePath(ctx, &text, urlFull, repoSlug)
extra := ""
if query != "" {
@ -1525,3 +1519,27 @@ func createDescriptionLink(href, content string) *html.Node {
textNode.Parent = linkNode
return linkNode
}
// Adds an optional repo slug and optionally the instance domain and URL
//
// The repo slug is added if the link points to a different repo
// The instance domain and sub-path is added if the link points to a different instance
func optionalRepoSlugAndInstancePath(ctx *RenderContext, text *string, fullURL, slug string) {
if len(ctx.Links.Base) > 0 {
// The fullURL is the url to e.g. the commit. The slug is e.g. `forgejo/forgejo`.
// To retrieve the instance domain and sub-path we need to remove the repo slug
slugStart := strings.LastIndex(fullURL, slug)
targetInstance := fullURL[:slugStart]
// Check if the URL points to a different instance
if setting.AppURL != targetInstance {
// Remove the http scheme for displaying
targetInstance = httpSchemePattern.ReplaceAllString(targetInstance, "")
*text = targetInstance + slug + "@" + *text
} else if !strings.HasSuffix(strings.TrimSuffix(ctx.Links.Base, "/"), slug) {
// If it is a link to a different repo, but on the same instance only add the repo slug
*text = slug + "@" + *text
}
}
}

View file

@ -12,6 +12,7 @@ import (
"forgejo.org/modules/git"
"forgejo.org/modules/setting"
"forgejo.org/modules/test"
"forgejo.org/modules/util"
"github.com/stretchr/testify/assert"
@ -19,9 +20,10 @@ import (
)
const (
TestAppURL = "http://localhost:3000/"
TestOrgRepo = "gogits/gogs"
TestRepoURL = TestAppURL + TestOrgRepo + "/"
TestAppURL = "http://localhost:3000/"
TestOrgRepo = "gogits/gogs"
TestRepoURLWithoutSlash = TestAppURL + TestOrgRepo
TestRepoURL = TestAppURL + TestOrgRepo + "/"
)
// externalIssueLink an HTML link to an alphanumeric-style issue
@ -107,7 +109,7 @@ func TestRender_IssueIndexPattern(t *testing.T) {
}
func TestRender_IssueIndexPattern2(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
// numeric: render inputs with valid mentions
test := func(s, expectedFmt, marker string, indices ...int) {
@ -174,7 +176,7 @@ func TestRender_IssueIndexPattern2(t *testing.T) {
}
func TestRender_IssueIndexPattern3(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
// alphanumeric: render inputs without valid mentions
test := func(s string) {
@ -202,7 +204,7 @@ func TestRender_IssueIndexPattern3(t *testing.T) {
}
func TestRender_IssueIndexPattern4(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
// alphanumeric: render inputs with valid mentions
test := func(s, expectedFmt string, names ...string) {
@ -222,7 +224,7 @@ func TestRender_IssueIndexPattern4(t *testing.T) {
}
func TestRender_IssueIndexPattern5(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
// regexp: render inputs without valid mentions
test := func(s, expectedFmt, pattern string, ids, names []string) {
@ -265,7 +267,7 @@ func TestRender_IssueIndexPattern5(t *testing.T) {
}
func TestRender_IssueIndexPattern_Document(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
metas := map[string]string{
"format": "https://someurl.com/{user}/{repo}/{index}",
"user": "someUser",
@ -301,9 +303,9 @@ func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *Rend
}
func TestRender_AutoLink(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
test := func(input, expected, base string) {
assert := func(input, expected, base string) {
var buffer strings.Builder
err := PostProcess(&RenderContext{
Ctx: git.DefaultContext,
@ -330,7 +332,7 @@ func TestRender_AutoLink(t *testing.T) {
t.Run("Issue", func(t *testing.T) {
// render valid issue URLs
test(util.URLJoin(TestRepoURL, "issues", "3333"),
assert(util.URLJoin(TestRepoURL, "issues", "3333"),
numericIssueLink(util.URLJoin(TestRepoURL, "issues"), "ref-issue", 3333, "#"),
TestRepoURL)
})
@ -338,81 +340,90 @@ func TestRender_AutoLink(t *testing.T) {
t.Run("Commit", func(t *testing.T) {
// render valid commit URLs
tmp := util.URLJoin(TestRepoURL, "commit", "d8a994ef243349f321568f9e36d5c3f444b99cae")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24</code></a>", TestRepoURL)
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">"+TestOrgRepo+"@d8a994ef24</code></a>", "https://localhost/forgejo/forgejo")
test(
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24</code></a>", TestRepoURLWithoutSlash)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">"+TestOrgRepo+"@d8a994ef24</code></a>", "/forgejo/forgejo")
assert(
tmp+"#diff-2",
"<a href=\""+tmp+"#diff-2\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>",
TestRepoURL,
)
test(
assert(
tmp+"#diff-953bb4f01b7c77fa18f0cd54211255051e647dbc",
"<a href=\""+tmp+"#diff-953bb4f01b7c77fa18f0cd54211255051e647dbc\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-953bb4f01b)</code></a>",
TestRepoURL,
TestRepoURLWithoutSlash,
)
// render other commit URLs
tmp = "https://external-link.gitea.io/go-gitea/gitea/commit/d8a994ef243349f321568f9e36d5c3f444b99cae#diff-2"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">go-gitea/gitea@d8a994ef24 (diff-2)</code></a>", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">external-link.gitea.io/go-gitea/gitea@d8a994ef24 (diff-2)</code></a>", TestOrgRepo)
defer test.MockVariableValue(&setting.AppURL, "https://external-link.gitea.io/")()
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">d8a994ef24 (diff-2)</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
tmp = "http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
tmp = TestAppURL + "gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">localhost:3000/gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/gogits/gogs")
tmp = "http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/sub/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/gogs@190d949293</code></a>", "http://localhost:3000/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">localhost:3000/sub/gogits/gogs@190d949293</code></a>", TestRepoURLWithoutSlash)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">localhost:3000/sub/gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
defer test.MockVariableValue(&setting.AppURL, TestAppURL+"sub/")()
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/sub/gogits/gogs")
tmp = "http://localhost:3000/sub1/sub2/sub3/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/sub1/sub2/sub3/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/gogs@190d949293</code></a>", "http://localhost:3000/sub1/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
defer test.MockVariableValue(&setting.AppURL, TestAppURL+"sub1/sub2/sub3/")()
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">190d949293</code></a>", "http://localhost:3000/sub1/sub2/sub3/gogits/gogs")
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">localhost:3000/sub1/sub2/sub3/gogits/gogs@190d949293</code></a>", "http://localhost:3000/sub1/gogits/gogs")
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">localhost:3000/sub1/sub2/sub3/gogits/gogs@190d949293</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
// if the repository happens to be named like one of the known app routes (e.g. `src`),
// we can parse the URL correctly, if there is no sub path
tmp = "http://localhost:3000/gogits/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/src@190d949293</code></a>", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/src@190d949293</code></a>", TestRepoURL)
tmp = "http://localhost:3000/gogits/src/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/src@190d949293</code></a>", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">gogits/src@190d949293</code></a>", TestRepoURL)
// but if there is a sub path, we cannot reliably distinguish the repo name from the app route
tmp = "http://localhost:3000/sub/gogits/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">sub/gogits@190d949293</code></a>", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"commit\"><code class=\"nohighlight\">sub/gogits@190d949293</code></a>", TestRepoURL)
})
t.Run("Compare", func(t *testing.T) {
tmp := util.URLJoin(TestRepoURL, "compare", "d8a994ef243349f321568f9e36d5c3f444b99cae..190d9492934af498c3f669d6a2431dc5459e5b20")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">d8a994ef24..190d949293</code></a>", TestRepoURL)
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">"+TestOrgRepo+"@d8a994ef24..190d949293</code></a>", "https://localhost/forgejo/forgejo")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">d8a994ef24..190d949293</code></a>", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">"+TestOrgRepo+"@d8a994ef24..190d949293</code></a>", "https://localhost/forgejo/forgejo")
defer test.MockVariableValue(&setting.AppURL, TestAppURL+"sub/")()
tmp = "http://localhost:3000/sub/gogits/gogs/compare/190d9492934af498c3f669d6a2431dc5459e5b20..d8a994ef243349f321568f9e36d5c3f444b99cae"
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "http://localhost:3000/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub/gogits/gogs")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub/gogits/gugs")
defer test.MockVariableValue(&setting.AppURL, "https://external-link.gitea.io/")()
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">localhost:3000/sub/gogits/gogs@190d949293..d8a994ef24</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
defer test.MockVariableValue(&setting.AppURL, TestAppURL+"sub1/sub2/sub3/")()
tmp = "http://localhost:3000/sub1/sub2/sub3/gogits/gogs/compare/190d9492934af498c3f669d6a2431dc5459e5b20..d8a994ef243349f321568f9e36d5c3f444b99cae"
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub1/sub2/sub3/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub1/gogits/gogs")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">190d949293..d8a994ef24</code></a>", "http://localhost:3000/sub1/sub2/sub3/gogits/gogs")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "/gogits/gous")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">gogits/gogs@190d949293..d8a994ef24</code></a>", "https://external-link.gitea.io/go-gitea/gitea")
tmp = "https://codeberg.org/forgejo/forgejo/compare/8bbac4c679bea930c74849c355a60ed3c52f8eb5...e2278e5a38187a1dc84dc41d583ec8b44e7257c1?files=options/locale/locale_fi-FI.ini"
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>", "https://codeberg.org/forgejo/forgejo")
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">forgejo/forgejo@8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>", TestRepoURL)
test(tmp+".", "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">forgejo/forgejo@8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>.", TestRepoURL)
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">codeberg.org/forgejo/forgejo@8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>", TestRepoURL)
assert(tmp+".", "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">codeberg.org/forgejo/forgejo@8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>.", TestRepoURL)
defer test.MockVariableValue(&setting.AppURL, "https://codeberg.org/")()
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini)</code></a>", "https://codeberg.org/forgejo/forgejo")
tmp = "https://codeberg.org/forgejo/forgejo/compare/8bbac4c679bea930c74849c355a60ed3c52f8eb5...e2278e5a38187a1dc84dc41d583ec8b44e7257c1?files=options/locale/locale_fi-FI.ini#L2"
test(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini#L2)</code></a>", "https://codeberg.org/forgejo/forgejo")
assert(tmp, "<a href=\""+tmp+"\" class=\"compare\"><code class=\"nohighlight\">8bbac4c679...e2278e5a38 (options/locale/locale_fi-FI.ini#L2)</code></a>", "https://codeberg.org/forgejo/forgejo")
})
t.Run("Invalid URLs", func(t *testing.T) {
tmp := "https://local host/gogits/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20"
test(tmp, "<a href=\"https://local\" class=\"link\">https://local</a> host/gogits/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20", TestRepoURL)
assert(tmp, "<a href=\"https://local\" class=\"link\">https://local</a> host/gogits/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20", TestRepoURL)
})
}
func TestRender_IssueIndexPatternRef(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
test := func(input, expected string) {
var buf strings.Builder
@ -428,7 +439,7 @@ func TestRender_IssueIndexPatternRef(t *testing.T) {
}
func TestRender_FullIssueURLs(t *testing.T) {
setting.AppURL = TestAppURL
defer test.MockVariableValue(&setting.AppURL, TestAppURL)()
test := func(input, expected string) {
var result strings.Builder

View file

@ -41,7 +41,7 @@ func TestMain(m *testing.M) {
}
func TestRender_Commits(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected string) {
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
@ -94,10 +94,19 @@ func TestRender_Commits(t *testing.T) {
fileStrangeChars := util.URLJoin(repo, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d", "path", "to", "file%20%23.txt")
test(fileStrangeChars, `<p><a href="`+fileStrangeChars+`" rel="nofollow"><code>eeb243c339/path/to/file #.txt</code></a></p>`)
commitLink := util.URLJoin(repo, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d")
test(commitLink, `<p><a href="`+commitLink+`" rel="nofollow"><code>eeb243c339</code></a></p>`)
crossCommitLink := util.URLJoin(markup.TestAppURL, "forgejo/forgejo", "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d")
test(crossCommitLink, `<p><a href="`+crossCommitLink+`" rel="nofollow"><code>forgejo/forgejo@eeb243c339</code></a></p>`)
extCommitLink := util.URLJoin("https://codeberg.org/", markup.TestOrgRepo, "src", "commit", "eeb243c3395e1921c5d90e73bd739827251fc99d")
test(extCommitLink, `<p><a href="`+extCommitLink+`" rel="nofollow"><code>codeberg.org/`+markup.TestOrgRepo+`@eeb243c339</code></a></p>`)
}
func TestRender_CrossReferences(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected string) {
buffer, err := markup.RenderString(&markup.RenderContext{
@ -140,7 +149,7 @@ func TestRender_CrossReferences(t *testing.T) {
}
func TestRender_links(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected string) {
buffer, err := markup.RenderString(&markup.RenderContext{
@ -242,12 +251,12 @@ func TestRender_links(t *testing.T) {
}
func TestRender_PullReviewCommitLink(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
sha := "190d9492934af498c3f669d6a2431dc5459e5b20"
prCommitLink := util.URLJoin(markup.TestRepoURL, "pulls", "1", "commits", sha)
test := func(input, expected, base string) {
assert := func(input, expected, base string) {
buffer, err := markup.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
RelativePath: ".md",
@ -261,27 +270,28 @@ func TestRender_PullReviewCommitLink(t *testing.T) {
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
}
test(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`, markup.TestRepoURL)
assert(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`, markup.TestRepoURL)
prCommitLink = util.URLJoin(markup.TestAppURL, "sub1", "sub2", markup.TestOrgRepo, "pulls", "1", "commits", sha)
test(
assert(
prCommitLink,
`<p><a href="`+prCommitLink+`" rel="nofollow">!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`,
`<p><a href="`+prCommitLink+`" rel="nofollow">localhost:3000/sub1/sub2/gogits/gogs@!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`,
util.URLJoin(markup.TestAppURL, "sub1", "sub2", markup.TestOrgRepo),
)
test(
assert(
prCommitLink,
`<p><a href="`+prCommitLink+`" rel="nofollow">`+markup.TestOrgRepo+`@!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`,
`<p><a href="`+prCommitLink+`" rel="nofollow">localhost:3000/sub1/sub2/gogits/gogs@!1 (commit <code>`+sha[0:10]+`</code>)</a></p>`,
markup.TestRepoURL,
)
prCommitLink = "https://codeberg.org/forgejo/forgejo/pulls/7979/commits/4d968c08e0a8d24bd2f3fb2a3a48b37e6d84a327#diff-7649acfa98a9ee3faf0d28b488bbff428317fc72"
test(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">!7979 (commit <code>4d968c08e0</code>)</a></p>`, "https://codeberg.org/forgejo/forgejo")
test(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">forgejo/forgejo@!7979 (commit <code>4d968c08e0</code>)</a></p>`, markup.TestRepoURL)
assert(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">codeberg.org/forgejo/forgejo@!7979 (commit <code>4d968c08e0</code>)</a></p>`, markup.TestRepoURL)
defer test.MockVariableValue(&setting.AppURL, "https://codeberg.org/")()
assert(prCommitLink, `<p><a href="`+prCommitLink+`" rel="nofollow">!7979 (commit <code>4d968c08e0</code>)</a></p>`, "https://codeberg.org/forgejo/forgejo")
}
func TestRender_email(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected string) {
res, err := markup.RenderString(&markup.RenderContext{
@ -365,7 +375,7 @@ func TestRender_email(t *testing.T) {
}
func TestRender_emoji(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
setting.StaticURLPrefix = markup.TestAppURL
test := func(input, expected string) {
@ -432,7 +442,7 @@ func TestRender_emoji(t *testing.T) {
}
func TestRender_ShortLinks(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
tree := util.URLJoin(markup.TestRepoURL, "src", "master")
test := func(input, expected, expectedWiki string) {
@ -545,7 +555,7 @@ func TestRender_ShortLinks(t *testing.T) {
}
func TestRender_RelativeImages(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
test := func(input, expected, expectedWiki string) {
buffer, err := markdown.RenderString(&markup.RenderContext{
@ -585,7 +595,7 @@ func TestRender_RelativeImages(t *testing.T) {
}
func Test_ParseClusterFuzz(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
localMetas := map[string]string{
"user": "go-gitea",
@ -621,7 +631,7 @@ func Test_ParseClusterFuzz(t *testing.T) {
}
func TestPostProcess_RenderDocument(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
setting.StaticURLPrefix = markup.TestAppURL // can't run standalone
localMetas := map[string]string{
@ -666,7 +676,7 @@ func TestPostProcess_RenderDocument(t *testing.T) {
}
func TestIssue16020(t *testing.T) {
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
localMetas := map[string]string{
"user": "go-gitea",
@ -731,7 +741,7 @@ func TestIssue18471(t *testing.T) {
}, strings.NewReader(data), &res)
require.NoError(t, err)
assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">783b039...da951ce</code></a>", res.String())
assert.Equal(t, "<a href=\"http://domain/org/repo/compare/783b039...da951ce\" class=\"compare\"><code class=\"nohighlight\">domain/org/repo@783b039...da951ce</code></a>", res.String())
}
func TestRender_FilePreview(t *testing.T) {
@ -740,7 +750,7 @@ func TestRender_FilePreview(t *testing.T) {
defer test.MockVariableValue(&setting.Langs, []string{"en-US"})()
translation.InitLocales(t.Context())
setting.AppURL = markup.TestAppURL
defer test.MockVariableValue(&setting.AppURL, markup.TestAppURL)()
markup.Init(&markup.ProcessorHelper{
GetRepoFileBlob: func(ctx context.Context, ownerName, repoName, commitSha, filePath string, language *string) (*git.Blob, error) {
gitRepo, err := git.OpenRepository(git.DefaultContext, "./tests/repo/repo1_filepreview")
@ -880,7 +890,7 @@ func TestRender_FilePreview(t *testing.T) {
testRender(
urlWithSub,
`<p><a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>gogits/gogs@190d949293/path/to/file.go (L2-L3)</code></a></p>`,
`<p><a href="http://localhost:3000/sub/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>localhost:3000/sub/gogits/gogs@190d949293/path/to/file.go (L2-L3)</code></a></p>`,
localMetas,
)
@ -920,7 +930,7 @@ func TestRender_FilePreview(t *testing.T) {
testRender(
"first without sub "+commitFilePreview+" second "+urlWithSub,
`<p>first without sub <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>190d949293/path/to/file.go (L2-L3)</code></a> second </p>`+
`<p>first without sub <a href="http://localhost:3000/gogits/gogs/src/commit/190d9492934af498c3f669d6a2431dc5459e5b20/path/to/file.go#L2-L3" rel="nofollow"><code>localhost:3000/gogits/gogs@190d949293/path/to/file.go (L2-L3)</code></a> second </p>`+
`<div class="file-preview-box">`+
`<div class="header">`+
`<div>`+