Skip to content

Commit a7c2dac

Browse files
ryanpetrellogerrod3
authored andcommitted
fix: RSS feeds show stale data for rebuilt packages
Use Max() instead of Min() for the added_at timestamp aggregation so feeds reflect the most recently added file for each (name, version) pair. Append a timestamp fragment to the guid so RSS readers treat rebuilds as new items. Raise UPDATES_LIMIT from 100 to 500 for indexes with large batch promotions. Fixes #1374 Assisted-by: AI (Claude Opus 4.6) Signed-off-by: Ryan Petrello <rpetrell@redhat.com> (cherry picked from commit a47e20f)
1 parent f19d43e commit a7c2dac

3 files changed

Lines changed: 40 additions & 7 deletions

File tree

‎CHANGES/1374.bugfix‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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`.

‎pulp_python/app/pypi/feeds.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from email.utils import getaddresses
33
from urllib.parse import urljoin
44

5-
from django.db.models import F, FilteredRelation, Min, Q
5+
from django.db.models import F, FilteredRelation, Max, Min, Q
66
from django.http.response import HttpResponse, HttpResponseNotFound
77
from django.utils.decorators import method_decorator
88
from django.utils.feedgenerator import Rss201rev2Feed
@@ -15,7 +15,7 @@
1515
from pulp_python.app.cache import PythonApiCache, find_base_path_cached
1616
from pulp_python.app.pypi.views import PyPIMixin, _etag_func
1717

18-
UPDATES_LIMIT = 100
18+
UPDATES_LIMIT = 500
1919
PACKAGES_LIMIT = 40
2020
PROJECT_RELEASES_LIMIT = 40
2121
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):
6666
qs.order_by()
6767
.values("name_normalized", "version")
6868
.annotate(
69-
added_at=Min("file_added_at"),
69+
added_at=Max("file_added_at"),
7070
name=Min("name"),
7171
summary=Min("summary"),
7272
author_email=Min("author_email"),
@@ -82,7 +82,7 @@ def iter_projects(content, repo_ver, limit=PACKAGES_LIMIT):
8282
qs.order_by()
8383
.values("name_normalized")
8484
.annotate(
85-
added_at=Min("file_added_at"),
85+
added_at=Max("file_added_at"),
8686
name=Min("name"),
8787
summary=Min("summary"),
8888
author_email=Min("author_email"),
@@ -98,7 +98,7 @@ def _item_dict(title, link, description, author_email, pubdate):
9898
"description": sanitize_xml_text(description),
9999
"author_email": format_author(author_email),
100100
"pubdate": pubdate,
101-
"unique_id": link,
101+
"unique_id": f"{link}#{pubdate.isoformat()}",
102102
}
103103

104104

@@ -118,7 +118,7 @@ def render_rss(title, link, description, items):
118118
author_email=item["author_email"],
119119
pubdate=item["pubdate"],
120120
unique_id=item["unique_id"],
121-
unique_id_is_permalink=True,
121+
unique_id_is_permalink=False,
122122
)
123123
return feed.writeString("utf-8")
124124

‎pulp_python/tests/functional/api/test_pypi_feeds.py‎

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,40 @@ def test_pinned_version_feeds(
125125

126126
item = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg))[0]
127127
assert item.findtext("link").endswith("pypi/shelf-reader/0.1/json")
128-
assert item.findtext("guid").endswith("pypi/shelf-reader/0.1/json")
128+
assert "pypi/shelf-reader/0.1/json#" in item.findtext("guid")
129129

130130
python_content_factory(TWINE_WHEEL_FILENAME, url=TWINE_WHEEL_URL, repository=repo)
131131
update_titles = _titles(_parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg)))
132132
assert update_titles == ["shelf-reader 0.1"]
133+
134+
135+
@pytest.mark.parallel
136+
def test_new_file_for_existing_version_updates_guid(
137+
bindings_cfg, python_content_factory, python_empty_repo_distro
138+
):
139+
"""Adding a new file for an existing (name, version) produces a new guid and updated date."""
140+
repo, distro = python_empty_repo_distro()
141+
142+
python_content_factory(PYTHON_EGG_FILENAME, url=PYTHON_EGG_URL, repository=repo)
143+
144+
items = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg))
145+
assert len(items) == 1
146+
first_guid = items[0].findtext("guid")
147+
first_date = items[0].findtext("pubDate")
148+
assert "pypi/shelf-reader/0.1/json" in first_guid
149+
150+
python_content_factory(PYTHON_WHEEL_FILENAME, url=PYTHON_WHEEL_URL, repository=repo)
151+
152+
items = _parse_items(_get_feed(distro, "rss/updates.xml", bindings_cfg))
153+
assert len(items) == 1
154+
second_guid = items[0].findtext("guid")
155+
second_date = items[0].findtext("pubDate")
156+
157+
assert second_guid != first_guid
158+
assert second_date >= first_date
159+
160+
release_items = _parse_items(
161+
_get_feed(distro, "rss/project/shelf-reader/releases.xml", bindings_cfg)
162+
)
163+
assert len(release_items) == 1
164+
assert release_items[0].findtext("guid") == second_guid

0 commit comments

Comments
 (0)