Check Links #122
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: Check Links | |
| # Checks all markdown files for broken links using lychee | |
| # Key flags: | |
| # --cache: Cache results to speed up subsequent runs | |
| # --exclude-link-local: Skip localhost/127.0.0.1 links (not reachable in CI) | |
| # .lycheeignore is auto-detected for URL patterns to exclude | |
| # Creates a GitHub issue on failure for visibility | |
| on: | |
| pull_request: | |
| paths: | |
| - "**.md" | |
| schedule: | |
| - cron: "0 0 * * 0" # Weekly on Sunday at midnight UTC | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| issues: write # Required for creating issue on failure | |
| jobs: | |
| linkChecker: | |
| name: Check Markdown Links | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| # Static key: lychee handles staleness via --max-cache-age 1d | |
| # Split restore/save pattern ensures cache is saved even on failure | |
| - name: Restore lychee cache | |
| id: restore-cache | |
| uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 | |
| with: | |
| path: .lycheecache | |
| key: cache-lychee-v1 | |
| - name: Link Checker | |
| uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2.7.0 | |
| with: | |
| args: >- | |
| --cache | |
| --max-cache-age 1d | |
| --verbose | |
| --no-progress | |
| --exclude-link-local | |
| '**/*.md' | |
| fail: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Save lychee cache | |
| uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 | |
| if: always() | |
| with: | |
| path: .lycheecache | |
| key: cache-lychee-v1 | |
| # Check for existing issue to avoid duplicates, then create or comment | |
| - name: Check for existing open issue | |
| if: failure() | |
| id: check-issue | |
| run: | | |
| issue=$(gh issue list --state open \ | |
| --search "in:title Broken links detected" \ | |
| --json number --jq '.[0].number // empty') | |
| echo "issue_number=$issue" >> "$GITHUB_OUTPUT" | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create issue for broken links | |
| if: failure() && steps.check-issue.outputs.issue_number == '' | |
| run: gh issue create --title "Broken links detected" --body-file ./lychee/out.md | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Comment on existing issue | |
| if: failure() && steps.check-issue.outputs.issue_number != '' | |
| run: | | |
| run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${RUN_ID}" | |
| { | |
| echo "## 🔄 Link check failed again" | |
| echo "" | |
| echo "**Run**: [${RUN_ID}](${run_url})" | |
| echo "**Triggered by**: ${GITHUB_EVENT_NAME}" | |
| echo "" | |
| cat ./lychee/out.md | |
| } | gh issue comment "${{ steps.check-issue.outputs.issue_number }}" --body-file - | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| RUN_ID: ${{ github.run_id }} |