Skip to content
Merged
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
19 changes: 19 additions & 0 deletions .github/workflows/sphinxbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,25 @@ jobs:
name: ${{ needs.build.outputs.artifact_name }}
path: stage/

# go.php is only deployed from master, so only check it against the master build
- name: Checkout go.php and its check
if: needs.build.outputs.branch_name == 'latest'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
path: repo
sparse-checkout: |
go.php/index.html
build/check-go-php-redirects.sh
build/tests/test-check-go-php-redirects.sh
sparse-checkout-cone-mode: false

- name: Check go.php redirect targets
if: needs.build.outputs.branch_name == 'latest'
run: |
bash repo/build/tests/test-check-go-php-redirects.sh
repo/build/check-go-php-redirects.sh repo/go.php/index.html "stage/${{ needs.build.outputs.branch_name }}"

- name: Strip canonical links from validation HTML
run: |
find "stage/${{ needs.build.outputs.branch_name }}" -name '*.html' -print0 | while IFS= read -r -d '' f; do
Expand Down
49 changes: 49 additions & 0 deletions build/check-go-php-redirects.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash
#
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Checks every go.php redirect target against a built documentation folder:
# the target must start with "/" (go.php appends it to the version path), the
# page must exist, and its #anchor, if any, must be an id on that page.
#
# Usage: build/check-go-php-redirects.sh go.php/index.html stage/latest

set -euo pipefail

go_php="$1"
build_dir="$2"
failed=0

fail() {
echo "::error file=${go_php}::${1}"
failed=1
}

while read -r key target; do
if [[ "$target" != /* ]]; then
fail "'${key}': '${target}' must start with /"
continue
fi

page="${target%%#*}"
# Like go.php, put the language in the second user_manual segment, English here
if [[ "$page" =~ ^/user_manual(/[^/]*)?(/.*)?$ ]]; then
page="/user_manual/en${BASH_REMATCH[2]}"
fi

path="${build_dir}${page}"
if [[ -d "$path" ]]; then
path="${path%/}/index.html"
fi
if [[ ! -f "$path" ]]; then
fail "'${key}': ${page} does not exist in the build"
continue
fi

if [[ "$target" == *#* ]] && ! grep -qF "id=\"${target#*#}\"" "$path"; then
fail "'${key}': anchor #${target#*#} not found in ${page}"
fi
done < <(sed -nE "s/^[[:space:]]*'([a-z0-9-]+)': '([^']*)',?[[:space:]]*$/\1 \2/p" "$go_php")

exit "$failed"
65 changes: 65 additions & 0 deletions build/tests/test-check-go-php-redirects.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Tests for build/check-go-php-redirects.sh. Run: bash build/tests/test-check-go-php-redirects.sh

set -euo pipefail

check="$(dirname "${BASH_SOURCE[0]}")/../check-go-php-redirects.sh"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT

failures=0

mkdir -p "$tmp/build/admin_manual/ai" "$tmp/build/user_manual/en/files"
echo '<html></html>' > "$tmp/build/admin_manual/index.html"
echo '<html></html>' > "$tmp/build/user_manual/en/index.html"
echo '<html></html>' > "$tmp/build/user_manual/en/files/access_webdav.html"
echo '<section id="improve-ai-task-pickup-speed"></section>' > "$tmp/build/admin_manual/ai/overview.html"

# Runs the check on a go.php holding the given mapping lines, prints exit code and errors
run_check() {
printf ' const mapping = {\n' > "$tmp/go.html"
printf ' %s\n' "$@" >> "$tmp/go.html"
printf ' }\n' >> "$tmp/go.html"
local output status=0
output=$(bash "$check" "$tmp/go.html" "$tmp/build") || status=$?
echo "$status ${output//"$tmp/go.html"/go.html}"
}

assert_eq() {
if [ "$2" = "$3" ]; then
echo "ok - $1"
else
echo "not ok - $1"
printf ' expected: %s\n actual: %s\n' "$2" "$3"
failures=$((failures + 1))
fi
}

assert_eq "valid page, directory and anchor targets pass" "0 " "$(run_check \
"'admin': '/admin_manual'," \
"'admin-ai-pickup-speed': '/admin_manual/ai/overview.html#improve-ai-task-pickup-speed'")"

assert_eq "user manual targets are checked in English, like go.php redirects them" "0 " "$(run_check \
"'user': '/user_manual'," \
"'user-webdav': '/user_manual/de/files/access_webdav.html',")"

assert_eq "user manual target without a language segment fails" \
"1 ::error file=go.html::'user-webdav': /user_manual/en/access_webdav.html does not exist in the build" \
"$(run_check "'user-webdav': '/user_manual/files/access_webdav.html',")"

assert_eq "target without leading slash fails" \
"1 ::error file=go.html::'admin-ai-pickup-speed': 'admin_manual/ai/overview.html' must start with /" \
"$(run_check "'admin-ai-pickup-speed': 'admin_manual/ai/overview.html',")"

assert_eq "missing page fails" \
"1 ::error file=go.html::'admin-sso': /admin_manual/sso.html does not exist in the build" \
"$(run_check "'admin-sso': '/admin_manual/sso.html',")"

assert_eq "missing anchor fails" \
"1 ::error file=go.html::'admin-ai': anchor #gone not found in /admin_manual/ai/overview.html" \
"$(run_check "'admin-ai': '/admin_manual/ai/overview.html#gone',")"

exit $((failures > 0))
4 changes: 2 additions & 2 deletions go.php/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ <h1>Redirecting to documentation...</h1>
'admin-sharing-federated': '/admin_manual/configuration_files/federated_cloud_sharing_configuration.html',
'admin-source_install': '/admin_manual/installation/source_installation.html',
'admin-sse-legacy-format': '/admin_manual/configuration_files/encryption_migration.html',
'admin-sso': '/admin_manual/configuration_server/sso_configuration.html',
'admin-sso': '/admin_manual/configuration_user/user_auth_oidc.html',
'admin-system-requirements': '/admin_manual/installation/system_requirements.html',
'admin-theming': '/admin_manual/configuration_server/theming.html',
'admin-theming-icons': '/admin_manual/configuration_server/theming.html#theming-of-icons',
'admin-theming-icons': '/admin_manual/configuration_server/theming.html#icon-theming',
'admin-transactional-locking': '/admin_manual/configuration_files/files_locking_transactional.html',
'admin-trusted-domains': '/admin_manual/installation/installation_wizard.html#trusted-domains',
'admin-update': '/admin_manual/maintenance/update.html',
Expand Down
Loading