Skip to content

Commit 9a9dc94

Browse files
committed
deploy: check for broken links
Broken links are quite an annoyance for readers, and at least for links that point to pages within the same static website, there are tools to help identify those. One such tool is called `lychee`. It has already a number of very useful options and even sports a GitHub Action for easy integration into GitHub workflows. To accommodate the migration of https://git-scm.com/ from a Rails App to a static site generated using Hugo, lychee was taught the trick needed to support checking links in a static website with "pretty URLs" (i.e. URLs lacking the `.html` file extension even though the files backing those URLs do have that extension, something GitHub Pages supports). With this mode, the automation that deploys https://git-scm.com/ can make use of that link checker. Seeing as broken links often originate from repositories outside of https://github.com/git/git-scm.com's control, rather than failing deployment when broken links are detected, let's follow the "best effort" strategy and open a ticket about the broken links while still letting the deployments complete. In PR builds, links are also checked, and broken links will let them fail. While it was tempting to use a convenient GitHub Action like `peter-evans/create-issue-from-file` to open the GitHub issue, there is no readily-available Action to either open, update, or update & close such a ticket, depending on the outcome of the link check and whether such a ticket exists already and is open. Therefore, I opted for a more verbose (and much more powerful) `actions/github-script` step to perform this part of the job. Based-on-feedback-by: Todd Zullinger <[email protected]> Helped-by: Matthias Endler <[email protected]> Helped-by: Thomas Zahner <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 5bf844c commit 9a9dc94

File tree

8 files changed

+93
-0
lines changed

8 files changed

+93
-0
lines changed

.github/actions/deploy-to-github-pages/action.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ description: 'Runs Hugo and Pagefind and then deploys the result to GitHub Pages
99
# environment:
1010
# name: github-pages
1111
# url: ${{ steps.<id-of-deployment-step>.outputs.url }}
12+
inputs:
13+
github-token:
14+
description: The GitHub token used to create an authenticated client
15+
default: ${{ github.token }}
16+
required: true
1217
outputs:
1318
url:
1419
description: The URL to which the site was deployed
@@ -62,3 +67,63 @@ runs:
6267
- name: deploy
6368
id: deploy
6469
uses: actions/deploy-pages@v4
70+
71+
- name: construct `--remap` option for lychee
72+
id: remap
73+
shell: bash
74+
run: |
75+
base_url='${{ steps.pages.outputs.base_url }}'
76+
echo "result=$(echo "$base_url" |
77+
sed 's|^\(.*\)\(/git-scm\.com\)$|(\1)?\2(.*)|') file://$PWD/public\$2" \
78+
>>$GITHUB_OUTPUT
79+
80+
- name: check for broken links
81+
id: lychee
82+
uses: lycheeverse/lychee-action@d4128702eae98bbc5ecf74df0165a8156c80920a # until an official version is out that includes https://github.com/lycheeverse/lychee/pull/1422
83+
with:
84+
lycheeVersion: nightly # until an official version includes https://github.com/lycheeverse/lychee/pull/1422
85+
args: >-
86+
--offline
87+
--fallback-extensions html
88+
--base '${{ steps.pages.outputs.base_url }}'
89+
--remap '${{ steps.remap.outputs.result }}'
90+
--exclude file:///path/to/repo.git/
91+
--exclude file:///caminho/para/o/reposit%C3%B3rio.git/
92+
--exclude file:///ruta/a/repositorio.git/
93+
--exclude file:///sl%C3%B3%C3%B0/til/hirsla.git/
94+
--exclude file:///Pfad/zum/Repo.git/
95+
--exclude file:///chemin/du/d%C3%A9p%C3%B4t.git/
96+
--exclude file:///srv/git/project.git
97+
public/
98+
output: lychee.md
99+
jobSummary: true
100+
fail: false
101+
failIfEmpty: false # needed because its default overrides `fail = false`
102+
103+
- name: ${{ env.lychee_exit_code != '0' && 'maybe close' || 'open or update' }} link checker issue
104+
uses: actions/github-script@v7
105+
with:
106+
github-token: ${{ inputs.github-token }}
107+
script: |
108+
const fs = await import('fs')
109+
// GitHub issues can only have 64k characters in their body
110+
const body = (s => {
111+
if (s.length < 65535) return s
112+
return s.replace(/^([^]{0,65000}\n)[^]*\n(.+)\n?$/, '$1\n[...]\n\n$2')
113+
})(await fs.promises.readFile('lychee.md', 'utf8'))
114+
115+
const req = { owner: context.repo.owner, repo: context.repo.repo }
116+
const q = `"Link+Checker+Report"+in:title+is:issue+label:linkchecker+is:open+repo:${req.owner}/${req.repo}`
117+
const issues = await github.rest.search.issuesAndPullRequests({ ...req, q, sort: 'created', per_page: 1 })
118+
119+
if (issues.data.items.length === 0) {
120+
if (process.env.lychee_exit_code !== '0') {
121+
await github.rest.issues.create({ ...req, title: 'Link Checker Report', body, labels: ['linkchecker'] })
122+
}
123+
} else {
124+
req.issue_number = issues.data.items[0].number
125+
await github.rest.issues.createComment({ ...req, body })
126+
if (process.env.lychee_exit_code === '0') {
127+
await github.rest.issues.update({ ...req, state: 'closed' })
128+
}
129+
}

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,22 @@ jobs:
5757
}
5858
done
5959
exit $res
60+
61+
- name: check for broken links
62+
id: lychee
63+
uses: lycheeverse/lychee-action@d4128702eae98bbc5ecf74df0165a8156c80920a # until an official version is out that includes https://github.com/lycheeverse/lychee/pull/1422
64+
with:
65+
lycheeVersion: nightly # until an official version includes https://github.com/lycheeverse/lychee/pull/1422
66+
args: >-
67+
--offline
68+
--fallback-extensions html
69+
--exclude file:///path/to/repo.git/
70+
--exclude file:///caminho/para/o/reposit%C3%B3rio.git/
71+
--exclude file:///ruta/a/repositorio.git/
72+
--exclude file:///sl%C3%B3%C3%B0/til/hirsla.git/
73+
--exclude file:///Pfad/zum/Repo.git/
74+
--exclude file:///chemin/du/d%C3%A9p%C3%B4t.git/
75+
--exclude file:///srv/git/project.git
76+
public/
77+
output: lychee.md
78+
jobSummary: true

.github/workflows/deploy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
permissions:
1313
pages: write # to deploy to GitHub Pages
1414
id-token: write # to verify that the deployment source is legit
15+
issues: write # to open tickets upon broken links
1516
environment:
1617
name: github-pages
1718
url: ${{ steps.deploy.outputs.url }}

.github/workflows/update-book.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ jobs:
109109
contents: write # to push changes (if any)
110110
pages: write # to deploy to GitHub Pages
111111
id-token: write # to verify that the deployment source is legit
112+
issues: write # to open tickets upon broken links
112113
environment:
113114
name: github-pages
114115
url: ${{ steps.deploy.outputs.url }}

.github/workflows/update-download-data.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
contents: write # to push changes (if any)
1414
pages: write # to deploy to GitHub Pages
1515
id-token: write # to verify that the deployment source is legit
16+
issues: write # to open tickets upon broken links
1617
environment:
1718
name: github-pages
1819
url: ${{ steps.deploy.outputs.url }}

.github/workflows/update-git-version-and-manual-pages.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
contents: write # to push changes (if any)
1919
pages: write # to deploy to GitHub Pages
2020
id-token: write # to verify that the deployment source is legit
21+
issues: write # to open tickets upon broken links
2122
environment:
2223
name: github-pages
2324
url: ${{ steps.deploy.outputs.url }}

.github/workflows/update-translated-manual-pages.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
contents: write # to push changes (if any)
3838
pages: write # to deploy to GitHub Pages
3939
id-token: write # to verify that the deployment source is legit
40+
issues: write # to open tickets upon broken links
4041
environment:
4142
name: github-pages
4243
url: ${{ steps.deploy.outputs.url }}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ The [list of GUI clients](https://git-scm.com/downloads/guis) has been construct
160160

161161
* https://pagefind.app/
162162

163+
### Lychee (link checker)
164+
165+
* https://lychee.cli.rs/
166+
163167
## License
164168

165169
The source code for the site is licensed under the MIT license, which you can find in

0 commit comments

Comments
 (0)