Check Links #6
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
| # ============================================================ | |
| # .github/workflows/links.yml (Lychee Link Checker) | |
| # ============================================================ | |
| # SOURCE: https://github.com/denisecase/templates | |
| # | |
| # WHY-FILE: Automated link checking. | |
| # OBS: Behavior is configured in lychee.toml in this repository. | |
| # OBS: Runs on pull requests and monthly on schedule; manual trigger always available. | |
| name: Check Links | |
| on: | |
| workflow_dispatch: # WHY: Manual trigger - always available | |
| pull_request: # WHY: Validates PR links before merge | |
| schedule: | |
| - cron: "0 6 1 * *" # WHY: Runs monthly (1st of month) | |
| concurrency: | |
| # WHY: Prevent multiple simultaneous link checks on same ref | |
| group: link-check-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read # WHY: Needed to checkout code. | |
| issues: write # WHY: Needed to create issue on scheduled failures. | |
| pull-requests: write # WHY: Needed to comment on PR if links broken. | |
| env: | |
| PYTHONUNBUFFERED: "1" # WHY: Real-time logging. | |
| PYTHONIOENCODING: "utf-8" # WHY: Ensure UTF-8 encoding for international characters. | |
| REPORT_FAILURES: "true" # WHY: Enable PR comments and scheduled issues for link failures. | |
| jobs: | |
| lychee: | |
| name: Link checks | |
| runs-on: ubuntu-latest # WHY: Linux environment matches most production deployments | |
| timeout-minutes: 20 # WHY: Prevent hanging jobs. If over time, likely stuck. | |
| steps: | |
| - name: 1) Checkout repository code | |
| uses: actions/checkout@v6 | |
| - name: 2) Check links with Lychee | |
| id: lychee | |
| uses: lycheeverse/lychee-action@v2.8.0 | |
| with: | |
| # WHY: Do not hard-fail this step; always run reporting steps. | |
| # Instead, fail the job explicitly at the end if exit_code != 0. | |
| fail: false | |
| args: > | |
| --config lychee.toml | |
| --user-agent "${{ github.repository }}/lychee" | |
| './**/*.bib' | |
| './**/*.md' | |
| './**/*.html' | |
| './**/*.tex' | |
| './**/*.yml' | |
| './**/*.yaml' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 3) Comment on PR if links broken | |
| if: steps.lychee.outputs.exit_code != 0 && github.event_name == 'pull_request' && env.REPORT_FAILURES == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const runUrl = `${context.payload.repository.html_url}/actions/runs/${context.runId}`; | |
| const comment = [ | |
| "## Link Check Results", | |
| "", | |
| `Some links appear broken. Check the workflow logs: ${runUrl}`, | |
| ].join("\n"); | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: comment, | |
| }); | |
| - name: 4) Create issue for scheduled failures | |
| # WHY: Track broken links found during scheduled checks | |
| # OBS: Only creates issue if none already open with 'broken-links' label | |
| if: steps.lychee.outputs.exit_code != 0 && github.event_name == 'schedule' && env.REPORT_FAILURES == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const date = new Date().toISOString().split("T")[0]; | |
| const title = `Link Check Failed - ${date}`; | |
| const runUrl = `${context.payload.repository.html_url}/actions/runs/${context.runId}`; | |
| const body = `Monthly link check found broken links.\n\nWorkflow logs: ${runUrl}`; | |
| const existing = await github.rest.issues.listForRepo({ | |
| owner, | |
| repo, | |
| labels: "broken-links", | |
| state: "open", | |
| per_page: 1, | |
| }); | |
| if (existing.data.length === 0) { | |
| await github.rest.issues.create({ | |
| owner, | |
| repo, | |
| title, | |
| body, | |
| labels: ["maintenance", "broken-links"], | |
| }); | |
| } | |
| - name: 5) Fail job if broken links were found | |
| if: steps.lychee.outputs.exit_code != 0 | |
| run: | | |
| echo "Lychee found broken links (exit_code != 0). Failing workflow." | |
| exit 1 |