Engineering

Een changelog-check voor GitHub Actions

5 min lezen

Elk team dat een changelog met de hand bijhoudt heeft na hetzelfde incident hetzelfde gesprek gehad: een release ging uit zonder item, iemand vraagt waarom, en het eerlijke antwoord is dat de persoon die het geschreven zou hebben snel bezig was en de changelog-stap alleen in het geheugen leefde. Changelog-automatisering behandelt wat een pipeline veilig kan automatiseren en wat nog een persoon nodig heeft; een changelog-check in CI is de andere helft van dat probleem, omdat het automatiseren van het schrijven niet helpt als niemand verplicht is het überhaupt te triggeren. GitHub Actions is waar de meeste teams hun pull-requestchecks al draaien, dus daar hoort deze ook thuis.

Waarom faalt “we vragen mensen een item toe te voegen” volgens een voorspelbaar patroon?

Omdat het in een pull request concurreert om aandacht met al het andere, en het het enige onderdeel is zonder directe consequentie bij overslaan. Tests falen luid en blokkeren de merge. Een ontbrekend changelog-item blokkeert niets, dus het verliest zodra iemand haast heeft, wat in de praktijk meestal is. Een beleid dat door geheugen wordt afgedwongen, verslechtert precies in het te verwachten tempo: prima de eerste paar weken nadat iedereen ermee instemt, dan stilletjes losgelaten zodra de persoon die het belangrijk vond op vakantie gaat of van team wisselt.

Wat verifieert een CI-check voor een changelog-item eigenlijk?

Niet de kwaliteit van de tekst, alleen of er een item bestaat en of het goed gevormd is, wat de juiste scope is voor een changelog-check die in CI draait in plaats van in iemands hoofd. Een gangbare vorm: de check kijkt naar de diff van de PR en vereist ofwel een nieuw bestand in een changeset-directory (het patroon dat Changesets en vergelijkbare tools gebruiken) of een gewijzigde regel in een changelog-bestand, en laat de build falen als geen van beide bestaat. De beoordeling van wat het item echt zegt gebeurt nog steeds waar het altijd gebeurde, in code review, omdat dat oordeel niet in een script thuishoort.

Wat de CI-check verifieertWat hij niet verifieert
Er staat een changeset of changelog-regel in de diffOf de formulering duidelijk is
Het item verwijst naar het juiste pakket, in een monorepoOf de wijziging überhaupt een item verdient
Het bestand is syntactisch geldig (frontmatter, JSON-vorm)Of het item eerlijk is over de impact

Heeft elke PR er een nodig, of zijn sommige wijzigingen uitgezonderd?

Sommige zijn uitgezonderd, en de uitzonderingslijst is waar deze systemen echt gebouwd of losgelaten worden. Een dependency-bump zonder zichtbaar effect, een wijziging die alleen tests raakt, een interne refactor zonder gedragswijziging: geen van deze zou een bijdrager moeten dwingen een changelog-item te verzinnen voor iets waar niemand die de changelog leest om geeft. Het werkende patroon is een label of vlag die een bijdrager kan toepassen (no-changelog-needed) en die de CI-check zonder bestand tevredenstelt, beoordeeld door wie de PR goedkeurt, zodat de uitzondering zelf dezelfde controle doorloopt die een item zou doorlopen.

Wat gebeurt er met legitieme uitzonderingen, zoals een dringende hotfix?

De gate hoort bij de merge, niet bij de deploy: een hotfix onder echte tijdsdruk kan mergen met een placeholder-item of een vervolgticket, mits de CI-check tevreden is met intentie in plaats van alleen een afgerond stuk tekst; sommige teams accepteren een stub van één regel die een maintainer bijschaaft voor de volgende release-snit. Wat de gate nooit zou moeten toestaan is de stap stilletjes overslaan, want een stub die vergeten wordt is een kleiner falen dan een item dat nooit heeft bestaan, en een stub laat op zijn minst een spoor achter dat iemand later kan vinden.

# .github/workflows/changelog-check.yml
on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
  changelog:
    if: >-
      !contains(github.event.pull_request.labels.*.name,
      'no-changelog-needed')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # de diff heeft de basisbranch nodig
      - name: Require changelog entry
        run: |
          base="origin/${{ github.base_ref }}"
          if ! git diff --name-only "$base"...HEAD \
              | grep -q '^\.changeset/'; then
            echo "No changeset. Add one, or have a maintainer"
            echo "apply the no-changelog-needed label."
            exit 1
          fi

Hoe weet je dat de check zelf klopt voordat hij echte PR’s gaat blokkeren?

Open eerst een proef-pull request tegen een wegwerpbranch: één met een changeset, één zonder, en één met het uitzonderingslabel, en bevestig dat alle drie de verwachte uitkomst krijgen voordat de check op ieders werk wordt toegepast. Een changelog-check die fail-open gaat, elke PR laat slagen omdat een voorwaarde achterstevoren is geschreven, is erger dan geen check, omdat het eruitziet als dekking die er niet is. workflow_dispatch op hetzelfde bestand, handmatig uitgevoerd tegen een paar recent gemergde PR’s, vangt de meeste van deze fouten zonder dat er een echte pull request voor nodig is.

Werkt hetzelfde idee ook buiten GitHub Actions?

De vorm blijft hetzelfde, alleen de syntax verandert. GitLab CI drukt dezelfde regel uit als een job-rules-blok dat $CI_MERGE_REQUEST_LABELS controleert in plaats van een GitHub Actions if, en een verplichte goedkeuring van de merge request kan de rol van de uitzonderingsbeoordeling overnemen. De check die dit artikel beschrijft is GitHub Actions omdat dat het platform is waar de meeste lezers al op zitten, maar de onderliggende eis, een machinaal gecontroleerde gate in plaats van een gevraagde afspraak, is overal hetzelfde waar CI vóór een merge draait.

Werkt dit hetzelfde in een monorepo?

Er is één stuk extra nodig: voor welk pakket het item is. Monorepo-changelogs behandelt waarom één repobreed bestand stopt te werken zodra pakketten onafhankelijk worden uitgebracht; de CI-check erft diezelfde eis; een changeset die geen pakket noemt is geen nuttig bewijs dat de juiste changelog zal bijwerken, alleen dat er ergens in de diff een bestand is veranderd. Tools die hiervoor gebouwd zijn (Changesets is de gangbare in het JavaScript-ecosysteem) vragen de bijdrager het betrokken pakket en een semver-bump te kiezen op hetzelfde moment dat de changeset wordt aangemaakt, zodat de CI-check beide stukken gratis krijgt in plaats van ze later af te leiden.

FAQ

Moet de CI-check de merge blokkeren, of alleen waarschuwen? Blokkeren. Een waarschuwing is functioneel identiek aan vriendelijk vragen, wat al gefaald heeft. Het uitzonderingslabel bestaat precies zodat een oprecht alleen-waarschuwen-geval toch een legitiem pad door dezelfde harde gate heeft.

Wie beoordeelt of een uitzonderingslabel correct is toegepast? Wie de pull request goedkeurt, als onderdeel van de beoordeling die diegene toch al doet. Het label zou nooit zelf toegepast en onbeoordeeld moeten blijven, anders wordt het dezelfde stille omweg die de gate juist moest sluiten.

Vervangt dit afdwingen in CI de behoefte aan een changelog-automatiseringspipeline? Nee, het voedt er een. Changelog-automatisering behandelt hoe gestructureerde items een pagina, een feed en een e-mail worden; de CI-check garandeert dat die gestructureerde items er überhaupt zijn om te automatiseren.

Wat is de kleinste versie hiervan die het waard is om eerst te bouwen? Eén enkele check die faalt als er geen bestand veranderd is onder een aangewezen changelog-directory, met één uitzonderingslabel. Pakketroutering en semver-afleiding voor een monorepo kunnen later komen; de kerngewoonte, een item bestaat of iemand heeft expliciet gezegd dat het niet nodig is, is wat het waard is om vanaf dag één te hebben.


De technische beweringen in dit artikel zijn niet onafhankelijk gecontroleerd. Klopt er iets niet, laat het ons weten, dan corrigeren we het.

Meer op changeloop: Changelog-tools vergeleken, Changelog-generator

changeloop
Het team achter een changelog die de cirkel rondmaakt. Je gebruikers vragen iets, je team levert het, degene die het vroeg hoort ervan.