Add tools/build_site.py: runs the full pipeline in dependency order (build_content -> build_listings -> seo_inject --all --sitemap -> build_botlinks -> build_search_index), each as a subprocess so a failing step aborts the build before anything downstream runs (no partial deploy). --check verifies non-destructively; --images also runs optimize_images. This is what CI will run in U5. Fix a build_content idempotence bug found via U4: the hero and article-header regions were emitted with leading indentation while the regex left the template's pre-tag whitespace in place, so indentation compounded (+16 spaces) on every rebuild. First line is now unindented; the full build is verified idempotent (identical git tree across two runs). Added a fixpoint test (re-rendering a page's own output is byte-identical) so this can't regress. docs/local-preview.md: build + serve on :8000 in all three languages. tools/README.md: document build_site + build_content. 26 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
2.0 KiB
Markdown
48 lines
2.0 KiB
Markdown
# tools/
|
|
|
|
## content_index.py
|
|
|
|
Reads the `content/` source tree (front-matter) as structured data. Its
|
|
`load_dates()` builds the article date registry consumed by `seo_inject.py`,
|
|
so **adding a post no longer needs a manual `ARTICLE_DATES` edit** — the date
|
|
lives in the post's front-matter (`date` / `date_type`). See
|
|
`docs/content-model.md`.
|
|
|
|
## build_site.py
|
|
|
|
One command to build the whole site from `content/`, in dependency order
|
|
(content pages -> listings -> SEO/sitemap -> bot links -> search index). This is
|
|
what CI runs before deploying. `--check` verifies without writing; `--images`
|
|
also runs image optimisation. Idempotent. See `docs/local-preview.md`.
|
|
|
|
## build_content.py
|
|
|
|
Renders the `content/` source files into the blog/news/event detail pages
|
|
(`--check` verifies the output matches the current site; `--write` emits pages).
|
|
See `docs/content-model.md` and the no-code CMS plan in `docs/plans/`.
|
|
|
|
## seo_inject.py
|
|
|
|
Injects a technical-SEO block into every language page (`en|mk|si/**/index.html`)
|
|
and regenerates `sitemap.xml` + `robots.txt`. Safe to re-run — the block lives
|
|
between `<!-- SEO:START -->` and `<!-- SEO:END -->` and is replaced in place.
|
|
|
|
The block adds: `meta description` (auto-extracted from the page's lead/subtitle
|
|
where available), `canonical`, `hreflang` alternates (en / mk / **sl** / x-default),
|
|
Open Graph, Twitter Card, and an Organization JSON-LD.
|
|
|
|
All absolute URLs point at the **final** domain `https://msosorg.com` (not the
|
|
temporary host), so nothing needs rewriting at launch. Note: the Slovene folder
|
|
is `/si/` but the ISO code is `sl` — the script maps `si → sl` for hreflang/locale.
|
|
|
|
### Usage
|
|
|
|
```sh
|
|
python tools/seo_inject.py # dry run: print the block for pilot pages
|
|
python tools/seo_inject.py --all # write the block into every page
|
|
python tools/seo_inject.py --all --sitemap # also rebuild sitemap.xml + robots.txt
|
|
```
|
|
|
|
Run `--all --sitemap` after adding, renaming, or deleting any page so canonical
|
|
tags, hreflang alternates, and the sitemap stay in sync.
|