Link Check #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: --verbose --no-progress --include-fragments --base 'https://rupertmckay.com' './_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'); | |
| } |