1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-25 19:58:36 +00:00

Improve nuget/rubygems package registries (#34741)

1. Add some missing (optional) fields for nuget v2, and sort the fields
to make it easier to maintain
2. Add missing "platform" for rubygems: `VERSION-PLATFORM` and
`VERSION_PLATFORM`

Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
wxiaoguang
2025-06-18 01:42:00 +08:00
committed by GitHub
parent 224aa64cd9
commit f214bb40a3
16 changed files with 335 additions and 136 deletions

View File

@@ -130,8 +130,8 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
pv := &packages_model.PackageVersion{
PackageID: p.ID,
CreatorID: pi.Owner.ID,
Version: container_model.UploadVersion,
LowerVersion: container_model.UploadVersion,
Version: container_module.UploadVersion,
LowerVersion: container_module.UploadVersion,
IsInternal: true,
MetadataJSON: "null",
}

View File

@@ -151,7 +151,7 @@ func processOciImageManifest(ctx context.Context, mci *manifestCreationInfo, buf
return err
}
uploadVersion, err := packages_model.GetInternalVersionByNameAndVersion(ctx, mci.Owner.ID, packages_model.TypeContainer, mci.Image, container_model.UploadVersion)
uploadVersion, err := packages_model.GetInternalVersionByNameAndVersion(ctx, mci.Owner.ID, packages_model.TypeContainer, mci.Image, container_module.UploadVersion)
if err != nil && err != packages_model.ErrPackageNotExist {
return err
}
@@ -492,7 +492,7 @@ func createManifestBlob(ctx context.Context, mci *manifestCreationInfo, pv *pack
pf, err := createFileFromBlobReference(ctx, pv, nil, &blobReference{
Digest: digest.Digest(manifestDigest),
MediaType: mci.MediaType,
Name: container_model.ManifestFilename,
Name: container_module.ManifestFilename,
File: &packages_model.PackageFileDescriptor{Blob: pb},
ExpectedSize: pb.Size,
IsLead: true,
@@ -505,7 +505,7 @@ func createManifestBlob(ctx context.Context, mci *manifestCreationInfo, pv *pack
OwnerID: mci.Owner.ID,
PackageType: packages_model.TypeContainer,
VersionID: pv.ID,
Query: container_model.ManifestFilename,
Query: container_module.ManifestFilename,
})
if err != nil {
return nil, false, "", err

View File

@@ -246,21 +246,30 @@ type TypedValue[T any] struct {
}
type FeedEntryProperties struct {
Version string `xml:"d:Version"`
NormalizedVersion string `xml:"d:NormalizedVersion"`
Authors string `xml:"d:Authors"`
Copyright string `xml:"d:Copyright,omitempty"`
Created TypedValue[time.Time] `xml:"d:Created"`
Dependencies string `xml:"d:Dependencies"`
Description string `xml:"d:Description"`
VersionDownloadCount TypedValue[int64] `xml:"d:VersionDownloadCount"`
DevelopmentDependency TypedValue[bool] `xml:"d:DevelopmentDependency"`
DownloadCount TypedValue[int64] `xml:"d:DownloadCount"`
PackageSize TypedValue[int64] `xml:"d:PackageSize"`
Created TypedValue[time.Time] `xml:"d:Created"`
ID string `xml:"d:Id"`
IconURL string `xml:"d:IconUrl,omitempty"`
Language string `xml:"d:Language,omitempty"`
LastUpdated TypedValue[time.Time] `xml:"d:LastUpdated"`
Published TypedValue[time.Time] `xml:"d:Published"`
LicenseURL string `xml:"d:LicenseUrl,omitempty"`
MinClientVersion string `xml:"d:MinClientVersion,omitempty"`
NormalizedVersion string `xml:"d:NormalizedVersion"`
Owners string `xml:"d:Owners,omitempty"`
PackageSize TypedValue[int64] `xml:"d:PackageSize"`
ProjectURL string `xml:"d:ProjectUrl,omitempty"`
Published TypedValue[time.Time] `xml:"d:Published"`
ReleaseNotes string `xml:"d:ReleaseNotes,omitempty"`
RequireLicenseAcceptance TypedValue[bool] `xml:"d:RequireLicenseAcceptance"`
Title string `xml:"d:Title"`
Tags string `xml:"d:Tags,omitempty"`
Title string `xml:"d:Title,omitempty"`
Version string `xml:"d:Version"`
VersionDownloadCount TypedValue[int64] `xml:"d:VersionDownloadCount"`
}
type FeedEntry struct {
@@ -353,21 +362,30 @@ func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNames
Author: metadata.Authors,
Content: content,
Properties: &FeedEntryProperties{
Version: pd.Version.Version,
NormalizedVersion: pd.Version.Version,
Authors: metadata.Authors,
Copyright: metadata.Copyright,
Created: createdValue,
Dependencies: buildDependencyString(metadata),
Description: metadata.Description,
VersionDownloadCount: TypedValue[int64]{Type: "Edm.Int64", Value: pd.Version.DownloadCount},
DevelopmentDependency: TypedValue[bool]{Type: "Edm.Boolean", Value: metadata.DevelopmentDependency},
DownloadCount: TypedValue[int64]{Type: "Edm.Int64", Value: pd.Version.DownloadCount},
PackageSize: TypedValue[int64]{Type: "Edm.Int64", Value: pd.CalculateBlobSize()},
Created: createdValue,
ID: pd.Package.Name,
IconURL: metadata.IconURL,
Language: metadata.Language,
LastUpdated: createdValue,
Published: createdValue,
LicenseURL: metadata.LicenseURL,
MinClientVersion: metadata.MinClientVersion,
NormalizedVersion: pd.Version.Version,
Owners: metadata.Owners,
PackageSize: TypedValue[int64]{Type: "Edm.Int64", Value: pd.CalculateBlobSize()},
ProjectURL: metadata.ProjectURL,
Published: createdValue,
ReleaseNotes: metadata.ReleaseNotes,
RequireLicenseAcceptance: TypedValue[bool]{Type: "Edm.Boolean", Value: metadata.RequireLicenseAcceptance},
Title: pd.Package.Name,
Tags: metadata.Tags,
Title: metadata.Title,
Version: pd.Version.Version,
VersionDownloadCount: TypedValue[int64]{Type: "Edm.Int64", Value: pd.Version.DownloadCount},
},
}

View File

@@ -14,6 +14,7 @@ import (
"strings"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/optional"
packages_module "code.gitea.io/gitea/modules/packages"
rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
@@ -309,7 +310,7 @@ func GetPackageInfo(ctx *context.Context) {
apiError(ctx, http.StatusNotFound, nil)
return
}
infoContent, err := makePackageInfo(ctx, versions)
infoContent, err := makePackageInfo(ctx, versions, cache.NewEphemeralCache())
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
@@ -317,7 +318,7 @@ func GetPackageInfo(ctx *context.Context) {
ctx.PlainText(http.StatusOK, infoContent)
}
// GetAllPackagesVersions returns a custom text based format containing information about all versions of all rubygems.
// GetAllPackagesVersions returns a custom text-based format containing information about all versions of all rubygems.
// ref: https://guides.rubygems.org/rubygems-org-compact-index-api/
func GetAllPackagesVersions(ctx *context.Context) {
packages, err := packages_model.GetPackagesByType(ctx, ctx.Package.Owner.ID, packages_model.TypeRubyGems)
@@ -326,6 +327,7 @@ func GetAllPackagesVersions(ctx *context.Context) {
return
}
ephemeralCache := cache.NewEphemeralCache()
out := &strings.Builder{}
out.WriteString("---\n")
for _, pkg := range packages {
@@ -338,7 +340,7 @@ func GetAllPackagesVersions(ctx *context.Context) {
continue
}
info, err := makePackageInfo(ctx, versions)
info, err := makePackageInfo(ctx, versions, ephemeralCache)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
@@ -348,7 +350,14 @@ func GetAllPackagesVersions(ctx *context.Context) {
_, _ = fmt.Fprintf(out, "%s ", pkg.Name)
for i, v := range versions {
sep := util.Iif(i == len(versions)-1, "", ",")
_, _ = fmt.Fprintf(out, "%s%s", v.Version, sep)
pd, err := packages_model.GetPackageDescriptorWithCache(ctx, v, ephemeralCache)
if errors.Is(err, util.ErrNotExist) {
continue
} else if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
writePackageVersionForList(pd.Metadata, v.Version, sep, out)
}
_, _ = fmt.Fprintf(out, " %x\n", md5.Sum([]byte(info)))
}
@@ -356,6 +365,16 @@ func GetAllPackagesVersions(ctx *context.Context) {
ctx.PlainText(http.StatusOK, out.String())
}
func writePackageVersionForList(metadata any, version, sep string, out *strings.Builder) {
if metadata, _ := metadata.(*rubygems_module.Metadata); metadata != nil && metadata.Platform != "" && metadata.Platform != "ruby" {
// VERSION_PLATFORM (see comment above in GetAllPackagesVersions)
_, _ = fmt.Fprintf(out, "%s_%s%s", version, metadata.Platform, sep)
} else {
// VERSION only
_, _ = fmt.Fprintf(out, "%s%s", version, sep)
}
}
func writePackageVersionRequirements(prefix string, reqs []rubygems_module.VersionRequirement, out *strings.Builder) {
out.WriteString(prefix)
if len(reqs) == 0 {
@@ -367,11 +386,21 @@ func writePackageVersionRequirements(prefix string, reqs []rubygems_module.Versi
}
}
func makePackageVersionDependency(ctx *context.Context, version *packages_model.PackageVersion) (string, error) {
func writePackageVersionForDependency(version, platform string, out *strings.Builder) {
if platform != "" && platform != "ruby" {
// VERSION-PLATFORM (see comment below in makePackageVersionDependency)
_, _ = fmt.Fprintf(out, "%s-%s ", version, platform)
} else {
// VERSION only
_, _ = fmt.Fprintf(out, "%s ", version)
}
}
func makePackageVersionDependency(ctx *context.Context, version *packages_model.PackageVersion, c *cache.EphemeralCache) (string, error) {
// format: VERSION[-PLATFORM] [DEPENDENCY[,DEPENDENCY,...]]|REQUIREMENT[,REQUIREMENT,...]
// DEPENDENCY: GEM:CONSTRAINT[&CONSTRAINT]
// REQUIREMENT: KEY:VALUE (always contains "checksum")
pd, err := packages_model.GetPackageDescriptor(ctx, version)
pd, err := packages_model.GetPackageDescriptorWithCache(ctx, version, c)
if err != nil {
return "", err
}
@@ -388,8 +417,7 @@ func makePackageVersionDependency(ctx *context.Context, version *packages_model.
}
buf := &strings.Builder{}
buf.WriteString(version.Version)
buf.WriteByte(' ')
writePackageVersionForDependency(version.Version, metadata.Platform, buf)
for i, dep := range metadata.RuntimeDependencies {
sep := util.Iif(i == 0, "", ",")
writePackageVersionRequirements(fmt.Sprintf("%s%s:", sep, dep.Name), dep.Version, buf)
@@ -404,10 +432,10 @@ func makePackageVersionDependency(ctx *context.Context, version *packages_model.
return buf.String(), nil
}
func makePackageInfo(ctx *context.Context, versions []*packages_model.PackageVersion) (string, error) {
func makePackageInfo(ctx *context.Context, versions []*packages_model.PackageVersion, c *cache.EphemeralCache) (string, error) {
ret := "---\n"
for _, v := range versions {
dep, err := makePackageVersionDependency(ctx, v)
dep, err := makePackageVersionDependency(ctx, v, c)
if err != nil {
return "", err
}

View File

@@ -0,0 +1,41 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package rubygems
import (
"strings"
"testing"
rubygems_module "code.gitea.io/gitea/modules/packages/rubygems"
"github.com/stretchr/testify/assert"
)
func TestWritePackageVersion(t *testing.T) {
buf := &strings.Builder{}
writePackageVersionForList(nil, "1.0", " ", buf)
assert.Equal(t, "1.0 ", buf.String())
buf.Reset()
writePackageVersionForList(&rubygems_module.Metadata{Platform: "ruby"}, "1.0", " ", buf)
assert.Equal(t, "1.0 ", buf.String())
buf.Reset()
writePackageVersionForList(&rubygems_module.Metadata{Platform: "linux"}, "1.0", " ", buf)
assert.Equal(t, "1.0_linux ", buf.String())
buf.Reset()
writePackageVersionForDependency("1.0", "", buf)
assert.Equal(t, "1.0 ", buf.String())
buf.Reset()
writePackageVersionForDependency("1.0", "ruby", buf)
assert.Equal(t, "1.0 ", buf.String())
buf.Reset()
writePackageVersionForDependency("1.0", "os", buf)
assert.Equal(t, "1.0-os ", buf.String())
buf.Reset()
}