Skip to content

Commit 3cbd9fb

Browse files
Gustedearl-warren
authored andcommitted
[GITEA] Improve HTML title on repositories
- The `<title>` element that lives inside the `<head>` element is an important element that gives browsers and search engine crawlers the title of the webpage, hence the element name. It's therefor important that this title is accurate. - Currently there are three issues with titles on repositories. It doesn't use the `FullName` and instead only uses the repository name, this doesn't distinguish which user or organisation the repository is on. It doesn't show the full treepath in the title when visiting an file inside a directory and instead only uses the latest path in treepath. It can show the repository name twice if the `.Title` variable also included the repository name such as on the repository homepage. - Use the repository's fullname (which include which user the repository is on) instead of just their name. - Display the repository's fullname if it isn't already in `.Title`. - Use the full treepath in the repository code view instead of just the last path. - Adds integration tests. - Adds a new repository (`repo59`) that has 3 depths for folders, which wasn't in any other fixture repository yet, so the full treepath for could be properly tested. - Resolves https://codeberg.org/forgejo/forgejo/issues/1276 (cherry picked from commit ff9a6a2cda34cf2b2e392cc47125ed0f619b287b) (cherry picked from commit 76dffc862103eb23d51445ef9d611296308c8413) (cherry picked from commit ff0615b9d0f3ea4bd86a28c4ac5b0c4740230c81) (cherry picked from commit 8712eaa394053a8c8f1f4cb17307e094c65c7059) (cherry picked from commit 0c11587582b8837778ee85f4e3b04241e5d71760)
1 parent 9f463a7 commit 3cbd9fb

25 files changed

+206
-10
lines changed

models/fixtures/release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,17 @@
136136
is_prerelease: false
137137
is_tag: false
138138
created_unix: 946684803
139+
140+
- id: 11
141+
repo_id: 59
142+
publisher_id: 2
143+
tag_name: "v1.0"
144+
lower_tag_name: "v1.0"
145+
target: "main"
146+
title: "v1.0"
147+
sha1: "d8f53dfb33f6ccf4169c34970b5e747511c18beb"
148+
num_commits: 1
149+
is_draft: false
150+
is_prerelease: false
151+
is_tag: false
152+
created_unix: 946684803

models/fixtures/repo_unit.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,38 @@
608608
type: 1
609609
created_unix: 946684810
610610

611+
# BEGIN Forgejo [GITEA] Improve HTML title on repositories
612+
-
613+
id: 1093
614+
repo_id: 59
615+
type: 1
616+
created_unix: 946684810
617+
618+
-
619+
id: 1094
620+
repo_id: 59
621+
type: 2
622+
created_unix: 946684810
623+
624+
-
625+
id: 1095
626+
repo_id: 59
627+
type: 3
628+
created_unix: 946684810
629+
630+
-
631+
id: 1096
632+
repo_id: 59
633+
type: 4
634+
created_unix: 946684810
635+
636+
-
637+
id: 1097
638+
repo_id: 59
639+
type: 5
640+
created_unix: 946684810
641+
# END Forgejo [GITEA] Improve HTML title on repositories
642+
611643
-
612644
id: 91
613645
repo_id: 58

models/fixtures/repository.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,7 @@
14671467
owner_name: user27
14681468
lower_name: repo49
14691469
name: repo49
1470+
description: A wonderful repository with more than just a README.md
14701471
default_branch: master
14711472
num_watches: 0
14721473
num_stars: 0
@@ -1693,3 +1694,16 @@
16931694
size: 0
16941695
is_fsck_enabled: true
16951696
close_issues_via_commit_in_any_branch: false
1697+
1698+
-
1699+
id: 59
1700+
owner_id: 2
1701+
owner_name: user2
1702+
lower_name: repo59
1703+
name: repo59
1704+
default_branch: master
1705+
is_empty: false
1706+
is_archived: false
1707+
is_private: false
1708+
status: 0
1709+
num_issues: 0

models/fixtures/user.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
num_followers: 2
6767
num_following: 1
6868
num_stars: 2
69-
num_repos: 14
69+
num_repos: 15
7070
num_teams: 0
7171
num_members: 0
7272
visibility: 0

models/repo/repo_list_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,12 @@ func getTestCases() []struct {
138138
{
139139
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
140140
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
141-
count: 31,
141+
count: 32,
142142
},
143143
{
144144
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
145145
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
146-
count: 36,
146+
count: 37,
147147
},
148148
{
149149
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
@@ -158,7 +158,7 @@ func getTestCases() []struct {
158158
{
159159
name: "AllPublic/PublicRepositoriesOfOrganization",
160160
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
161-
count: 31,
161+
count: 32,
162162
},
163163
{
164164
name: "AllTemplates",

routers/web/repo/view.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
165165

166166
if ctx.Repo.TreePath != "" {
167167
ctx.Data["HideRepoInfo"] = true
168-
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
168+
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+util.PathEscapeSegments(ctx.Repo.TreePath), ctx.Repo.RefName)
169169
}
170170

171171
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
@@ -344,7 +344,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
344344
}
345345
defer dataRc.Close()
346346

347-
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
347+
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+util.PathEscapeSegments(ctx.Repo.TreePath), ctx.Repo.RefName)
348348
ctx.Data["FileIsSymlink"] = entry.IsLink()
349349
ctx.Data["FileName"] = blob.Name()
350350
ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)

templates/base/head.tmpl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<html lang="{{ctx.Locale.Lang}}" class="theme-{{if .SignedUser.Theme}}{{.SignedUser.Theme}}{{else}}{{DefaultTheme}}{{end}}">
33
<head>
44
<meta name="viewport" content="width=device-width, initial-scale=1">
5-
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
5+
{{/* Display `- .Repsository.FullName` only if `.Title` does not already start with that. */}}
6+
<title>{{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppName}}</title>
67
{{if .ManifestData}}<link rel="manifest" href="data:{{.ManifestData}}">{{end}}
78
<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}">
89
<meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}">
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ref: refs/heads/master
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[core]
2+
repositoryformatversion = 0
3+
filemode = true
4+
bare = true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Unnamed repository; edit this file 'description' to name the repository.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# git ls-files --others --exclude-from=.git/info/exclude
2+
# Lines that start with '#' are comments.
3+
# For a project mostly in C, the following would be a good set of
4+
# exclude patterns (uncomment them if you want to use them):
5+
# *.[oa]
6+
# *~
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# pack-refs with: peeled fully-peeled sorted
2+
d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/heads/master
3+
d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/tags/v1.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d8f53dfb33f6ccf4169c34970b5e747511c18beb

tests/integration/api_repo_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ func TestAPISearchRepo(t *testing.T) {
9393
}{
9494
{
9595
name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
96-
nil: {count: 33},
97-
user: {count: 33},
98-
user2: {count: 33},
96+
nil: {count: 34},
97+
user: {count: 34},
98+
user2: {count: 34},
9999
},
100100
},
101101
{

tests/integration/integration_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,18 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
531531
doc := NewHTMLParser(t, resp.Body)
532532
return doc.GetCSRF()
533533
}
534+
535+
func GetHTMLTitle(t testing.TB, session *TestSession, urlStr string) string {
536+
t.Helper()
537+
538+
req := NewRequest(t, "GET", urlStr)
539+
var resp *httptest.ResponseRecorder
540+
if session == nil {
541+
resp = MakeRequest(t, req, http.StatusOK)
542+
} else {
543+
resp = session.MakeRequest(t, req, http.StatusOK)
544+
}
545+
546+
doc := NewHTMLParser(t, resp.Body)
547+
return doc.Find("head title").Text()
548+
}

tests/integration/repo_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,107 @@ func TestGeneratedSourceLink(t *testing.T) {
444444
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
445445
})
446446
}
447+
448+
func TestRepoHTMLTitle(t *testing.T) {
449+
defer tests.PrepareTestEnv(t)()
450+
451+
t.Run("Repository homepage", func(t *testing.T) {
452+
t.Run("Without description", func(t *testing.T) {
453+
defer tests.PrintCurrentTest(t)()
454+
455+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1")
456+
assert.EqualValues(t, "user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
457+
})
458+
t.Run("With description", func(t *testing.T) {
459+
defer tests.PrintCurrentTest(t)()
460+
461+
htmlTitle := GetHTMLTitle(t, nil, "/user27/repo49")
462+
assert.EqualValues(t, "user27/repo49: A wonderful repository with more than just a README.md - Gitea: Git with a cup of tea", htmlTitle)
463+
})
464+
})
465+
466+
t.Run("Code view", func(t *testing.T) {
467+
t.Run("Directory", func(t *testing.T) {
468+
t.Run("Default branch", func(t *testing.T) {
469+
defer tests.PrintCurrentTest(t)()
470+
471+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting")
472+
assert.EqualValues(t, "repo59/deep/nesting at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
473+
})
474+
t.Run("Non-default branch", func(t *testing.T) {
475+
defer tests.PrintCurrentTest(t)()
476+
477+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting")
478+
assert.EqualValues(t, "repo59/deep/nesting at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
479+
})
480+
t.Run("Commit", func(t *testing.T) {
481+
defer tests.PrintCurrentTest(t)()
482+
483+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/")
484+
assert.EqualValues(t, "repo59/deep/nesting at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
485+
})
486+
t.Run("Tag", func(t *testing.T) {
487+
defer tests.PrintCurrentTest(t)()
488+
489+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/")
490+
assert.EqualValues(t, "repo59/deep/nesting at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
491+
})
492+
})
493+
t.Run("File", func(t *testing.T) {
494+
t.Run("Default branch", func(t *testing.T) {
495+
defer tests.PrintCurrentTest(t)()
496+
497+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting/folder/secret_sauce_recipe.txt")
498+
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
499+
})
500+
t.Run("Non-default branch", func(t *testing.T) {
501+
defer tests.PrintCurrentTest(t)()
502+
503+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting/folder/secret_sauce_recipe.txt")
504+
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
505+
})
506+
t.Run("Commit", func(t *testing.T) {
507+
defer tests.PrintCurrentTest(t)()
508+
509+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/folder/secret_sauce_recipe.txt")
510+
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
511+
})
512+
t.Run("Tag", func(t *testing.T) {
513+
defer tests.PrintCurrentTest(t)()
514+
515+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/folder/secret_sauce_recipe.txt")
516+
assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
517+
})
518+
})
519+
})
520+
521+
t.Run("Issues view", func(t *testing.T) {
522+
t.Run("Overview page", func(t *testing.T) {
523+
defer tests.PrintCurrentTest(t)()
524+
525+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues")
526+
assert.EqualValues(t, "Issues - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
527+
})
528+
t.Run("View issue page", func(t *testing.T) {
529+
defer tests.PrintCurrentTest(t)()
530+
531+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues/1")
532+
assert.EqualValues(t, "#1 - issue1 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
533+
})
534+
})
535+
536+
t.Run("Pull requests view", func(t *testing.T) {
537+
t.Run("Overview page", func(t *testing.T) {
538+
defer tests.PrintCurrentTest(t)()
539+
540+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls")
541+
assert.EqualValues(t, "Pull Requests - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
542+
})
543+
t.Run("View pull request", func(t *testing.T) {
544+
defer tests.PrintCurrentTest(t)()
545+
546+
htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls/2")
547+
assert.EqualValues(t, "#2 - issue2 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
548+
})
549+
})
550+
}

0 commit comments

Comments
 (0)