diff --git a/.github/workflows/linkcheck.yaml b/.github/workflows/linkcheck.yaml new file mode 100644 index 00000000..fc94e9e5 --- /dev/null +++ b/.github/workflows/linkcheck.yaml @@ -0,0 +1,38 @@ +name: Link check + +on: + pull_request: + push: + branches: + - main + schedule: + # Mondays 06:00 UTC, so link rot is caught even without PR activity + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: {} + +jobs: + lychee: + name: lychee + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Check links + uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 + with: + args: >- + --config lychee.toml + --no-progress + 'doc/content/**/*.md' + 'exampleSite/content/**/*.md' + 'README.md' + 'CHANGELOG.md' + fail: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000..b022f823 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,30 @@ +# Configuration for lychee (https://lychee.cli.rs) +# Run locally with: lychee --config lychee.toml 'doc/content/**/*.md' README.md + +# Don't fail on these; 403/429 are usually bot-blocking, not dead links +accept = ["200..=299", "403", "429"] + +max_retries = 3 +retry_wait_time = 5 +timeout = 20 +max_concurrency = 16 + +# Hugo template syntax in layouts is not a URL +exclude = [ + "^https?://fonts\\.gstatic\\.com", + "^https?://fonts\\.googleapis\\.com", + "^https?://cdn\\.jsdelivr\\.net", + "^https?://cdnjs\\.cloudflare\\.com", + "\\{\\{.*\\}\\}", + "^https?://localhost", + "^https?://127\\.0\\.0\\.1", + "^https?://example\\.(com|org)", +] + +# Relative links can't resolve without a built site +exclude_path = [] +include_fragments = false +exclude_all_private = true + +# Use GitHub API for github.com links (avoids rate limits; needs GITHUB_TOKEN) +github_token = ""