Vývoj

Kontrola changelogu pro GitHub Actions

4 min čtení

Každý tým, který vede changelog ručně, zažil stejný rozhovor po stejném incidentu: vydání vyšlo bez záznamu, někdo se ptá proč, a upřímná odpověď je, že člověk, který by ho napsal, spěchal a krok changelogu žil jen v paměti. Automatizace changelogu pokrývá, co pipeline může bezpečně automatizovat a co ještě potřebuje člověka; kontrola changelogu v CI je druhá polovina tohoto problému, protože automatizace psaní nepomáhá, pokud není nikdo povinen ji vůbec spustit. GitHub Actions je místo, kde většina týmů už spouští kontroly pro pull requesty, takže je to i místo, kde žije tahle.

Proč “žádáme lidi, aby přidali záznam” selhává podle předvídatelného vzoru?

Protože to soutěží o pozornost se vším ostatním v pull requestu, a je to jediná část bez okamžitého následku za přeskočení. Testy selhávají hlasitě a blokují merge. Chybějící záznam changelogu neblokuje nic, takže prohrává, jakmile má někdo naspěch, což je v praxi většinu času. Politika vynucovaná pamětí degraduje přesně tempem, jaké by se dalo čekat: dobrá první pár týdnů po souhlasu všech, pak potichu opuštěná, jakmile člověk, kterému na tom záleželo, odjede na dovolenou nebo přejde do jiného týmu.

Co vlastně ověřuje CI check pro záznam changelogu?

Ne kvalitu psaní, jen že záznam existuje a má správný tvar, což je správný rozsah pro kontrolu changelogu, která běží v CI, ne v něčí hlavě. Běžná podoba: check se dívá na diff PR a vyžaduje buď nový soubor v adresáři changesetů (vzor, který používají Changesets a podobné nástroje), nebo změněný řádek v souboru changelogu, a nechá build selhat, pokud neexistuje ani jedno. Kontrola toho, co záznam vlastně říká, se pořád děje tam, kde se vždycky dělala, v code review, protože ten úsudek do skriptu nepatří.

Co CI check ověřujeCo neověřuje
V diffu existuje changeset nebo řádek changeloguZda je formulace jasná
Záznam odkazuje na správný balíček, v monorepuZda si změna vůbec zaslouží záznam
Soubor je syntakticky platný (frontmatter, tvar JSON)Zda je záznam upřímný o dopadu

Potřebuje ho každé PR, nebo jsou některé změny osvobozené?

Některé jsou osvobozené, a seznam výjimek je místo, kde se takové systémy skutečně staví nebo opouštějí. Zvýšení závislosti bez viditelného efektu, změna jen testů, interní refaktor bez změny chování: nic z toho by nemělo nutit přispěvatelku vymýšlet záznam changelogu pro něco, na čem nikomu, kdo changelog čte, nezáleží. Fungující vzor je štítek nebo flag, který přispěvatelka může uplatnit (no-changelog-needed) a který splní CI check bez souboru, kontrolovaný tím, kdo PR schvaluje, takže výjimka sama projde stejnou kontrolou, jakou by prošel záznam.

Co se stane s legitimními výjimkami, jako je naléhavý hotfix?

Brána patří na merge, ne na deploy: hotfix pod skutečným časovým tlakem může mergovat se záznamem-zástupným nebo navazujícím tiketem, pokud je CI check spokojený se záměrem místo jen dokončeného odstavce; některé týmy přijímají jednořádkový stub, který maintainerka vyladí před dalším řezem vydání. Co by brána nikdy neměla dovolit, je potichu přeskočit krok, protože zapomenutý stub je menší selhání než záznam, který nikdy neexistoval, a stub aspoň zanechá stopu, kterou někdo může najít později.

# .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 # diff potřebuje základní větev
      - 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

Jak zjistíte, že je kontrola sama správná, než začne blokovat skutečná PR?

Nejdřív otevřete zkušební pull request proti zahazovací větvi: jeden s changesetem, jeden bez něj, a jeden se štítkem výjimky, a potvrďte, že všechny tři dostanou očekávaný výsledek, než check začne platit pro práci kohokoli jiného. CI check changelogu, který selže otevřeně, tedy propustí každé PR, protože podmínka byla napsaná obráceně, je horší než žádný check, protože vypadá jako pokrytí, které ve skutečnosti neexistuje. workflow_dispatch na stejném souboru, spuštěný ručně proti několika nedávno mergnutým PR, odhalí většinu takových chyb bez potřeby živého pull requestu.

Funguje stejná myšlenka i mimo GitHub Actions?

Tvar zůstává stejný, mění se jen syntaxe. GitLab CI vyjadřuje stejné pravidlo jako blok rules v jobu, který kontroluje $CI_MERGE_REQUEST_LABELS místo GitHub Actions if, a povinné schválení merge requestu může nahradit krok revize výjimky. Check popsaný v tomto článku je GitHub Actions, protože to je platforma, na které už je většina čtenářů, ale základní požadavek, strojově kontrolovaná brána místo poprošené konvence, je stejný všude, kde CI běží před mergem.

Funguje to stejně v monorepu?

Potřebuje jeden díl navíc: pro který balíček je záznam. Changelogy monorepa pokrývá, proč jeden soubor pro celý repozitář přestane fungovat, jakmile se balíčky vydávají nezávisle; CI check dědí stejný požadavek; changeset, který nejmenuje balíček, není užitečný důkaz, že se aktualizuje správný changelog, jen že se někde v diffu změnil nějaký soubor. Nástroje postavené pro tohle (Changesets je ten běžný v ekosystému JavaScriptu) žádají přispěvatelku, aby vybrala postižený balíček a semver skok ve stejném okamžiku, kdy se changeset vytváří, takže CI check dostane obě části zdarma místo toho, aby je odvozoval později.

FAQ

Měl by CI check blokovat merge, nebo jen varovat? Blokovat. Varování je funkčně totožné se zdvořilým požádáním, což už selhalo. Štítek výjimky existuje přesně proto, aby skutečný případ jen-varování měl i tak legitimní cestu skrz stejnou přísnou bránu.

Kdo kontroluje, jestli byl štítek výjimky uplatněn správně? Kdokoli schvaluje pull request, jako součást revize, kterou stejně už dělá. Štítek by nikdy neměl být uplatněn sám sebou a bez kontroly, jinak se stane stejnou tichou skulinou, kterou měla brána zavřít.

Nahrazuje vynucení tohohle v CI potřebu pipeline automatizace changelogu? Ne, živí ji. Automatizace changelogu pokrývá proměnu strukturovaných záznamů ve stránku, feed a e-mail; CI check je to, co zaručuje, že tyto strukturované záznamy vůbec existují, aby se daly automatizovat.

Jaká nejmenší verze tohohle stojí za to postavit jako první? Jeden check, který selže, pokud se nezměnil žádný soubor pod určeným adresářem changelogu, s jedním štítkem výjimky. Směrování podle balíčku a odvozování semver pro monorepo může přijít později; hlavní návyk, záznam existuje nebo někdo explicitně řekl, že není potřeba, je to, co stojí za to mít od prvního dne.


Technická tvrzení v tomto článku nikdo nezávisle neověřil. Pokud tu něco nesedí, dej nám vědět a opravíme to.

Související na changeloop: Srovnání nástrojů pro changelog, Generátor changelogu

changeloop
Tým, který vyvíjí changelog uzavírající smyčku. Uživatelé o něco požádají, tvůj tým to doručí, ten, kdo žádal, se to dozví.