feat(cms): U3 derive article dates from content/ front-matter
Replace the hand-maintained ARTICLE_DATES registry as the source of
truth with dates read from content/ front-matter, so publishing a post
via the CMS needs no manual registry edit (plan R4).
- tools/content_index.py: load_dates() reads content/ front-matter into
{source_folder/slug: {published|modified: iso}}. Standalone (os+yaml),
no import cycle with seo_inject.
- tools/seo_inject.py: ARTICLE_DATES is now {**static_fallback,
**content_dates}; content wins. The static table is kept only as a
fallback for entries not present in content/.
- migration now preserves the published-vs-modified distinction
(date_type), so the switch is byte-identical: content-derived dates
equal the old static table exactly (17/17, incl. the one 'modified').
Verified: full `seo_inject --all --sitemap` + build_listings +
build_botlinks run produces ZERO changes to any site page. build_content
--check still reproduces all 51 pages.
build_botlinks.py needs no change (it scrapes built pages, which are a
pure function of content/). Listings get content-driven dates for free
via seo_inject.ARTICLE_DATES.
tools/tests/test_content_index.py: 5 tests (dates == legacy registry,
merged registry unchanged, published/modified distinction, events key on
projects/<slug>, one ISO date per entry).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
596290acf8
commit
8ff968739a
9 files changed
+174
-14
No files matched your search
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests for tools/content_index.py + the seo_inject date wiring (U3).
|
||||
|
||||
Core guarantee: deriving ARTICLE_DATES from content/ front-matter reproduces the
|
||||
previously hand-maintained registry exactly (dates AND the published/modified
|
||||
distinction), so JSON-LD / meta output does not regress — while new posts no
|
||||
longer need a manual registry edit.
|
||||
|
||||
Run directly: python tools/tests/test_content_index.py
|
||||
Or with pytest: pytest tools/tests/test_content_index.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
TOOLS = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
sys.path.insert(0, TOOLS)
|
||||
|
||||
import content_index # noqa: E402
|
||||
import seo_inject # noqa: E402
|
||||
|
||||
|
||||
class DatesMatchLegacyRegistry(unittest.TestCase):
|
||||
def test_content_dates_equal_static_fallback(self):
|
||||
"""content/ front-matter reproduces the old hand-maintained table 1:1."""
|
||||
self.assertEqual(content_index.load_dates(), seo_inject._STATIC_ARTICLE_DATES)
|
||||
|
||||
def test_effective_registry_matches(self):
|
||||
"""The merged ARTICLE_DATES seo_inject actually uses is unchanged."""
|
||||
self.assertEqual(seo_inject.ARTICLE_DATES, seo_inject._STATIC_ARTICLE_DATES)
|
||||
|
||||
def test_published_modified_distinction_preserved(self):
|
||||
dates = content_index.load_dates()
|
||||
# This blog carried a 'modified' date, not 'published' — must survive.
|
||||
self.assertEqual(dates["blog/how-to-open-slovenian-bank-account"],
|
||||
{"modified": "2026-08-01"})
|
||||
# A normal entry defaults to 'published'.
|
||||
self.assertEqual(dates["news/proof-of-means-updated-2026"],
|
||||
{"published": "2026-08-01"})
|
||||
|
||||
|
||||
class RegistryShape(unittest.TestCase):
|
||||
def test_keys_use_source_folder(self):
|
||||
# Events live under content/events/ but must key on projects/<slug>
|
||||
# (their URL + schema key), not events/<slug>.
|
||||
dates = content_index.load_dates()
|
||||
self.assertIn("projects/paint-and-wine-at-sunset", dates)
|
||||
self.assertNotIn("events/paint-and-wine-at-sunset", dates)
|
||||
|
||||
def test_every_entry_has_one_iso_date(self):
|
||||
for key, rec in content_index.load_dates().items():
|
||||
self.assertEqual(len(rec), 1, f"{key}: expected one date kind")
|
||||
(kind, iso), = rec.items()
|
||||
self.assertIn(kind, ("published", "modified"))
|
||||
self.assertRegex(iso, r"^\d{4}-\d{2}-\d{2}$", f"{key}: bad ISO date")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in new issue
Block a user