diff --git a/models/fixtures/release.yml b/models/fixtures/release.yml
index 4ed7df440d..844deb3a7b 100644
--- a/models/fixtures/release.yml
+++ b/models/fixtures/release.yml
@@ -136,3 +136,17 @@
is_prerelease: false
is_tag: false
created_unix: 946684803
+
+- id: 11
+ repo_id: 59
+ publisher_id: 2
+ tag_name: "v1.0"
+ lower_tag_name: "v1.0"
+ target: "main"
+ title: "v1.0"
+ sha1: "d8f53dfb33f6ccf4169c34970b5e747511c18beb"
+ num_commits: 1
+ is_draft: false
+ is_prerelease: false
+ is_tag: false
+ created_unix: 946684803
diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml
index c22eb8c2a2..6afef2a432 100644
--- a/models/fixtures/repo_unit.yml
+++ b/models/fixtures/repo_unit.yml
@@ -608,6 +608,38 @@
type: 1
created_unix: 946684810
+# BEGIN Forgejo [GITEA] Improve HTML title on repositories
+-
+ id: 1093
+ repo_id: 59
+ type: 1
+ created_unix: 946684810
+
+-
+ id: 1094
+ repo_id: 59
+ type: 2
+ created_unix: 946684810
+
+-
+ id: 1095
+ repo_id: 59
+ type: 3
+ created_unix: 946684810
+
+-
+ id: 1096
+ repo_id: 59
+ type: 4
+ created_unix: 946684810
+
+-
+ id: 1097
+ repo_id: 59
+ type: 5
+ created_unix: 946684810
+# END Forgejo [GITEA] Improve HTML title on repositories
+
-
id: 91
repo_id: 58
diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml
index c63b7ebd48..999d1f56ae 100644
--- a/models/fixtures/repository.yml
+++ b/models/fixtures/repository.yml
@@ -1467,6 +1467,7 @@
owner_name: user27
lower_name: repo49
name: repo49
+ description: A wonderful repository with more than just a README.md
default_branch: master
num_watches: 0
num_stars: 0
@@ -1693,3 +1694,16 @@
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false
+
+-
+ id: 59
+ owner_id: 2
+ owner_name: user2
+ lower_name: repo59
+ name: repo59
+ default_branch: master
+ is_empty: false
+ is_archived: false
+ is_private: false
+ status: 0
+ num_issues: 0
diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml
index fd51379816..79fbb981f6 100644
--- a/models/fixtures/user.yml
+++ b/models/fixtures/user.yml
@@ -66,7 +66,7 @@
num_followers: 2
num_following: 1
num_stars: 2
- num_repos: 14
+ num_repos: 15
num_teams: 0
num_members: 0
visibility: 0
diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go
index 8a1799aac0..a8b958109c 100644
--- a/models/repo/repo_list_test.go
+++ b/models/repo/repo_list_test.go
@@ -138,12 +138,12 @@ func getTestCases() []struct {
{
name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse},
- count: 31,
+ count: 32,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse},
- count: 36,
+ count: 37,
},
{
name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
@@ -158,7 +158,7 @@ func getTestCases() []struct {
{
name: "AllPublic/PublicRepositoriesOfOrganization",
opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse},
- count: 31,
+ count: 32,
},
{
name: "AllTemplates",
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 91c00b049e..b864bfed43 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -165,7 +165,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
if ctx.Repo.TreePath != "" {
ctx.Data["HideRepoInfo"] = true
- ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
+ ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+util.PathEscapeSegments(ctx.Repo.TreePath), ctx.Repo.RefName)
}
subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true)
@@ -344,7 +344,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
defer dataRc.Close()
- ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
+ ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+util.PathEscapeSegments(ctx.Repo.TreePath), ctx.Repo.RefName)
ctx.Data["FileIsSymlink"] = entry.IsLink()
ctx.Data["FileName"] = blob.Name()
ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index c3645209cd..08c68752e2 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -2,7 +2,8 @@
- {{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}
+ {{/* Display `- .Repsository.FullName` only if `.Title` does not already start with that. */}}
+ {{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppName}}
{{if .ManifestData}}{{end}}
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/HEAD b/tests/gitea-repositories-meta/user2/repo59.git/HEAD
new file mode 100644
index 0000000000..cb089cd89a
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/config b/tests/gitea-repositories-meta/user2/repo59.git/config
new file mode 100644
index 0000000000..07d359d07c
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/config
@@ -0,0 +1,4 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = true
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/description b/tests/gitea-repositories-meta/user2/repo59.git/description
new file mode 100644
index 0000000000..498b267a8c
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/info/exclude b/tests/gitea-repositories-meta/user2/repo59.git/info/exclude
new file mode 100644
index 0000000000..a5196d1be8
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/40/8bbd3bd1f96950f8cf2f98c479557f6b18817a b/tests/gitea-repositories-meta/user2/repo59.git/objects/40/8bbd3bd1f96950f8cf2f98c479557f6b18817a
new file mode 100644
index 0000000000..567284ef1c
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/40/8bbd3bd1f96950f8cf2f98c479557f6b18817a differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/5d/5c87a90af64cc67f22d60a942d5efaef8bc96b b/tests/gitea-repositories-meta/user2/repo59.git/objects/5d/5c87a90af64cc67f22d60a942d5efaef8bc96b
new file mode 100644
index 0000000000..f23960f4cc
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/5d/5c87a90af64cc67f22d60a942d5efaef8bc96b differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/88/3e2970ed6937cbb63311e941adb97df0ae3a52 b/tests/gitea-repositories-meta/user2/repo59.git/objects/88/3e2970ed6937cbb63311e941adb97df0ae3a52
new file mode 100644
index 0000000000..46cc9e3e5e
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/88/3e2970ed6937cbb63311e941adb97df0ae3a52 differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/8c/ac7a8f434451410cc91ab9c04d07baff974ad8 b/tests/gitea-repositories-meta/user2/repo59.git/objects/8c/ac7a8f434451410cc91ab9c04d07baff974ad8
new file mode 100644
index 0000000000..5a1e79326f
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/8c/ac7a8f434451410cc91ab9c04d07baff974ad8 differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/a0/ccafed39086ef520be6886d9395eb2100d317e b/tests/gitea-repositories-meta/user2/repo59.git/objects/a0/ccafed39086ef520be6886d9395eb2100d317e
new file mode 100644
index 0000000000..3b71228a7e
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/a0/ccafed39086ef520be6886d9395eb2100d317e differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/ab/e2a9ddfd7f542ff89bc13960a929dc8ca86c99 b/tests/gitea-repositories-meta/user2/repo59.git/objects/ab/e2a9ddfd7f542ff89bc13960a929dc8ca86c99
new file mode 100644
index 0000000000..dcbd3b3eb9
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/ab/e2a9ddfd7f542ff89bc13960a929dc8ca86c99 differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/cd/879fb6cf5b7bbe0fbc3a0ef44c8695fde89a56 b/tests/gitea-repositories-meta/user2/repo59.git/objects/cd/879fb6cf5b7bbe0fbc3a0ef44c8695fde89a56
new file mode 100644
index 0000000000..cd9cea6797
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/cd/879fb6cf5b7bbe0fbc3a0ef44c8695fde89a56 differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/d8/f53dfb33f6ccf4169c34970b5e747511c18beb b/tests/gitea-repositories-meta/user2/repo59.git/objects/d8/f53dfb33f6ccf4169c34970b5e747511c18beb
new file mode 100644
index 0000000000..bea28c9f69
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/d8/f53dfb33f6ccf4169c34970b5e747511c18beb differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/objects/f3/c1ec36c0e7605be54e71f24035caa675b7ba41 b/tests/gitea-repositories-meta/user2/repo59.git/objects/f3/c1ec36c0e7605be54e71f24035caa675b7ba41
new file mode 100644
index 0000000000..b6803eb5a2
Binary files /dev/null and b/tests/gitea-repositories-meta/user2/repo59.git/objects/f3/c1ec36c0e7605be54e71f24035caa675b7ba41 differ
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/packed-refs b/tests/gitea-repositories-meta/user2/repo59.git/packed-refs
new file mode 100644
index 0000000000..114c84d2aa
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/packed-refs
@@ -0,0 +1,3 @@
+# pack-refs with: peeled fully-peeled sorted
+d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/heads/master
+d8f53dfb33f6ccf4169c34970b5e747511c18beb refs/tags/v1.0
diff --git a/tests/gitea-repositories-meta/user2/repo59.git/refs/heads/cake-recipe b/tests/gitea-repositories-meta/user2/repo59.git/refs/heads/cake-recipe
new file mode 100644
index 0000000000..63bbea6692
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/repo59.git/refs/heads/cake-recipe
@@ -0,0 +1 @@
+d8f53dfb33f6ccf4169c34970b5e747511c18beb
diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go
index a6d32a89ea..edab964475 100644
--- a/tests/integration/api_repo_test.go
+++ b/tests/integration/api_repo_test.go
@@ -93,9 +93,9 @@ func TestAPISearchRepo(t *testing.T) {
}{
{
name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
- nil: {count: 33},
- user: {count: 33},
- user2: {count: 33},
+ nil: {count: 34},
+ user: {count: 34},
+ user2: {count: 34},
},
},
{
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 49a714c343..a3d0eb1019 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -531,3 +531,18 @@ func GetCSRF(t testing.TB, session *TestSession, urlStr string) string {
doc := NewHTMLParser(t, resp.Body)
return doc.GetCSRF()
}
+
+func GetHTMLTitle(t testing.TB, session *TestSession, urlStr string) string {
+ t.Helper()
+
+ req := NewRequest(t, "GET", urlStr)
+ var resp *httptest.ResponseRecorder
+ if session == nil {
+ resp = MakeRequest(t, req, http.StatusOK)
+ } else {
+ resp = session.MakeRequest(t, req, http.StatusOK)
+ }
+
+ doc := NewHTMLParser(t, resp.Body)
+ return doc.Find("head title").Text()
+}
diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go
index 99a27d6a7f..6beb12dce9 100644
--- a/tests/integration/repo_test.go
+++ b/tests/integration/repo_test.go
@@ -444,3 +444,107 @@ func TestGeneratedSourceLink(t *testing.T) {
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
})
}
+
+func TestRepoHTMLTitle(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ t.Run("Repository homepage", func(t *testing.T) {
+ t.Run("Without description", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1")
+ assert.EqualValues(t, "user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("With description", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user27/repo49")
+ assert.EqualValues(t, "user27/repo49: A wonderful repository with more than just a README.md - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ })
+
+ t.Run("Code view", func(t *testing.T) {
+ t.Run("Directory", func(t *testing.T) {
+ t.Run("Default branch", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting")
+ assert.EqualValues(t, "repo59/deep/nesting at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Non-default branch", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting")
+ assert.EqualValues(t, "repo59/deep/nesting at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Commit", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/")
+ assert.EqualValues(t, "repo59/deep/nesting at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Tag", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/")
+ assert.EqualValues(t, "repo59/deep/nesting at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ })
+ t.Run("File", func(t *testing.T) {
+ t.Run("Default branch", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/master/deep/nesting/folder/secret_sauce_recipe.txt")
+ assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at master - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Non-default branch", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/branch/cake-recipe/deep/nesting/folder/secret_sauce_recipe.txt")
+ assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Commit", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/folder/secret_sauce_recipe.txt")
+ assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("Tag", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo59/src/tag/v1.0/deep/nesting/folder/secret_sauce_recipe.txt")
+ assert.EqualValues(t, "repo59/deep/nesting/folder/secret_sauce_recipe.txt at v1.0 - user2/repo59 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ })
+ })
+
+ t.Run("Issues view", func(t *testing.T) {
+ t.Run("Overview page", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues")
+ assert.EqualValues(t, "Issues - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("View issue page", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/issues/1")
+ assert.EqualValues(t, "#1 - issue1 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ })
+
+ t.Run("Pull requests view", func(t *testing.T) {
+ t.Run("Overview page", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls")
+ assert.EqualValues(t, "Pull Requests - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ t.Run("View pull request", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ htmlTitle := GetHTMLTitle(t, nil, "/user2/repo1/pulls/2")
+ assert.EqualValues(t, "#2 - issue2 - user2/repo1 - Gitea: Git with a cup of tea", htmlTitle)
+ })
+ })
+}