diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 5b0f4940d1..5295bfdb2a 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -75,12 +75,13 @@ const ( // entries == ctx.Repo.Commit.SubTree(ctx.Repo.TreePath).ListEntries() // // FIXME: There has to be a more efficient way of doing this -func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { +func FindReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, tryWellKnownDirs bool) (string, *git.TreeEntry, error) { // Create a list of extensions in priority order // 1. Markdown files - with and without localisation - e.g. README.en-us.md or README.md - // 2. Txt files - e.g. README.txt - // 3. No extension - e.g. README - exts := append(localizedExtensions(".md", ctx.Locale.Language()), ".txt", "") // sorted by priority + // 2. Org-Mode files - with and without localisation - e.g. README.en-us.org or README.org + // 3. Txt files - e.g. README.txt + // 4. No extension - e.g. README + exts := append(append(localizedExtensions(".md", ctx.Locale.Language()), localizedExtensions(".org", ctx.Locale.Language())...), ".txt", "") // sorted by priority extCount := len(exts) readmeFiles := make([]*git.TreeEntry, extCount+1) @@ -151,7 +152,7 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try return "", nil, err } - subfolder, readmeFile, err := findReadmeFileInEntries(ctx, childEntries, false) + subfolder, readmeFile, err := FindReadmeFileInEntries(ctx, childEntries, false) if err != nil && !git.IsErrNotExist(err) { return "", nil, err } @@ -175,7 +176,7 @@ func renderDirectory(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefName) } - subfolder, readmeFile, err := findReadmeFileInEntries(ctx, entries, true) + subfolder, readmeFile, err := FindReadmeFileInEntries(ctx, entries, true) if err != nil { ctx.ServerError("findReadmeFileInEntries", err) return diff --git a/tests/integration/repo_view_test.go b/tests/integration/repo_view_test.go new file mode 100644 index 0000000000..8a77532c9b --- /dev/null +++ b/tests/integration/repo_view_test.go @@ -0,0 +1,154 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/url" + "strings" + "testing" + + unit_model "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/routers/web/repo" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/contexttest" + files_service "code.gitea.io/gitea/services/repository/files" + + "github.com/stretchr/testify/assert" +) + +func createRepoAndGetContext(t *testing.T, files []string, deleteMdReadme bool) (*context.Context, func()) { + t.Helper() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}) + + size := len(files) + if deleteMdReadme { + size++ + } + changeFiles := make([]*files_service.ChangeRepoFile, size) + for i, e := range files { + changeFiles[i] = &files_service.ChangeRepoFile{ + Operation: "create", + TreePath: e, + ContentReader: strings.NewReader("test"), + } + } + if deleteMdReadme { + changeFiles[len(files)] = &files_service.ChangeRepoFile{ + Operation: "delete", + TreePath: "README.md", + } + } + + // README.md is already added by auto init + repo, _, f := CreateDeclarativeRepo(t, user, "readmetest", []unit_model.Type{unit_model.TypeCode}, nil, changeFiles) + + ctx, _ := contexttest.MockContext(t, "user1/readmetest") + ctx.SetParams(":id", fmt.Sprint(repo.ID)) + contexttest.LoadRepo(t, ctx, repo.ID) + contexttest.LoadRepoCommit(t, ctx) + return ctx, f +} + +func TestRepoView_FindReadme(t *testing.T) { + t.Run("PrioOneLocalizedMdReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.en.md", "README.en.org", "README.org", "README.txt", "README.tex"}, false) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.en.md", file.Name()) + }) + }) + t.Run("PrioTwoMdReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.en.org", "README.org", "README.txt", "README.tex"}, false) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.md", file.Name()) + }) + }) + t.Run("PrioThreeLocalizedOrgReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.en.org", "README.org", "README.txt", "README.tex"}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.en.org", file.Name()) + }) + }) + t.Run("PrioFourOrgReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.org", "README.txt", "README.tex"}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.org", file.Name()) + }) + }) + t.Run("PrioFiveTxtReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.txt", "README", "README.tex"}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.txt", file.Name()) + }) + }) + t.Run("PrioSixWithoutExtensionReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README", "README.tex"}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README", file.Name()) + }) + }) + t.Run("PrioSevenAnyReadme", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{"README.tex"}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Equal(t, "README.tex", file.Name()) + }) + }) + t.Run("DoNotPickReadmeIfNonPresent", func(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + ctx, f := createRepoAndGetContext(t, []string{}, true) + defer f() + + tree, _ := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + entries, _ := tree.ListEntries() + _, file, _ := repo.FindReadmeFileInEntries(ctx, entries, false) + + assert.Nil(t, file) + }) + }) +}