Skip to content

Commit faa84e6

Browse files
docs(site): root of bertini2.org redirects to the current release (chooser → /versions.html) (#340)
## What `bertini2.org` currently lands on a **version chooser**. Most visitors don't want to pick a version — they want the current docs. Make the site **root redirect straight to the current stable release**. ## How The site root is generated by `tools/assemble_versioned_docs.py` (the store is served directly from the `docs-store` branch, ADR-0050). This changes what that generator writes at the root: - **`/index.html`** → a redirect (`<meta refresh>` + canonical) to `/v{stable}/`. The target follows the `stable` pointer, so it stays correct every release. If there's no stable version yet (bootstrap), it falls back to serving the chooser. - **`/versions.html`** (new) → the human-readable chooser that used to be the root (the "latest" card + every version). The root redirect links to it for the few who want an older version. - **`/versions.json`** unchanged (machine-readable index); **`/stable/`** unchanged. ## Effect `bertini2.org` → the current release's docs immediately; `bertini2.org/versions.html` → the chooser. Takes effect on the next docs deploy (i.e. the next release's redeploy). Tests in `tools/test_assemble_versioned_docs.py` updated to assert the root is a redirect to the current release and the chooser lives at `/versions.html`. 14 passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents 23e0782 + 38e7945 commit faa84e6

2 files changed

Lines changed: 47 additions & 10 deletions

File tree

tools/assemble_versioned_docs.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
``/CNAME`` file (written when ``--cname`` is given) is what keeps the custom domain across builds.
1313
1414
Truth vs. derived (mirrors the records doctrine, ADR-0045/0047): the ``v*/`` directories present in
15-
the store ARE the truth. ``versions.json`` and the root ``index.html`` are *derived, rebuildable
16-
views* -- regenerated from whatever version directories exist, every run. Delete a ``v*/`` dir and
17-
re-run and it simply drops out of the listing.
15+
the store ARE the truth. ``versions.json``, the root ``index.html``, and ``versions.html`` are
16+
*derived, rebuildable views* -- regenerated from whatever version directories exist, every run.
17+
Delete a ``v*/`` dir and re-run and it simply drops out of the listing.
18+
19+
The site root redirects straight to the current release -- most visitors do not want to pick a
20+
version. The human-readable chooser lives at ``/versions.html`` (root links to it), and
21+
``/versions.json`` is the machine-readable index.
1822
1923
Layout produced in the store::
2024
21-
/ root landing page (this script generates it) -- lists versions
25+
/ root: redirect to the current release (falls back to the chooser if none)
26+
/versions.html the human-readable version chooser (lists every version)
2227
/versions.json derived machine-readable version index
2328
/style.css shared stylesheet (copied from the built site)
2429
/.nojekyll so GitHub Pages serves _static/ etc. verbatim
@@ -69,7 +74,25 @@
6974
</html>
7075
"""
7176

72-
ROOT_INDEX_TEMPLATE = """<!DOCTYPE html>
77+
# The site root sends visitors straight to the current release -- most people do not want to pick a
78+
# version. The human-readable version chooser lives at /versions.html (linked here for the few who
79+
# do), and /versions.json is the machine-readable index.
80+
ROOT_REDIRECT_TEMPLATE = """<!DOCTYPE html>
81+
<html lang="en">
82+
<head>
83+
<meta charset="UTF-8">
84+
<meta http-equiv="refresh" content="0; url=/{vdir}/">
85+
<link rel="canonical" href="/{vdir}/">
86+
<title>Bertini 2 -- Documentation</title>
87+
</head>
88+
<body>
89+
<p>Redirecting to the <a href="/{vdir}/">latest documentation ({vdir})</a>&hellip;
90+
&nbsp;&middot;&nbsp; <a href="/versions.html">all versions</a></p>
91+
</body>
92+
</html>
93+
"""
94+
95+
VERSIONS_PAGE_TEMPLATE = """<!DOCTYPE html>
7396
<html lang="en">
7497
<head>
7598
<meta charset="UTF-8">
@@ -179,8 +202,8 @@ def load_prior(store: Path):
179202
return dates, data.get("stable")
180203

181204

182-
def render_root_index(records, stable) -> str:
183-
"""Build the root landing HTML from the derived version records."""
205+
def render_versions_page(records, stable) -> str:
206+
"""Build the /versions.html chooser HTML from the derived version records."""
184207
items = []
185208
for rec in records:
186209
tag = ' <span class="tag">stable</span>' if rec["version"] == stable else ""
@@ -191,7 +214,7 @@ def render_root_index(records, stable) -> str:
191214
)
192215
stable_href = f"v{stable}/" if stable else (records[0]["path"] if records else "#")
193216
stable_label = f" (v{html.escape(stable)})" if stable else ""
194-
return ROOT_INDEX_TEMPLATE.format(
217+
return VERSIONS_PAGE_TEMPLATE.format(
195218
stable_href=html.escape(stable_href),
196219
stable_label=stable_label,
197220
version_items="\n".join(items) if items else " <li>No versions yet.</li>",
@@ -266,7 +289,13 @@ def main(argv=None):
266289
(store / "versions.json").write_text(
267290
json.dumps({"generated": today, "stable": stable, "versions": records}, indent=2) + "\n"
268291
)
269-
(store / "index.html").write_text(render_root_index(records, stable))
292+
# Root sends visitors to the current release; the chooser is a separate /versions.html. With no
293+
# stable version yet (bootstrap), fall back to serving the chooser at the root.
294+
(store / "versions.html").write_text(render_versions_page(records, stable))
295+
if stable:
296+
(store / "index.html").write_text(ROOT_REDIRECT_TEMPLATE.format(vdir=f"v{stable}"))
297+
else:
298+
(store / "index.html").write_text(render_versions_page(records, stable))
270299

271300
print(f"OK: {vdir} written{' + stable redirect' if args.stable else ''}"
272301
f"{' + CNAME ' + args.cname if args.cname else ''}; "

tools/test_assemble_versioned_docs.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ def test_first_release_creates_everything(tmp_path):
6666
assert data["stable"] == "3.0.0"
6767
assert [v["version"] for v in data["versions"]] == ["3.0.0"]
6868
assert data["versions"][0]["stable"] is True
69-
assert "v3.0.0/" in (store / "index.html").read_text()
69+
# root is a redirect to the current release (not a chooser); the chooser is /versions.html.
70+
root = (store / "index.html").read_text()
71+
assert 'http-equiv="refresh"' in root and "url=/v3.0.0/" in root
72+
versions = (store / "versions.html").read_text()
73+
assert "All versions" in versions and 'href="v3.0.0/"' in versions
7074

7175

7276
def test_newer_release_moves_stable_and_preserves_old(tmp_path):
@@ -83,6 +87,10 @@ def test_newer_release_moves_stable_and_preserves_old(tmp_path):
8387
assert dates == {"3.0.0": "2026-07-14", "3.1.0": "2026-09-01"}
8488
# /stable/ now redirects to 3.1.0
8589
assert "/v3.1.0/" in stable_target(store)
90+
# root redirect follows stable to the newest release; the chooser lists both.
91+
assert "url=/v3.1.0/" in (store / "index.html").read_text()
92+
versions = (store / "versions.html").read_text()
93+
assert 'href="v3.1.0/"' in versions and 'href="v3.0.0/"' in versions
8694

8795

8896
def test_patch_to_old_line_does_not_move_stable(tmp_path):

0 commit comments

Comments
 (0)