Use Project-URL metadata field to get a PyPI package's homepage URL (#33089)

Resolves #33085.

(cherry picked from commit 188e0ee8e40ad0b32f9db33a0a217043cfdf3610)

Conflicts:
	tests/integration/api_packages_pypi_test.go
  trivial context conflict
This commit is contained in:
Kemal Zebari 2025-01-03 13:09:47 -08:00 committed by Earl Warren
parent e507fa30df
commit 76a85d26c8
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
3 changed files with 116 additions and 10 deletions

View file

@ -10,6 +10,7 @@ import (
"regexp"
"sort"
"strings"
"unicode"
packages_model "code.gitea.io/gitea/models/packages"
packages_module "code.gitea.io/gitea/modules/packages"
@ -139,9 +140,30 @@ func UploadPackageFile(ctx *context.Context) {
return
}
projectURL := ctx.Req.FormValue("home_page")
if !validation.IsValidURL(projectURL) {
projectURL = ""
// Ensure ctx.Req.Form exists.
_ = ctx.Req.ParseForm()
var homepageURL string
projectURLs := ctx.Req.Form["project_urls"]
for _, purl := range projectURLs {
label, url, found := strings.Cut(purl, ",")
if !found {
continue
}
if normalizeLabel(label) != "homepage" {
continue
}
homepageURL = strings.TrimSpace(url)
break
}
if len(homepageURL) == 0 {
// TODO: Home-page is a deprecated metadata field. Remove this branch once it's no longer apart of the spec.
homepageURL = ctx.Req.FormValue("home_page")
}
if !validation.IsValidURL(homepageURL) {
homepageURL = ""
}
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
@ -160,7 +182,7 @@ func UploadPackageFile(ctx *context.Context) {
Description: ctx.Req.FormValue("description"),
LongDescription: ctx.Req.FormValue("long_description"),
Summary: ctx.Req.FormValue("summary"),
ProjectURL: projectURL,
ProjectURL: homepageURL,
License: ctx.Req.FormValue("license"),
RequiresPython: ctx.Req.FormValue("requires_python"),
},
@ -189,6 +211,23 @@ func UploadPackageFile(ctx *context.Context) {
ctx.Status(http.StatusCreated)
}
// Normalizes a Project-URL label.
// See https://packaging.python.org/en/latest/specifications/well-known-project-urls/#label-normalization.
func normalizeLabel(label string) string {
var builder strings.Builder
// "A label is normalized by deleting all ASCII punctuation and whitespace, and then converting the result
// to lowercase."
for _, r := range label {
if unicode.IsPunct(r) || unicode.IsSpace(r) {
continue
}
builder.WriteRune(unicode.ToLower(r))
}
return builder.String()
}
func isValidNameAndVersion(packageName, packageVersion string) bool {
return nameMatcher.MatchString(packageName) && versionMatcher.MatchString(packageVersion)
}