chore: trek gedeelde config en workflow-commentaar gelijk met de rest van de organisatie #143
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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, | |
| }); |