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:
@@ -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",
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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},
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
}
|
||||
|
41
routers/api/packages/rubygems/rubygems_test.go
Normal file
41
routers/api/packages/rubygems/rubygems_test.go
Normal 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()
|
||||
}
|
Reference in New Issue
Block a user