Skip to content

Commit 192963b

Browse files
authored
Merge pull request #15140 from nextcloud/fix/numbered-version-in-titles
fix: show numbered version in manual titles and version picker
2 parents 3fbdb4c + 15a5017 commit 192963b

10 files changed

Lines changed: 263 additions & 143 deletions

File tree

.github/workflows/sphinxbuild.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,40 @@ jobs:
5959
- name: Checkout repository
6060
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6161

62+
- name: Get stable branches
63+
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
64+
id: stable_branches
65+
run: |
66+
branches=$(git ls-remote --heads origin "heads/stable[0-9][0-9]" \
67+
| awk '{gsub(/^refs\/heads\/stable/, "", $2); print $2}' \
68+
| sort -n -r | tr '\n' ' ')
69+
echo "branches=$branches" >> $GITHUB_OUTPUT
70+
71+
- name: Setup PHP for version validation
72+
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
73+
uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2.37.1
74+
75+
- name: Validate version constants in conf.py
76+
if: github.ref == 'refs/heads/master' || github.base_ref == 'master'
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
run: |
80+
eval $(php build/detect-versions.php ${{ steps.stable_branches.outputs.branches }})
81+
82+
conf_stable=$(grep -m1 '^\s*version_stable\s*=' conf.py | grep -o '[0-9]\+')
83+
conf_start=$(grep -m1 '^\s*version_start\s*=' conf.py | grep -o '[0-9]\+')
84+
85+
err=0
86+
if [ "$highest_stable" != "$conf_stable" ]; then
87+
echo "::error::version_stable in conf.py ($conf_stable) != highest released stable ($highest_stable). Update conf.py."
88+
err=1
89+
fi
90+
if [ "$lowest_stable" != "$conf_start" ]; then
91+
echo "::error::version_start in conf.py ($conf_start) != lowest existing stable branch ($lowest_stable). Update conf.py."
92+
err=1
93+
fi
94+
exit $err
95+
6296
- name: Set up Python
6397
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
6498
with:
@@ -242,7 +276,10 @@ jobs:
242276
if [[ "$branch" == stable* ]]; then
243277
echo "release=${branch#stable}" >> $GITHUB_OUTPUT
244278
else
245-
echo "release=latest" >> $GITHUB_OUTPUT
279+
# For master (latest), derive the dev version from conf.py so the
280+
# PDF cover shows a real version number rather than "latest".
281+
version_stable=$(grep -m1 '^\s*version_stable\s*=' conf.py | grep -o '[0-9]\+')
282+
echo "release=$((version_stable + 1))" >> $GITHUB_OUTPUT
246283
fi
247284
248285
- name: Build pdf documentation

admin_manual/_templates/versions.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
data-toggle="rst-current-version"
1010
aria-expanded="false"
1111
aria-controls="rst-other-versions-admin">
12-
☁️ {{ current_version }}
12+
☁️ {{ display_version }}
1313
<span class="fa fa-caret-down" aria-hidden="true"></span>
1414
</button>
1515
<div id="rst-other-versions-admin" class="rst-other-versions">
1616
<dl>
1717
<dt>☁️ {{ _('Versions') }}</dt>
18-
{% for slug, url in versions|reverse %}
18+
{% for slug, url, label in versions|reverse %}
1919
<dd style="width: 32%">
2020
<a href="{{ url }}"
2121
{% if current_version == slug %}
2222
style="color: var(--dark-link-color);"
2323
{% endif %}
2424
>
25-
{{ slug }}
25+
{{ label }}
2626
</a>
2727
</dd>
2828
{% endfor %}

admin_manual/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
# -- Project information -----------------------------------------------------
2121
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
2222

23-
project = u'Nextcloud %s Administration Manual' % (version)
23+
project = u'Nextcloud %s Administration Manual' % (display_version)
24+
html_title = project
2425

2526
# -- General configuration ---------------------------------------------------
2627
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

build/build-index.php

Lines changed: 7 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,6 @@
11
<?php
22
require_once 'server-block.php';
3-
4-
/**
5-
* Get the GitHub API headers with optional authentication
6-
*/
7-
function get_github_headers(): string {
8-
$headers = 'User-Agent: Nextcloud Documentation Builder';
9-
if ($token = getenv('GITHUB_TOKEN')) {
10-
$headers .= "\r\nAuthorization: token $token";
11-
}
12-
return $headers;
13-
}
14-
15-
/**
16-
* Get the repository name for a given version
17-
* Nextcloud moved to nextcloud-releases/server starting with version 32
18-
*/
19-
function get_repo_for_version(int $version): string {
20-
return $version >= 32 ? 'nextcloud-releases/server' : 'nextcloud/server';
21-
}
22-
23-
/**
24-
* Parse the HTTP status code from the response headers populated by file_get_contents.
25-
*
26-
* @param array $headers The $http_response_header array
27-
*/
28-
function parse_http_status(array $headers): int {
29-
preg_match('/HTTP\/[\d.]+ (\d+)/', $headers[0] ?? '', $matches);
30-
return (int)($matches[1] ?? 0);
31-
}
32-
33-
/**
34-
* Fetch release info for a given version from the GitHub API.
35-
*
36-
* Returns an array ['date' => int] if the release exists (HTTP 200).
37-
* Returns null if the release does not exist (HTTP 404).
38-
* Exits with code 1 on any other HTTP status (rate limit, server error, etc.)
39-
* to prevent silently generating empty or incorrect index sections.
40-
*/
41-
function fetch_release_info(int $version): ?array {
42-
$repo = get_repo_for_version($version);
43-
$url = sprintf('https://api.github.com/repos/%s/releases/tags/v%d.0.0', $repo, $version);
44-
45-
$context = stream_context_create([
46-
'http' => [
47-
'header' => get_github_headers(),
48-
'timeout' => 10,
49-
'ignore_errors' => true
50-
]
51-
]);
52-
53-
$response = @file_get_contents($url, false, $context);
54-
55-
// FIXME: function_exists conditional can be dropped once we don't need to support <8.4.0
56-
if (function_exists('http_get_last_response_headers')) {
57-
/** @var array|null */
58-
$http_response_header = \http_get_last_response_headers();
59-
}
60-
61-
$status = isset($http_response_header) && is_array($http_response_header)
62-
? parse_http_status($http_response_header)
63-
: 0;
64-
65-
if ($status === 200) {
66-
$data = json_decode($response, true);
67-
$publishedAt = $data['published_at'] ?? $data['created_at'] ?? null;
68-
return ['date' => $publishedAt ? strtotime($publishedAt) : time()];
69-
}
70-
71-
if ($status === 404) {
72-
return null;
73-
}
74-
75-
// Any non-200/non-404 response (403 rate limit, 429, 5xx, network failure)
76-
// must abort so we never deploy an index with empty or wrong sections.
77-
fwrite(STDERR, "GitHub API error (HTTP $status) checking v$version.0.0 — aborting to avoid deploying incorrect index\n");
78-
exit(1);
79-
}
3+
require_once 'detect-versions.php';
804

815
// Parse and validate command-line arguments
826
/** @var int[] */
@@ -90,47 +14,16 @@ function fetch_release_info(int $version): ?array {
9014
exit(1);
9115
}
9216

93-
// Fetch release information from GitHub
94-
$released_branches = [];
95-
$oneYearAgo = time() - (365 * 24 * 60 * 60);
96-
$foundOutOfSupport = null;
97-
98-
foreach ($branches as $branch) {
99-
if ($foundOutOfSupport !== null) {
100-
fwrite(STDOUT, "🛑 Version $branch is unsupported (older than version $foundOutOfSupport)\n");
101-
$released_branches[$branch] = $releaseTime;
102-
$releaseType = $releaseTime >= $oneYearAgo ? 'stable' : 'unsupported';
103-
continue;
104-
}
105-
106-
$info = fetch_release_info($branch);
107-
if ($info === null) {
108-
fwrite(STDERR, "⏳ Version $branch is not released (tag v$branch.0.0 not found)\n");
109-
continue;
110-
}
111-
112-
$releaseTime = $info['date'];
113-
$released_branches[$branch] = $releaseTime;
114-
if ($releaseTime < $oneYearAgo) {
115-
fwrite(STDOUT, "🛑 Version $branch is unsupported (released on " . date('Y-m-d', $releaseTime) . ")\n");
116-
$foundOutOfSupport = $branch;
117-
} else {
118-
fwrite(STDOUT, "✅ Version $branch is supported (released on " . date('Y-m-d', $releaseTime) . ")\n");
119-
}
120-
}
121-
122-
// Determine development version
123-
if (isset($released_branches[$branches[0]])) {
124-
$devVersion = $branches[0] + 1;
125-
$devStatus = 'development';
126-
} else {
127-
$devVersion = $branches[0];
128-
$devStatus = 'upcoming';
129-
}
17+
// Detect version metadata (API calls happen here)
18+
$versions = detect_versions($branches);
19+
$released_branches = $versions['released'];
20+
$devVersion = $versions['dev_version'];
21+
$devStatus = isset($released_branches[$branches[0]]) ? 'development' : 'upcoming';
13022

13123
fwrite(STDERR, "➡️ Version $devVersion ($devStatus)\n");
13224

13325
// Collect released stable versions within support window
26+
$oneYearAgo = time() - (365 * 24 * 60 * 60);
13427
$stableVersions = [];
13528
foreach ($branches as $branch) {
13629
if (isset($released_branches[$branch]) && $released_branches[$branch] >= $oneYearAgo) {

0 commit comments

Comments
 (0)