Deterministic episode ordering and shared URL helpers #34

Manually merged
marvin8 merged 6 commits from feat/issue-27-deterministic-sort-url-helper into main 2026-08-20 02:06:17 +00:00
Collaborator

Closes #27

Two code-quality improvements:

  • Deterministic ordering — discover_episodes() now uses the filename as a secondary sort key, so episodes sharing a date sort deterministically instead of in filesystem order.
  • Shared URL helper — extracted build_channel_url() and build_file_url() into a new sub2pod/urls.py, replacing the repeated quote(channel_dir.name, safe='') / base_url.rstrip('/') pattern in feed.py and opml.py.

Covered by Tryke tests (red → green), including a new tests/test_urls.py for the helper and a same-date determinism test in tests/test_discovery.py.

Closes #27 Two code-quality improvements: - **Deterministic ordering** — `discover_episodes()` now uses the filename as a secondary sort key, so episodes sharing a date sort deterministically instead of in filesystem order. - **Shared URL helper** — extracted `build_channel_url()` and `build_file_url()` into a new `sub2pod/urls.py`, replacing the repeated `quote(channel_dir.name, safe='')` / `base_url.rstrip('/')` pattern in `feed.py` and `opml.py`. Covered by Tryke tests (red → green), including a new `tests/test_urls.py` for the helper and a same-date determinism test in `tests/test_discovery.py`.
♻️ extract shared URL-building helpers into urls.py
All checks were successful
/ gitleaks (pull_request) Successful in 17s
/ checks (pull_request) Successful in 1m42s
/ publish (pull_request) Has been skipped
/ deploy-docs (pull_request) Has been skipped
/ pr-review (pull_request) Successful in 4m1s
354d7e9a89
📝 add release notes for deterministic episode ordering
Some checks failed
/ gitleaks (pull_request) Successful in 19s
/ checks (pull_request) Failing after 2m5s
/ publish (pull_request) Has been skipped
/ deploy-docs (pull_request) Has been skipped
/ pr-review (pull_request) Successful in 4m41s
078ace428e
⬆️ deps: bump cyclopts, complexipy, prek, ruff, ty, uv
All checks were successful
/ gitleaks (pull_request) Successful in 17s
/ checks (pull_request) Successful in 1m57s
/ publish (pull_request) Has been skipped
/ deploy-docs (pull_request) Has been skipped
/ pr-review (pull_request) Successful in 2m51s
e3691549f9
forgejo-actions left a comment

WuMing

Found 3 issue(s). See inline comments below.

## WuMing Found **3** issue(s). See inline comments below.
Release-Notes.md Outdated
@ -8,3 +10,4 @@
---
Episodes that share a publication date now come back in a consistent, predictable order instead of whatever order the filesystem happened to return. If you regenerated a feed and the episode list seemed to shuffle for no reason, this fixes it.

docs [LOW]

The pronoun "this" in "this fixes it" lacks a clear antecedent. It is not obvious whether it refers to the episode list, the ordering behavior, or the release itself. Consider writing "this change fixes it" or "this release fixes it."

**docs** [LOW] The pronoun "this" in "this fixes it" lacks a clear antecedent. It is not obvious whether it refers to the episode list, the ordering behavior, or the release itself. Consider writing "this change fixes it" or "this release fixes it." <!-- wuming:sha256:b08d66940c9699f2c8f3679c464e600b4f3474ef5253dc5ac102b45fbf430e6f -->
marvin8 marked this conversation as resolved
@ -11,3 +10,4 @@
from sub2pod.discovery import Episode
from sub2pod.nfo import ChannelInfo
from sub2pod.urls import build_file_url

tests [LOW]

feed.py URL construction was refactored to use build_file_url, but no test file for feed.py appears in the diff. Add or update feed tests to verify generated file/artwork URLs still use the helper correctly.

**tests** [LOW] feed.py URL construction was refactored to use build_file_url, but no test file for feed.py appears in the diff. Add or update feed tests to verify generated file/artwork URLs still use the helper correctly. <!-- wuming:sha256:8c3dbb05ca19badd88871fc7ad8f15d0af2a9b1cbf6f145c29d925718ee318e6 -->
marvin8 marked this conversation as resolved
@ -7,3 +6,4 @@
from lxml import etree # ty: ignore[unresolved-import]
from sub2pod.nfo import ChannelInfo
from sub2pod.urls import build_channel_url

tests [LOW]

opml.py URL construction was refactored to use build_channel_url, but no test file for opml.py appears in the diff. Add or update an OPML test asserting the generated outline feed URLs after the refactor.

**tests** [LOW] opml.py URL construction was refactored to use build_channel_url, but no test file for opml.py appears in the diff. Add or update an OPML test asserting the generated outline feed URLs after the refactor. <!-- wuming:sha256:6d53596ba5118aec52e484fbfc98dee6ebb2dc133792252765c2bcca56530fd3 -->
marvin8 marked this conversation as resolved
✏️ clarify release notes antecedent
All checks were successful
/ gitleaks (pull_request) Successful in 14s
/ checks (pull_request) Successful in 2m8s
/ publish (pull_request) Has been skipped
/ deploy-docs (pull_request) Has been skipped
/ pr-review (pull_request) Successful in 4m6s
5fbfa2425a
Author
Collaborator

WuMing review — 1 fixed, 2 declined

Release-Notes.md line 13

The pronoun "this" in "this fixes it" lacks a clear antecedent…

✅ Fixed in commit 5fbfa24 — reworded to "this change fixes it".

src/sub2pod/feed.py line 13

feed.py URL construction was refactored to use build_file_url, but no test file for feed.py appears in the diff…

🔴 Declined — the refactor is already covered. tests/test_urls.py (new, in this diff) directly tests build_file_url()/build_channel_url(), and tests/test_feed.py's build_enclosure_url tests still assert the percent-encoded URLs end-to-end. The full 118-test suite passes against the refactored code.

src/sub2pod/opml.py line 9

opml.py URL construction was refactored to use build_channel_url, but no test file for opml.py appears in the diff…

🔴 Declined — tests/test_opml.py's test_percent_encoding asserts xmlUrl == "https://pod.example.com/Links%20%26%20Friends/feed.xml", which is exactly build_channel_url() + /feed.xml. That test passes against the refactored code.

### WuMing review — 1 fixed, 2 declined [`Release-Notes.md` line 13](https://forge.marvin8.zone/marvin8/sub2pod/pulls/34#issuecomment-1726) > The pronoun "this" in "this fixes it" lacks a clear antecedent… ✅ Fixed in commit `5fbfa24` — reworded to "this change fixes it". [`src/sub2pod/feed.py` line 13](https://forge.marvin8.zone/marvin8/sub2pod/pulls/34#issuecomment-1727) > feed.py URL construction was refactored to use build_file_url, but no test file for feed.py appears in the diff… 🔴 Declined — the refactor is already covered. `tests/test_urls.py` (new, in this diff) directly tests `build_file_url()`/`build_channel_url()`, and `tests/test_feed.py`'s `build_enclosure_url` tests still assert the percent-encoded URLs end-to-end. The full 118-test suite passes against the refactored code. [`src/sub2pod/opml.py` line 9](https://forge.marvin8.zone/marvin8/sub2pod/pulls/34#issuecomment-1728) > opml.py URL construction was refactored to use build_channel_url, but no test file for opml.py appears in the diff… 🔴 Declined — `tests/test_opml.py`'s `test_percent_encoding` asserts `xmlUrl == "https://pod.example.com/Links%20%26%20Friends/feed.xml"`, which is exactly `build_channel_url()` + `/feed.xml`. That test passes against the refactored code.
forgejo-actions left a comment

WuMing

Found 1 issue(s). See inline comments below.

## WuMing Found **1** issue(s). See inline comments below.
@ -3,3 +3,3 @@
---
sub2pod 0.3.1
sub2pod 0.3.4

docs [MEDIUM]

The previous version in this file is 0.3.1, but this change bumps it to 0.3.4, skipping 0.3.2 and 0.3.3. If this PR is the next release, it should probably be 0.3.2, or the release notes need entries for the missing intermediate versions.

**docs** [MEDIUM] The previous version in this file is 0.3.1, but this change bumps it to 0.3.4, skipping 0.3.2 and 0.3.3. If this PR is the next release, it should probably be 0.3.2, or the release notes need entries for the missing intermediate versions. <!-- wuming:sha256:2cacc5066df2b6d308710dd2b81927d8aca10a698ad7091eb02a7711cc59fdc0 -->
marvin8 marked this conversation as resolved
Author
Collaborator

Release-Notes.md line 5

The previous version in this file is 0.3.1, but this change bumps it to 0.3.4, skipping 0.3.2 and 0.3.3…

🔴 Declined — 0.3.2, 0.3.3, and 0.3.4 are all already released (see git tags / CHANGELOG). pyproject.toml is at 0.3.4; the Release-Notes.md intro was simply stale at 0.3.1. I synced it to the current version per the project rule ("update the version in the intro from pyproject.toml if it has changed"). The next release will be 0.3.5 via just release, not 0.3.2.

[`Release-Notes.md` line 5](https://forge.marvin8.zone/marvin8/sub2pod/pulls/34#issuecomment-1732) > The previous version in this file is 0.3.1, but this change bumps it to 0.3.4, skipping 0.3.2 and 0.3.3… 🔴 Declined — 0.3.2, 0.3.3, and 0.3.4 are all already released (see git tags / CHANGELOG). `pyproject.toml` is at `0.3.4`; the `Release-Notes.md` intro was simply stale at `0.3.1`. I synced it to the current version per the project rule ("update the version in the intro from pyproject.toml if it has changed"). The next release will be 0.3.5 via `just release`, not 0.3.2.
🔧 align pre-commit revs with pyproject and bump zaojun to 1.7.4
All checks were successful
/ gitleaks (pull_request) Successful in 16s
/ checks (pull_request) Successful in 2m42s
/ publish (pull_request) Has been skipped
/ deploy-docs (pull_request) Has been skipped
/ pr-review (pull_request) Successful in 3m20s
c8d11f3009
marvin8 approved these changes 2026-08-20 02:05:50 +00:00
marvin8 manually merged commit 628ee94c9c into main 2026-08-20 02:06:17 +00:00
marvin8 deleted branch feat/issue-27-deterministic-sort-url-helper 2026-08-20 02:06:48 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
marvin8/sub2pod!34
No description provided.