Skip to content

chore: trek gedeelde config en workflow-commentaar gelijk met de rest van de organisatie #143

chore: trek gedeelde config en workflow-commentaar gelijk met de rest van de organisatie

chore: trek gedeelde config en workflow-commentaar gelijk met de rest van de organisatie #143

Workflow file for this run

name: PR Checks
on:
pull_request:
branches: [main, development]
# Nothing by default; each job asks for exactly what it needs. Granting
# pull-requests: write at the top handed it to every job, including the ones
# that only read the checkout.
permissions: {}
jobs:
# ── 1. Markdown formatting ──────────────────────────────────────────────────
markdown:
name: Markdown lint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24.2.0
with:
globs: "src/content/**/*.md"
# ── 2. Images must be AVIF ──────────────────────────────────────────────────
image-format:
name: No PNG/JPG in static/images
runs-on: ubuntu-latest
# pull-requests: write for the comment this job posts when it finds a PNG.
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Find non-AVIF images
id: check
run: |
{
echo "files<<EOF"
find src/static/images -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" \) | sort
echo "EOF"
} >> "$GITHUB_OUTPUT"
count=$(find src/static/images -type f \( -iname "*.png" -o -iname "*.jpg" -o -iname "*.jpeg" \) | wc -l)
if [ "$count" -gt 0 ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
else
echo "found=false" >> "$GITHUB_OUTPUT"
echo "All images are AVIF."
fi
- name: Post PR comment
if: steps.check.outputs.found == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
FILES: ${{ steps.check.outputs.files }}
ACTOR: ${{ github.event.pull_request.user.login }}
with:
script: |
const files = process.env.FILES.trim().split('\n').map(f => `- \`${f}\``).join('\n');
const actor = process.env.ACTOR;
const body = [
`Hey @${actor}, looks like you forgot something!`,
'',
'The following images in `src/static/images/` are not in AVIF format:',
files,
'',
'Please convert them before merging. Install `avifenc` first:',
'```bash',
'sudo pacman -S libavif',
'```',
'',
'Then batch-convert all images in `static/images/`:',
'```bash',
'cd src/static/images',
'for f in *.png *.jpg *.jpeg; do',
' [ -f "$f" ] && avifenc -q 80 -s 6 "$f" "${f%.*}.avif" && rm "$f"',
'done',
'```',
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body,
});
- name: Annotate and fail
if: steps.check.outputs.found == 'true'
env:
FILES: ${{ steps.check.outputs.files }}
run: |
while IFS= read -r f; do
echo "::error file=$f::Convert to AVIF before merging (see README → Image assets)"
done <<< "$FILES"
exit 1
# ── 3. Both EN and NL files present ─────────────────────────────────────────
bilingual:
name: EN/NL file parity
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check every .md has a matching .nl.md
run: |
missing=""
for en in src/content/docs/*.md; do
base="${en%.md}"
nl="${base}.nl.md"
# Skip files that are already .nl.md
[[ "$en" == *.nl.md ]] && continue
if [ ! -f "$nl" ]; then
missing="$missing\n $en → $nl missing"
fi
done
if [ -n "$missing" ]; then
echo -e "::error::Missing Dutch translation(s):$missing"
exit 1
fi
echo "All docs have EN + NL versions."
# ── 4. Hugo builds without errors ───────────────────────────────────────────
hugo-build:
name: Hugo build
runs-on: ubuntu-latest
permissions:
contents: read
env:
HUGO_VERSION: 0.165.0
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: src/go.mod
- name: Install Hugo
run: |
wget -O "${{ runner.temp }}/hugo.deb" \
"https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb" \
&& sudo dpkg -i "${{ runner.temp }}/hugo.deb"
- name: Build
env:
HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
HUGO_ENVIRONMENT: production
TZ: Europe/Amsterdam
run: cd src && hugo --gc --minify --baseURL "http://localhost/"
- name: Upload built site
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: hugo-public
path: src/public/
retention-days: 1
# ── 5. Broken internal links ─────────────────────────────────────────────────
link-check:
name: Broken link check
runs-on: ubuntu-latest
permissions:
contents: read
needs: hugo-build
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: hugo-public
path: public/
# Installed by hand rather than through lycheeverse/lychee-action. That
# action fetches its binary with a bare `curl -sfLO`: no retry, and no
# check on what comes back. This job and one in THectic.nl both failed on
# that download within a quarter of an hour when GitHub's release CDN was
# having a bad day, neither having checked a single link. Pinned version,
# verified checksum, retried download.
- name: Install lychee
env:
# extractVersion: lychee tagt zijn releases als "lychee-v0.24.2" en
# niet als "v0.24.2", dus het standaardpatroon leest de versie er niet
# uit.
# renovate: datasource=github-releases depName=lycheeverse/lychee extractVersion=^lychee-v(?<version>.+)$
LYCHEE_VERSION: "0.24.2"
# Uit de lychee-x86_64-unknown-linux-gnu.tar.gz.sha256 van de release zelf
LYCHEE_SHA256: "1f4e0ef7f6554a6ed33dd7ac144fb2e1bbed98598e7af973042fc5cd43951c9a"
run: |
curl -sSL --fail-with-body -o lychee.tar.gz \
--retry 5 --retry-delay 3 --retry-all-errors \
"https://github.com/lycheeverse/lychee/releases/download/lychee-v${LYCHEE_VERSION}/lychee-x86_64-unknown-linux-gnu.tar.gz"
echo "${LYCHEE_SHA256} lychee.tar.gz" | sha256sum -c -
tar -xzf lychee.tar.gz lychee-x86_64-unknown-linux-gnu/lychee
sudo install -m 0755 lychee-x86_64-unknown-linux-gnu/lychee /usr/local/bin/lychee
lychee --version
# --index-files: without it lychee treats a link to /docs/applications/ as
# a link to a directory and stops there, so it can never look inside for
# the #fragment. Every anchor into another page then reports "Cannot find
# fragment" even though the heading is right there. Hugo serves every page
# as <page>/index.html, so this flag is what makes --include-fragments
# usable at all here.
#
# The glob is quoted deliberately. Unquoted, bash expands it first, and
# without globstar ** collapses to a single level -- which is why this job
# was checking 95 links instead of 3379.
- name: Check internal links
run: |
lychee --offline --include-fragments --index-files index.html \
--root-dir ./public "public/**/*.html"
# ── 6. Auto-tick PR checklist ────────────────────────────────────────────────
update-checklist:
name: Update PR checklist
runs-on: ubuntu-latest
# pull-requests: write to rewrite the description's checklist.
permissions:
pull-requests: write
if: always()
# pr-title staat niet in deze needs: die controle is een eigen workflow
# (pr-title.yml), gelijk aan de andere repositories, en een job kan niet
# wachten op een job in een andere workflow. Het vinkje hieronder wordt
# daarom uit de titel zelf afgeleid in plaats van uit een jobresultaat.
needs: [bilingual, image-format, hugo-build, link-check]
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
RESULT_BILINGUAL: ${{ needs.bilingual.result }}
RESULT_IMAGE_FORMAT: ${{ needs.image-format.result }}
RESULT_HUGO_BUILD: ${{ needs.hugo-build.result }}
RESULT_LINK_CHECK: ${{ needs.link-check.result }}
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
let body = pr.body || '';
// ── Tick checklist items based on CI results ──────────────────────
const setCheck = (keyword, passed) => {
body = body.replace(
new RegExp(`- \\[[ xX]\\] (.*${keyword}.*)`, 'i'),
`- [${passed ? 'x' : ' '}] $1`
);
};
// Dezelfde typelijst als pr-title.yml en CONTRIBUTING.md. Scope en
// een `!` voor een breaking change zijn toegestaan: feat(nav)!: ...
const TITLE_RE =
/^(feat|fix|content|docs|chore|refactor|style|revert)(\([^)]+\))?!?: .+/;
setCheck('PR title follows', TITLE_RE.test(pr.title));
setCheck('Both EN and NL', process.env.RESULT_BILINGUAL === 'success');
setCheck('Media is in AVIF', process.env.RESULT_IMAGE_FORMAT === 'success');
setCheck('No broken image', process.env.RESULT_LINK_CHECK === 'success');
setCheck('Tested locally', process.env.RESULT_HUGO_BUILD === 'success');
// ── Remove unchecked "Type of change" options ─────────────────────
body = body.replace(/^- \[ \] `\w+` —[^\n]*\n?/gm, '');
// ── Collapse leftover blank lines ─────────────────────────────────
body = body.replace(/\n{3,}/g, '\n\n');
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
body,
});