diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml new file mode 100644 index 00000000000..baa6e79e098 --- /dev/null +++ b/.github/workflows/link-check.yml @@ -0,0 +1,60 @@ +name: Link check + +on: + pull_request: + branches: [master] + workflow_dispatch: + +concurrency: + group: link-check-${{ github.ref }} + cancel-in-progress: true + +jobs: + link-check: + runs-on: ubuntu-latest + timeout-minutes: 60 + env: + PORT: 4000 + BASE_URL: http://localhost:4000 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: npm + + - run: npm ci + + - name: Build CSS + run: npm run build-css + + - name: Start Realm dev server + run: | + npx realm develop --port "$PORT" > realm.log 2>&1 & + echo $! > realm.pid + + - name: Wait for server + run: npx --yes wait-on "$BASE_URL" --timeout 180000 + + - name: Crawl and check links + run: | + npx --yes linkinator@^6 "$BASE_URL" \ + --config linkinator.config.json \ + --format csv > linkinator-report.csv + + - name: Stop Realm server + if: always() + run: | + if [ -f realm.pid ]; then kill "$(cat realm.pid)" 2>/dev/null || true; fi + + - name: Upload report + if: always() + uses: actions/upload-artifact@v4 + with: + name: link-check-report + path: | + linkinator-report.csv + realm.log + if-no-files-found: warn diff --git a/.gitignore b/.gitignore index 359a51cad53..5fe044ba0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ _code-samples/*/*/*[Ss]etup.json # PHP composer.lock + +# Link checker artifacts +linkinator-report.csv +realm.log diff --git a/linkinator.config.json b/linkinator.config.json new file mode 100644 index 00000000000..e8b52e09922 --- /dev/null +++ b/linkinator.config.json @@ -0,0 +1,22 @@ +{ + "recurse": true, + "retry": true, + "timeout": 20000, + "concurrency": 5, + "skip": [ + "http://localhost:4000/@l10n/(?!en-US)", + "^https?://(twitter|x)\\.com", + "^https?://(www\\.)?linkedin\\.com", + "^https?://chat\\.openai\\.com", + "^https?://chatgpt\\.com", + "^https?://claude\\.ai", + "^https?://(www\\.)?medium\\.com" + ], + "headers": { + "*": { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.9" + } + } +}