enhance(citation): render citations server-side (#39373)

Replace citation-js with a Go port of ruby-cff, which GitHub uses for
"Cite this repository", rendering APA and BibTeX server-side and
dropping about 770KB of JS. Output matches GitHub on 1568 of 1571
real-world files, the rest are improvements over GitHub.

- `CITATION.cff` wins over `CITATION.bib`, matched case-insensitively
and through symlinks
- `CITATION.bib` is offered as-is, without APA

Signed-off-by: silverwind <me@silverwind.io>
This commit is contained in:
silverwind authored and GitHub committed 2026-10-03 02:28:34 +00:00
1 parent fb067e1115
commit 2baa5a16f8
15 files changed
+704 -361

No files matched your search

+19
View File
@@ -44,6 +44,7 @@ func TestRepoView(t *testing.T) {
t.Run("ViewRepoDirectory", testViewRepoDirectory)
t.Run("ViewRepoDirectoryReadme", testViewRepoDirectoryReadme)
t.Run("ViewRepoSymlink", testViewRepoSymlink)
t.Run("ViewRepoCitationPicksCFFCaseInsensitivelyThroughSymlink", testViewRepoCitationPicksCFFCaseInsensitivelyThroughSymlink)
t.Run("MarkDownReadmeImage", testMarkDownReadmeImage)
t.Run("MarkDownReadmeImageSubfolder", testMarkDownReadmeImageSubfolder)
t.Run("GeneratedSourceLink", testGeneratedSourceLink)
@@ -512,6 +513,24 @@ func testViewRepoSymlink(t *testing.T) {
assert.Equal(t, "/user2/repo1/src/branch/symlink/some/other/path/awefulcake.txt?follow_symlink=1", resp.Header().Get("Location"))
}
func testViewRepoCitationPicksCFFCaseInsensitivelyThroughSymlink(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 2, ID: 1})
require.NoError(t, git.ForceFastImport(t.Context(), repo.CodeStorageRepo(), []git.FastImportCommit{
{
Ref: "refs/heads/citation", Message: "test", Files: []git.FastImportFile{
{Path: "CITATION.CFF/README.md", Content: "not a citation"},
{Path: "CITATION.bib", Content: "@misc{key}"},
{Mode: git.EntryModeSymlink, Path: "citation.cff", Content: "meta/citation.yaml"},
{Path: "meta/citation.yaml", Content: "title: Tool\nauthors: [{name: Team}]\n"},
},
},
}))
resp := MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/src/branch/citation"), http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Equal(t, "Team. Tool [Computer software]", htmlDoc.Find("#cite-repo-modal .citation-apa").AttrOr("data-text", ""))
assert.Equal(t, "/user2/repo1/src/branch/citation/citation.cff", htmlDoc.Find("#cite-repo-modal a.jump").AttrOr("href", ""))
}
func testMarkDownReadmeImage(t *testing.T) {
defer tests.PrintCurrentTest(t)()