GitLab Release Notes automatisch aus Merge Requests generieren
AI generated
CI/CD
.yml
GitLab · CI/CD · Releases
Release Notes automatisch generieren
aus Merge-Request-Titeln und Labels, als letzter Schritt jeder Deploy-Pipeline

Manuell gepflegte Release Notes veralten fast immer schneller, als sie geschrieben werden, weil niemand nach einem hektischen Deploy noch Zeit findet, sie sauber nachzutragen. Mit einer Conventional-Commits-Konvention, klaren Merge-Request-Labels und der GitLab Releases API lassen sich Release Notes stattdessen automatisiert aus genau den Informationen erzeugen, die ohnehin bei jedem Merge Request anfallen. Dieser Artikel zeigt den kompletten Weg von der Commit-Konvention bis zur Integration als letzter Schritt der Deploy-Pipeline.

16 Min. Lesezeit Releases API · Automatisierung GitLab CI/CD · Conventional Commits

1. Warum manuelle Release Notes ein Wartungsproblem sind

Release Notes von Hand zu pflegen bedeutet in der Praxis fast immer, dass jemand kurz vor oder nach einem Deploy in Eile eine Liste der wichtigsten Aenderungen zusammenschreibt, meist aus dem Gedaechtnis und ohne systematischen Abgleich mit dem, was tatsaechlich in den Merge Requests seit dem letzten Release gelandet ist. Kleinere, aber fuer Kunden durchaus relevante Aenderungen fallen dabei regelmaessig unter den Tisch, weil sie schlicht vergessen werden.

Das eigentliche Problem ist dabei nicht Faulheit, sondern dass die Information, was sich geaendert hat, technisch bereits vollstaendig vorliegt: in den Merge-Request-Titeln, den vergebenen Labels und der Commit-Historie seit dem letzten Tag. Diese Daten muessen nur noch strukturiert ausgelesen und automatisiert zusammengefasst werden, statt sie ein zweites Mal von Hand zu rekonstruieren.

2. Conventional Commits als strukturelle Grundlage

Die Conventional-Commits-Konvention schreibt vor, dass jede Commit-Message mit einem Praefix wie feat:, fix:, docs: oder chore: beginnt, gefolgt von einer kurzen Beschreibung der Aenderung, sowie optional einem ! nach dem Typ oder einer BREAKING CHANGE:-Zeile im Body fuer inkompatible Aenderungen. Diese einfache, maschinenlesbare Struktur macht es moeglich, Commits automatisch nach Kategorien wie Neue Funktionen, Fehlerbehebungen und Breaking Changes zu sortieren.

Damit die Konvention tatsaechlich eingehalten wird, lohnt sich ein Commit-Message-Linter als eigener CI-Job, der jeden Merge Request auf das korrekte Praefix prueft und fehlschlaegt, wenn keine Commit-Message dem erwarteten Muster entspricht. Ohne eine solche Durchsetzung verwaessert die Konvention erfahrungsgemaess innerhalb weniger Wochen, weil einzelne Commits ohne Praefix committet werden und die automatische Kategorisierung dadurch luecken bekommt.


# Beispiele fuer Conventional-Commits-konforme Messages
feat(checkout): add support for saved payment methods
fix(catalog): correct price rounding for bundle products
feat(api)!: remove deprecated v1 product endpoint

BREAKING CHANGE: Clients must migrate to the v2 product endpoint.

3. Merge Request Titel und Labels als Datenquelle

Neben der Commit-Historie liefert GitLab selbst bereits eine strukturierte Datenquelle: jeder Merge Request hat einen Titel, ein oder mehrere Labels und ein Ziel-Milestone. Eine sinnvolle Label-Konvention, etwa type::feature, type::fix, type::breaking und type::internal, macht die Kategorisierung fuer Release Notes unabhaengig davon, ob jeder einzelne Commit innerhalb des Merge Requests der Conventional-Commits-Konvention folgt.

Der Merge-Request-Titel selbst sollte dabei bewusst kundenverstaendlich formuliert werden, statt technischer Implementierungsdetails, weil er haeufig direkt oder nur leicht angepasst in die finalen Release Notes uebernommen wird. Ein Titel wie Neue Zahlungsart: Rechnungskauf fuer B2B-Kunden eignet sich fuer Release Notes deutlich besser als refactor PaymentMethodProvider interface, auch wenn beide Formulierungen fuer den Code-Review selbst gleichermassen gueltig waeren.

4. Der Aufbau der GitLab Releases API

Die GitLab Releases API erlaubt es, ueber einen POST-Request an /projects/:id/releases ein neues Release mit Tag-Name, Beschreibung und optionalen Release-Assets wie kompilierten Artefakten zu erstellen. Die Beschreibung selbst wird als Markdown-Text uebergeben, wodurch sich Ueberschriften, Aufzaehlungen und Links zu den jeweiligen Merge Requests direkt in der Release-Ansicht von GitLab darstellen lassen.

Praktisch bewaehrt sich dabei die Kombination mit der GitLab-eigenen release-cli, die als vorgefertigtes CI/CD-Component fuer genau diesen Zweck existiert und den API-Aufruf kapselt, sodass in der eigenen Pipeline nur noch die generierte Markdown-Beschreibung als Datei uebergeben werden muss, statt den rohen API-Request von Hand zu bauen.


curl --request POST \
  --header "PRIVATE-TOKEN: $CI_JOB_TOKEN" \
  --header "Content-Type: application/json" \
  --data "{
    \"tag_name\": \"v2.14.0\",
    \"name\": \"Release v2.14.0\",
    \"description\": \"$(cat release-notes.md)\"
  }" \
  "https://gitlab.mironsoft.de/api/v4/projects/$CI_PROJECT_ID/releases"

5. Ein Pipeline-Job, der Release Notes aus Merge Requests generiert

Ein dedizierter Job kurz vor dem eigentlichen Deploy ruft ueber die GitLab-API alle Merge Requests ab, die seit dem letzten Tag in den Ziel-Branch gemergt wurden, gefiltert nach dem Merge-Datum und dem Ziel-Branch. Fuer jeden gefundenen Merge Request werden Titel, Labels und die Merge-Request-URL ausgelesen und in einer strukturierten Markdown-Datei zusammengefasst, sortiert nach der Label-Kategorie.

Dieses Skript laesst sich in Python oder direkt in Bash mit curl und jq umsetzen, wobei Python bei komplexerer Filterlogik meist die wartbarere Wahl ist. Wichtig ist, dass der Job idempotent bleibt, also bei einem erneuten Lauf fuer denselben Tag dieselbe Ausgabe erzeugt, statt bei jedem erneuten Trigger unterschiedliche Ergebnisse zu liefern.


generate_release_notes:
  stage: release
  image: python:3.12-slim
  script:
    - pip install --quiet python-gitlab
    - python scripts/generate_release_notes.py
        --project-id "$CI_PROJECT_ID"
        --since-tag "$(git describe --tags --abbrev=0 HEAD^)"
        --output release-notes.md
  artifacts:
    paths:
      - release-notes.md
  rules:
    - if: '$CI_COMMIT_TAG'

6. Kategorisierung nach Labels in der Release-Beschreibung

Die generierte Markdown-Datei gliedert sich sinnvollerweise in feste Abschnitte wie ## Neue Funktionen, ## Fehlerbehebungen und ## Breaking Changes, wobei jeder Merge Request anhand seines type::-Labels der passenden Kategorie zugeordnet wird. Merge Requests ohne passendes Label landen in einer separaten Kategorie Sonstige Aenderungen, statt stillschweigend aus den Release Notes zu verschwinden, was gleichzeitig als Signal dient, die Label-Disziplin im Team zu verbessern.

Breaking Changes verdienen dabei eine optisch hervorgehobene, eigene Position ganz oben in den Release Notes, weil sie fuer Kunden und andere Teams die groesste Aufmerksamkeit brauchen. Ein type::breaking-Label sollte deshalb in der Pipeline-Logik immer Vorrang vor anderen Labels desselben Merge Requests haben, selbst wenn zusaetzlich noch type::feature gesetzt ist.

7. Integration in die Deploy-Pipeline als letzter Schritt

Der Release-Notes-Job sollte bewusst als letzter Schritt der Deploy-Pipeline laufen, nachdem der eigentliche Deploy erfolgreich abgeschlossen wurde, ausgeloest ueber eine rules:-Bedingung, die nur bei einem gesetzten Git-Tag greift. Damit entsteht ein Release-Eintrag ausschliesslich fuer tatsaechlich produktiv ausgerollte Versionen, nicht fuer jeden beliebigen Merge in den main-Branch.

Diese Reihenfolge stellt zusaetzlich sicher, dass die Release Notes niemals einen fehlgeschlagenen Deploy dokumentieren: Schlaegt der eigentliche Deploy-Job fehl, wird der nachgelagerte Release-Notes-Job ueber eine needs:-Abhaengigkeit gar nicht erst ausgefuehrt, wodurch keine irrefuehrende Release-Ankuendigung fuer eine Version entsteht, die in Wahrheit nie live ging.


publish_release:
  stage: release
  needs:
    - job: deploy_production
      artifacts: false
    - job: generate_release_notes
  script:
    - >
      release-cli create --name "Release $CI_COMMIT_TAG"
      --tag-name "$CI_COMMIT_TAG"
      --description "$(cat release-notes.md)"
  rules:
    - if: '$CI_COMMIT_TAG'

8. Grenzen der Automatisierung: Was sie nicht ersetzt

Automatisch generierte Release Notes ersetzen keine manuelle Kuration, sobald ein Release mehrere zusammenhaengende, aber technisch getrennte Merge Requests umfasst, die inhaltlich besser als ein einziger Punkt statt als mehrere separate Eintraege dargestellt werden. Hier bleibt ein kurzer manueller Redigier-Schritt vor der eigentlichen Veroeffentlichung sinnvoll, auch wenn der Grossteil der Arbeit automatisiert erledigt wird.

Auch Breaking Changes sollten trotz automatischer Hervorhebung nie ausschliesslich auf die automatisierte Beschreibung vertrauen, sondern zusaetzlich in einem separaten Migrationsleitfaden dokumentiert werden, der konkrete Schritte fuer betroffene Nutzer beschreibt. Die Automatisierung liefert die zuverlaessige Rohfassung, die redaktionelle Feinarbeit bei komplexeren Releases bleibt weiterhin Aufgabe eines Menschen.

9. Checkliste fuer den Einstieg in automatisierte Release Notes

Der Einstieg gelingt am einfachsten mit einer klaren Label-Konvention im Team, einem Commit-Message-Linter als CI-Job und einem einzelnen Pipeline-Job, der die GitLab-API abfragt und eine Markdown-Datei erzeugt. Erst danach folgt die Integration in die Releases API als letzter Schritt der Deploy-Pipeline.

Die folgende Tabelle vergleicht die drei zentralen Datenquellen fuer automatisierte Release Notes und zeigt, welche Kombination fuer welchen Anwendungsfall die verlaesslichsten Ergebnisse liefert.

Datenquelle Struktur Kundenverstaendlichkeit Empfehlung
Rohe Commit-Historie Unstrukturiert ohne Konvention Niedrig Nicht direkt fuer Release Notes nutzen
Conventional Commits Praefix-basiert, maschinenlesbar Mittel Fuer technische Changelogs geeignet
Merge Request Titel Ein Titel pro fachlicher Aenderung Hoch, bei sorgfaeltiger Formulierung Beste Basis fuer Release Notes
Merge Request Labels Explizite Kategorisierung Hoch, mit Konvention Fuer Sortierung nach Kategorie

Mironsoft

CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung

Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?

Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.

Pipeline-Review

Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.

Zero-Downtime-Deployment

Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.

CI/CD-Automatisierung

Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.

10. Zusammenfassung

Automatische Release Notes: Das Wichtigste auf einen Blick

Kernidee

Release Notes aus Informationen generieren, die ohnehin in Merge-Request-Titeln, Labels und Commits vorliegen, statt sie doppelt von Hand zu schreiben.

Strukturelle Basis

Conventional Commits fuer maschinenlesbare Commits, ergaenzt um eine type::-Label-Konvention fuer Merge Requests.

Technischer Weg

Ein Pipeline-Job liest Merge Requests seit dem letzten Tag ueber die GitLab-API aus und erzeugt daraus eine Markdown-Beschreibung fuer die Releases API.

Grenze der Automatisierung

Komplexe, zusammenhaengende Releases und Breaking-Change-Migrationsleitfaeden brauchen weiterhin manuelle redaktionelle Nacharbeit.

11. FAQ: Automatische Release Notes: Das Wichtigste auf einen Blick

1Brauche ich zwingend Conventional Commits fuer automatisierte Release Notes?
Nein, Merge-Request-Titel und Labels reichen fuer die meisten Projekte als Datenquelle bereits aus. Conventional Commits helfen zusaetzlich bei technischen Changelogs, sind aber keine harte Voraussetzung fuer die GitLab-Releases-API-Integration.
2Wie stelle ich sicher, dass Merge Requests konsequent gelabelt werden?
Am zuverlaessigsten ueber eine Pflichtfeld-Vorlage im Merge-Request-Template kombiniert mit einer CI-Regel, die einen Merge Request ohne type::-Label blockiert oder zumindest mit einer Warnung versieht.
3Kann ich die Releases API auch ohne die release-cli direkt per curl ansprechen?
Ja, ein einfacher POST-Request an /projects/:id/releases mit Tag-Name und Beschreibung reicht aus. Die release-cli kapselt diesen Aufruf lediglich komfortabler und wird als vorgefertigtes CI/CD-Component gepflegt.
4Was passiert mit Merge Requests ohne passendes Label?
Sie sollten in eine separate Kategorie wie Sonstige Aenderungen einsortiert werden, statt stillschweigend zu verschwinden. Das macht gleichzeitig sichtbar, wo die Label-Disziplin im Team noch verbessert werden sollte.
5Warum sollte der Release-Notes-Job erst nach dem erfolgreichen Deploy laufen?
Damit niemals ein Release-Eintrag fuer eine Version entsteht, die tatsaechlich nie produktiv ausgerollt wurde. Eine needs:-Abhaengigkeit vom Deploy-Job verhindert das zuverlaessig.
6Wie werden Breaking Changes in automatisierten Release Notes hervorgehoben?
Ueber ein dediziertes type::breaking-Label, das in der Generierungslogik immer Vorrang vor anderen Labels desselben Merge Requests erhaelt und ganz oben in den Release Notes platziert wird.
7Ersetzt die Automatisierung eine manuelle Migrationsanleitung bei Breaking Changes?
Nein, fuer konkrete Migrationsschritte bleibt ein separater, manuell gepflegter Leitfaden noetig. Die automatisierten Release Notes liefern lediglich die zuverlaessige Uebersicht, welche Aenderung ueberhaupt stattgefunden hat.
8Kann ich automatisierte Release Notes mit mehreren Sprachen kombinieren?
Grundsaetzlich ja, indem Merge-Request-Titel konsequent zweisprachig gepflegt oder nachtraeglich uebersetzt werden. Fuer die meisten internen Projekte reicht jedoch eine einzige Sprache in den technischen Release Notes aus.
9Wie gehe ich mit mehreren zusammenhaengenden Merge Requests fuer ein Feature um?
Am besten mit einem kurzen manuellen Redigier-Schritt vor der Veroeffentlichung, der mehrere technisch getrennte, aber inhaltlich zusammengehoerige Eintraege zu einem einzigen, verstaendlichen Punkt zusammenfasst.
10Funktioniert die GitLab Releases API auch fuer GitLab.com und selbstgehostete Instanzen gleichermassen?
Ja, die API-Struktur ist identisch, lediglich die Basis-URL unterscheidet sich zwischen gitlab.com und einer selbstgehosteten GitLab-Instanz mit eigener Domain.