From b21841b2f150c457e2b3daf983931d1f6efdb0b2 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:05:35 +0200 Subject: [PATCH 01/11] fix: show numbered version in manual titles and version picker Replace the bare "latest" label with the actual Nextcloud version number (derived from version_stable + 1) across all three manuals. - Add display_version = str(version_stable + 1) in conf.py, auto-updating when version_stable increments at each release - Use display_version in project names, html_title, and |version| RST substitution so titles read "Nextcloud 34 User Manual" instead of "Nextcloud latest User Manual" - Update generateVersionsDocs to return (slug, url, label) 3-tuples so the version picker shows "33 (stable)" and "34 (latest)" rather than bare "stable" / "latest" slugs - Update all three versions.html templates to render the label and expose display_version for the collapsed picker button Signed-off-by: skjnldsv --- admin_manual/_templates/versions.html | 4 ++-- admin_manual/conf.py | 3 ++- conf.py | 28 +++++++++++------------ developer_manual/_templates/versions.html | 4 ++-- developer_manual/conf.py | 3 ++- user_manual/_templates/versions.html | 4 ++-- user_manual/conf.py | 5 ++-- 7 files changed, 27 insertions(+), 24 deletions(-) diff --git a/admin_manual/_templates/versions.html b/admin_manual/_templates/versions.html index 70c5e22dee2..b8c514d113e 100644 --- a/admin_manual/_templates/versions.html +++ b/admin_manual/_templates/versions.html @@ -8,14 +8,14 @@
☁️ {{ _('Versions') }}
- {% for slug, url in versions|reverse %} + {% for slug, url, label in versions|reverse %}
- {{ slug }} + {{ label }}
{% endfor %} diff --git a/admin_manual/conf.py b/admin_manual/conf.py index aa7dab6953b..4cbe4abf438 100644 --- a/admin_manual/conf.py +++ b/admin_manual/conf.py @@ -20,7 +20,8 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = u'Nextcloud %s Administration Manual' % (version) +project = u'Nextcloud %s Administration Manual' % (display_version) +html_title = project # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/conf.py b/conf.py index deec64e0ace..0f580233387 100644 --- a/conf.py +++ b/conf.py @@ -56,35 +56,34 @@ # disable including the reST sources in HTML builds (in _sources/) (default is True) html_copy_source = False +# building the versions list +version_start = 31 # THIS IS THE OLDEST SUPPORTED VERSION NUMBER + + # THIS IS THE VERSION THAT IS MAPPED TO https://docs.nextcloud.com/server/stable/ +version_stable = 32 # CHANGING IT MUST RESULT IN A CHANGE OF THE SYMLINK ON THE LIVE SERVER + +# Also search for "TODO ON RELEASE" in the rst files + # substitutions go here rst_epilog = """ .. |version| replace:: %s -""" % (release) +""" % (display_version) # Replace hardcoded /latest/ URLs in all .rst source files with the actual release def replace_latest(app, docname, source): if release != 'latest': source[0] = source[0].replace('/server/latest/', '/server/%s/' % release) - + def setup(app): app.connect('source-read', replace_latest) - -# building the versions list -version_start = 31 # THIS IS THE OLDEST SUPPORTED VERSION NUMBER - - # THIS IS THE VERSION THAT IS MAPPED TO https://docs.nextcloud.com/server/stable/ -version_stable = 32 # CHANGING IT MUST RESULT IN A CHANGE OF THE SYMLINK ON THE LIVE SERVER - -# Also search for "TODO ON RELEASE" in the rst files - def generateVersionsDocs(current_docs): versions_doc = [] for v in range(version_start, version_stable + 1): url = 'https://docs.nextcloud.com/server/%s/%s' % (str(v), current_docs) - versions_doc.append(tuple((v, url))) - versions_doc.append(tuple(('stable', 'https://docs.nextcloud.com/server/%s/%s' % ('stable', current_docs)))) - versions_doc.append(tuple(('latest', 'https://docs.nextcloud.com/server/%s/%s' % ('latest', current_docs)))) + versions_doc.append((v, url, str(v))) + versions_doc.append(('stable', 'https://docs.nextcloud.com/server/stable/%s' % current_docs, '%s (stable)' % version_stable)) + versions_doc.append(('latest', 'https://docs.nextcloud.com/server/latest/%s' % current_docs, '%s (latest)' % display_version)) return versions_doc if version.isdigit(): @@ -94,6 +93,7 @@ def generateVersionsDocs(current_docs): html_context = { 'current_version': version, + 'display_version': display_version, 'READTHEDOCS': True, # force github plugin diff --git a/developer_manual/_templates/versions.html b/developer_manual/_templates/versions.html index 70c5e22dee2..b8c514d113e 100644 --- a/developer_manual/_templates/versions.html +++ b/developer_manual/_templates/versions.html @@ -8,14 +8,14 @@
☁️ {{ _('Versions') }}
- {% for slug, url in versions|reverse %} + {% for slug, url, label in versions|reverse %}
- {{ slug }} + {{ label }}
{% endfor %} diff --git a/developer_manual/conf.py b/developer_manual/conf.py index 61d72760015..25071039ccf 100644 --- a/developer_manual/conf.py +++ b/developer_manual/conf.py @@ -22,7 +22,8 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = "Nextcloud %s Developer Manual" % (version) +project = "Nextcloud %s Developer Manual" % (display_version) +html_title = project # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration diff --git a/user_manual/_templates/versions.html b/user_manual/_templates/versions.html index 78076e86268..39b7dda82db 100644 --- a/user_manual/_templates/versions.html +++ b/user_manual/_templates/versions.html @@ -83,14 +83,14 @@
☁️ {{ _('Versions') }}
- {% for slug, url in versions|reverse %} + {% for slug, url, label in versions|reverse %}
- {{ slug }} + {{ label }}
{% endfor %} diff --git a/user_manual/conf.py b/user_manual/conf.py index d0b1e0f99b6..9a6382e5d82 100644 --- a/user_manual/conf.py +++ b/user_manual/conf.py @@ -20,7 +20,8 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = u'Nextcloud %s User Manual' % (version) +project = u'Nextcloud %s User Manual' % (display_version) +html_title = project # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -55,7 +56,7 @@ ## Markup # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-markup # a substitution that will be included in every source file -rst_epilog = '.. |version| replace:: %s' % version +rst_epilog = '.. |version| replace:: %s' % display_version # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output From 54693a867df7569f736b242fbe3eee0e69b947bd Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:15:08 +0200 Subject: [PATCH 02/11] ci: validate version_start and version_stable against stableNN branches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a validation step in the build-html job that detects the highest and lowest stableNN branches via git ls-remote and fails if either drifts from the hardcoded constants in conf.py. Local builds are unaffected — the hardcoded values remain the fallback. Update conf.py comments to explain the CI validation and the conditions under which each constant must change. Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 65059bec02c..2e01fbb9b91 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -59,6 +59,29 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Validate version constants in conf.py + run: | + highest_stable=$(git ls-remote --heads origin \ + | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' \ + | sort -n | tail -1) + lowest_stable=$(git ls-remote --heads origin \ + | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' \ + | sort -n | head -1) + + conf_stable=$(grep -m1 '^\s*version_stable\s*=' conf.py | grep -o '[0-9]\+') + conf_start=$(grep -m1 '^\s*version_start\s*=' conf.py | grep -o '[0-9]\+') + + err=0 + if [ "$highest_stable" != "$conf_stable" ]; then + echo "::error::version_stable in conf.py ($conf_stable) != detected highest stable branch ($highest_stable). Update conf.py." + err=1 + fi + if [ "$lowest_stable" != "$conf_start" ]; then + echo "::error::version_start in conf.py ($conf_start) != detected lowest stable branch ($lowest_stable). Update conf.py." + err=1 + fi + exit $err + - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: From eb42a8f4362e678595a6dc4b85baf8b4e069b6d4 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:17:28 +0200 Subject: [PATCH 03/11] ci: only validate version constants when building master Old/stable branches have historically correct conf.py snapshots from their era; validating against current remote branches would always fail. Restrict the check to master and PRs targeting master where keeping version_stable and version_start current actually matters. Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 2e01fbb9b91..7e3ccf27cb1 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -60,6 +60,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Validate version constants in conf.py + if: github.ref == 'refs/heads/master' || github.base_ref == 'master' run: | highest_stable=$(git ls-remote --heads origin \ | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' \ From b401c9fece4950badd0a02c1bf25528e05629d96 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:19:00 +0200 Subject: [PATCH 04/11] ci: use GitHub API to detect highest released stable for validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git ls-remote alone would pick up a stableNN branch that exists but hasn't had vN.0.0 released yet (RC phase). Mirror the same curl + GitHub API release check used in the stage-and-check job and build-index.php to find the true highest released stable. version_start (lowest documented) still uses ls-remote — branch existence is the right signal there. Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 7e3ccf27cb1..c50d69caf06 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -61,10 +61,26 @@ jobs: - name: Validate version constants in conf.py if: github.ref == 'refs/heads/master' || github.base_ref == 'master' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - highest_stable=$(git ls-remote --heads origin \ - | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' \ - | sort -n | tail -1) + # version_stable: highest stableNN branch whose vN.0.0 release actually exists. + # Mirrors the is_version_released() check in build/build-index.php and stage-and-check. + # A branch that exists but has no release yet (e.g. RC phase) must be skipped. + highest_stable="" + for n in $(git ls-remote --heads origin \ + | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' | sort -n -r); do + repo=$( [ "$n" -ge 32 ] && echo "nextcloud-releases/server" || echo "nextcloud/server" ) + status=$(curl -s -o /dev/null -w "%{http_code}" \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + "https://api.github.com/repos/${repo}/releases/tags/v${n}.0.0") + if [ "$status" = "200" ]; then + highest_stable="$n" + break + fi + done + + # version_start: lowest stableNN branch that still exists (branch existence = still documented). lowest_stable=$(git ls-remote --heads origin \ | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' \ | sort -n | head -1) @@ -73,12 +89,16 @@ jobs: conf_start=$(grep -m1 '^\s*version_start\s*=' conf.py | grep -o '[0-9]\+') err=0 + if [ -z "$highest_stable" ]; then + echo "::error::Could not detect any released stable branch." + exit 1 + fi if [ "$highest_stable" != "$conf_stable" ]; then - echo "::error::version_stable in conf.py ($conf_stable) != detected highest stable branch ($highest_stable). Update conf.py." + echo "::error::version_stable in conf.py ($conf_stable) != highest released stable ($highest_stable). Update conf.py." err=1 fi if [ "$lowest_stable" != "$conf_start" ]; then - echo "::error::version_start in conf.py ($conf_start) != detected lowest stable branch ($lowest_stable). Update conf.py." + echo "::error::version_start in conf.py ($conf_start) != lowest existing stable branch ($lowest_stable). Update conf.py." err=1 fi exit $err From 0d379c7a144576e05c827454186911e2229ab09d Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:52:53 +0200 Subject: [PATCH 05/11] fix: derive PDF release version from conf.py on master Instead of hardcoding "latest" as DOCS_RELEASE for master branch PDF builds, compute version_stable + 1 from conf.py so the PDF cover page shows the actual development version number (35) rather than "latest". Stable branch builds are unaffected. Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index c50d69caf06..4a1c3d65410 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -286,7 +286,10 @@ jobs: if [[ "$branch" == stable* ]]; then echo "release=${branch#stable}" >> $GITHUB_OUTPUT else - echo "release=latest" >> $GITHUB_OUTPUT + # For master (latest), derive the dev version from conf.py so the + # PDF cover shows a real version number rather than "latest". + version_stable=$(grep -m1 '^\s*version_stable\s*=' conf.py | grep -o '[0-9]\+') + echo "release=$((version_stable + 1))" >> $GITHUB_OUTPUT fi - name: Build pdf documentation From 1ea7d0d662e2cbbdcf47feaa0a42295df5961209 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Mon, 15 Jun 2026 15:53:16 +0200 Subject: [PATCH 06/11] fix: exclude version_stable from numbered range in version picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: exclude version_stable from numbered range in version picker version_stable is already shown as "N (stable)" — including it in the plain numbered range caused it to appear twice in the picker. Signed-off-by: skjnldsv [skip ci] --- conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.py b/conf.py index 0f580233387..4ab089222ad 100644 --- a/conf.py +++ b/conf.py @@ -79,7 +79,7 @@ def setup(app): def generateVersionsDocs(current_docs): versions_doc = [] - for v in range(version_start, version_stable + 1): + for v in range(version_start, version_stable): url = 'https://docs.nextcloud.com/server/%s/%s' % (str(v), current_docs) versions_doc.append((v, url, str(v))) versions_doc.append(('stable', 'https://docs.nextcloud.com/server/stable/%s' % current_docs, '%s (stable)' % version_stable)) From c63af7d60a85d39c4c9dbb3f0067b1dfa48a9b6f Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 16 Jun 2026 09:24:21 +0200 Subject: [PATCH 07/11] fix: add display_version, update version_stable/start for current state The cherry-pick missed the display_version definition entirely, causing a NameError on any build. Add it with GITHUB_REF-based stable branch detection so HTML builds show the correct version number. Update version_stable from 32 to 34 (current highest released stable) and version_start from 31 to 32 (oldest documented) so the version picker reflects the current state of all branches. Signed-off-by: skjnldsv --- conf.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/conf.py b/conf.py index 4ab089222ad..49136051b08 100644 --- a/conf.py +++ b/conf.py @@ -57,10 +57,20 @@ html_copy_source = False # building the versions list -version_start = 31 # THIS IS THE OLDEST SUPPORTED VERSION NUMBER - - # THIS IS THE VERSION THAT IS MAPPED TO https://docs.nextcloud.com/server/stable/ -version_stable = 32 # CHANGING IT MUST RESULT IN A CHANGE OF THE SYMLINK ON THE LIVE SERVER +# Update version_start when the lowest stableNN branch is deleted (version goes EoL). +# Update version_stable when a new NC release ships (highest stableNN branch added). +version_start = 32 # oldest documented version + + # latest released stable — CHANGING IT MUST RESULT IN A CHANGE OF THE SYMLINK ON THE LIVE SERVER +version_stable = 34 # mapped to https://docs.nextcloud.com/server/stable/ + +import re as _re +_stable_branch = _re.match(r'refs/heads/stable(\d+)$', os.environ.get('GITHUB_REF', '')) +display_version = ( + release if release != 'latest' # PDF/ePub builds (DOCS_RELEASE set) + else _stable_branch.group(1) if _stable_branch # HTML builds on stableNN branches + else str(version_stable + 1) # HTML builds on master +) # Also search for "TODO ON RELEASE" in the rst files From ba45283e1bd36ae550ac5507d0f14022cbe7ccea Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 16 Jun 2026 09:36:14 +0200 Subject: [PATCH 08/11] fix: use GITHUB_BASE_REF to detect stable branch for display_version and PDF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous approach matched GITHUB_REF against stable branch patterns, which broke for backport/*/stableNN branches where GITHUB_REF is the source branch, not the target. Use GITHUB_BASE_REF (the PR target branch, always stableNN) for PRs, falling back to GITHUB_REF for direct pushes. Both are matched strictly against ^stable([0-9]+)$ — no loose suffix matching. Also set html_context current_version to the detected stable version integer so the picker correctly highlights the current docs version instead of always showing "latest" as selected. Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 11 ++++++----- conf.py | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 4a1c3d65410..2b80a444454 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -282,12 +282,13 @@ jobs: - name: Compute PDF release version id: pdf_version run: | - branch="${GITHUB_REF#refs/heads/}" - if [[ "$branch" == stable* ]]; then - echo "release=${branch#stable}" >> $GITHUB_OUTPUT + # For PRs use the target branch; for pushes use the current branch. + # This handles both stable33 direct pushes and backport/*/stable33 PRs. + branch="${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}" + if [[ "$branch" =~ ^stable([0-9]+)$ ]]; then + echo "release=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT else - # For master (latest), derive the dev version from conf.py so the - # PDF cover shows a real version number rather than "latest". + # master: derive the dev version from conf.py. version_stable=$(grep -m1 '^\s*version_stable\s*=' conf.py | grep -o '[0-9]\+') echo "release=$((version_stable + 1))" >> $GITHUB_OUTPUT fi diff --git a/conf.py b/conf.py index 49136051b08..eca2811b913 100644 --- a/conf.py +++ b/conf.py @@ -65,11 +65,19 @@ version_stable = 34 # mapped to https://docs.nextcloud.com/server/stable/ import re as _re -_stable_branch = _re.match(r'refs/heads/stable(\d+)$', os.environ.get('GITHUB_REF', '')) +# Detect stable branch version for display purposes. +# For PRs: GITHUB_BASE_REF is the target branch (e.g. 'stable33'). +# For direct pushes: GITHUB_REF is 'refs/heads/stable33'. +_base = os.environ.get('GITHUB_BASE_REF', '') +_ref = os.environ.get('GITHUB_REF', '') +_stable_ver = ( + _re.match(r'^stable(\d+)$', _base) + or _re.match(r'^refs/heads/stable(\d+)$', _ref) +) display_version = ( - release if release != 'latest' # PDF/ePub builds (DOCS_RELEASE set) - else _stable_branch.group(1) if _stable_branch # HTML builds on stableNN branches - else str(version_stable + 1) # HTML builds on master + release if release != 'latest' # PDF/ePub builds (DOCS_RELEASE set) + else _stable_ver.group(1) if _stable_ver # stableNN branches and PRs targeting them + else str(version_stable + 1) # master ) # Also search for "TODO ON RELEASE" in the rst files @@ -102,7 +110,7 @@ def generateVersionsDocs(current_docs): github_branch = 'master' html_context = { - 'current_version': version, + 'current_version': int(_stable_ver.group(1)) if _stable_ver else version, 'display_version': display_version, 'READTHEDOCS': True, From 9e033e4d731e77a6fbc0e700068dddc4c47e4645 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 16 Jun 2026 09:40:41 +0200 Subject: [PATCH 09/11] fix: add shell: bash to PDF release version step (container uses sh) Signed-off-by: skjnldsv --- .github/workflows/sphinxbuild.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 2b80a444454..62d1a21946c 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -281,6 +281,7 @@ jobs: - name: Compute PDF release version id: pdf_version + shell: bash run: | # For PRs use the target branch; for pushes use the current branch. # This handles both stable33 direct pushes and backport/*/stable33 PRs. From 8f309cc5a683a874d2f061380cca38a2138f4c2e Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 16 Jun 2026 09:53:33 +0200 Subject: [PATCH 10/11] fix: use version_stable+1 for latest picker label, not display_version display_version reflects the current branch (e.g. '32' on stable32), which is correct for titles and the picker button but wrong for the 'latest' picker entry which should always show the master dev version. Signed-off-by: skjnldsv --- conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.py b/conf.py index eca2811b913..35aba6062ca 100644 --- a/conf.py +++ b/conf.py @@ -101,7 +101,7 @@ def generateVersionsDocs(current_docs): url = 'https://docs.nextcloud.com/server/%s/%s' % (str(v), current_docs) versions_doc.append((v, url, str(v))) versions_doc.append(('stable', 'https://docs.nextcloud.com/server/stable/%s' % current_docs, '%s (stable)' % version_stable)) - versions_doc.append(('latest', 'https://docs.nextcloud.com/server/latest/%s' % current_docs, '%s (latest)' % display_version)) + versions_doc.append(('latest', 'https://docs.nextcloud.com/server/latest/%s' % current_docs, '%s (latest)' % str(version_stable + 1))) return versions_doc if version.isdigit(): From df5256a50bccfb16faab3c995ce4fa0f9f978c0d Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 16 Jun 2026 09:56:02 +0200 Subject: [PATCH 11/11] feat: add unsupported version entry to picker when viewing old branch docs When building docs for a branch older than version_start (e.g. stable26), the picker now includes that version labeled "(unsupported)" at the bottom, so users can see: 35 (latest), 34 (stable), 33, 32, 26 (unsupported). Signed-off-by: skjnldsv --- conf.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/conf.py b/conf.py index 35aba6062ca..7b5962b2ce3 100644 --- a/conf.py +++ b/conf.py @@ -97,6 +97,15 @@ def setup(app): def generateVersionsDocs(current_docs): versions_doc = [] + + # If viewing an unsupported (older than version_start) branch, prepend it so it + # appears last after the template's |reverse — e.g. "26 (unsupported)" at the bottom. + if _stable_ver: + branch_ver = int(_stable_ver.group(1)) + if branch_ver < version_start: + url = 'https://docs.nextcloud.com/server/%s/%s' % (str(branch_ver), current_docs) + versions_doc.append((branch_ver, url, '%s (unsupported)' % branch_ver)) + for v in range(version_start, version_stable): url = 'https://docs.nextcloud.com/server/%s/%s' % (str(v), current_docs) versions_doc.append((v, url, str(v)))