Skip to content

Check for Dead Links #17

Check for Dead Links

Check for Dead Links #17

Workflow file for this run

name: Check for Dead Links
on:
schedule:
# Run every Sunday at 2 AM UTC
- cron: '0 2 * * 0'
workflow_dispatch:
pull_request:
paths:
- '**.md'
- 'mkdocs.yml'
jobs:
link-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Link Checker
uses: lycheeverse/lychee-action@v2
with:
# Check all markdown files
args: >
--verbose
--no-progress
--accept=200,201,202,203,204,301,302,303,307,308
--timeout 20
--max-retries 3
--user-agent "Mozilla/5.0 (compatible; pms-wiki-link-checker)"
--exclude-private
--exclude "^(?i:mailto)"
--exclude "^(?i:javascript)"
--exclude "github.com/.*/edit/"
--exclude "github.com/.*/blob/"
--exclude "localhost"
--exclude "127.0.0.1"
--exclude "example.com"
--exclude "example.org"
--exclude "plausible.ktz.cloud"
--exclude "techhub.social"
--exclude "reddit.com"
--exclude "www.reddit.com"
--exclude-path node_modules/
--exclude-path .git/
'**/*.md'
fail: true
format: markdown
output: ./lychee-report.md
jobSummary: true
- name: Upload link check report
if: failure()
uses: actions/upload-artifact@v4
with:
name: link-check-report
path: lychee-report.md
- name: Create actionable issue for broken links
if: failure() && github.event_name == 'schedule'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const report = fs.readFileSync('./lychee-report.md', 'utf8');
// Parse the lychee report to extract broken links
const lines = report.split('\n');
const brokenLinks = [];
let currentFile = '';
for (const line of lines) {
// Match file paths in the report
if (line.includes('.md') && !line.includes('|')) {
currentFile = line.trim().replace(/^\*\*/, '').replace(/\*\*$/, '');
}
// Match broken links
if (line.includes('[') && line.includes('](') && line.includes('Failed')) {
const match = line.match(/\[.*?\]\((.*?)\)/);
if (match) {
brokenLinks.push({
file: currentFile,
url: match[1],
line: line.trim()
});
}
}
}
const issueBody = `## Broken Links Detected
The automated link checker found ${brokenLinks.length} broken link(s) in the documentation that need to be fixed.
### Instructions for fixing:
Please update the following broken links in the documentation files. For each broken link, either:
1. Update the URL to the correct destination
2. Remove the link if it's no longer relevant
3. Replace with an archived version from Wayback Machine if appropriate
### Broken Links to Fix:
${brokenLinks.map((link, index) =>
`${index + 1}. **File:** \`${link.file}\`
**Broken URL:** ${link.url}
**Action:** Find this URL in the file and update or remove it
`).join('\n')}
### Full Report:
<details>
<summary>Click to see the full lychee report</summary>
\`\`\`
${report}
\`\`\`
</details>
---
*This issue was automatically generated by the dead link checker workflow.*`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Fix ${brokenLinks.length} broken link(s) in documentation`,
body: issueBody,
labels: ['documentation', 'broken-links', 'automated', 'good first issue']
});
- name: Comment PR with link check results
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const report = fs.readFileSync('./lychee-report.md', 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## ❌ Dead Links Found\n\n${report}\n\nPlease fix these broken links before merging.`
});