fix(packages): render markdown links relative to linked repo (#37676)

Package-page markdown (READMEs, descriptions, release notes) was
rendered as a plain document, so relative links and images resolved
against the site root and 404'd. This renders it in the context of the
package's linked repository instead, falling back to plain rendering
when the package has no linked repo.

For a README link `[usage](docs/usage.md)` in a package linked to
`user/repo` (default branch `main`):

| | Resolved link |
|---|---|
| Before | `/docs/usage.md` |
| After | `/user/repo/src/branch/main/docs/usage.md` |

For an npm monorepo package with `repository.directory: packages/foo`,
an image `![logo](logo.png)` resolves to
`/user/repo/src/branch/main/packages/foo/logo.png`.

Applied to every package content template that renders markdown:
`cargo`, `chef`, `composer`, `npm`, `nuget`, `pub`, `pypi`. Links
resolve against the repository default branch (metadata records no
publish commit). Only the web package detail page is affected; registry
API responses are unchanged.

Note: as part of restructuring `npm.tmpl`, the package description and
README now render as separate sections instead of the README replacing
the description, matching the existing `cargo`/`composer`/`pub` layout.

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Thomas Hallock
2026-05-24 09:13:49 +00:00
committed by GitHub
co-authored by silverwind Claude wxiaoguang
parent 748d4a8040
commit 6f4027a6be
12 changed files with 99 additions and 24 deletions
+32
View File
@@ -194,6 +194,38 @@ space</p>
assert.Equal(t, expected, string(newTestRenderUtils(t).MarkdownToHtml(testInput())))
}
func TestRenderPackageMarkdown(t *testing.T) {
defer test.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
mockRepo := &repo.Repository{
ID: 1, OwnerName: "user13", Name: "repo11", DefaultBranch: "main",
Owner: &user_model.User{ID: 13, Name: "user13"},
Units: []*repo.RepoUnit{},
}
ut := newTestRenderUtils(t)
t.Run("LinkedRepoWithDirectory", func(t *testing.T) {
rendered := ut.RenderPackageMarkdown("[docs](docs/getting-started.md)\n![logo](logo.png)", mockRepo, "pkg-subdir")
expected := `<div class="markup markdown"><p><a href="/user13/repo11/src/branch/main/pkg-subdir/docs/getting-started.md" rel="nofollow">docs</a>
<a href="/user13/repo11/src/branch/main/pkg-subdir/logo.png" target="_blank" rel="nofollow noopener"><img src="/user13/repo11/media/branch/main/pkg-subdir/logo.png" alt="logo"/></a></p>
</div>`
assert.Equal(t, expected, strings.TrimSpace(string(rendered)))
})
t.Run("LinkedRepoWithEmptyDirectory", func(t *testing.T) {
rendered := ut.RenderPackageMarkdown("[docs](docs/getting-started.md)", mockRepo, "")
expected := `<div class="markup markdown"><p><a href="/user13/repo11/src/branch/main/docs/getting-started.md" rel="nofollow">docs</a></p>
</div>`
assert.Equal(t, expected, strings.TrimSpace(string(rendered)))
})
t.Run("UnlinkedRepo", func(t *testing.T) {
rendered := ut.RenderPackageMarkdown("[docs](docs/getting-started.md)", nil, "pkg-subdir")
expected := `<div class="markup markdown"><p><a href="/docs/getting-started.md" rel="nofollow">docs</a></p>
</div>`
assert.Equal(t, expected, strings.TrimSpace(string(rendered)))
})
}
func TestRenderLabels(t *testing.T) {
ut := newTestRenderUtils(t)
label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}