From 43f08033375043d5a3e346e7a24d76df8242a0e0 Mon Sep 17 00:00:00 2001 From: Ashley Willis Date: Tue, 2 Jun 2026 13:21:14 -0700 Subject: [PATCH] Add scheduled link checker workflow with lychee-action Replace the existing Python-based link checker with lycheeverse/lychee-action. - Run weekly on Sundays and on PRs that touch markdown files - Scheduled runs check all markdown files and open an issue on failures - PR runs check only changed markdown files to avoid false positives - Cache link check results between runs - Add .lycheeignore for known flaky domains (Twitter, LinkedIn, etc.) - Add link checker status badge to README Closes #23 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/link-check.yml | 84 +++++++++++++++++++++++++++++--- .lycheeignore | 16 ++++++ README.md | 2 + 3 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 .lycheeignore diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml index b01d1e5..b553c06 100644 --- a/.github/workflows/link-check.yml +++ b/.github/workflows/link-check.yml @@ -1,18 +1,86 @@ -name: Link check +name: Link Check on: + schedule: + - cron: "0 3 * * 0" # Every Sunday at 3 AM UTC pull_request: + paths: + - "**.md" workflow_dispatch: - schedule: - - cron: "0 17 1 * *" + +permissions: + contents: read + issues: write jobs: - links: + link-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + + - name: Restore lychee cache + uses: actions/cache@v4 + with: + path: .lycheecache + key: cache-lychee-${{ github.sha }} + restore-keys: cache-lychee- + + # On PRs, only check changed markdown files to avoid failing on + # pre-existing broken links unrelated to this PR. + - name: Get changed markdown files + id: changed + if: github.event_name == 'pull_request' + run: | + files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only | grep '\.md$' || true) + echo "md_files<> "$GITHUB_OUTPUT" + echo "$files" >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + if [ -z "$files" ]; then + echo "has_md=false" >> "$GITHUB_OUTPUT" + else + echo "has_md=true" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Check links (all files) + id: lychee-all + if: github.event_name != 'pull_request' + uses: lycheeverse/lychee-action@v2 + with: + args: >- + --verbose + --no-progress + --timeout 10 + --max-retries 3 + --max-concurrency 8 + --cache + --max-cache-age 1d + '**/*.md' + fail: false + output: /tmp/lychee/out.md + + - name: Check links (changed files only) + id: lychee-pr + if: github.event_name == 'pull_request' && steps.changed.outputs.has_md == 'true' + uses: lycheeverse/lychee-action@v2 + with: + args: >- + --verbose + --no-progress + --timeout 10 + --max-retries 3 + --max-concurrency 8 + --cache + --max-cache-age 1d + ${{ steps.changed.outputs.md_files }} + fail: true + output: /tmp/lychee/out.md + + - name: Open issue on broken links (scheduled runs only) + if: github.event_name == 'schedule' && steps.lychee-all.outputs.exit_code != 0 + uses: peter-evans/create-issue-from-file@v5 with: - python-version: "3.x" - - name: Check links - run: python scripts/check_links.py --online --include-resources + title: "🔗 Broken links found" + content-filepath: /tmp/lychee/out.md + labels: maintenance diff --git a/.lycheeignore b/.lycheeignore new file mode 100644 index 0000000..aa8c9b8 --- /dev/null +++ b/.lycheeignore @@ -0,0 +1,16 @@ +# Known flaky or rate-limited URLs +# Add URLs (one per line) that should be excluded from link checking. +# Supports regex patterns. + +# Twitter/X often rate-limits or blocks automated checks +https?://(www\.)?twitter\.com(/.*)? +https?://(www\.)?x\.com(/.*)? + +# LinkedIn blocks automated requests +https?://(www\.)?linkedin\.com(/.*)? + +# Facebook blocks automated requests +https?://(www\.)?facebook\.com(/.*)? + +# Archive.org can be slow or intermittently unavailable +https?://web\.archive\.org(/.*)? diff --git a/README.md b/README.md index d44a241..a41f68b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Learn to Code +[![Link Check](https://github.com/ashleymcnamara/learn_to_code/actions/workflows/link-check.yml/badge.svg)](https://github.com/ashleymcnamara/learn_to_code/actions/workflows/link-check.yml) + A free-first, beginner-friendly guide to learning programming, computer science, AI, and the practical tools developers use every day.