mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-27 00:23:41 +09: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:
		| @@ -44,7 +44,7 @@ func (opts *BlobSearchOptions) toConds() builder.Cond { | ||||
| 		cond = cond.And(builder.Eq{"package_version.lower_version": strings.ToLower(opts.Tag)}) | ||||
| 	} | ||||
| 	if opts.IsManifest { | ||||
| 		cond = cond.And(builder.Eq{"package_file.lower_name": ManifestFilename}) | ||||
| 		cond = cond.And(builder.Eq{"package_file.lower_name": container_module.ManifestFilename}) | ||||
| 	} | ||||
| 	if opts.OnlyLead { | ||||
| 		cond = cond.And(builder.Eq{"package_file.is_lead": true}) | ||||
| @@ -235,7 +235,7 @@ func SearchImageTags(ctx context.Context, opts *ImageTagsSearchOptions) ([]*pack | ||||
| func SearchExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) ([]*packages.PackageFile, error) { | ||||
| 	var cond builder.Cond = builder.Eq{ | ||||
| 		"package_version.is_internal":   true, | ||||
| 		"package_version.lower_version": UploadVersion, | ||||
| 		"package_version.lower_version": container_module.UploadVersion, | ||||
| 		"package.type":                  packages.TypeContainer, | ||||
| 	} | ||||
| 	cond = cond.And(builder.Lt{"package_file.created_unix": time.Now().Add(-olderThan).Unix()}) | ||||
|   | ||||
| @@ -103,10 +103,10 @@ func (pd *PackageDescriptor) CalculateBlobSize() int64 { | ||||
|  | ||||
| // GetPackageDescriptor gets the package description for a version | ||||
| func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDescriptor, error) { | ||||
| 	return getPackageDescriptor(ctx, pv, cache.NewEphemeralCache()) | ||||
| 	return GetPackageDescriptorWithCache(ctx, pv, cache.NewEphemeralCache()) | ||||
| } | ||||
|  | ||||
| func getPackageDescriptor(ctx context.Context, pv *PackageVersion, c *cache.EphemeralCache) (*PackageDescriptor, error) { | ||||
| func GetPackageDescriptorWithCache(ctx context.Context, pv *PackageVersion, c *cache.EphemeralCache) (*PackageDescriptor, error) { | ||||
| 	p, err := cache.GetWithEphemeralCache(ctx, c, "package", pv.PackageID, GetPackageByID) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -270,7 +270,7 @@ func GetPackageDescriptors(ctx context.Context, pvs []*PackageVersion) ([]*Packa | ||||
| func getPackageDescriptors(ctx context.Context, pvs []*PackageVersion, c *cache.EphemeralCache) ([]*PackageDescriptor, error) { | ||||
| 	pds := make([]*PackageDescriptor, 0, len(pvs)) | ||||
| 	for _, pv := range pvs { | ||||
| 		pd, err := getPackageDescriptor(ctx, pv, c) | ||||
| 		pd, err := GetPackageDescriptorWithCache(ctx, pv, c) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -57,14 +57,24 @@ type Package struct { | ||||
|  | ||||
| // Metadata represents the metadata of a Nuget package | ||||
| 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"` | ||||
| 	RequireLicenseAcceptance bool                    `json:"require_license_acceptance"` | ||||
| 	Dependencies             map[string][]Dependency `json:"dependencies,omitempty"` | ||||
| 	Authors                  string `json:"authors,omitempty"` | ||||
| 	Copyright                string `json:"copyright,omitempty"` | ||||
| 	Description              string `json:"description,omitempty"` | ||||
| 	DevelopmentDependency    bool   `json:"development_dependency,omitempty"` | ||||
| 	IconURL                  string `json:"icon_url,omitempty"` | ||||
| 	Language                 string `json:"language,omitempty"` | ||||
| 	LicenseURL               string `json:"license_url,omitempty"` | ||||
| 	MinClientVersion         string `json:"min_client_version,omitempty"` | ||||
| 	Owners                   string `json:"owners,omitempty"` | ||||
| 	ProjectURL               string `json:"project_url,omitempty"` | ||||
| 	Readme                   string `json:"readme,omitempty"` | ||||
| 	ReleaseNotes             string `json:"release_notes,omitempty"` | ||||
| 	RepositoryURL            string `json:"repository_url,omitempty"` | ||||
| 	RequireLicenseAcceptance bool   `json:"require_license_acceptance"` | ||||
| 	Tags                     string `json:"tags,omitempty"` | ||||
| 	Title                    string `json:"title,omitempty"` | ||||
|  | ||||
| 	Dependencies map[string][]Dependency `json:"dependencies,omitempty"` | ||||
| } | ||||
|  | ||||
| // Dependency represents a dependency of a Nuget package | ||||
| @@ -74,24 +84,30 @@ type Dependency struct { | ||||
| } | ||||
|  | ||||
| // https://learn.microsoft.com/en-us/nuget/reference/nuspec | ||||
| // https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.Packaging/compiler/resources/nuspec.xsd | ||||
| type nuspecPackage struct { | ||||
| 	Metadata struct { | ||||
| 		ID                       string `xml:"id"` | ||||
| 		Version                  string `xml:"version"` | ||||
| 		Authors                  string `xml:"authors"` | ||||
| 		RequireLicenseAcceptance bool   `xml:"requireLicenseAcceptance"` | ||||
| 		// required fields | ||||
| 		Authors     string `xml:"authors"` | ||||
| 		Description string `xml:"description"` | ||||
| 		ID          string `xml:"id"` | ||||
| 		Version     string `xml:"version"` | ||||
|  | ||||
| 		// optional fields | ||||
| 		Copyright                string `xml:"copyright"` | ||||
| 		DevelopmentDependency    bool   `xml:"developmentDependency"` | ||||
| 		IconURL                  string `xml:"iconUrl"` | ||||
| 		Language                 string `xml:"language"` | ||||
| 		LicenseURL               string `xml:"licenseUrl"` | ||||
| 		MinClientVersion         string `xml:"minClientVersion,attr"` | ||||
| 		Owners                   string `xml:"owners"` | ||||
| 		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"` | ||||
| 			} `xml:"packageType"` | ||||
| 		} `xml:"packageTypes"` | ||||
| 		Repository struct { | ||||
| 			URL string `xml:"url,attr"` | ||||
| 		} `xml:"repository"` | ||||
| 		ReleaseNotes             string `xml:"releaseNotes"` | ||||
| 		RequireLicenseAcceptance bool   `xml:"requireLicenseAcceptance"` | ||||
| 		Tags                     string `xml:"tags"` | ||||
| 		Title                    string `xml:"title"` | ||||
|  | ||||
| 		Dependencies struct { | ||||
| 			Dependency []struct { | ||||
| 				ID      string `xml:"id,attr"` | ||||
| @@ -107,6 +123,14 @@ type nuspecPackage struct { | ||||
| 				} `xml:"dependency"` | ||||
| 			} `xml:"group"` | ||||
| 		} `xml:"dependencies"` | ||||
| 		PackageTypes struct { | ||||
| 			PackageType []struct { | ||||
| 				Name string `xml:"name,attr"` | ||||
| 			} `xml:"packageType"` | ||||
| 		} `xml:"packageTypes"` | ||||
| 		Repository struct { | ||||
| 			URL string `xml:"url,attr"` | ||||
| 		} `xml:"repository"` | ||||
| 	} `xml:"metadata"` | ||||
| } | ||||
|  | ||||
| @@ -167,13 +191,23 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { | ||||
| 	} | ||||
|  | ||||
| 	m := &Metadata{ | ||||
| 		Description:              p.Metadata.Description, | ||||
| 		ReleaseNotes:             p.Metadata.ReleaseNotes, | ||||
| 		Authors:                  p.Metadata.Authors, | ||||
| 		Copyright:                p.Metadata.Copyright, | ||||
| 		Description:              p.Metadata.Description, | ||||
| 		DevelopmentDependency:    p.Metadata.DevelopmentDependency, | ||||
| 		IconURL:                  p.Metadata.IconURL, | ||||
| 		Language:                 p.Metadata.Language, | ||||
| 		LicenseURL:               p.Metadata.LicenseURL, | ||||
| 		MinClientVersion:         p.Metadata.MinClientVersion, | ||||
| 		Owners:                   p.Metadata.Owners, | ||||
| 		ProjectURL:               p.Metadata.ProjectURL, | ||||
| 		ReleaseNotes:             p.Metadata.ReleaseNotes, | ||||
| 		RepositoryURL:            p.Metadata.Repository.URL, | ||||
| 		RequireLicenseAcceptance: p.Metadata.RequireLicenseAcceptance, | ||||
| 		Dependencies:             make(map[string][]Dependency), | ||||
| 		Tags:                     p.Metadata.Tags, | ||||
| 		Title:                    p.Metadata.Title, | ||||
|  | ||||
| 		Dependencies: make(map[string][]Dependency), | ||||
| 	} | ||||
|  | ||||
| 	if p.Metadata.Readme != "" { | ||||
| @@ -227,13 +261,13 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { | ||||
| func toNormalizedVersion(v *version.Version) string { | ||||
| 	var buf bytes.Buffer | ||||
| 	segments := v.Segments64() | ||||
| 	fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2]) | ||||
| 	_, _ = fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2]) | ||||
| 	if len(segments) > 3 && segments[3] > 0 { | ||||
| 		fmt.Fprintf(&buf, ".%d", segments[3]) | ||||
| 		_, _ = fmt.Fprintf(&buf, ".%d", segments[3]) | ||||
| 	} | ||||
| 	pre := v.Prerelease() | ||||
| 	if pre != "" { | ||||
| 		fmt.Fprint(&buf, "-", pre) | ||||
| 		_, _ = fmt.Fprint(&buf, "-", pre) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|   | ||||
| @@ -12,44 +12,62 @@ import ( | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	id                = "System.Gitea" | ||||
| 	semver            = "1.0.1" | ||||
| 	authors           = "Gitea Authors" | ||||
| 	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" | ||||
| 	dependencyVersion = "5.0.0" | ||||
| 	authors                  = "Gitea Authors" | ||||
| 	copyright                = "Package Copyright" | ||||
| 	dependencyID             = "System.Text.Json" | ||||
| 	dependencyVersion        = "5.0.0" | ||||
| 	developmentDependency    = true | ||||
| 	description              = "Package Description" | ||||
| 	iconURL                  = "https://gitea.io/favicon.png" | ||||
| 	id                       = "System.Gitea" | ||||
| 	language                 = "Package Language" | ||||
| 	licenseURL               = "https://gitea.io/license" | ||||
| 	minClientVersion         = "1.0.0.0" | ||||
| 	owners                   = "Package Owners" | ||||
| 	projectURL               = "https://gitea.io" | ||||
| 	readme                   = "Readme" | ||||
| 	releaseNotes             = "Package Release Notes" | ||||
| 	repositoryURL            = "https://gitea.io/gitea/gitea" | ||||
| 	requireLicenseAcceptance = true | ||||
| 	tags                     = "tag_1 tag_2 tag_3" | ||||
| 	targetFramework          = ".NETStandard2.1" | ||||
| 	title                    = "Package Title" | ||||
| 	versionStr               = "1.0.1" | ||||
| ) | ||||
|  | ||||
| const nuspecContent = `<?xml version="1.0" encoding="utf-8"?> | ||||
| <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> | ||||
|   <metadata> | ||||
|     <id>` + id + `</id> | ||||
|     <version>` + semver + `</version> | ||||
|     <authors>` + authors + `</authors> | ||||
|     <requireLicenseAcceptance>true</requireLicenseAcceptance> | ||||
|     <projectUrl>` + projectURL + `</projectUrl> | ||||
|     <description>` + description + `</description> | ||||
|     <releaseNotes>` + releaseNotes + `</releaseNotes> | ||||
|     <repository url="` + repositoryURL + `" /> | ||||
|     <readme>README.md</readme> | ||||
|     <dependencies> | ||||
|       <group targetFramework="` + targetFramework + `"> | ||||
|         <dependency id="` + dependencyID + `" version="` + dependencyVersion + `" exclude="Build,Analyzers" /> | ||||
|       </group> | ||||
|     </dependencies> | ||||
|   </metadata> | ||||
| 	<metadata minClientVersion="` + minClientVersion + `"> | ||||
| 		<authors>` + authors + `</authors> | ||||
| 		<copyright>` + copyright + `</copyright> | ||||
| 		<description>` + description + `</description> | ||||
| 		<developmentDependency>true</developmentDependency> | ||||
| 		<iconUrl>` + iconURL + `</iconUrl> | ||||
| 		<id>` + id + `</id> | ||||
| 		<language>` + language + `</language> | ||||
| 		<licenseUrl>` + licenseURL + `</licenseUrl> | ||||
| 		<owners>` + owners + `</owners> | ||||
| 		<projectUrl>` + projectURL + `</projectUrl> | ||||
| 		<readme>README.md</readme> | ||||
| 		<releaseNotes>` + releaseNotes + `</releaseNotes> | ||||
| 		<repository url="` + repositoryURL + `" /> | ||||
| 		<requireLicenseAcceptance>true</requireLicenseAcceptance> | ||||
| 		<tags>` + tags + `</tags> | ||||
| 		<title>` + title + `</title> | ||||
| 		<version>` + versionStr + `</version> | ||||
| 		<dependencies> | ||||
| 			<group targetFramework="` + targetFramework + `"> | ||||
| 				<dependency id="` + dependencyID + `" version="` + dependencyVersion + `" exclude="Build,Analyzers" /> | ||||
| 			</group> | ||||
| 		</dependencies> | ||||
| 	</metadata> | ||||
| </package>` | ||||
|  | ||||
| const symbolsNuspecContent = `<?xml version="1.0" encoding="utf-8"?> | ||||
| <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> | ||||
|   <metadata> | ||||
|     <id>` + id + `</id> | ||||
|     <version>` + semver + `</version> | ||||
|     <version>` + versionStr + `</version> | ||||
|     <description>` + description + `</description> | ||||
|     <packageTypes> | ||||
|       <packageType name="SymbolsPackage" /> | ||||
| @@ -140,14 +158,26 @@ func TestParsePackageMetaData(t *testing.T) { | ||||
| 		assert.NotNil(t, np) | ||||
| 		assert.Equal(t, DependencyPackage, np.PackageType) | ||||
|  | ||||
| 		assert.Equal(t, id, np.ID) | ||||
| 		assert.Equal(t, semver, np.Version) | ||||
| 		assert.Equal(t, authors, np.Metadata.Authors) | ||||
| 		assert.Equal(t, projectURL, np.Metadata.ProjectURL) | ||||
| 		assert.Equal(t, description, np.Metadata.Description) | ||||
| 		assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) | ||||
| 		assert.Equal(t, id, np.ID) | ||||
| 		assert.Equal(t, versionStr, np.Version) | ||||
|  | ||||
| 		assert.Equal(t, copyright, np.Metadata.Copyright) | ||||
| 		assert.Equal(t, developmentDependency, np.Metadata.DevelopmentDependency) | ||||
| 		assert.Equal(t, iconURL, np.Metadata.IconURL) | ||||
| 		assert.Equal(t, language, np.Metadata.Language) | ||||
| 		assert.Equal(t, licenseURL, np.Metadata.LicenseURL) | ||||
| 		assert.Equal(t, minClientVersion, np.Metadata.MinClientVersion) | ||||
| 		assert.Equal(t, owners, np.Metadata.Owners) | ||||
| 		assert.Equal(t, projectURL, np.Metadata.ProjectURL) | ||||
| 		assert.Equal(t, readme, np.Metadata.Readme) | ||||
| 		assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes) | ||||
| 		assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL) | ||||
| 		assert.Equal(t, requireLicenseAcceptance, np.Metadata.RequireLicenseAcceptance) | ||||
| 		assert.Equal(t, tags, np.Metadata.Tags) | ||||
| 		assert.Equal(t, title, np.Metadata.Title) | ||||
|  | ||||
| 		assert.Len(t, np.Metadata.Dependencies, 1) | ||||
| 		assert.Contains(t, np.Metadata.Dependencies, targetFramework) | ||||
| 		deps := np.Metadata.Dependencies[targetFramework] | ||||
| @@ -180,7 +210,7 @@ func TestParsePackageMetaData(t *testing.T) { | ||||
| 		assert.Equal(t, SymbolsPackage, np.PackageType) | ||||
|  | ||||
| 		assert.Equal(t, id, np.ID) | ||||
| 		assert.Equal(t, semver, np.Version) | ||||
| 		assert.Equal(t, versionStr, np.Version) | ||||
| 		assert.Equal(t, description, np.Metadata.Description) | ||||
| 		assert.Empty(t, np.Metadata.Dependencies) | ||||
| 	}) | ||||
|   | ||||
| @@ -34,7 +34,7 @@ type PortablePdbList []*PortablePdb | ||||
|  | ||||
| func (l PortablePdbList) Close() { | ||||
| 	for _, pdb := range l { | ||||
| 		pdb.Content.Close() | ||||
| 		_ = pdb.Content.Close() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -65,7 +65,7 @@ func ExtractPortablePdb(r io.ReaderAt, size int64) (PortablePdbList, error) { | ||||
|  | ||||
| 				buf, err := packages.CreateHashedBufferFromReader(f) | ||||
|  | ||||
| 				f.Close() | ||||
| 				_ = f.Close() | ||||
|  | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| @@ -73,12 +73,12 @@ func ExtractPortablePdb(r io.ReaderAt, size int64) (PortablePdbList, error) { | ||||
|  | ||||
| 				id, err := ParseDebugHeaderID(buf) | ||||
| 				if err != nil { | ||||
| 					buf.Close() | ||||
| 					_ = buf.Close() | ||||
| 					return fmt.Errorf("Invalid PDB file: %w", err) | ||||
| 				} | ||||
|  | ||||
| 				if _, err := buf.Seek(0, io.SeekStart); err != nil { | ||||
| 					buf.Close() | ||||
| 					_ = buf.Close() | ||||
| 					return err | ||||
| 				} | ||||
|  | ||||
|   | ||||
| @@ -24,14 +24,14 @@ func TestExtractPortablePdb(t *testing.T) { | ||||
| 		var buf bytes.Buffer | ||||
| 		archive := zip.NewWriter(&buf) | ||||
| 		w, _ := archive.Create(name) | ||||
| 		w.Write(content) | ||||
| 		archive.Close() | ||||
| 		_, _ = w.Write(content) | ||||
| 		_ = archive.Close() | ||||
| 		return buf.Bytes() | ||||
| 	} | ||||
|  | ||||
| 	t.Run("MissingPdbFiles", func(t *testing.T) { | ||||
| 		var buf bytes.Buffer | ||||
| 		zip.NewWriter(&buf).Close() | ||||
| 		_ = zip.NewWriter(&buf).Close() | ||||
|  | ||||
| 		pdbs, err := ExtractPortablePdb(bytes.NewReader(buf.Bytes()), int64(buf.Len())) | ||||
| 		assert.ErrorIs(t, err, ErrMissingPdbFiles) | ||||
|   | ||||
| @@ -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() | ||||
| } | ||||
| @@ -57,7 +57,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e | ||||
| 		Type: packages_model.TypeContainer, | ||||
| 		Version: packages_model.SearchValue{ | ||||
| 			ExactMatch: true, | ||||
| 			Value:      container_model.UploadVersion, | ||||
| 			Value:      container_module.UploadVersion, | ||||
| 		}, | ||||
| 		IsInternal: optional.Some(true), | ||||
| 		HasFiles:   optional.Some(false), | ||||
|   | ||||
| @@ -18,7 +18,6 @@ import ( | ||||
| 	auth_model "code.gitea.io/gitea/models/auth" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	packages_model "code.gitea.io/gitea/models/packages" | ||||
| 	container_model "code.gitea.io/gitea/models/packages/container" | ||||
| 	"code.gitea.io/gitea/models/unittest" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	container_module "code.gitea.io/gitea/modules/packages/container" | ||||
| @@ -71,8 +70,8 @@ func TestPackageContainer(t *testing.T) { | ||||
| 	configContent := `{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/true"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"container":"b89fe92a887d55c0961f02bdfbfd8ac3ddf66167db374770d2d9e9fab3311510","container_config":{"Hostname":"b89fe92a887d","Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/true\"]"],"ArgsEscaped":true,"Image":"sha256:9bd8b88dc68b80cffe126cc820e4b52c6e558eb3b37680bfee8e5f3ed7b8c257"},"created":"2022-01-01T00:00:00.000000000Z","docker_version":"20.10.12","history":[{"created":"2022-01-01T00:00:00.000000000Z","created_by":"/bin/sh -c #(nop) COPY file:0e7589b0c800daaf6fa460d2677101e4676dd9491980210cb345480e513f3602 in /true "},{"created":"2022-01-01T00:00:00.000000001Z","created_by":"/bin/sh -c #(nop)  CMD [\"/true\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:0ff3b91bdf21ecdf2f2f3d4372c2098a14dbe06cd678e8f0a85fd4902d00e2e2"]}}` | ||||
|  | ||||
| 	manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6" | ||||
| 	manifestContent := `{"schemaVersion":2,"mediaType":"` + container_model.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` | ||||
| 	manifestContentType := container_model.ContentTypeDockerDistributionManifestV2 | ||||
| 	manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` | ||||
| 	manifestContentType := container_module.ContentTypeDockerDistributionManifestV2 | ||||
|  | ||||
| 	untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d" | ||||
| 	untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` | ||||
| @@ -252,7 +251,7 @@ func TestPackageContainer(t *testing.T) { | ||||
| 				assert.Equal(t, fmt.Sprintf("/v2/%s/%s/blobs/%s", user.Name, image, blobDigest), resp.Header().Get("Location")) | ||||
| 				assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest")) | ||||
|  | ||||
| 				pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_model.UploadVersion) | ||||
| 				pv, err := packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, container_module.UploadVersion) | ||||
| 				assert.NoError(t, err) | ||||
|  | ||||
| 				pfs, err := packages_model.GetFilesByVersionID(db.DefaultContext, pv.ID) | ||||
| @@ -432,7 +431,7 @@ func TestPackageContainer(t *testing.T) { | ||||
| 						assert.Len(t, pd.Files, 3) | ||||
| 						for _, pfd := range pd.Files { | ||||
| 							switch pfd.File.Name { | ||||
| 							case container_model.ManifestFilename: | ||||
| 							case container_module.ManifestFilename: | ||||
| 								assert.True(t, pfd.File.IsLead) | ||||
| 								assert.Equal(t, "application/vnd.docker.distribution.manifest.v2+json", pfd.Properties.GetByName(container_module.PropertyMediaType)) | ||||
| 								assert.Equal(t, manifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest)) | ||||
| @@ -534,7 +533,7 @@ func TestPackageContainer(t *testing.T) { | ||||
|  | ||||
| 				assert.Len(t, pd.Files, 3) | ||||
| 				for _, pfd := range pd.Files { | ||||
| 					if pfd.File.Name == container_model.ManifestFilename { | ||||
| 					if pfd.File.Name == container_module.ManifestFilename { | ||||
| 						assert.True(t, pfd.File.IsLead) | ||||
| 						assert.Equal(t, oci.MediaTypeImageManifest, pfd.Properties.GetByName(container_module.PropertyMediaType)) | ||||
| 						assert.Equal(t, untaggedManifestDigest, pfd.Properties.GetByName(container_module.PropertyDigest)) | ||||
|   | ||||
| @@ -46,21 +46,30 @@ func TestPackageNuGet(t *testing.T) { | ||||
| 	defer tests.PrepareTestEnv(t)() | ||||
|  | ||||
| 	type FeedEntryProperties struct { | ||||
| 		Version                  string                      `xml:"Version"` | ||||
| 		NormalizedVersion        string                      `xml:"NormalizedVersion"` | ||||
| 		Authors                  string                      `xml:"Authors"` | ||||
| 		Copyright                string                      `xml:"Copyright,omitempty"` | ||||
| 		Created                  nuget.TypedValue[time.Time] `xml:"Created"` | ||||
| 		Dependencies             string                      `xml:"Dependencies"` | ||||
| 		Description              string                      `xml:"Description"` | ||||
| 		VersionDownloadCount     nuget.TypedValue[int64]     `xml:"VersionDownloadCount"` | ||||
| 		DevelopmentDependency    nuget.TypedValue[bool]      `xml:"DevelopmentDependency"` | ||||
| 		DownloadCount            nuget.TypedValue[int64]     `xml:"DownloadCount"` | ||||
| 		PackageSize              nuget.TypedValue[int64]     `xml:"PackageSize"` | ||||
| 		Created                  nuget.TypedValue[time.Time] `xml:"Created"` | ||||
| 		ID                       string                      `xml:"Id"` | ||||
| 		IconURL                  string                      `xml:"IconUrl,omitempty"` | ||||
| 		Language                 string                      `xml:"Language,omitempty"` | ||||
| 		LastUpdated              nuget.TypedValue[time.Time] `xml:"LastUpdated"` | ||||
| 		Published                nuget.TypedValue[time.Time] `xml:"Published"` | ||||
| 		LicenseURL               string                      `xml:"LicenseUrl,omitempty"` | ||||
| 		MinClientVersion         string                      `xml:"MinClientVersion,omitempty"` | ||||
| 		NormalizedVersion        string                      `xml:"NormalizedVersion"` | ||||
| 		Owners                   string                      `xml:"Owners,omitempty"` | ||||
| 		PackageSize              nuget.TypedValue[int64]     `xml:"PackageSize"` | ||||
| 		ProjectURL               string                      `xml:"ProjectUrl,omitempty"` | ||||
| 		Published                nuget.TypedValue[time.Time] `xml:"Published"` | ||||
| 		ReleaseNotes             string                      `xml:"ReleaseNotes,omitempty"` | ||||
| 		RequireLicenseAcceptance nuget.TypedValue[bool]      `xml:"RequireLicenseAcceptance"` | ||||
| 		Tags                     string                      `xml:"Tags,omitempty"` | ||||
| 		Title                    string                      `xml:"Title"` | ||||
| 		Version                  string                      `xml:"Version"` | ||||
| 		VersionDownloadCount     nuget.TypedValue[int64]     `xml:"VersionDownloadCount"` | ||||
| 	} | ||||
|  | ||||
| 	type FeedEntry struct { | ||||
| @@ -86,28 +95,54 @@ func TestPackageNuGet(t *testing.T) { | ||||
| 	readToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadPackage) | ||||
| 	badToken := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadNotification) | ||||
|  | ||||
| 	packageName := "test.package" | ||||
| 	packageName := "test.package" // id | ||||
| 	packageID := packageName | ||||
| 	packageVersion := "1.0.3" | ||||
| 	packageAuthors := "KN4CK3R" | ||||
| 	packageDescription := "Gitea Test Package" | ||||
|  | ||||
| 	symbolFilename := "test.pdb" | ||||
| 	symbolID := "d910bb6948bd4c6cb40155bcf52c3c94" | ||||
|  | ||||
| 	packageCopyright := "Package Copyright" | ||||
| 	packageIconURL := "https://gitea.io/favicon.png" | ||||
| 	packageLanguage := "Package Language" | ||||
| 	packageLicenseURL := "https://gitea.io/license" | ||||
| 	packageMinClientVersion := "1.0.0.0" | ||||
| 	packageOwners := "Package Owners" | ||||
| 	packageProjectURL := "https://gitea.io" | ||||
| 	packageReleaseNotes := "Package Release Notes" | ||||
| 	packageTags := "tag_1 tag_2 tag_3" | ||||
| 	packageTitle := "Package Title" | ||||
| 	packageDevelopmentDependency := true | ||||
| 	packageRequireLicenseAcceptance := true | ||||
|  | ||||
| 	createNuspec := func(id, version string) string { | ||||
| 		return `<?xml version="1.0" encoding="utf-8"?> | ||||
| <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> | ||||
| 	<metadata> | ||||
| 		<id>` + id + `</id> | ||||
| 		<version>` + version + `</version> | ||||
| 		<authors>` + packageAuthors + `</authors> | ||||
| 		<description>` + packageDescription + `</description> | ||||
| 		<dependencies> | ||||
| 			<group targetFramework=".NETStandard2.0"> | ||||
| 				<dependency id="Microsoft.CSharp" version="4.5.0" /> | ||||
| 			</group> | ||||
| 		</dependencies> | ||||
| 	</metadata> | ||||
| </package>` | ||||
| 		<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> | ||||
| 			<metadata minClientVersion="` + packageMinClientVersion + `"> | ||||
| 				<authors>` + packageAuthors + `</authors> | ||||
| 				<copyright>` + packageCopyright + `</copyright> | ||||
| 				<description>` + packageDescription + `</description> | ||||
| 				<developmentDependency>true</developmentDependency> | ||||
| 				<iconUrl>` + packageIconURL + `</iconUrl> | ||||
| 				<id>` + id + `</id> | ||||
| 				<language>` + packageLanguage + `</language> | ||||
| 				<licenseUrl>` + packageLicenseURL + `</licenseUrl> | ||||
| 				<owners>` + packageOwners + `</owners> | ||||
| 				<projectUrl>` + packageProjectURL + `</projectUrl> | ||||
| 				<releaseNotes>` + packageReleaseNotes + `</releaseNotes> | ||||
| 				<requireLicenseAcceptance>true</requireLicenseAcceptance> | ||||
| 				<tags>` + packageTags + `</tags> | ||||
| 				<title>` + packageTitle + `</title> | ||||
| 				<version>` + version + `</version> | ||||
| 				<dependencies> | ||||
| 					<group targetFramework=".NETStandard2.0"> | ||||
| 						<dependency id="Microsoft.CSharp" version="4.5.0" /> | ||||
| 					</group> | ||||
| 				</dependencies> | ||||
| 			</metadata> | ||||
| 		</package>` | ||||
| 	} | ||||
|  | ||||
| 	createPackage := func(id, version string) *bytes.Buffer { | ||||
| @@ -393,7 +428,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) | ||||
|  | ||||
| 					pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) | ||||
| 					assert.NoError(t, err) | ||||
| 					assert.Equal(t, int64(412), pb.Size) | ||||
| 					assert.Equal(t, int64(610), pb.Size) | ||||
| 				case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion): | ||||
| 					assert.False(t, pf.IsLead) | ||||
|  | ||||
| @@ -405,7 +440,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) | ||||
|  | ||||
| 					pb, err := packages.GetBlobByID(db.DefaultContext, pf.BlobID) | ||||
| 					assert.NoError(t, err) | ||||
| 					assert.Equal(t, int64(427), pb.Size) | ||||
| 					assert.Equal(t, int64(996), pb.Size) | ||||
| 				case symbolFilename: | ||||
| 					assert.False(t, pf.IsLead) | ||||
|  | ||||
| @@ -736,10 +771,24 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) | ||||
| 				var result FeedEntry | ||||
| 				decodeXML(t, resp, &result) | ||||
|  | ||||
| 				assert.Equal(t, packageName, result.Properties.Title) | ||||
| 				assert.Equal(t, packageVersion, result.Properties.Version) | ||||
| 				assert.Equal(t, packageAuthors, result.Properties.Authors) | ||||
| 				assert.Equal(t, packageDescription, result.Properties.Description) | ||||
| 				assert.Equal(t, packageID, result.Properties.ID) | ||||
| 				assert.Equal(t, packageVersion, result.Properties.Version) | ||||
|  | ||||
| 				assert.Equal(t, packageCopyright, result.Properties.Copyright) | ||||
| 				assert.Equal(t, packageDevelopmentDependency, result.Properties.DevelopmentDependency.Value) | ||||
| 				assert.Equal(t, packageIconURL, result.Properties.IconURL) | ||||
| 				assert.Equal(t, packageLanguage, result.Properties.Language) | ||||
| 				assert.Equal(t, packageLicenseURL, result.Properties.LicenseURL) | ||||
| 				assert.Equal(t, packageMinClientVersion, result.Properties.MinClientVersion) | ||||
| 				assert.Equal(t, packageOwners, result.Properties.Owners) | ||||
| 				assert.Equal(t, packageProjectURL, result.Properties.ProjectURL) | ||||
| 				assert.Equal(t, packageReleaseNotes, result.Properties.ReleaseNotes) | ||||
| 				assert.Equal(t, packageRequireLicenseAcceptance, result.Properties.RequireLicenseAcceptance.Value) | ||||
| 				assert.Equal(t, packageTags, result.Properties.Tags) | ||||
| 				assert.Equal(t, packageTitle, result.Properties.Title) | ||||
|  | ||||
| 				assert.Equal(t, "Microsoft.CSharp:4.5.0:.NETStandard2.0", result.Properties.Dependencies) | ||||
| 			}) | ||||
|  | ||||
|   | ||||
| @@ -15,9 +15,9 @@ import ( | ||||
| 	auth_model "code.gitea.io/gitea/models/auth" | ||||
| 	"code.gitea.io/gitea/models/db" | ||||
| 	packages_model "code.gitea.io/gitea/models/packages" | ||||
| 	container_model "code.gitea.io/gitea/models/packages/container" | ||||
| 	"code.gitea.io/gitea/models/unittest" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	container_module "code.gitea.io/gitea/modules/packages/container" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| @@ -538,7 +538,7 @@ func TestPackageCleanup(t *testing.T) { | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.NotEmpty(t, pbs) | ||||
|  | ||||
| 		_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion) | ||||
| 		_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_module.UploadVersion) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration) | ||||
| @@ -548,7 +548,7 @@ func TestPackageCleanup(t *testing.T) { | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Empty(t, pbs) | ||||
|  | ||||
| 		_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion) | ||||
| 		_, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_module.UploadVersion) | ||||
| 		assert.ErrorIs(t, err, packages_model.ErrPackageNotExist) | ||||
| 	}) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user