Skip to content
Merged
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
59 changes: 42 additions & 17 deletions .github/workflows/linkcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,68 @@ jobs:
linkcheck:
runs-on: ubuntu-latest
permissions:
contents: read # read the latest release asset
issues: write # required for peter-evans/create-issue-from-file
steps:
# This repo deploys GitHub Pages via the artifact workflow (OIDC), so
# there is no gh-pages branch to check out — mirror the live site instead.
- name: Mirror published site
id: mirror
# This repo deploys GitHub Pages via the artifact workflow (no gh-pages
# branch). Check links against the published HTML release asset — a
# permanent tarball of the full site (HTML plus _static/_images/etc.) —
# so lychee resolves local asset and root-relative links without
# depending on the live site being reachable.
- name: Download and extract latest release HTML
id: fetch
env:
GH_TOKEN: ${{ github.token }}
run: |
wget --quiet --recursive --no-parent --no-host-directories \
--accept html https://dp.quantecon.org/ || true
count=$(find . -name '*.html' | wc -l | tr -d ' ')
echo "Mirrored $count HTML file(s) from https://dp.quantecon.org/"
# `|| true` + 2>/dev/null: a transient gh api error (rate-limit/auth)
# must not abort the step under `set -eo pipefail` — fall through to
# the empty-input guard below so it reports "release asset missing".
asset_url=$(gh api repos/${{ github.repository }}/releases/latest \
--jq '.assets[] | select(.name | endswith(".tar.gz")) | .browser_download_url' 2>/dev/null | head -1 || true)
mkdir -p _site
if [ -n "$asset_url" ]; then
# `curl -f` fails on HTTP errors; an `if !` guard catches a failed
# or partial download/extract and discards the incomplete tree, so
# lychee never runs against a half-extracted site (which would
# reintroduce "file not found" false positives).
if ! curl -fsSL "$asset_url" | tar -xz -C _site; then
echo "::warning::could not download/extract $asset_url — treating as no usable asset"
rm -rf _site && mkdir -p _site
fi
fi
count=$(find _site -name '*.html' | wc -l | tr -d ' ')
echo "Extracted $count HTML file(s) from the latest release asset"
if [ "$count" -eq 0 ]; then
# Mirror failed (site down or wget broke). Don't run lychee against
# an empty mirror and report green surface the failure instead.
# No usable release asset — don't run lychee against an empty tree
# and report green; surface the failure instead.
echo "ok=false" >> "$GITHUB_OUTPUT"
mkdir -p lychee
{
echo "## Link Checker — mirror failed"
echo "## Link Checker — release asset missing"
echo
echo "\`wget\` mirrored **0 HTML files** from https://dp.quantecon.org/, so the link check did not run."
echo "The live site may be down, or the mirror step may be broken — please investigate."
echo "Could not download or extract an HTML \`.tar.gz\` from the latest release, so the link check did not run."
echo "Check that the most recent \`publish-*\` release has the \`lecture-dp-html-*.tar.gz\` asset attached."
} > lychee/out.md
else
echo "ok=true" >> "$GITHUB_OUTPUT"
fi

- name: Link Checker
id: lychee
if: steps.mirror.outputs.ok == 'true'
if: steps.fetch.outputs.ok == 'true'
uses: lycheeverse/lychee-action@v2
with:
fail: false
args: --accept 403,503 '**/*.html'
# Check only the top-level lecture pages — not theme partials under
# _static/ (e.g. webpack-macros.html holds raw Jinja `{{ pathto(...) }}`
# that isn't a real link). 200 must stay in --accept or every working
# link is flagged; --root-dir resolves root-relative links (e.g.
# /_notebooks/*.ipynb, /_pdf/*.pdf) against the extracted site root.
args: --accept 200,403,503 --root-dir ${{ github.workspace }}/_site '_site/*.html'

# Open an issue if the mirror failed, or if lychee found broken links.
# Open an issue if the release asset was missing, or lychee found broken links.
- name: Create Issue From File
if: steps.mirror.outputs.ok != 'true' || steps.lychee.outputs.exit_code != 0
if: steps.fetch.outputs.ok != 'true' || steps.lychee.outputs.exit_code != 0
uses: peter-evans/create-issue-from-file@v6
with:
title: Link Checker Report
Expand Down