Skip to content

Commit 7a2ed6c

Browse files
authored
Better link checking (#2499)
1 parent 45dea8c commit 7a2ed6c

File tree

8 files changed

+180
-46
lines changed

8 files changed

+180
-46
lines changed

.github/scripts/link-check.sh

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
export MSYS_NO_PATHCONV=1 # for Git Bash on Windows
6+
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
ROOT_DIR="$SCRIPT_DIR/../.."
9+
DEPENDENCIES_DOCKERFILE="$ROOT_DIR/dependencies.Dockerfile"
10+
11+
# Parse command line arguments
12+
LOCAL_LINKS_ONLY=false
13+
TARGET=""
14+
15+
while [[ $# -gt 0 ]]; do
16+
case $1 in
17+
--local-links-only)
18+
LOCAL_LINKS_ONLY=true
19+
shift
20+
;;
21+
*)
22+
# Treat any other arguments as file paths
23+
TARGET="$TARGET $1"
24+
shift
25+
;;
26+
esac
27+
done
28+
29+
# Extract lychee version from dependencies.dockerfile
30+
LYCHEE_VERSION=$(grep "FROM lycheeverse/lychee:" "$DEPENDENCIES_DOCKERFILE" | sed 's/.*FROM lycheeverse\/lychee:\([^ ]*\).*/\1/')
31+
32+
if [[ -z "$TARGET" ]]; then
33+
TARGET="."
34+
fi
35+
36+
# Build the lychee command with optional GitHub token
37+
CMD="lycheeverse/lychee:$LYCHEE_VERSION --verbose --root-dir /data"
38+
39+
# Add GitHub token if available
40+
if [[ -n "$GITHUB_TOKEN" ]]; then
41+
CMD="$CMD --github-token $GITHUB_TOKEN"
42+
fi
43+
44+
if [[ "$LOCAL_LINKS_ONLY" == "true" ]]; then
45+
CMD="$CMD --scheme file --include-fragments"
46+
else
47+
CMD="$CMD --config .github/scripts/lychee-config.toml"
48+
fi
49+
50+
CMD="$CMD $TARGET"
51+
52+
# Determine if we should allocate a TTY
53+
DOCKER_FLAGS="--rm --init"
54+
if [[ -t 0 ]]; then
55+
DOCKER_FLAGS="$DOCKER_FLAGS -it"
56+
else
57+
DOCKER_FLAGS="$DOCKER_FLAGS -i"
58+
fi
59+
60+
# Run lychee with proper signal handling
61+
exec docker run $DOCKER_FLAGS -v "$ROOT_DIR":/data -w /data $CMD
File renamed without changes.

.github/workflows/changelog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ jobs:
8080
- name: Run markdown-link-check on the changelog
8181
run: |
8282
make chlog-preview &> changelog_preview.md
83-
make markdown-link-check-changelog-preview
83+
make markdown-link-check FILES=changelog_preview.md

.github/workflows/checks.yml

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,8 @@ jobs:
3737
- name: run yamllint
3838
run: yamllint . -f github
3939

40-
markdown-link-check:
41-
runs-on: ubuntu-latest
42-
steps:
43-
- name: check out code
44-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
45-
46-
- name: install dependencies
47-
run: npm install
48-
49-
- name: run markdown-link-check
50-
run: make markdown-link-check
51-
env:
52-
LYCHEE_GITHUB_TOKEN: ${{ github.token }}
40+
link-check:
41+
uses: ./.github/workflows/reusable-link-check.yml
5342

5443
markdown-toc-check:
5544
runs-on: ubuntu-latest
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Daily link check
2+
3+
on:
4+
schedule:
5+
# Daily at 02:00 UTC
6+
- cron: "0 2 * * *"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
issues: write
12+
13+
jobs:
14+
link-check:
15+
uses: ./.github/workflows/reusable-link-check.yml
16+
17+
workflow-notification:
18+
needs:
19+
- link-check
20+
if: always()
21+
uses: ./.github/workflows/reusable-workflow-notification.yml
22+
with:
23+
success: ${{ needs.link-check.result == 'success' }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Reusable - Link check
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
link-check:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
14+
with:
15+
fetch-depth: 0 # needed for merge-base below
16+
17+
- name: Link check - local links only (all files)
18+
if: github.event_name == 'pull_request'
19+
env:
20+
GITHUB_TOKEN: ${{ github.token }}
21+
run: make markdown-link-check-local-only
22+
23+
- name: Get modified files
24+
if: github.event_name == 'pull_request'
25+
id: modified-files
26+
run: |
27+
merge_base=$(git merge-base origin/${{ github.base_ref }} HEAD)
28+
# Using lychee's default extension filter here to match when it runs against all files
29+
modified_files=$(git diff --name-only $merge_base...${{ github.event.pull_request.head.sha }} \
30+
| grep -E '\.(md|mkd|mdx|mdown|mdwn|mkdn|mkdown|markdown|html|htm|txt)$' \
31+
| tr '\n' ' ' || true)
32+
echo "files=$modified_files" >> $GITHUB_OUTPUT
33+
34+
- name: Link check - all links (modified files only)
35+
if: github.event_name == 'pull_request' && steps.modified-files.outputs.files != ''
36+
env:
37+
GITHUB_TOKEN: ${{ github.token }}
38+
run: make markdown-link-check FILES="${{ steps.modified-files.outputs.files }}"
39+
40+
- name: Link check - all links (all files)
41+
if: github.event_name != 'pull_request'
42+
env:
43+
GITHUB_TOKEN: ${{ github.token }}
44+
run: make markdown-link-check
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# this is useful because notifications for scheduled workflows are only sent to
2+
# the user who initially created the given workflow
3+
name: Reusable - Workflow notification
4+
5+
on:
6+
workflow_call:
7+
inputs:
8+
success:
9+
type: boolean
10+
required: true
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
workflow-notification:
17+
permissions:
18+
contents: read
19+
issues: write
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23+
24+
- name: Open issue or add comment if issue already open
25+
env:
26+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
run: |
28+
# TODO (trask) search doesn't support exact phrases, so it's possible that this could grab the wrong issue
29+
number=$(gh issue list --search "in:title Workflow failed: $GITHUB_WORKFLOW" --limit 1 --json number -q .[].number)
30+
31+
echo $number
32+
echo ${{ inputs.success }}
33+
34+
if [[ $number ]]; then
35+
if [[ "${{ inputs.success }}" == "true" ]]; then
36+
gh issue close $number
37+
else
38+
gh issue comment $number \
39+
--body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)."
40+
fi
41+
elif [[ "${{ inputs.success }}" == "false" ]]; then
42+
gh issue create --title "Workflow failed: $GITHUB_WORKFLOW (#$GITHUB_RUN_NUMBER)" \
43+
--body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)."
44+
fi

Makefile

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,8 @@ else
1010
SED ?= sed
1111
endif
1212

13-
14-
ifeq ($(LYCHEE_GITHUB_TOKEN),)
15-
LYCHEE_GITHUB_TOKEN_ARG :=
16-
else
17-
LYCHEE_GITHUB_TOKEN_ARG := --env GITHUB_TOKEN=$(LYCHEE_GITHUB_TOKEN)
18-
endif
19-
2013
TOOLS_DIR := $(PWD)/internal/tools
2114

22-
MARKDOWN_LINK_CHECK_ARG= # pass extra arguments such as --exclude '^http'
2315
MISSPELL_BINARY=bin/misspell
2416
MISSPELL = $(TOOLS_DIR)/$(MISSPELL_BINARY)
2517

@@ -33,14 +25,12 @@ CONTAINER_REPOSITORY=docker.io
3325
# Per container overrides for the repository resolution.
3426
WEAVER_CONTAINER_REPOSITORY=$(CONTAINER_REPOSITORY)
3527
OPA_CONTAINER_REPOSITORY=$(CONTAINER_REPOSITORY)
36-
LYCHEE_CONTAINER_REPOSITORY=$(CONTAINER_REPOSITORY)
3728

3829
# Versioned, non-qualified references to containers used in this Makefile.
3930
# These are parsed from dependencies.Dockerfile so dependabot will autoupdate
4031
# the versions of docker files we use.
4132
VERSIONED_WEAVER_CONTAINER_NO_REPO=$(shell cat dependencies.Dockerfile | awk '$$4=="weaver" {print $$2}')
4233
VERSIONED_OPA_CONTAINER_NO_REPO=$(shell cat dependencies.Dockerfile | awk '$$4=="opa" {print $$2}')
43-
VERSIONED_LYCHEE_CONTAINER_NO_REPO=$(shell cat dependencies.Dockerfile | awk '$$4=="lychee" {print $$2}')
4434

4535
# Fully qualified references to containers used in this Makefile. These
4636
# include the container repository, so that the build will work with tools
@@ -52,7 +42,6 @@ VERSIONED_LYCHEE_CONTAINER_NO_REPO=$(shell cat dependencies.Dockerfile | awk '$$
5242
# and no unqualified-search registries are defined in "/etc/containers/registries.conf"
5343
WEAVER_CONTAINER=$(WEAVER_CONTAINER_REPOSITORY)/$(VERSIONED_WEAVER_CONTAINER_NO_REPO)
5444
OPA_CONTAINER=$(OPA_CONTAINER_REPOSITORY)/$(VERSIONED_OPA_CONTAINER_NO_REPO)
55-
LYCHEE_CONTAINER=$(LYCHEE_CONTAINER_REPOSITORY)/$(VERSIONED_LYCHEE_CONTAINER_NO_REPO)
5645

5746
# Determine if "docker" is actually podman
5847
DOCKER_VERSION_OUTPUT := $(shell docker --version 2>&1)
@@ -121,27 +110,11 @@ normalized-link-check:
121110

122111
.PHONY: markdown-link-check
123112
markdown-link-check: normalized-link-check
124-
$(DOCKER_RUN) --rm \
125-
$(DOCKER_USER_IS_HOST_USER_ARG) \
126-
--mount 'type=bind,source=$(PWD),target=/home/repo' $(LYCHEE_GITHUB_TOKEN_ARG) \
127-
$(LYCHEE_CONTAINER) \
128-
--config home/repo/.lychee.toml \
129-
--root-dir /home/repo \
130-
--verbose \
131-
--timeout=60 \
132-
$(MARKDOWN_LINK_CHECK_ARG) \
133-
home/repo
134-
135-
.PHONY: markdown-link-check-changelog-preview
136-
markdown-link-check-changelog-preview:
137-
$(DOCKER_RUN) --rm \
138-
$(DOCKER_USER_IS_HOST_USER_ARG) \
139-
--mount 'type=bind,source=$(PWD),target=/home/repo' $(LYCHEE_GITHUB_TOKEN_ARG) \
140-
$(LYCHEE_CONTAINER) \
141-
--config /home/repo/.lychee.toml \
142-
--root-dir /home/repo \
143-
--verbose \
144-
home/repo/changelog_preview.md
113+
.github/scripts/link-check.sh $(FILES)
114+
115+
.PHONY: markdown-link-check-local-only
116+
markdown-link-check-local-only: normalized-link-check
117+
.github/scripts/link-check.sh --local-links-only $(FILES)
145118

146119
# This target runs markdown-toc on all files that contain
147120
# a comment <!-- tocstop -->.

0 commit comments

Comments
 (0)