Skip to content

Commit cef4f06

Browse files
committed
Added link checker
1 parent 76df8ae commit cef4f06

6 files changed

Lines changed: 195 additions & 3 deletions

File tree

.github/workflows/link_check.yaml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: "Check documentation links"
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- "[0-9]+.[0-9]+"
8+
workflow_dispatch:
9+
inputs:
10+
force_recheck:
11+
description: "Clear lychee cache and recheck all links from scratch"
12+
type: boolean
13+
default: false
14+
pull_request: ~
15+
schedule:
16+
- cron: "0 6 * * *"
17+
18+
jobs:
19+
link-check:
20+
runs-on: ubuntu-latest
21+
strategy:
22+
matrix:
23+
python-version: [3.13]
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- name: Set up Python ${{ matrix.python-version }}
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
33+
- name: Install MkDocs dependencies
34+
run: |
35+
python -m pip install --upgrade pip
36+
pip install -r requirements.txt
37+
38+
- name: Build documentation
39+
run: mkdocs build --strict
40+
41+
- name: Restore lychee cache
42+
if: ${{ !inputs.force_recheck }}
43+
uses: actions/cache@v4
44+
with:
45+
path: .lycheecache
46+
key: lychee-${{ github.ref_name }}-${{ hashFiles('lychee.toml') }}
47+
restore-keys: |
48+
lychee-${{ github.ref_name }}-
49+
lychee-
50+
51+
- name: Check links
52+
uses: lycheeverse/lychee-action@v2
53+
with:
54+
args: >-
55+
--config lychee.toml
56+
--cache
57+
--cache-exclude-status "400.."
58+
site
59+
fail: true
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
62+
63+
- name: Upload link-check report
64+
if: always()
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: lychee-report
68+
path: lychee-report.md
69+
if-no-files-found: ignore

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ auth.json
1212
yarn.lock
1313
docs/css/*.map
1414
.deptrac.cache
15+
.lycheecache
16+
lychee-report.md

docs/js/custom.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $(document).ready(function() {
55
const latestVersionNumber = '5.0';
66

77
// replace edit url
8-
let branchName = 'master';
8+
let branchName = '5.0';
99
const branchNameRegexp = /\/en\/([a-z0-9-_.]*)\//g.exec(document.location.href);
1010
const eolVersions = window.eol_versions ?? [];
1111

@@ -21,7 +21,7 @@ $(document).ready(function() {
2121
}
2222

2323
if (!/^\d+\.\d+$/.test(branchName) && branchName !== 'latest') {
24-
branchName = 'master';
24+
branchName = '5.0';
2525
}
2626

2727
// Insert version into header links

lychee.toml

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
############################# Display #############################
2+
3+
# Verbose program output
4+
verbose = "warn"
5+
6+
# Output format
7+
format = "markdown"
8+
9+
# Path to report output file
10+
output = "lychee-report.md"
11+
12+
# Don't show interactive progress bar while checking links.
13+
no_progress = false
14+
15+
############################# Cache ###############################
16+
17+
# Enable link caching to avoid re-checking identical links across runs.
18+
cache = true
19+
20+
# Discard cached results older than this duration.
21+
max_cache_age = "1d"
22+
23+
############################# Runtime #############################
24+
25+
# Maximum number of allowed redirects. Set to 0 to fail on any redirect —
26+
# a redirect usually signals moved or reorganised content that should be
27+
# updated at the source.
28+
max_redirects = 0
29+
30+
# Maximum number of allowed retries before a link is declared dead.
31+
max_retries = 3
32+
33+
# Minimum wait time in seconds between retries of failed requests.
34+
retry_wait_time = 2
35+
36+
# Maximum number of concurrent link checks across all hosts.
37+
max_concurrency = 8
38+
39+
############################# Requests ############################
40+
41+
# Website timeout from connect to response finished (seconds).
42+
timeout = 20
43+
44+
# Comma-separated list of accepted status codes for valid links.
45+
# 429 = Too Many Requests (rate-limited, treat as valid).
46+
accept = ["200", "429"]
47+
48+
# Proceed for server connections considered insecure (invalid TLS).
49+
insecure = false
50+
51+
# Only check external links (https/http). Local file:// paths — i.e. all
52+
# relative and root-relative internal links — are skipped entirely.
53+
# Internal links are already validated by `mkdocs build --strict`.
54+
scheme = ["https", "http"]
55+
56+
# Use HEAD requests — much faster than GET since no body is downloaded.
57+
# Fragment checking requires GET, so include_fragments is disabled;
58+
# internal anchor links are already validated by `mkdocs build --strict`.
59+
method = "head"
60+
61+
# Mimic a browser to avoid Cloudflare bot-detection (403) on sites like doc.ibexa.co.
62+
user_agent = "Mozilla/5.0 (compatible; lychee link checker)"
63+
64+
# Do NOT check anchor fragments — requires full GET downloads for every URL.
65+
include_fragments = false
66+
67+
# Do NOT check links inside <code> and <pre> blocks.
68+
include_verbatim = false
69+
70+
############################# Exclusions ##########################
71+
72+
# Exclude URLs from checking (treated as regular expressions).
73+
exclude = [
74+
# LinkedIn blocks automated requests
75+
"^https?://(www\\.)?linkedin\\.com",
76+
# Localhost and loopback addresses
77+
"^https?://localhost",
78+
"^https?://127\\.0\\.0\\.1",
79+
# Placeholder/example domains
80+
"^https?://example\\.com",
81+
# GitHub login/auth pages often rate-limit or redirect bots
82+
"^https?://github\\.com/login",
83+
]
84+
85+
# Exclude these input paths from being scanned.
86+
exclude_path = [
87+
# Search index, assets and sitemap contain no meaningful external links
88+
"site/search",
89+
"site/assets",
90+
"site/404.html",
91+
"site/sitemap.xml",
92+
"site/robots.txt",
93+
]
94+
95+
# Check the specified file extensions
96+
extensions = ["html"]
97+
98+
# Exclude all private IPs from checking.
99+
exclude_all_private = true
100+
101+
############################# Local files #########################
102+
103+
# Required to resolve root-relative links (e.g. href="/") found in every page.
104+
# Combined with scheme = ["https", "http"], the resulting file:// paths are
105+
# silently skipped — no HTTP check, no error.
106+
root_dir = "site"
107+
108+
############################# Hosts ###############################
109+
110+
# Global limit: at most 2 simultaneous requests to any single host.
111+
host_concurrency = 2
112+
113+
# Global minimum interval between requests to the same host.
114+
host_request_interval = "500ms"
115+
116+
# Stricter throttling for Cloudflare-protected hosts.
117+
# [hosts] tables must come last in the file (TOML section scoping).
118+
[hosts."doc.ibexa.co"]
119+
concurrency = 1
120+
request_interval = "1s"

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ INHERIT: plugins.yml
22

33
site_name: Developer Documentation
44
repo_url: https://github.com/ibexa/documentation-developer
5+
edit_uri: edit/5.0/docs
56
site_url: https://doc.ibexa.co/en/latest/
67
copyright: "Copyright 1999-2026 Ibexa AS and others"
78
validation:

tools/api_refs/.phpdoc/template/components/source.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
{% block content %}
44
<div class="md-header__source">
5-
{% set href = 'https://github.com/ibexa/documentation-developer/tree/master/docs/api/php_api' %}
5+
{% set href = 'https://github.com/ibexa/documentation-developer/tree/5.0/docs/api/php_api' %}
66
{% if node.file is not null %}
77
{% set path = node.file.path|split('/', 4) %}
88
{% set package = path|slice(1, 2)|join('/') %}

0 commit comments

Comments
 (0)