diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 00000000..9da554a9 --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,59 @@ +name: External Links + +on: + push: + branches: [main] + pull_request: + schedule: + # Weekly link-rot check, independent of code changes. + - cron: "0 9 * * 1" + workflow_dispatch: + +permissions: {} + +concurrency: + group: links-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + lychee: + name: Lychee + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + issues: write + + steps: + - name: Clone repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Restore lychee cache + uses: actions/cache@v4 + with: + path: .lycheecache + key: lychee-${{ github.sha }} + restore-keys: lychee- + + - name: Run lychee + uses: lycheeverse/lychee-action@v2 + with: + # README.md is a GitHub-only artifact with pre-existing + # broken references (LICENSE files, lockup paths); excluded + # from this check. Docs site content lives in src/pages/. + args: >- + --root-dir ${{ github.workspace }} + 'src/pages/**/*.{md,mdx}' + 'vocs.config.ts' + fail: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Open issue on scheduled failure + if: failure() && github.event_name == 'schedule' + uses: peter-evans/create-issue-from-file@v5 + with: + title: "Broken external links detected" + content-filepath: ./lychee/out.md + labels: docs, links diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000..2fd902e9 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,41 @@ +# lychee configuration for the Tempo docs site. +# Validates external links in markdown, MDX, and config sources. +# See https://lychee.cli.rs/usage/config/ + +# Network settings +max_redirects = 10 +max_concurrency = 16 +timeout = 20 +retry_wait_time = 2 + +# Some hosts (Twitter, LinkedIn, Cloudflare-protected sites) reject the default UA. +user_agent = "Mozilla/5.0 (compatible; tempo-docs-link-checker/1.0; +https://docs.tempo.xyz)" + +# Auth-walled or rate-limited statuses are still "reachable". +accept = ["200..=299", "401", "403", "429"] + +exclude_path = [ + "node_modules", + "dist", + ".vocs", + ".vercel", + "playwright-report", + "test-results", + "patches", +] + +exclude = [ + # Local / placeholder hosts. + "^https?://localhost", + "^https?://127\\.0\\.0\\.1", + "^https?://0\\.0\\.0\\.0", + "^https?://\\[::1\\]", + "^https?://([a-z0-9-]+\\.)*example\\.(com|org|net)", + # SVG xmlns reference, not a real link. + "^http://www\\.w3\\.org/2000/svg$", +] + +# Reuse cached results across runs. +cache = true +max_cache_age = "1d" +no_progress = true diff --git a/vite.config.ts b/vite.config.ts index 08ed63aa..3dd4c302 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -101,11 +101,27 @@ function syncTips(): Plugin { await Promise.all( tipFiles.map(async (file) => { let content = await fetch(file.download_url).then((r) => r.text()) - // Fix dead links in TIPs that reference local paths instead of GitHub URLs + // Fix dead links in TIPs that reference paths in the tempoxyz/tempo + // repo. These resolve fine on github.com but break Vocs' dead-link + // checker, since the files don't exist in the docs site. Rewriting + // them here lets us keep `checkDeadlinks: true` without forking + // upstream content. Add new patterns as upstream typos appear. content = content.replace( /\(tips\/ref-impls\/src\/interfaces\/(\w+\.sol)\)/g, '(https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/$1)', ) + // TIP-1011 references `tips/verify/src/interfaces/...` (upstream typo + // of `ref-impls`). Map it to the actual tempoxyz/tempo location. + content = content.replace( + /\(tips\/verify\/src\/interfaces\/(\w+\.sol)\)/g, + '(https://github.com/tempoxyz/tempo/blob/main/tips/ref-impls/src/interfaces/$1)', + ) + // tip-0000 links to `./tip_template.md`, which lives in the tempo + // repo but not in the docs site. + content = content.replace( + /\(\.\/tip_template\.md\)/g, + '(https://github.com/tempoxyz/tempo/blob/main/tips/tip_template.md)', + ) // Escape angle brackets outside of code blocks/inline code so MDX doesn't // treat them as JSX (e.g. `Mapping` in prose). content = escapeAngleBrackets(content) diff --git a/vocs.config.ts b/vocs.config.ts index 0f792237..d9045790 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -20,8 +20,7 @@ export default defineConfig({ // textColor: 'white', // }, changelog: Changelog.github({ prereleases: true, repo: 'tempoxyz/tempo' }), - // TODO: Set back to true once tempoxyz/tempo#tip-1011 dead link is fixed - checkDeadlinks: 'warn', + checkDeadlinks: true, editLink: { link: 'https://github.com/tempoxyz/docs/edit/main/src/pages/:path', text: 'Suggest changes to this page', @@ -468,7 +467,7 @@ export default defineConfig({ }, { text: 'Reference Implementation', - link: 'https://github.com/tempoxyz/tempo/blob/main/tips/ref-impls/src/TIP20.sol', + link: 'https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/ITIP20.sol', }, { text: 'Rust Implementation', @@ -504,7 +503,7 @@ export default defineConfig({ }, { text: 'Reference Implementation', - link: 'https://github.com/tempoxyz/tempo/blob/main/tips/ref-impls/src/TIP403Registry.sol', + link: 'https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/ITIP403Registry.sol', }, { text: 'Rust Implementation', @@ -538,7 +537,7 @@ export default defineConfig({ }, { text: 'Reference Implementation', - link: 'https://github.com/tempoxyz/tempo/blob/main/tips/ref-impls/src/FeeManager.sol', + link: 'https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/IFeeManager.sol', }, { text: 'Rust Implementation', @@ -626,11 +625,11 @@ export default defineConfig({ }, { text: 'Reference Implementation', - link: 'https://github.com/tempoxyz/tempo/blob/main/tips/ref-impls/src/stablecoinDex.sol', + link: 'https://github.com/tempoxyz/tempo-std/blob/master/src/interfaces/IStablecoinDEX.sol', }, { text: 'Rust Implementation', - link: 'https://github.com/tempoxyz/tempo/tree/main/crates/precompiles/src/stablecoin_exchange', + link: 'https://github.com/tempoxyz/tempo/tree/main/crates/precompiles/src/stablecoin_dex', }, ], },