1616 runs-on : ubuntu-latest
1717 steps :
1818 - name : Checkout repository
19- uses : actions/checkout@v4
19+ uses : actions/checkout@v5
2020
2121 - name : Create lychee config
2222 run : |
3232
3333 # Exclude patterns (regex)
3434 exclude = [
35+ # Malformed ToC anchor links generated by the docs platform
36+ # These contain internal routing params (domain/host/auth/audience/version/path)
37+ # and are not real broken links — this is a fern-platform rendering bug
38+ "buildwithfern\\.com/_/buildwithfern\\.com/",
39+ "app\\.buildwithfern\\.com/buildwithfern\\.com/",
40+
3541 # Placeholder/example URLs
3642 "^https://example\\.com",
3743 "^https://github\\.com/owner/repo",
4147 "^https://c\\.vialoops\\.com",
4248 "_vercel/(speed-)?insights",
4349
50+ # Next.js image optimization URLs with content hashes that go stale after each deployment
51+ # These are generated by the platform (not source-level links) and resolve after redeployment
52+ "buildwithfern\\.com/_next/image",
53+
4454 # Asset URLs that work on the live site but are not directly accessible
4555 "buildwithfern\\.com/learn/dashboard/assets/pdf-ui\\.png",
4656
6474 "^tel:",
6575 "^javascript:",
6676
67- # Anchor-only links
68- "^#",
69-
7077 # All GitHub URLs - checked separately in dedicated steps
7178 "^https://github\\.com/"
7279 ]
@@ -326,7 +333,7 @@ jobs:
326333
327334
328335 - name : Upload URLs (early, for debugging)
329- uses : actions/upload-artifact@v4
336+ uses : actions/upload-artifact@v6
330337 with :
331338 name : urls
332339 path : |
@@ -363,6 +370,7 @@ jobs:
363370 --max-retries 3
364371 --retry-wait-time 10
365372 --max-concurrency 20
373+ --include-fragments
366374 --files-from urls.txt
367375 output : ./lychee-raw-main.md
368376 format : markdown
@@ -504,6 +512,11 @@ jobs:
504512 url=$(echo "$line" | sed -E 's/.*<([^>]+)>.*/\1/')
505513 status=$(echo "$line" | sed -E 's/.*\[([0-9]+)\].*/\1/')
506514
515+ # Skip malformed ToC anchor links (fern-platform rendering bug)
516+ if echo "$url" | grep -qE 'buildwithfern\.com/_/buildwithfern\.com/|app\.buildwithfern\.com/buildwithfern\.com/'; then
517+ continue
518+ fi
519+
507520 # Check if this is a repo-internal GitHub URL (blob/main pattern)
508521 if echo "$url" | grep -qE '^https://github\.com/fern-api/docs/blob/main/'; then
509522 # Extract relative path from URL (strip prefix and query string)
@@ -706,15 +719,15 @@ jobs:
706719
707720 - name : Upload errors-only report
708721 if : always()
709- uses : actions/upload-artifact@v4
722+ uses : actions/upload-artifact@v6
710723 with :
711724 name : lychee-report
712725 path : ./lychee-report.md
713726 if-no-files-found : ignore
714727
715728 - name : Upload lychee outputs and verification results
716729 if : always()
717- uses : actions/upload-artifact@v4
730+ uses : actions/upload-artifact@v6
718731 with :
719732 name : lychee-outputs
720733 path : |
@@ -727,7 +740,7 @@ jobs:
727740 - name : Create PR for broken links
728741 id : create-pr
729742 if : steps.check_failures.outputs.has_other_failures == 'true' || steps.retry429.outputs.has_429_failures == 'true' || steps.verify_github.outputs.has_missing == 'true'
730- uses : actions/github-script@v7
743+ uses : actions/github-script@v8
731744 env :
732745 DEVIN_PROMPT : |
733746 @devin-ai-integration Please fix the broken links detected by the scheduled link checker.
@@ -816,6 +829,15 @@ jobs:
816829 scaffoldContent += '\n---\n';
817830 scaffoldContent += `[View workflow run](https://github.com/${owner}/${repo}/actions/runs/${context.runId})\n`;
818831
832+ // Truncate PR body to stay under GitHub's 65536 character limit
833+ // The full content is still written to the scaffold file
834+ const MAX_PR_BODY_LENGTH = 60000; // leave headroom for safety
835+ let prBody = scaffoldContent;
836+ if (prBody.length > MAX_PR_BODY_LENGTH) {
837+ const truncationNote = `\n\n---\n⚠️ **Report truncated** — full list is in the scaffold file (\`${filePath}\`) on the branch.\n[View workflow run](https://github.com/${owner}/${repo}/actions/runs/${context.runId})\n`;
838+ prBody = prBody.substring(0, MAX_PR_BODY_LENGTH - truncationNote.length) + truncationNote;
839+ }
840+
819841 // Get the base branch ref
820842 const baseRef = await github.rest.git.getRef({
821843 owner,
@@ -953,7 +975,7 @@ jobs:
953975 title: 'Fix broken links (Devin)',
954976 head: branchName,
955977 base: baseBranch,
956- body: scaffoldContent ,
978+ body: prBody ,
957979 draft: true,
958980 });
959981
@@ -968,7 +990,7 @@ jobs:
968990
969991 - name : Send Slack notification for broken links
970992 if : steps.create-pr.outputs.pr_created == 'true'
971- uses : actions/github-script@v7
993+ uses : actions/github-script@v8
972994 env :
973995 SLACK_TOKEN : ${{ secrets.DEVIN_AI_PR_BOT_SLACK_TOKEN }}
974996 PR_URL : ${{ steps.create-pr.outputs.pr_url }}
0 commit comments