Skip to content

Commit e8a1388

Browse files
scopdi
andauthored
Add project releases RSS feed (#7013)
* Add project releases RSS feed Closes #1683 * Add authors to project releases RSS feeds * Add project releases RSS feed docs * Move project releases feed to /rss/project/{name}/releases.xml * Rename package releases feed to project releases feed in docs * Improve project rss feed example rendering Co-authored-by: Dustin Ingram <[email protected]> * Use descending release date order in RSS feeds Co-authored-by: Dustin Ingram <[email protected]> * Don't overwrite base feeds, provide for adding instead Co-authored-by: Dustin Ingram <[email protected]> * Don't overwrite base feeds, provide for adding instead Co-authored-by: Dustin Ingram <[email protected]> * Don't overwrite base feeds, provide for adding instead Co-authored-by: Dustin Ingram <[email protected]> * Test project releases RSS feed ordering Co-authored-by: Dustin Ingram <[email protected]> * Test project releases RSS feed ordering Co-authored-by: Dustin Ingram <[email protected]> * Add RSS feed link to release history tab Co-authored-by: Dustin Ingram <[email protected]> * Update tests/unit/rss/test_views.py * Update translations Co-authored-by: Dustin Ingram <[email protected]>
1 parent a7d2321 commit e8a1388

File tree

11 files changed

+221
-103
lines changed

11 files changed

+221
-103
lines changed

docs/api-reference/feeds.rst

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
Feeds
22
=====
33

4-
PyPI offers two RSS feeds, the `Newest Packages Feed`_ and the `Latest Updates
5-
Feed`_. You can also call its APIs to get more details on project activity.
4+
PyPI offers three RSS feeds, the `Newest Packages Feed`_, the `Latest Updates
5+
Feed`_, and the `Project Releases Feed`_. You can also call its APIs to get
6+
more details on project activity.
67

78

89
Newest Packages Feed
@@ -21,6 +22,15 @@ newly created releases for individual projects on PyPI, including the project
2122
name and description, release version, and a link to the release page.
2223

2324

25+
Project Releases Feed
26+
---------------------
27+
28+
Available at ``https://pypi.org/rss/project/<project_name>/releases.xml`` for each
29+
project, this feed provides the latest releases for the given project on
30+
PyPI, including the package name and description, release version, and a link
31+
to the release page.
32+
33+
2434
Project and release activity details
2535
------------------------------------
2636

tests/unit/rss/test_views.py

+29
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,35 @@ def test_rss_packages(db_request):
7373
assert db_request.response.content_type == "text/xml"
7474

7575

76+
def test_rss_project_releases(db_request):
77+
db_request.find_service = pretend.call_recorder(
78+
lambda *args, **kwargs: pretend.stub(
79+
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
80+
)
81+
)
82+
83+
db_request.session = pretend.stub()
84+
85+
project = ProjectFactory.create()
86+
87+
release_v1 = ReleaseFactory.create(project=project, version="1.0.0")
88+
release_v1.created = datetime.date(2018, 1, 1)
89+
release_v3 = ReleaseFactory.create(project=project, version="3.0.0")
90+
release_v3.created = datetime.date(2019, 1, 1)
91+
release_v2 = ReleaseFactory.create(project=project, version="2.0.0")
92+
release_v2.created = datetime.date(2020, 1, 1)
93+
94+
release_v3.author_email = "[email protected]"
95+
96+
assert rss.rss_project_releases(project, db_request) == {
97+
"project": project,
98+
"latest_releases": tuple(
99+
zip((release_v2, release_v3, release_v1), (None, "[email protected]", None))
100+
),
101+
}
102+
assert db_request.response.content_type == "text/xml"
103+
104+
76105
def test_format_author(db_request):
77106
db_request.find_service = pretend.call_recorder(
78107
lambda *args, **kwargs: pretend.stub(

tests/unit/test_routes.py

+8
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@ def add_policy(name, filename):
303303
pretend.call("ses.hook", "/_/ses-hook/", domain=warehouse),
304304
pretend.call("rss.updates", "/rss/updates.xml", domain=warehouse),
305305
pretend.call("rss.packages", "/rss/packages.xml", domain=warehouse),
306+
pretend.call(
307+
"rss.project.releases",
308+
"/rss/project/{name}/releases.xml",
309+
factory="warehouse.packaging.models:ProjectFactory",
310+
traverse="/{name}/",
311+
read_only=True,
312+
domain=warehouse,
313+
),
306314
pretend.call("legacy.api.simple.index", "/simple/", domain=warehouse),
307315
pretend.call(
308316
"legacy.api.simple.detail",

0 commit comments

Comments
 (0)