Skip to content

Commit e08d9dc

Browse files
tobixenclaude
andcommitted
ci: make lychee link checking robust and consistent
CI workflow (.github/workflows/linkcheck.yml): Two link-check runs (push + the matching pull_request) fired within a couple of seconds, both queried for an open report issue, both found none, and both created one - producing duplicate "Link Checker Report" issues (e.g. github.com//issues/44 and /45). - Restrict issue create/close to the default branch (schedule, push to master, manual dispatch); PR and feature-branch runs only surface the lychee output in the job log. This removes the noise source and, since only master-ref runs touch issues, the race itself. - Add a concurrency group keyed on the ref to serialise same-ref runs. - Fold any pre-existing duplicate open issues into the oldest one, and close all open report issues (not just the first) when links are healthy. - More resilience: --timeout 30, --max-retries 6, --retry-wait-time 2. Local pre-commit hook (.pre-commit-config.yaml): The hook was silently dead - `types: [markdown, rst]` is an AND, so it required a file to be both markdown and rst at once, matching nothing; and the lychee-docker image for the pinned rev was never published. That is why the broken doc links below were only ever caught by CI, not locally. Replace it with the canonical block shared across my projects: the auto-installing `id: lychee` (no docker), latest rev lychee-v0.24.2, a whole-tree scan (args end in '.', pass_filenames: false) so all file types are checked rather than only md/rst, run at the pre-push stage. lychee only auto-discovers a non-dot `lychee.toml`, so rename .lychee.toml -> lychee.toml; the hook then needs no --config, and the CI workflow points at the new name. Gitignore the .lycheecache the hook writes locally. Doc fixes: the docs/CALENDAR_SERVER_RECOMMENDATIONS.md references in USER_GUIDE.md and TASK_MANAGEMENT.md were missing the leading C (and the docs/ prefix) - genuinely broken links the checker was flagging. prompt: lychee is set up in an annoying way, it's creating new issues on every run if lychee fails. Please make the lychee setup more robust (more caching, more retries, don't create new issues if there already exists open issues, etc) followup-prompt: fix tingbok and icalendar-searcher too. Things should be as similar as possible on all three projects, so lychee should run latest version, it should check all files (not only *.rst / *.md) and it should run from pre-commit before pushing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5d57f55 commit e08d9dc

6 files changed

Lines changed: 49 additions & 18 deletions

File tree

‎.github/workflows/linkcheck.yml‎

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@ name: Link check
22

33
on:
44
push:
5+
branches:
6+
- master
57
pull_request:
68
workflow_dispatch:
79
schedule:
810
- cron: "03 22 * * *"
911

12+
# Serialise runs that share a ref so two link-check runs never race to create
13+
# the "Link Checker Report" issue. (The old setup let a push and the matching
14+
# pull_request run both file an issue at the same second - cf. issues #44/#45.)
15+
concurrency:
16+
group: linkcheck-${{ github.ref }}
17+
cancel-in-progress: false
18+
1019
jobs:
1120
linkcheck:
1221
runs-on: ubuntu-latest
@@ -26,29 +35,43 @@ jobs:
2635
with:
2736
fail: false
2837
args: >-
29-
--config .lychee.toml
30-
--timeout 20
31-
--max-retries 3
38+
--config lychee.toml
39+
--timeout 30
40+
--max-retries 6
41+
--retry-wait-time 2
3242
--cache
3343
--max-cache-age 14d
3444
.
45+
46+
# Issue management only happens on the default branch (scheduled run, push
47+
# to master, or manual dispatch). PR and feature-branch runs only surface
48+
# the lychee output in the job log: this avoids issue noise from transient
49+
# branch states and removes the duplicate-issue race entirely, since only
50+
# master-ref runs touch issues and the concurrency group serialises those.
3551
- name: Create or update Link Checker issue
36-
if: steps.lychee.outputs.exit_code != 0
52+
if: steps.lychee.outputs.exit_code != 0 && github.ref == 'refs/heads/master'
3753
env:
3854
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3955
run: |
40-
EXISTING=$(gh issue list --label "report" --state open --json number --jq '.[0].number' 2>/dev/null || echo "")
41-
if [ -n "$EXISTING" ]; then
42-
gh issue edit "$EXISTING" --body-file ./lychee/out.md
56+
# Keep the oldest open report issue as the canonical one and fold any
57+
# duplicates into it, so accumulated dupes self-heal over time.
58+
ISSUES=$(gh issue list --label "report" --state open --json number --jq '.[].number' | sort -n)
59+
CANON=$(printf '%s\n' "$ISSUES" | head -1)
60+
for n in $(printf '%s\n' "$ISSUES" | tail -n +2); do
61+
gh issue close "$n" --comment "Duplicate of #${CANON} - auto-closed by the link checker."
62+
done
63+
if [ -n "$CANON" ]; then
64+
gh issue edit "$CANON" --body-file ./lychee/out.md
4365
else
4466
gh issue create --title "Link Checker Report" --body-file ./lychee/out.md --label "report"
4567
fi
4668
- name: Close Link Checker issue if all links are healthy
47-
if: steps.lychee.outputs.exit_code == 0
69+
if: steps.lychee.outputs.exit_code == 0 && github.ref == 'refs/heads/master'
4870
env:
4971
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5072
run: |
51-
EXISTING=$(gh issue list --label "report" --state open --json number --jq '.[0].number' 2>/dev/null || echo "")
52-
if [ -n "$EXISTING" ]; then
53-
gh issue close "$EXISTING" --comment "All links are now healthy."
54-
fi
73+
# Close every open report issue, not just the first, so stragglers from
74+
# earlier races also get cleaned up.
75+
for n in $(gh issue list --label "report" --state open --json number --jq '.[].number'); do
76+
gh issue close "$n" --comment "All links are now healthy."
77+
done

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ docs/build/
5555
tmp/
5656
*.log
5757

58+
# lychee link checker local cache
59+
.lycheecache
60+
5861
# OS
5962
.DS_Store
6063
Thumbs.db

‎.pre-commit-config.yaml‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,13 @@ repos:
6161
stages: [commit-msg]
6262

6363
- repo: https://github.com/lycheeverse/lychee
64-
rev: lychee-v0.23.0
64+
rev: lychee-v0.24.2
6565
hooks:
66-
- id: lychee-docker
67-
args: ["--no-progress", "--timeout", "10", "--config", ".lychee.toml"]
68-
types: [markdown, rst]
66+
- id: lychee
67+
# Check links across the whole working tree (all file types, not just
68+
# md/rst). pass_filenames: false -> pre-commit passes only '.', so the
69+
# whole repo is scanned rather than just the changed files. lychee
70+
# auto-discovers lychee.toml, so no --config needed.
71+
args: ["--no-progress", "--timeout", "10", "--cache", "--max-cache-age", "1d", "."]
72+
pass_filenames: false
73+
stages: [pre-push]

‎TASK_MANAGEMENT.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ Those are not much relevant wrg of task handling in plann
313313

314314
## Daily task management and interactive mode
315315

316-
This is specifically directed towards using plann for daily task management. See also the [USER GUIDE](USER_GUIDE.md) for more generic user guide. I will assume that your calendar server needs to support advanced CalDAV queries (see [CALENDAR SERVER RECOMMENDATIONS](docs/ALENDAR_SERVER_RECOMMENDATIONS.md)).
316+
This is specifically directed towards using plann for daily task management. See also the [USER GUIDE](USER_GUIDE.md) for more generic user guide. I will assume that your calendar server needs to support advanced CalDAV queries (see [CALENDAR SERVER RECOMMENDATIONS](docs/CALENDAR_SERVER_RECOMMENDATIONS.md)).
317317

318318
### Adding tasks
319319

‎USER_GUIDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Those commands are made mostly for making `plann` more convenient to use for the
3232
* interactive manage-tasks - go through your tasks and make suggestions
3333
* interactive update-config - (TODO: NOT IMPLEMENTED YET). This one is not used by the primary author and is probably under-tested. Its primary intention is to make it easy for others to use the tool.
3434

35-
Note that many of those commands have only been tested on DAViCal (see the [`docs/ALENDAR_SERVER_RECOMMENDATIONS.md`](CALENDAR_SERVER_RECOMMENDATIONS.md) file)
35+
Note that many of those commands have only been tested on DAViCal (see the [`docs/CALENDAR_SERVER_RECOMMENDATIONS.md`](docs/CALENDAR_SERVER_RECOMMENDATIONS.md) file)
3636

3737

3838
## Global options
File renamed without changes.

0 commit comments

Comments
 (0)