Skip to content

fix(docs): stop the version banner showing on the stable docs - #142

Open
skoudoro wants to merge 1 commit into
tee-ar-ex:masterfrom
skoudoro:fix/doc-version-switcher-stable
Open

fix(docs): stop the version banner showing on the stable docs#142
skoudoro wants to merge 1 commit into
tee-ar-ex:masterfrom
skoudoro:fix/doc-version-switcher-stable

Conversation

@skoudoro

@skoudoro skoudoro commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Closes #141.

Root cause

Not gh-pages, not the deploy workflow — one field in switcher.json.

tools/update_switcher.py appended a synthetic entry and always moved preferred onto it:

{"name": "stable", "version": "stable", "url": ".../stable/", "preferred": true}

But pydata-sphinx-theme gates the version-warning banner on a semver parse of the preferred entry's version field:

// _static/scripts/pydata-sphinx-theme.js (theme 0.21.0)
const t = e => "string" == typeof e && /^[v\d]/.test(e) && o.test(e);  // o = semver regex
...
const s = r[0].version, a = r[0].url;   // "stable", ".../stable/"
const i = t(o) && t(s);                 // t("stable") === false  ->  i === false
if (i && n(o, s, "=")) return;          // suppression branch unreachable
...
m.innerText = o ? `version ${o}` : "an unknown version";

"stable" fails the /^[v\d]/ test, so the suppression branch could never run and every page fell through to the final else. That is the banner in the issue — rendered on /stable/ itself, with a "Switch to stable version" button linking back to the page you are already on.

Fix

Drop the pseudo-version entry. Following the numpy/scipy/pandas convention, the newest release is the stable entry and is served from the /stable/ alias:

[
    {"name": "dev",            "version": "dev",   "url": ".../dev/"},
    {"name": "0.5.0 (stable)", "version": "0.5.0", "url": ".../stable/", "preferred": true},
    {"name": "0.4.0",          "version": "0.4.0", "url": ".../0.4.0/"},
    {"name": "0.3",            "version": "0.3",   "url": ".../0.3/"}
]

This is a pure data fix. Every deployed page fetches switcher.json from the site root at runtime (the URL is hardcoded absolute in conf.py), so correcting the file fixes /stable/, /0.4.0/, /0.3/ and /dev/ retroactively, with no doc rebuild.

Verification

Ran the theme's own regex and predicate, copied verbatim from the deployed bundle, against both the current and the proposed file:

Page current switcher this PR
/stable/ banner: "version 0.5.0" ← the bug no banner
/0.5.0/ banner: "version 0.5.0" no banner
/0.4.0/ banner: "version 0.4.0" banner: "an old version (0.4.0)"
/0.3/ banner: "version 0.3" banner: "an old version (0.3)"
/dev/ banner: "an unstable development version" unchanged

The old-release banners were wrong for the same reason: with an unparseable preferred version the < comparison could not run either, so they reported a bare version X.Y.Z instead of an old version (X.Y.Z).

Changes

  • tools/update_switcher.py — rewritten around build_switcher(). The newest release gets preferred, the " (stable)" name suffix and the /stable/ URL; older releases keep their versioned URL. New parse_version() and is_latest() helpers, and a --rebuild mode. Stdlib only, since the deploy job runs this with the bare runner Python and installs no dependencies.
  • .github/workflows/docbuild.yml
    • Read switcher.json from the gh-pages worktree instead of curl-ing the published site. Pages serves that through a CDN cache, so two tags pushed in quick succession could be built from a stale copy and silently drop an entry.
    • Only copy to stable/ when the tag is the newest release, so a backport tag such as 0.4.1 published after 0.5.0 still gets its own folder but cannot demote stable.
    • New workflow_dispatch rebuild-switcher job, so the live site can be fixed without cutting a release. It derives the version list from the folders actually published on gh-pages rather than from git tag -l, because tags 0.0.10.2.9 predate the versioned docs and have no folder to link to.
  • docs/source/conf.pyversion_match collapsed to "dev" if "dev" in version else version. Behaviour is unchanged; the previous form was only accidentally correct.
  • trx/tests/test_update_switcher.py — new. update_switcher.py was untested and is the thing that broke. 22 tests, including a named regression test asserting no entry ever carries "version": "stable", plus coverage of the backport guard and --rebuild idempotency.

After merge

Run the workflow manually (Actions → Documentation build → Run workflow) to rewrite switcher.json on gh-pages and fix the live banner. Clear localStorage.pst_banner_pref before checking — the theme remembers dismissals for 14 days and will otherwise mask the result.

The version switcher marked a synthetic `{"version": "stable"}` entry as
preferred. pydata-sphinx-theme gates the warning banner on

    const i = t(o) && t(s);          // t = /^[v\d]/ + semver regex
    if (i && n(o, s, "=")) return;   // suppress banner

where `s` is the preferred entry's version. `t("stable")` is false, so the
suppression branch was unreachable and every page rendered
"This is documentation for version 0.5.0. [Switch to stable version]" —
including /stable/ itself, whose button linked back to the current page.

Drop the pseudo-version entry: the newest release is now the preferred one
and is served from the /stable/ alias, named "0.5.0 (stable)". Older
releases keep their own versioned URL, so they correctly report "an old
version (X.Y.Z)" instead of a bare "version X.Y.Z".

Also in the release workflow:

- Read switcher.json from the gh-pages worktree instead of curl-ing the
  published site, which is served through a CDN cache and could hand the
  build a stale copy.
- Only copy to stable/ when the tag is the newest release, so a backport
  tag cannot demote a newer one.
- Add a workflow_dispatch job that rebuilds switcher.json from the version
  folders present on gh-pages, to fix the live site without cutting a
  release. The folder list is used rather than git tags because tags
  predating the versioned docs have no folder to link to.

Closes tee-ar-ex#141
@codecov

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.86%. Comparing base (eac5318) to head (6f0002a).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #142      +/-   ##
==========================================
+ Coverage   86.46%   86.86%   +0.40%     
==========================================
  Files          13       14       +1     
  Lines        2881     2970      +89     
==========================================
+ Hits         2491     2580      +89     
  Misses        390      390              
Flag Coverage Δ
unittests 86.86% <100.00%> (+0.40%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@arokem

arokem commented Sep 9, 2026

Copy link
Copy Markdown
Member

Thank for doing this!

One question:

Clear localStorage.pst_banner_pref before checking

How/where do I do that? I am not familiar with localStorage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants