From e14b8009840bdac6729043a67710c7e04beebb7c Mon Sep 17 00:00:00 2001 From: Gerrod Ubben Date: Sat, 13 Sep 2025 01:43:58 -0400 Subject: [PATCH] Fix publish failure when handling bad dist name metadata fixes: #907 --- CHANGES/907.bugfix | 1 + pulp_python/app/tasks/publish.py | 14 +++++----- pulp_python/pytest_plugin.py | 2 +- .../functional/api/test_crud_publications.py | 27 +++++++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 CHANGES/907.bugfix diff --git a/CHANGES/907.bugfix b/CHANGES/907.bugfix new file mode 100644 index 00000000..4e380f3e --- /dev/null +++ b/CHANGES/907.bugfix @@ -0,0 +1 @@ +Fixed publication error when package's dists contain differing versions of its name. diff --git a/pulp_python/app/tasks/publish.py b/pulp_python/app/tasks/publish.py index e8325a5c..79bcbfb7 100644 --- a/pulp_python/app/tasks/publish.py +++ b/pulp_python/app/tasks/publish.py @@ -59,9 +59,9 @@ def write_simple_api(publication): python_models.PythonPackageContent.objects.filter( pk__in=publication.repository_version.content, _pulp_domain=domain ) - .order_by("name") + .order_by("name__normalize") .values_list("name", flat=True) - .distinct() + .distinct("name__normalize") ) # write the root index, which lists all of the projects for which there is a package available @@ -80,22 +80,22 @@ def write_simple_api(publication): packages = python_models.PythonPackageContent.objects.filter( pk__in=publication.repository_version.content, _pulp_domain=domain ) - releases = packages.order_by("name").values("name", "filename", "sha256") + releases = packages.order_by("name__normalize").values("name", "filename", "sha256") ind = 0 - current_name = project_names[ind] + current_name = canonicalize_name(project_names[ind]) package_releases = [] for release in releases.iterator(): - if release["name"] != current_name: + if canonicalize_name(release["name"]) != current_name: write_project_page( - name=canonicalize_name(current_name), + name=current_name, simple_dir=simple_dir, package_releases=package_releases, publication=publication, ) package_releases = [] ind += 1 - current_name = project_names[ind] + current_name = canonicalize_name(project_names[ind]) relative_path = release["filename"] path = f"../../{relative_path}" checksum = release["sha256"] diff --git a/pulp_python/pytest_plugin.py b/pulp_python/pytest_plugin.py index f19f7c1f..1a3f756c 100644 --- a/pulp_python/pytest_plugin.py +++ b/pulp_python/pytest_plugin.py @@ -178,7 +178,7 @@ def _gen_python_content(relative_path=PYTHON_EGG_FILENAME, url=None, **body): task = python_bindings.ContentPackagesApi.create(**body).task response = monitor_task(task) - return python_bindings.ContentPackagesApi.read(response.created_resources[0]) + return python_bindings.ContentPackagesApi.read(response.created_resources[-1]) yield _gen_python_content diff --git a/pulp_python/tests/functional/api/test_crud_publications.py b/pulp_python/tests/functional/api/test_crud_publications.py index 9659d4ee..b54b8aa9 100644 --- a/pulp_python/tests/functional/api/test_crud_publications.py +++ b/pulp_python/tests/functional/api/test_crud_publications.py @@ -1,5 +1,6 @@ import pytest import random +from pypi_simple import PyPISimple from urllib.parse import urljoin from pulp_python.tests.functional.constants import ( @@ -109,3 +110,29 @@ def test_new_content_is_published(python_publication_workflow, python_distributi url = urljoin(distro.base_url, "simple/") proper, msgs = ensure_simple(url, {"shelf-reader": releases}) assert proper is True, msgs + + +@pytest.mark.parallel +def test_non_matching_canonicalized_name( + python_repo, python_content_factory, python_publication_factory, python_distribution_factory +): + """Ensures a package with dists that have non-matching canonicalized names is published.""" + packages = [] + filenames = ["msg_parser-1.0.0-py2.py3-none-any.whl", "msg_parser-1.0.0.tar.gz"] + with PyPISimple() as client: + page = client.get_project_page("msg-parser") + for pkg in page.packages: + if pkg.filename in filenames: + c = python_content_factory(pkg.filename, url=pkg.url, repository=python_repo) + if c.filename.endswith(".tar.gz"): + # The metadata name in the SDist is not the same as the Wheel's name + assert c.name == "msg_parser" + else: + assert c.name == "msg-parser" + packages.append(c) + pub = python_publication_factory(repository=python_repo) + distro = python_distribution_factory(publication=pub) + + url = urljoin(distro.base_url, "simple/") + proper, msgs = ensure_simple(url, {"msg-parser": filenames}) + assert proper is True, msgs