diff --git a/CHANGES/1374.bugfix b/CHANGES/1374.bugfix new file mode 100644 index 000000000..63c479555 --- /dev/null +++ b/CHANGES/1374.bugfix @@ -0,0 +1 @@ +RSS feeds now reflect the most recently added file for each release, produce unique guids when content is updated, and support up to 500 entries in `updates.xml`. diff --git a/pulp_python/app/pypi/feeds.py b/pulp_python/app/pypi/feeds.py index 7c789ffab..4be42e7a5 100644 --- a/pulp_python/app/pypi/feeds.py +++ b/pulp_python/app/pypi/feeds.py @@ -2,7 +2,7 @@ from email.utils import getaddresses from urllib.parse import urljoin -from django.db.models import F, FilteredRelation, Min, Q +from django.db.models import F, FilteredRelation, Max, Min, Q from django.http.response import HttpResponse, HttpResponseNotFound from django.utils.decorators import method_decorator from django.utils.feedgenerator import Rss201rev2Feed @@ -15,7 +15,7 @@ from pulp_python.app.cache import PythonApiCache, find_base_path_cached from pulp_python.app.pypi.views import PyPIMixin, _etag_func -UPDATES_LIMIT = 100 +UPDATES_LIMIT = 500 PACKAGES_LIMIT = 40 PROJECT_RELEASES_LIMIT = 40 RSS_CONTENT_TYPE = "application/rss+xml; charset=utf-8" @@ -66,7 +66,7 @@ def iter_releases(content, repo_ver, name_normalized=None, limit=UPDATES_LIMIT): qs.order_by() .values("name_normalized", "version") .annotate( - added_at=Min("file_added_at"), + added_at=Max("file_added_at"), name=Min("name"), summary=Min("summary"), author_email=Min("author_email"), @@ -82,7 +82,7 @@ def iter_projects(content, repo_ver, limit=PACKAGES_LIMIT): qs.order_by() .values("name_normalized") .annotate( - added_at=Min("file_added_at"), + added_at=Max("file_added_at"), name=Min("name"), summary=Min("summary"), author_email=Min("author_email"), @@ -98,7 +98,7 @@ def _item_dict(title, link, description, author_email, pubdate): "description": sanitize_xml_text(description), "author_email": format_author(author_email), "pubdate": pubdate, - "unique_id": link, + "unique_id": f"{link}#{pubdate.isoformat()}", } @@ -118,7 +118,7 @@ def render_rss(title, link, description, items): author_email=item["author_email"], pubdate=item["pubdate"], unique_id=item["unique_id"], - unique_id_is_permalink=True, + unique_id_is_permalink=False, ) return feed.writeString("utf-8") diff --git a/pulp_python/tests/functional/api/test_pypi_feeds.py b/pulp_python/tests/functional/api/test_pypi_feeds.py index 41f0ab791..63786d774 100644 --- a/pulp_python/tests/functional/api/test_pypi_feeds.py +++ b/pulp_python/tests/functional/api/test_pypi_feeds.py @@ -125,8 +125,40 @@ def test_pinned_version_feeds( item = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg))[0] assert item.findtext("link").endswith("pypi/shelf-reader/0.1/json") - assert item.findtext("guid").endswith("pypi/shelf-reader/0.1/json") + assert "pypi/shelf-reader/0.1/json#" in item.findtext("guid") python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL, repository=repo) update_titles = _titles(_parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg))) assert update_titles == ["shelf-reader 0.1"] + + +@pytest.mark.parallel +def test_new_file_for_existing_version_updates_guid( + bindings_cfg, python_content_factory, python_empty_repo_distro +): + """Adding a new file for an existing (name, version) produces a new guid and updated date.""" + repo, distro = python_empty_repo_distro() + + python_content_factory(PYTHON_EGG_FILENAME, url=PYTHON_EGG_URL, repository=repo) + + items = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg)) + assert len(items) == 1 + first_guid = items[0].findtext("guid") + first_date = items[0].findtext("pubDate") + assert "pypi/shelf-reader/0.1/json" in first_guid + + python_content_factory(PYTHON_WHEEL_FILENAME, url=PYTHON_WHEEL_URL, repository=repo) + + items = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg)) + assert len(items) == 1 + second_guid = items[0].findtext("guid") + second_date = items[0].findtext("pubDate") + + assert second_guid != first_guid + assert second_date >= first_date + + release_items = _parse_items( + _get_feed(distro, "rss/project/shelf-reader/releases.xml", bindings_cfg) + ) + assert len(release_items) == 1 + assert release_items[0].findtext("guid") == second_guid