Skip to content

Link Check

Link Check #6

Workflow file for this run

name: Link Check
on:
# Run monthly to catch link rot
schedule:
- cron: "0 0 1 * *" # First day of each month at midnight
# Also run on workflow_dispatch so you can trigger manually
workflow_dispatch:
# Run on PRs to catch broken links before merging
pull_request:
paths:
- "src/**/*.md"
- "src/**/*.njk"
jobs:
link-check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.x"
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Check links
id: lychee
uses: lycheeverse/lychee-action@v1
with:
# Check all HTML files in the built site
args: --config lychee.toml "./_site/**/*.html"
# Fail the workflow if broken links are found
fail: true
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Close issue if links are fixed
if: success()
uses: actions/github-script@v7
with:
script: |
// Find any open issues with the broken-links label
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: ['broken-links']
});
// Close all open broken-links issues
for (const issue of issues.data) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `✅ All links are now working! Closing this issue.\n\nFixed in [workflow run](${context.payload.repository.html_url}/actions/runs/${context.runId}).`
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});
console.log(`Closed issue #${issue.number}`);
}
- name: Create or update issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const title = '🔗 Broken links detected';
const body = `The link checker found broken links.\n\n**Workflow run:** ${context.payload.repository.html_url}/actions/runs/${context.runId}\n\n**Date:** ${new Date().toISOString()}\n\nPlease check the workflow run for details on which links are broken.`;
// Check if an issue already exists
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: ['broken-links']
});
if (issues.data.length > 0) {
// Update existing issue
const issue = issues.data[0];
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `🔗 Broken links still detected (or new ones found).\n\n**Latest workflow run:** ${context.payload.repository.html_url}/actions/runs/${context.runId}\n**Date:** ${new Date().toISOString()}`
});
console.log(`Updated existing issue #${issue.number}`);
} else {
// Create new issue
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
body: body,
labels: ['broken-links']
});
console.log('Created new issue');
}