Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 76 additions & 8 deletions .github/workflows/link-check.yml
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +11 to +13

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-
Comment on lines +25 to +26

# 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<<EOF" >> "$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'
Comment on lines +51 to +59
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 }}
Comment on lines +68 to +76
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
16 changes: 16 additions & 0 deletions .lycheeignore
Original file line number Diff line number Diff line change
@@ -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(/.*)?
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
Loading