From 6c8c5a0aec25f4d7157bb7625b5b932072aa340c Mon Sep 17 00:00:00 2001 From: lucasrodes Date: Sun, 7 Jun 2026 11:46:25 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A4=96=20Cut-over=20prose=20+?= =?UTF-8?q?=20COVID=20docs=20redirect=20for=20docs.owid.io?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- INFRASTRUCTURE.md | 21 +++++++++++---------- README.md | 8 ++++---- _worker.js | 21 +++++++++++++++++++-- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/INFRASTRUCTURE.md b/INFRASTRUCTURE.md index 341b8bd..f29add2 100644 --- a/INFRASTRUCTURE.md +++ b/INFRASTRUCTURE.md @@ -3,7 +3,7 @@ This repo is the **umbrella** of OWID's technical documentation. Its content is small (a landing page plus links into the subprojects). What makes it special is that it owns the custom domain and acts as a **router** in front of subproject Pages projects, so one URL transparently serves docs from multiple GitHub repos. ``` - docs-cf.owid.io (later: docs.owid.io) + docs.owid.io (staging alias: docs-cf.owid.io) │ ▼ ┌──────────────────────────────┐ @@ -34,7 +34,7 @@ This repo is the **umbrella** of OWID's technical documentation. Its content is Each subproject repo owns: - a `.github/workflows/deploy-docs-cf.yml` that builds the docs and uploads to its Pages project via `wrangler pages deploy` -- a sed-override of `site_url` in CI so the canonical/sitemap URLs reflect the production path on `docs-cf.owid.io/projects//` +- a sed-override of `site_url` in CI so the canonical/sitemap URLs reflect the production path on `docs.owid.io/projects//` Per-PR previews still work on each project's own `*.pages.dev` URL — the umbrella router is only invoked for traffic to the custom domain. @@ -44,9 +44,10 @@ Lives at repo root, copied into `site/` by the deploy workflow so CF Pages picks Responsibilities, in order: -1. **Legacy URL rewrite** — strip the `/en/latest` segment baked into old ReadTheDocs links and 301 to the canonical path. -2. **Subproject routing** — match a `SUBPROJECTS` prefix, `fetch()` the same path on the target Pages project, and stream the response back. -3. **Fallback** — `env.ASSETS.fetch(request)` serves this repo's own static assets (umbrella landing page, CSS, etc.). +1. **COVID docs redirect** — `/projects/covid/*` 301s to the legacy COVID docs at their native ReadTheDocs URL (`owidcovid-19-data.readthedocs.io`); they were never migrated to CF Pages. Runs before the `/en/latest` rewrite because RtD needs the version segment intact. +2. **Legacy URL rewrite** — strip the `/en/latest` segment baked into old ReadTheDocs links and 301 to the canonical path. +3. **Subproject routing** — match a `SUBPROJECTS` prefix, `fetch()` the same path on the target Pages project, and stream the response back. +4. **Fallback** — `env.ASSETS.fetch(request)` serves this repo's own static assets (umbrella landing page, CSS, etc.). To add a new subproject, append one line to the `SUBPROJECTS` map. @@ -61,7 +62,7 @@ Concrete example: a hypothetical `owid/foo-docs` repo serving its docs at `docs. ``` 2. **Add a workflow** in `owid/foo` mirroring [`.github/workflows/deploy-docs-cf.yml`](./.github/workflows/deploy-docs-cf.yml) from this repo or from `owid/etl`. Two things to adjust: - - sed-replace `site_url` to `https://docs-cf.owid.io/projects/foo/` (later `docs.owid.io/projects/foo/`). + - sed-replace `site_url` to `https://docs.owid.io/projects/foo/`. - Stage the build into `staging/projects/foo/` before `wrangler pages deploy`. 3. **Add repo secrets** in `owid/foo`: `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` (same values used by the other repos). @@ -88,7 +89,7 @@ CF dashboard → **owid.io zone** → Caching → Configuration → Purge Cache ### Swapping the custom domain -Currently `docs-cf.owid.io` is bound to the `owid-docs` Pages project. To re-attach to another project (e.g., during emergency rollback), detach from the source first, wait ~30 s, then attach to the target. +`docs.owid.io` (plus the staging alias `docs-cf.owid.io`) is bound to the `owid-docs` Pages project. To re-attach to another project (e.g., during emergency rollback), detach from the source first, wait ~30 s, then attach to the target. ### Production branch @@ -103,7 +104,7 @@ Each subproject repo + this one needs: One token + account ID pair works for all repos. -## Related deployments (unchanged today) +## Related deployments (legacy) -- **ReadTheDocs** — still serves `https://docs.owid.io/` and the subprojects. Builds untouched. Will be decommissioned once the CF mirror has been validated and `docs.owid.io` DNS is repointed. -- **GitHub Pages** — `.github/workflows/docs.yml` in this repo still publishes a copy. No active consumer; can be removed after the cut-over. +- **ReadTheDocs** — no longer serves `https://docs.owid.io/` (DNS was repointed to CF Pages). The RtD projects (`owid-docs`, `owid-etl`, `owid-grapher-py`) can be archived once the cut-over has been stable for a while. The **COVID docs** stay on RtD indefinitely at `https://owidcovid-19-data.readthedocs.io/` — `_worker.js` redirects `/projects/covid/*` there. The `docs.owid.io` custom domain must stay removed from the RtD `owid-docs` project, otherwise RtD redirects the COVID docs' native URL back to `docs.owid.io` and the redirect loops. +- **GitHub Pages** — `.github/workflows/docs.yml` in this repo still publishes a copy. No active consumer; can be removed now that the cut-over is done. diff --git a/README.md b/README.md index be745c3..e4dfa99 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ Umbrella site for OWID's technical documentation. -Production URL during the parallel-hosting phase: **https://docs-cf.owid.io/**. -The current production URL on ReadTheDocs is unchanged: **https://docs.owid.io/**. +Production URL: **https://docs.owid.io/** (served from Cloudflare Pages). +`docs-cf.owid.io` remains attached as a staging alias from the parallel-hosting phase. ## What's in this repo @@ -13,8 +13,8 @@ The current production URL on ReadTheDocs is unchanged: **https://docs.owid.io/* | `zensical.toml` | Site config (Zensical / Material) | | `_worker.js` | Cloudflare Pages worker — proxies subproject paths to other Pages projects (`/projects/etl/*`, `/projects/owid-grapher-py/*`, …) | | `.github/workflows/deploy-docs-cf.yml` | Builds + deploys this site to Cloudflare Pages on every push to `main` | -| `.github/workflows/docs.yml` | Legacy GitHub Pages deploy (will be removed after the RtD cut-over) | -| `.readthedocs.yml` | RtD build config (unchanged during the transition) | +| `.github/workflows/docs.yml` | Legacy GitHub Pages deploy (to be removed now that the RtD cut-over is done) | +| `.readthedocs.yml` | Legacy RtD build config (to be removed once the cut-over has been stable for a while) | | `INFRASTRUCTURE.md` | How the CF deployment fits together + how to add a new subproject | ## Local development diff --git a/_worker.js b/_worker.js index 737835a..9e337c8 100644 --- a/_worker.js +++ b/_worker.js @@ -2,8 +2,8 @@ // // When present at the deployment root, this file intercepts ALL requests // for this Pages project. We use it as a thin router so that one custom -// domain (docs-cf.owid.io and later docs.owid.io) can transparently serve -// docs from multiple source repos: +// domain (docs.owid.io) can transparently serve docs from multiple +// source repos: // // /projects/etl/* → proxied to https://owid-etl-docs.pages.dev/projects/etl/* // everything else → served from this project's own static assets @@ -17,6 +17,15 @@ const SUBPROJECTS = { "/projects/owid-grapher-py/": "https://owid-grapher-py-docs.pages.dev", }; +// The legacy COVID docs were never migrated to CF Pages — they stay on +// ReadTheDocs at their native URL. This must be checked BEFORE the +// /en/latest rewrite below: RtD needs the version segment intact. +// NOTE: requires docs.owid.io to be removed as custom domain from the +// RtD project at cut-over, otherwise RtD bounces the native URL back +// here and we loop. +const COVID_PREFIX = "/projects/covid"; +const COVID_ORIGIN = "https://owidcovid-19-data.readthedocs.io"; + // Legacy ReadTheDocs URLs include an /en/latest segment (e.g. // /projects/etl/en/latest/, /en/latest/). 301 to the canonical form so // existing inbound links from blog posts / Slack / bookmarks keep working. @@ -26,6 +35,14 @@ export default { async fetch(request, env) { const url = new URL(request.url); + if ( + url.pathname === COVID_PREFIX || + url.pathname.startsWith(`${COVID_PREFIX}/`) + ) { + const rest = url.pathname.slice(COVID_PREFIX.length); + return Response.redirect(`${COVID_ORIGIN}${rest}${url.search}`, 301); + } + if (RTD_LEGACY.test(url.pathname)) { url.pathname = url.pathname.replace(RTD_LEGACY, "$1") || "/"; return Response.redirect(url.toString(), 301);