From 099abd69c68e0273c905de81c4fbeacc9b0533ba Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Apr 2024 07:13:00 +0200 Subject: [PATCH 1/4] Read flat dependencies. Co-authored-by: Benjamin Heemann --- modules/packages/nuget/metadata.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 3c478b1c0288c..4a674b99baf0d 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -71,6 +71,7 @@ type Dependency struct { Version string `json:"version"` } +// https://learn.microsoft.com/en-us/nuget/reference/nuspec type nuspecPackage struct { Metadata struct { ID string `xml:"id"` @@ -89,6 +90,11 @@ type nuspecPackage struct { URL string `xml:"url,attr"` } `xml:"repository"` Dependencies struct { + Dependency []struct { + ID string `xml:"id,attr"` + Version string `xml:"version,attr"` + Exclude string `xml:"exclude,attr"` + } `xml:"dependency"` Group []struct { TargetFramework string `xml:"targetFramework,attr"` Dependency []struct { @@ -166,6 +172,19 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) { Dependencies: make(map[string][]Dependency), } + if len(p.Metadata.Dependencies.Dependency) > 0 { + deps := make([]Dependency, 0, len(p.Metadata.Dependencies.Dependency)) + for _, dep := range p.Metadata.Dependencies.Dependency { + if dep.ID == "" || dep.Version == "" { + continue + } + deps = append(deps, Dependency{ + ID: dep.ID, + Version: dep.Version, + }) + } + m.Dependencies[""] = deps + } for _, group := range p.Metadata.Dependencies.Group { deps := make([]Dependency, 0, len(group.Dependency)) for _, dep := range group.Dependency { From 3944903bd7126c3293418912c9ae7aad19fa8ae5 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Apr 2024 07:14:00 +0200 Subject: [PATCH 2/4] Render text as markdown. --- templates/package/content/nuget.tmpl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index 0911260fbaa21..e4ec12774dba3 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -18,10 +18,8 @@ {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes}}

{{ctx.Locale.Tr "packages.about"}}

-
- {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}} - {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{.PackageDescriptor.Metadata.ReleaseNotes}}{{end}} -
+ {{if .PackageDescriptor.Metadata.Description}}
{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Description}}
{{end}} + {{if .PackageDescriptor.Metadata.ReleaseNotes}}
{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.ReleaseNotes}}
{{end}} {{end}} {{if .PackageDescriptor.Metadata.Dependencies}} From bf098c4a7591c9ed9f214b5c39f0f09f877ac523 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Apr 2024 07:24:00 +0200 Subject: [PATCH 3/4] Extract and render readme. --- modules/packages/nuget/metadata.go | 17 ++++++++++++++--- templates/package/content/nuget.tmpl | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 4a674b99baf0d..6769c514cc2ff 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -58,6 +58,7 @@ type Package struct { type Metadata struct { Description string `json:"description,omitempty"` ReleaseNotes string `json:"release_notes,omitempty"` + Readme string `json:"readme,omitempty"` Authors string `json:"authors,omitempty"` ProjectURL string `json:"project_url,omitempty"` RepositoryURL string `json:"repository_url,omitempty"` @@ -81,6 +82,7 @@ type nuspecPackage struct { ProjectURL string `xml:"projectUrl"` Description string `xml:"description"` ReleaseNotes string `xml:"releaseNotes"` + Readme string `xml:"readme"` PackageTypes struct { PackageType []struct { Name string `xml:"name,attr"` @@ -90,7 +92,7 @@ type nuspecPackage struct { URL string `xml:"url,attr"` } `xml:"repository"` Dependencies struct { - Dependency []struct { + Dependency []struct { ID string `xml:"id,attr"` Version string `xml:"version,attr"` Exclude string `xml:"exclude,attr"` @@ -128,14 +130,14 @@ func ParsePackageMetaData(r io.ReaderAt, size int64) (*Package, error) { } defer f.Close() - return ParseNuspecMetaData(f) + return ParseNuspecMetaData(archive, f) } } return nil, ErrMissingNuspecFile } // ParseNuspecMetaData parses a Nuspec file to retrieve the metadata of a Nuget package -func ParseNuspecMetaData(r io.Reader) (*Package, error) { +func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { var p nuspecPackage if err := xml.NewDecoder(r).Decode(&p); err != nil { return nil, err @@ -172,6 +174,15 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) { Dependencies: make(map[string][]Dependency), } + if p.Metadata.Readme != "" { + f, err := archive.Open(p.Metadata.Readme) + if err == nil { + buf, _ := io.ReadAll(f) + m.Readme = string(buf) + _ = f.Close() + } + } + if len(p.Metadata.Dependencies.Dependency) > 0 { deps := make([]Dependency, 0, len(p.Metadata.Dependencies.Dependency)) for _, dep := range p.Metadata.Dependencies.Dependency { diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index e4ec12774dba3..f1fe420c0ba24 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -16,9 +16,10 @@ - {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes}} + {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes .PackageDescriptor.Metadata.Readme}}

{{ctx.Locale.Tr "packages.about"}}

{{if .PackageDescriptor.Metadata.Description}}
{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Description}}
{{end}} + {{if .PackageDescriptor.Metadata.Readme}}
{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Readme}}
{{end}} {{if .PackageDescriptor.Metadata.ReleaseNotes}}
{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.ReleaseNotes}}
{{end}} {{end}} From 240986bceb754781ee61c3a6f8b9f23a0db4d48c Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Thu, 4 Apr 2024 23:24:00 +0200 Subject: [PATCH 4/4] Combine tests. --- modules/packages/nuget/metadata_test.go | 62 +++++++++++++++---------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go index bba2bff4a538a..f466492f8a85e 100644 --- a/modules/packages/nuget/metadata_test.go +++ b/modules/packages/nuget/metadata_test.go @@ -6,7 +6,6 @@ package nuget import ( "archive/zip" "bytes" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -19,6 +18,7 @@ const ( projectURL = "https://gitea.io" description = "Package Description" releaseNotes = "Package Release Notes" + readme = "Readme" repositoryURL = "https://gitea.io/gitea/gitea" targetFramework = ".NETStandard2.1" dependencyID = "System.Text.Json" @@ -36,6 +36,7 @@ const nuspecContent = ` ` + description + ` ` + releaseNotes + ` + README.md @@ -60,17 +61,19 @@ const symbolsNuspecContent = ` ` func TestParsePackageMetaData(t *testing.T) { - createArchive := func(name, content string) []byte { + createArchive := func(files map[string]string) []byte { var buf bytes.Buffer archive := zip.NewWriter(&buf) - w, _ := archive.Create(name) - w.Write([]byte(content)) + for name, content := range files { + w, _ := archive.Create(name) + w.Write([]byte(content)) + } archive.Close() return buf.Bytes() } t.Run("MissingNuspecFile", func(t *testing.T) { - data := createArchive("dummy.txt", "") + data := createArchive(map[string]string{"dummy.txt": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -78,7 +81,7 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("MissingNuspecFileInRoot", func(t *testing.T) { - data := createArchive("sub/package.nuspec", "") + data := createArchive(map[string]string{"sub/package.nuspec": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -86,7 +89,7 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidNuspecFile", func(t *testing.T) { - data := createArchive("package.nuspec", "") + data := createArchive(map[string]string{"package.nuspec": ""}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -94,10 +97,10 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidPackageId", func(t *testing.T) { - data := createArchive("package.nuspec", ` + data := createArchive(map[string]string{"package.nuspec": ` - `) + `}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) @@ -105,30 +108,34 @@ func TestParsePackageMetaData(t *testing.T) { }) t.Run("InvalidPackageVersion", func(t *testing.T) { - data := createArchive("package.nuspec", ` + data := createArchive(map[string]string{"package.nuspec": ` - `+id+` + ` + id + ` - `) + `}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.Nil(t, np) assert.ErrorIs(t, err, ErrNuspecInvalidVersion) }) - t.Run("Valid", func(t *testing.T) { - data := createArchive("package.nuspec", nuspecContent) + t.Run("MissingReadme", func(t *testing.T) { + data := createArchive(map[string]string{"package.nuspec": nuspecContent}) np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) + assert.Empty(t, np.Metadata.Readme) }) -} -func TestParseNuspecMetaData(t *testing.T) { t.Run("Dependency Package", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(nuspecContent)) + data := createArchive(map[string]string{ + "package.nuspec": nuspecContent, + "README.md": readme, + }) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, DependencyPackage, np.PackageType) @@ -139,6 +146,7 @@ func TestParseNuspecMetaData(t *testing.T) { assert.Equal(t, projectURL, np.Metadata.ProjectURL) assert.Equal(t, description, np.Metadata.Description) assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) + assert.Equal(t, readme, np.Metadata.Readme) assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL) assert.Len(t, np.Metadata.Dependencies, 1) assert.Contains(t, np.Metadata.Dependencies, targetFramework) @@ -148,13 +156,15 @@ func TestParseNuspecMetaData(t *testing.T) { assert.Equal(t, dependencyVersion, deps[0].Version) t.Run("NormalizedVersion", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(` - - - test - 1.04.5.2.5-rc.1+metadata - -`)) + data := createArchive(map[string]string{"package.nuspec": ` + + + test + 1.04.5.2.5-rc.1+metadata + + `}) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, "1.4.5.2-rc.1", np.Version) @@ -162,7 +172,9 @@ func TestParseNuspecMetaData(t *testing.T) { }) t.Run("Symbols Package", func(t *testing.T) { - np, err := ParseNuspecMetaData(strings.NewReader(symbolsNuspecContent)) + data := createArchive(map[string]string{"package.nuspec": symbolsNuspecContent}) + + np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data))) assert.NoError(t, err) assert.NotNil(t, np) assert.Equal(t, SymbolsPackage, np.PackageType)