check-links.yml
Run a lychee link check with a bundled config, a PR skip-label, and an auto-filed issue when links break on main.
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
lychee-config |
string | '' |
Path in the caller repo to a lychee config; falls back to the bundled default. |
lychee-args |
string | '' |
Arguments and globs passed to lychee; a sensible default glob set is used when empty. Do not pass --format or --output. |
fail-if-empty |
boolean | false |
Fail the run when no links are found. |
create-issue-on-main |
boolean | true |
File an issue when links break on the main branch. |
skip-label |
string | 'links checked by hand' |
PR label that skips the link check. |
fail-on-any-5xx |
boolean | false |
Fail on every 5xx server error, not only on one on a line the PR adds. |
runs-on |
string | empty (CI_RUNNER variable, else ubuntu-latest) |
Runner label for the job. Use a self-hosted label only for a private repository; never for a public one, whose pull requests can run arbitrary code on it (#1167). |
A 404, a network error, or a timeout fails the check wherever the link is. The one exception is a network error saying the certificate is not trusted (“SSL certificate not trusted”): it is a fault of the host’s certificate chain or the runner’s trust store, so the link is unverified, not known dead. It is reported as a warning annotation naming the URL on every line, and does not fail the run (gha#1416). A 5xx server error is usually a host that is briefly down rather than a dead link, so it fails a pull request only when the link is on a line the PR adds. Any other 5xx is reported as a warning annotation and in the job summary, and does not fail the run (gha#1052). On any other event, such as a push, a scheduled run, workflow_dispatch, merge_group, or pull_request_target, the workflow passes no diff base, so every 5xx is a warning unless fail-on-any-5xx is set. The check-links composite that this workflow calls defaults its base-ref input to all, so a direct caller of the composite still fails on every 5xx unless it passes a ref or ''.
Permissions
Grant issues: write, pull-requests: read, and contents: read (it opens an issue on main failures).
Example
# Copy to .github/workflows/check-links.yml in your repo.
# NOTE: the calling job grants issues:write so the workflow can open an issue
# when links break on main. Required because repos default to a read-only token.
name: Check Links
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
schedule:
# Run weekly on Mondays at 9:00 UTC to catch link rot
- cron: "0 9 * * 1"
workflow_dispatch:
jobs:
check:
permissions:
contents: read
issues: write
pull-requests: read
uses: Morrison-Lab/gha/.github/workflows/check-links.yml@v2
# with:
# lychee-config: lychee.toml # use a repo-local config instead of the bundled default
# fail-if-empty: true # fail when no links are found (default: false)
# create-issue-on-main: true
# skip-label: 'links checked by hand'
# fail-on-any-5xx: true # fail on every 5xx, not only on PR-added lines (@v3)
# runs-on: private-runner # self-hosted runner label (private repositories only)See examples/check-links.yml for the full caller stub.