diff --git a/modules/packages/npm/creator.go b/modules/packages/npm/creator.go
index cc7695726bb..c49e1267a7a 100644
--- a/modules/packages/npm/creator.go
+++ b/modules/packages/npm/creator.go
@@ -181,10 +181,11 @@ func (u *User) UnmarshalJSON(data []byte) error {
return nil
}
-// Repository https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#version
+// Repository https://docs.npmjs.com/cli/v11/configuring-npm/package-json#repository
type Repository struct {
- Type string `json:"type"`
- URL string `json:"url"`
+ Type string `json:"type"`
+ URL string `json:"url"`
+ Directory string `json:"directory,omitempty"`
}
// PackageAttachment https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#package
diff --git a/modules/packages/npm/creator_test.go b/modules/packages/npm/creator_test.go
index 40c50de91f9..7474d6c9f4b 100644
--- a/modules/packages/npm/creator_test.go
+++ b/modules/packages/npm/creator_test.go
@@ -28,8 +28,9 @@ func TestParsePackage(t *testing.T) {
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
integrity := "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg=="
repository := Repository{
- Type: "gitea",
- URL: "http://localhost:3000/gitea/test.git",
+ Type: "gitea",
+ URL: "http://localhost:3000/gitea/test.git",
+ Directory: "packages/test-package",
}
t.Run("InvalidUpload", func(t *testing.T) {
@@ -298,6 +299,7 @@ func TestParsePackage(t *testing.T) {
assert.Equal(t, "1.2.0", p.Metadata.Dependencies["package"])
assert.Equal(t, repository.Type, p.Metadata.Repository.Type)
assert.Equal(t, repository.URL, p.Metadata.Repository.URL)
+ assert.Equal(t, repository.Directory, p.Metadata.Repository.Directory)
})
t.Run("ValidLicenseMap", func(t *testing.T) {
diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go
index 9d05bb2a0b6..b78196bd5c9 100644
--- a/modules/templates/util_render.go
+++ b/modules/templates/util_render.go
@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/emoji"
+ "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
@@ -223,6 +224,25 @@ func (ut *RenderUtils) MarkdownToHtml(input string) template.HTML { //nolint:rev
return output
}
+// RenderPackageMarkdown renders package page Markdown so relative links resolve against the
+// linked repository's default branch instead of the site root, falling back to plain rendering
+// when there is no linked repository. pkgTreePath optionally roots links in a subdirectory
+// (e.g. npm's repository.directory for monorepo packages).
+func (ut *RenderUtils) RenderPackageMarkdown(input string, linkedRepo *repo.Repository, pkgTreePath ...string) template.HTML {
+ if linkedRepo == nil {
+ return `
` + ut.MarkdownToHtml(input) + `
`
+ }
+ rctx := renderhelper.NewRenderContextRepoFile(ut.ctx, linkedRepo, renderhelper.RepoFileOptions{
+ CurrentRefSubURL: git.RefNameFromBranch(linkedRepo.DefaultBranch).RefWebLinkPath(),
+ CurrentTreePath: util.OptionalArg(pkgTreePath),
+ })
+ output, err := markdown.RenderString(rctx, input)
+ if err != nil {
+ log.Error("RenderString: %v", err)
+ }
+ return `` + output + `
`
+}
+
func (ut *RenderUtils) RenderLabels(labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML {
isPullRequest := issue != nil && issue.IsPull
baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues"))
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index de7768e91c3..61dcb4937f1 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -194,6 +194,38 @@ space
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", mockRepo, "pkg-subdir")
+ expected := ``
+ 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 := ``
+ 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 := ``
+ 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"}
diff --git a/templates/package/content/cargo.tmpl b/templates/package/content/cargo.tmpl
index ebb23e86597..5c04ab8aae9 100644
--- a/templates/package/content/cargo.tmpl
+++ b/templates/package/content/cargo.tmpl
@@ -27,7 +27,7 @@ git-fetch-with-cli = true
{{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.Readme}}
{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}
{{end}}
- {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Readme}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Readme .PackageDescriptor.Repository}}
{{end}}
{{end}}
{{if .PackageDescriptor.Metadata.Dependencies}}
diff --git a/templates/package/content/chef.tmpl b/templates/package/content/chef.tmpl
index d1c17d36a49..0912aff792c 100644
--- a/templates/package/content/chef.tmpl
+++ b/templates/package/content/chef.tmpl
@@ -20,7 +20,7 @@
{{if .PackageDescriptor.Metadata.Description}}
{{.PackageDescriptor.Metadata.Description}}
{{end}}
- {{if .PackageDescriptor.Metadata.LongDescription}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.LongDescription}}{{end}}
+ {{if .PackageDescriptor.Metadata.LongDescription}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.LongDescription .PackageDescriptor.Repository}}{{end}}
{{end}}
diff --git a/templates/package/content/composer.tmpl b/templates/package/content/composer.tmpl
index 2e8cfb77ebc..5bbc19e9f25 100644
--- a/templates/package/content/composer.tmpl
+++ b/templates/package/content/composer.tmpl
@@ -25,7 +25,7 @@
{{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.Comments}}
{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}
{{end}}
- {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Readme}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Readme .PackageDescriptor.Repository}}
{{end}}
{{if .PackageDescriptor.Metadata.Comments}}{{StringUtils.Join .PackageDescriptor.Metadata.Comments " "}}
{{end}}
{{end}}
diff --git a/templates/package/content/npm.tmpl b/templates/package/content/npm.tmpl
index 28bcf45ee87..89f4c940081 100644
--- a/templates/package/content/npm.tmpl
+++ b/templates/package/content/npm.tmpl
@@ -22,15 +22,8 @@
{{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.Readme}}
-
- {{if .PackageDescriptor.Metadata.Readme}}
-
- {{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Readme}}
-
- {{else if .PackageDescriptor.Metadata.Description}}
- {{.PackageDescriptor.Metadata.Description}}
- {{end}}
-
+ {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Readme .PackageDescriptor.Repository .PackageDescriptor.Metadata.Repository.Directory}}
{{end}}
{{end}}
{{if or .PackageDescriptor.Metadata.Dependencies .PackageDescriptor.Metadata.DevelopmentDependencies .PackageDescriptor.Metadata.PeerDependencies .PackageDescriptor.Metadata.OptionalDependencies}}
diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl
index 7f874044cc1..fc9a715a28e 100644
--- a/templates/package/content/nuget.tmpl
+++ b/templates/package/content/nuget.tmpl
@@ -18,9 +18,9 @@
{{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes .PackageDescriptor.Metadata.Readme}}
- {{if .PackageDescriptor.Metadata.Description}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Description}}
{{end}}
- {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Readme}}
{{end}}
- {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.ReleaseNotes}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Description}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Description .PackageDescriptor.Repository}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Readme .PackageDescriptor.Repository}}
{{end}}
+ {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.ReleaseNotes .PackageDescriptor.Repository}}
{{end}}
{{end}}
{{if .PackageDescriptor.Metadata.Dependencies}}
diff --git a/templates/package/content/pub.tmpl b/templates/package/content/pub.tmpl
index 9eefcf71625..5dafa2db47e 100644
--- a/templates/package/content/pub.tmpl
+++ b/templates/package/content/pub.tmpl
@@ -14,6 +14,6 @@
{{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.Readme}}
{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}
{{end}}
- {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Readme}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Readme .PackageDescriptor.Repository}}
{{end}}
{{end}}
{{end}}
diff --git a/templates/package/content/pypi.tmpl b/templates/package/content/pypi.tmpl
index 4afdc1b72a7..c570e60e6bf 100644
--- a/templates/package/content/pypi.tmpl
+++ b/templates/package/content/pypi.tmpl
@@ -16,9 +16,9 @@
{{if .PackageDescriptor.Metadata.Summary}}{{.PackageDescriptor.Metadata.Summary}}{{end}}
{{if .PackageDescriptor.Metadata.LongDescription}}
- {{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.LongDescription}}
+ {{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.LongDescription .PackageDescriptor.Repository}}
{{else if .PackageDescriptor.Metadata.Description}}
- {{ctx.RenderUtils.MarkdownToHtml .PackageDescriptor.Metadata.Description}}
+ {{ctx.RenderUtils.RenderPackageMarkdown .PackageDescriptor.Metadata.Description .PackageDescriptor.Repository}}
{{end}}
{{end}}
diff --git a/tests/integration/api_packages_npm_test.go b/tests/integration/api_packages_npm_test.go
index 92f9b61081b..8fb892cc866 100644
--- a/tests/integration/api_packages_npm_test.go
+++ b/tests/integration/api_packages_npm_test.go
@@ -13,6 +13,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/packages"
+ repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/packages/npm"
@@ -20,6 +21,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestPackageNpm(t *testing.T) {
@@ -39,6 +41,7 @@ func TestPackageNpm(t *testing.T) {
packageBinPath := "./cli.sh"
repoType := "gitea"
repoURL := "http://localhost:3000/gitea/test.git"
+ repoDirectory := "package-subdir"
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
@@ -67,8 +70,10 @@ func TestPackageNpm(t *testing.T) {
},
"repository": {
"type": "` + repoType + `",
- "url": "` + repoURL + `"
+ "url": "` + repoURL + `",
+ "directory": "` + repoDirectory + `"
},
+ "readme": "[docs](docs/usage.md)\n",
"peerDependencies": {
"tea": "2.x",
"soy-milk": "1.2"
@@ -282,6 +287,28 @@ func TestPackageNpm(t *testing.T) {
}
})
+ t.Run("WebViewReadmeRepoLinks", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeNpm)
+ assert.NoError(t, err)
+ require.Len(t, pvs, 1)
+
+ // link the package to a repository so README relative links resolve against
+ // repository files instead of the site root
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ assert.NoError(t, packages.SetRepositoryLink(t.Context(), pvs[0].PackageID, repo.ID))
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages/npm/%s/%s", user.Name, url.PathEscape(packageName), packageVersion)).
+ AddBasicAuth(user.Name)
+ resp := MakeRequest(t, req, http.StatusOK)
+ doc := NewHTMLParser(t, resp.Body)
+ rendered, _ := doc.Find(".markup.markdown").Html()
+ assert.Equal(t, `docs
+
+`, rendered)
+ })
+
t.Run("Delete", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()