Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 14 additions & 17 deletions .github/workflows/sphinxbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,38 +60,35 @@ jobs:
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3

- name: Get stable branches
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
id: stable_branches
run: |
branches=$(git ls-remote --heads origin "heads/stable[0-9][0-9]" \
| awk '{gsub(/^refs\/heads\/stable/, "", $2); print $2}' \
| sort -n -r | tr '\n' ' ')
echo "branches=$branches" >> $GITHUB_OUTPUT

- name: Setup PHP for version validation
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
- name: Setup PHP for version detection
uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2.37.1

- name: Validate version constants in conf.py
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
- name: Detect and export version constants
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Detect current highest released stable and lowest supported stable via
# GitHub API (same logic as build/build-index.php and generate-top-index.yml).
# Exports DOCS_VERSION_STABLE and DOCS_VERSION_START so conf.py always has
# accurate values without manual updates to any branch.
eval $(php build/detect-versions.php ${{ steps.stable_branches.outputs.branches }})
echo "DOCS_VERSION_STABLE=$highest_stable" >> $GITHUB_ENV
echo "DOCS_VERSION_START=$lowest_stable" >> $GITHUB_ENV

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) != 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) != lowest existing stable branch ($lowest_stable). Update conf.py."
err=1
# Compute display version: branch number for stableNN builds, dev version for master.
branch="${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}"
if [[ "$branch" =~ ^stable([0-9]+)$ ]]; then
echo "DOCS_DISPLAY_VERSION=${BASH_REMATCH[1]}" >> $GITHUB_ENV
else
echo "DOCS_DISPLAY_VERSION=$((highest_stable + 1))" >> $GITHUB_ENV
fi
exit $err

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
Expand Down
41 changes: 41 additions & 0 deletions _shared_assets/static/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,44 @@ table.docutils {
#code-style table.docutils {
width: 100%;
}

/* Version picker lists — 2-column grid, emoji as absolute ::before bullet */
.rst-versions .rst-other-versions {
padding-left: 26px;
}

.rst-versions .rst-other-versions dl.nc-versions-list,
.rst-versions .rst-other-versions dl.nc-languages-list {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 6px;
}

.rst-versions .rst-other-versions dl.nc-versions-list dt,
.rst-versions .rst-other-versions dl.nc-languages-list dt {
grid-column: span 2;
position: relative;
padding: 0;
}

.rst-versions .rst-other-versions dl dt::before {
position: absolute;
left: -22px;
height: 18px;
width: 18px;
font-size: 16px;
line-height: 18px;
}

.rst-versions .rst-other-versions dl.nc-versions-list dt::before {
content: "☁️";
}

.rst-versions .rst-other-versions dl.nc-languages-list dt::before {
content: "🌐";
}

.rst-versions .rst-other-versions dd a {
padding: 0;
}
6 changes: 3 additions & 3 deletions admin_manual/_templates/versions.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
<span class="fa fa-caret-down" aria-hidden="true"></span>
</button>
<div id="rst-other-versions-admin" class="rst-other-versions">
<dl>
<dt>☁️ {{ _('Versions') }}</dt>
<dl class="nc-versions-list">
<dt>{{ _('Versions') }}</dt>
{% for slug, url, label in versions|reverse %}
<dd style="width: 32%">
<dd>
<a href="{{ url }}"
{% if current_version == slug %}
style="color: var(--dark-link-color);"
Expand Down
3 changes: 3 additions & 0 deletions build/detect-versions.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ function fetch_release_info(int $version): ?array {
*/
function detect_versions(array $branches): array {
rsort($branches, SORT_NUMERIC);
// Nextcloud's support policy: a release is supported for 1 year after its initial
// release. Versions released more than a year ago are considered out of support
// and count as $lowest_stable only if no newer in-support version exists.
$oneYearAgo = time() - (365 * 24 * 60 * 60);
$released = [];
$firstOutOfSupportTime = null;
Expand Down
47 changes: 17 additions & 30 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,15 @@
html_copy_source = False

# building the versions list
# CI validates both constants against actual stableNN branches (see sphinxbuild.yml).
# 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
# Detect stable branch version for display purposes.
# For PRs: GITHUB_BASE_REF is the target branch (e.g. 'stable34').
# For direct pushes: GITHUB_REF is 'refs/heads/stable34'.
_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_ver.group(1) if _stable_ver # stableNN branches and PRs targeting them
else str(version_stable + 1) # master
# In CI: DOCS_VERSION_STABLE and DOCS_VERSION_START are injected by sphinxbuild.yml
# via detect-versions.php so these values are always current without manual updates.
# Fallbacks here are used for local builds only.
version_start = int(os.environ.get('DOCS_VERSION_START', 32))
version_stable = int(os.environ.get('DOCS_VERSION_STABLE', 34)) # CHANGING IT MUST RESULT IN A CHANGE OF THE SYMLINK ON THE LIVE SERVER
# In CI: DOCS_DISPLAY_VERSION is injected by sphinxbuild.yml.
# Fallback: PDF/ePub builds use release (DOCS_RELEASE); local master builds use version_stable+1.
display_version = os.environ.get('DOCS_DISPLAY_VERSION') or (
release if release != 'latest' else str(version_stable + 1)
)

# Also search for "TODO ON RELEASE" in the rst files
Expand All @@ -100,17 +88,16 @@ def generateVersionsDocs(current_docs):

# 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))
if display_version.isdigit() and int(display_version) < version_start:
branch_ver = int(display_version)
url = 'https://docs.nextcloud.com/server/%s/%s' % (display_version, 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)))
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)' % str(version_stable + 1)))
versions_doc.append((v, url, '%s (stable)' % v))
versions_doc.append(('stable', 'https://docs.nextcloud.com/server/stable/%s' % current_docs, '%s (latest)' % version_stable))
versions_doc.append(('latest', 'https://docs.nextcloud.com/server/latest/%s' % current_docs, '%s (upcoming)' % str(version_stable + 1)))
return versions_doc

if version.isdigit():
Expand All @@ -119,7 +106,7 @@ def generateVersionsDocs(current_docs):
github_branch = 'master'

html_context = {
'current_version': int(_stable_ver.group(1)) if _stable_ver else version,
'current_version': int(display_version) if display_version.isdigit() else version,
'display_version': display_version,
'READTHEDOCS': True,

Expand Down
6 changes: 3 additions & 3 deletions developer_manual/_templates/versions.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
<span class="fa fa-caret-down" aria-hidden="true"></span>
</button>
<div id="rst-other-versions-dev" class="rst-other-versions">
<dl>
<dt>☁️ {{ _('Versions') }}</dt>
<dl class="nc-versions-list">
<dt>{{ _('Versions') }}</dt>
{% for slug, url, label in versions|reverse %}
<dd style="width: 32%">
<dd>
<a href="{{ url }}"
{% if current_version == slug %}
style="color: var(--dark-link-color);"
Expand Down
12 changes: 6 additions & 6 deletions user_manual/_templates/versions.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@
<span class="fa fa-caret-down" aria-hidden="true"></span>
</button>
<div id="rst-other-versions-user" class="rst-other-versions">
<dl>
<dt>🌐 {{ _('Languages') }}</dt>
<dl class="nc-languages-list">
<dt>{{ _('Languages') }}</dt>
{% for lang in sorted_languages %}
<dd style="width: 32%; vertical-align: top;">
<dd>
<a href="/server/latest/user_manual/{{ lang.code }}/"
{% if lang.code == language %}
style="color: var(--dark-link-color);"
Expand All @@ -88,10 +88,10 @@
</dl>
</div>
<div class="rst-other-versions">
<dl>
<dt>☁️ {{ _('Versions') }}</dt>
<dl class="nc-versions-list">
<dt>{{ _('Versions') }}</dt>
{% for slug, url, label in versions|reverse %}
<dd style="width: 32%">
<dd>
<a href="{{ url }}"
{% if current_version == slug %}
style="color: var(--dark-link-color);"
Expand Down
Loading