kurmann / GitHub.Workflows

Zentrale Sammelstelle für Reusable GitHub-Workflows.
Apache License 2.0
0 stars 0 forks source link

Wechseln auf Semantic-Release #3

Closed kurmann closed 6 months ago

kurmann commented 6 months ago

Vorabdiskussion:

kurmann commented 6 months ago

Ich denke, wir fahren genauso fort mit den Conventional Commits, wie du vorgeschlagen hast, auch mit den englischen Kurzbezeichnungen.


Das klingt nach einem sehr guten Plan! Die Verwendung von Conventional Commits mit englischen Kurzbezeichnungen bietet mehrere Vorteile, insbesondere in Bezug auf die Automatisierung und die Skalierbarkeit deines Projekts. Hier sind einige Tipps, um den Übergang zu diesem System zu erleichtern und es effektiv zu nutzen:

1. Einrichten eines klaren Commit-Nachrichtenformats

Stelle sicher, dass jede Commit-Nachricht einem einheitlichen Format folgt, das den Typ der Änderung (wie feat, fix, docs usw.), den betroffenen Bereich und eine kurze, klare Beschreibung umfasst. Beispiel:

feat(login): add captcha to login form

Dies erleichtert das spätere Durchsuchen des Git-Verlaufs und die automatische Generierung von Release Notes.

2. Automatisierung der Release-Notes

Integriere Tools wie Release Drafter in deinen GitHub-Workflow, um auf Basis deiner Conventional Commits automatisch Release Notes zu generieren. Diese Tools können die Commit-Nachrichten analysieren und entsprechend formatierte und kategorisierte Release Notes erstellen.

3. Verwendung von Commit-Linting-Tools

Erwäge die Verwendung von Tools wie commitlint, die dabei helfen, die Einhaltung der Conventional Commit-Konventionen zu überwachen. Dies kann besonders hilfreich sein, um Konsistenz zu wahren, wenn das Projekt wächst oder wenn mehr Entwickler beteiligt sind.

4. Schulung und Dokumentation

Da du derzeit alleine arbeitest, ist es einfacher, neue Prozesse einzuführen. Dennoch ist es eine gute Idee, eine Dokumentation zu erstellen, die deine Commit-Konventionen und den Release-Prozess erklärt. Dies wird zukünftigen Mitarbeitern oder dir selbst helfen, die getroffenen Entscheidungen und Prozesse nachzuvollziehen.

5. Integration in den CI/CD-Workflow

Stelle sicher, dass deine Continuous Integration (CI) und Continuous Deployment (CD) Pipelines gut mit den Conventional Commits harmonieren. Du könntest zum Beispiel automatische Versionssprünge oder das Deployment basierend auf dem Typ der Commits konfigurieren.

6. Regelmäßige Überprüfungen und Anpassungen

Überprüfe regelmäßig die Effektivität deiner Conventional Commit-Strategie und passe sie bei Bedarf an. Dies könnte bedeuten, neue Typen hinzuzufügen, die Beschreibungen zu verfeinern oder die Automatisierung zu erweitern.

Durch die Verwendung von Conventional Commits legst du ein starkes Fundament für ein nachhaltiges Projektmanagement, das sowohl automatisierte Prozesse unterstützt als auch die manuelle Last bei der Verwaltung von Releases reduziert. Wenn du noch Fragen hast oder Unterstützung bei der Implementierung benötigst, stehe ich dir gerne zur Verfügung!

kurmann commented 6 months ago

Ich arbeite mit Visual Studio Code. Ich bin interessiert an einem Prüfmechanismus ähnlich wie CommitLint.


Für Visual Studio Code gibt es verschiedene Erweiterungen und Konfigurationen, die dir helfen können, ähnlich wie CommitLint deine Commit-Nachrichten zu prüfen und sicherzustellen, dass sie den Conventional Commits-Konventionen entsprechen. Hier sind einige Schritte, die du durchführen kannst, um eine solche Funktionalität in VS Code zu implementieren:

1. Husky und commitlint einrichten

Zuerst kannst du commitlint zusammen mit Husky in deinem Projekt einrichten. Husky ermöglicht es dir, Git Hooks einfach zu handhaben, und commitlint prüft, ob deine Commit-Nachrichten den festgelegten Konventionen entsprechen.

Schritt-für-Schritt-Anleitung:

a. Installiere die benötigten Pakete:

   npm install --save-dev @commitlint/config-conventional @commitlint/cli husky

b. Konfiguriere commitlint: Erstelle eine Datei namens commitlint.config.js im Wurzelverzeichnis deines Projekts:

   module.exports = {
     extends: ['@commitlint/config-conventional'],
   };

c. Aktiviere Husky und füge den commit-msg Hook hinzu: Füge folgendes Script zu deinem package.json hinzu, oder führe es in deiner Kommandozeile aus, um Husky zu konfigurieren und den commit-msg Hook zu setzen:

   {
     "husky": {
       "hooks": {
         "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
       }
     }
   }

Oder benutze Husky's neue Methode (falls du Husky v5 oder höher benutzt):

   npx husky add .husky/commit-msg "npx commitlint --edit $1"

2. VS Code Erweiterungen für Conventional Commits

Es gibt auch Erweiterungen in VS Code, die dir helfen können, deine Commit-Nachrichten zu formatieren:

Conventional Commits Extension:

Schritte zur Nutzung der Extension:

3. Integration überprüfen

Nachdem du alles eingerichtet hast, versuche, einen Commit zu machen. Wenn die Nachricht nicht den Regeln von commitlint entspricht, solltest du eine Fehlermeldung in deinem Terminal sehen, die dich darauf hinweist, was korrigiert werden muss.

Durch die Kombination dieser Tools und Erweiterungen in deinem Entwicklungsworkflow kannst du sicherstellen, dass deine Commits konsistent sind und den Best Practices entsprechen, was die Wartung des Projekts und die automatisierte Erstellung von Release Notes erleichtert.

kurmann commented 6 months ago

Herzlichen Dank, jetzt weiss ich, wie es funktionieren würde. Ich lasse diesen Schritt momentan noch aus, weil es sonst einfach zu viel ist für den Moment. Kannst du mir nochmal zusammenfassen, am besten in Markdown, damit ich das gleich in GitHub dokumentieren kann, auf was ich achten muss, wenn ich finalisierende Commits schreiben will und Conventional Commits einsetzen möchte.


Natürlich, hier ist eine zusammenfassende Dokumentation im Markdown-Format, die du für deine GitHub-Projektdokumentation verwenden kannst. Diese Zusammenfassung gibt dir einen Überblick darüber, wie du finalisierende Commits schreiben kannst und wie du die Conventional Commits-Richtlinien anwendest:

# Richtlinien für Conventional Commits

Conventional Commits bieten eine einfache Reihe von Regeln für das Erstellen konsistenter Commit-Nachrichten. Dies ermöglicht es, automatisierte Tools zu verwenden, um die Versionsverwaltung und die Generierung von Release-Notes zu erleichtern.

## Grundstruktur eines Conventional Commit

Jeder Commit sollte folgende Struktur haben:
(): [optional body] [optional footer] ``` ### Typ Der Typ deines Commits zeigt die Art der Änderungen an, die du im Commit durchführst. Typische Typen sind: - `feat`: Fügt eine neue Funktion hinzu. - `fix`: Behebt einen Fehler. - `docs`: Änderungen nur in der Dokumentation. - `style`: Änderungen, die den Stil betreffen, aber die Funktion nicht ändern. - `refactor`: Codeänderung, die weder einen neuen Fehler behebt noch eine neue Funktion hinzufügt. - `test`: Fügt fehlende Tests hinzu oder korrigiert bestehende Tests. - `chore`: Änderungen an der Build-Prozess oder Hilfs-Tools und Bibliotheken. ### Scope Der Scope ist optional und kann verwendet werden, um den Ort der Änderung anzugeben. Beispiele für Scopes sind Modulnamen, Dateinamen oder andere logisch abgrenzbare Komponenten deines Projekts. ### Beschreibung Die Beschreibung enthält eine prägnante Erklärung der Änderungen. Sie sollte klar und direkt sein. ## Finalisierende Commits Für finalisierende Commits, die den Abschluss eines Features oder eine wesentliche Änderung markieren, sollten folgende zusätzliche Richtlinien beachtet werden: - **Verwende den Typ `feat` oder `fix`**, um die Wichtigkeit und den Einfluss der Änderung zu betonen. - **Gib einen klaren und spezifischen Scope an**, der den Bereich des Projekts identifiziert, den der Commit beeinflusst. - **Die Beschreibung sollte den Abschluss des Features oder der Änderung deutlich machen**. Beispiel: "Vervollständigen der Benutzerprofil-Überarbeitung." ## Beispiel ```text feat(profile): Vervollständigen der Benutzerprofil-Überarbeitung Dieser Commit führt die finale Version der neuen Benutzerprofile ein. Es umfasst die Überarbeitung des UI/UX, die Verbesserung der Datenvalidierung und die Optimierung der Abfrageeffizienz. BREAKING CHANGE: Ändert die Art und Weise, wie Benutzerdaten verarbeitet werden. Alte Datenmodelle sind nicht mehr kompatibel. ``` Durch die Verwendung dieser Richtlinien stellst du sicher, dass deine Commits informativ, nützlich und automatisierungsfreundlich sind. ``` Diese Richtlinien helfen dir, eine klare und effektive Commit-Geschichte zu pflegen, die es einfacher macht, Änderungen nachzuvollziehen und automatisierte Prozesse wie die Release-Erstellung zu unterstützen.
kurmann commented 6 months ago

Ich habe alles verstanden, aber den Ausdruck in den Klammern nicht. Beispielsweise Feature(Profile). Im Prinzip möchtest du ja hier einen Verweis auf das aktuelle Feature machen. Ist dann das Wort Profile eine Kurzversion davon? Ist es überhaupt nötig? Und überhaupt, ich verstehe es nicht ganz.


Ganz genau, der Ausdruck in den Klammern bei einem Conventional Commit, bekannt als scope, ist optional und dient dazu, den Kontext oder den spezifischen Bereich des Projekts zu spezifizieren, der von dem Commit betroffen ist. Dieser Kontext kann helfen, die Commits im Repository besser zu organisieren und auf einen Blick zu verstehen, welche Teile des Projekts von einer Änderung betroffen sind.

Verwendung des Scope

Der scope gibt an, welcher Teil des Projekts durch den Commit modifiziert wird. In einem größeren Projekt, das aus vielen Modulen oder Komponenten besteht, kann der scope dazu verwendet werden, den spezifischen Bereich klarzustellen. Einige Beispiele:

Ist der Scope nötig?

Beispiel ohne Scope

Wenn du entscheidest, dass der Scope für dein Projekt nicht nötig ist oder eine bestimmte Commit-Nachricht keinen spezifischen Bereich betrifft, kannst du ihn weglassen:

feat: add captcha to login form

Beispiel mit Scope

Wenn du jedoch das Gefühl hast, dass der Scope zur Klarheit beiträgt, besonders in einem größeren oder modulareren Projekt, kannst du ihn einfügen:

feat(login): add captcha to login form

Hier bedeutet login, dass die Änderung spezifisch für den Login-Bereich oder die Login-Seite der Anwendung ist.

Entscheidungskriterien

Letztendlich hängt die Entscheidung, ob und wie du Scopes verwendest, von deinen spezifischen Projektanforderungen und deinen Vorlieben ab. Die konsequente Verwendung einmal gewählter Konventionen ist jedoch wichtig für die Aufrechterhaltung einer klaren und nützlichen Commit-Historie.

kurmann commented 6 months ago

Nein, den Sinn darin sehe ich aktuell nicht, da ich einen modularen Monolithen verwende und für jedes Modul ein eigenes Git-Hub-Repository. Somit würde das wahrscheinlich wegfallen, weil der Scope nicht speziell definiert werden muss, weil schon klein genug. Kannst du mir bitte die Markdown-Dokumentation nochmals aktualisieren? Danke.


Absolut, das macht Sinn. Wenn jedes Modul sein eigenes Repository hat, ist der Scope oft redundant, weil der Kontext bereits durch das Repository selbst gegeben ist. Hier ist die aktualisierte Markdown-Dokumentation ohne die Verwendung von Scope, die du in dein GitHub-Repository integrieren kannst:

# Richtlinien für Conventional Commits

Conventional Commits bieten eine einfache Reihe von Regeln für das Erstellen konsistenter Commit-Nachrichten. Dies ermöglicht es, automatisierte Tools zu verwenden, um die Versionsverwaltung und die Generierung von Release-Notes zu erleichtern.

## Grundstruktur eines Conventional Commit

Jeder Commit sollte folgende Struktur haben:
: [optional body] [optional footer] ``` ### Typ Der Typ deines Commits zeigt die Art der Änderungen an, die du im Commit durchführst. Typische Typen sind: - `feat`: Fügt eine neue Funktion hinzu. - `fix`: Behebt einen Fehler. - `docs`: Änderungen nur in der Dokumentation. - `style`: Änderungen, die den Stil betreffen, aber die Funktion nicht ändern. - `refactor`: Codeänderung, die weder einen neuen Fehler behebt noch eine neue Funktion hinzufügt. - `test`: Fügt fehlende Tests hinzu oder korrigiert bestehende Tests. - `chore`: Änderungen an der Build-Prozess oder Hilfs-Tools und Bibliotheken. ### Beschreibung Die Beschreibung enthält eine prägnante Erklärung der Änderungen. Sie sollte klar und direkt sein. ## Finalisierende Commits Für finalisierende Commits, die den Abschluss eines Features oder eine wesentliche Änderung markieren, sollten folgende zusätzliche Richtlinien beachtet werden: - **Verwende den Typ `feat` oder `fix`**, um die Wichtigkeit und den Einfluss der Änderung zu betonen. - **Die Beschreibung sollte den Abschluss des Features oder der Änderung deutlich machen**. Beispiel: "Vervollständigen der Benutzerprofil-Überarbeitung." ## Beispiel ```text feat: complete major overhaul of user profiles Dieser Commit führt die finale Version der neuen Benutzerprofile ein. Es umfasst die Überarbeitung des UI/UX, die Verbesserung der Datenvalidierung und die Optimierung der Abfrageeffizienz. BREAKING CHANGE: Ändert die Art und Weise, wie Benutzerdaten verarbeitet werden. Alte Datenmodelle sind nicht mehr kompatibel. ``` Durch die Verwendung dieser Richtlinien stellst du sicher, dass deine Commits informativ, nützlich und automatisierungsfreundlich sind. ``` Diese Richtlinien helfen dir, eine klare und effektive Commit-Geschichte zu pflegen, die es einfacher macht, Änderungen nachzuvollziehen und automatisierte Prozesse wie die Release-Erstellung zu unterstützen.
kurmann commented 6 months ago

Verstanden. Jetzt nochmals zurück bitte zur vorangehenden Diskussion. Ich gehe davon aus, dass es sinnvoll ist, nur einen Conventional Commit Pro Feature zu verwenden. Ansonsten wird möglicherweise wahrscheinlich immer das Neueste übernommen. Wo genau und wie funktioniert jetzt das Zusammenführen in Release Nodes? Mir ist bewusst, dass das mit dem Release-Drafter passiert. Grundsätzlich möchte ich mit jedem neuen Feature die Major- oder Minor-Version erhören und ich müsste das auch irgendwo festlegen. Dann müssten die Commit-Nachrichten zusammengeführt werden in einen existierenden Chatslog unter dieser Versionsnummer. Ich habe das immer noch nicht genau verstanden, wie das jetzt funktioniert.


Um den Prozess zu klären und zu verstehen, wie Release Drafter in Kombination mit Conventional Commits funktioniert, ist es wichtig, einige Details über das Management von Versionen und das Zusammenführen von Commit-Nachrichten in Release Notes zu kennen. Release Drafter nutzt die Informationen aus deinen Commit-Nachrichten oder Pull Requests, um automatisch Release Notes zu generieren und die Versionen deines Projekts entsprechend zu aktualisieren.

Schritt-für-Schritt-Anleitung für Release Drafter

1. Einrichtung des Release Drafter

Zuerst musst du Release Drafter in deinem Repository einrichten, indem du eine Konfigurationsdatei .github/release-drafter.yml erstellst. In dieser Datei definierst du, wie deine Release Notes strukturiert und wie Versionen gehandhabt werden sollen.

2. Konfiguration von Versionierung

Wenn du möchtest, dass jede neue Feature-Einführung die Major- oder Minor-Version erhöht, musst du dies in deinen Commit-Nachrichten entsprechend kennzeichnen. Du kannst dies mit den Labels major oder minor tun, die du deinen Conventional Commit-Nachrichten hinzufügst.

version-resolver:
  major:
    labels:
      - 'major'
  minor:
    labels:
      - 'minor'
  patch:
    labels:
      - 'fix'
    default: 'patch'

In deinen Commit-Nachrichten könntest du beispielsweise folgendes verwenden:

feat(user-profile): add new fields to user profiles #minor

BREAKING CHANGE: Requires database migration

Hierbei bewirkt das #minor im Titel oder das BREAKING CHANGE im Text, dass der Release Drafter automatisch versteht, dass eine neue Minor-Version erstellt werden sollte.

3. Automatisches Generieren von Release Notes

Release Drafter erstellt basierend auf deinen Commits oder den gemergten Pull Requests automatisch Release Notes. Die Commits werden unter den Versionen zusammengefasst, die du durch deine Tags oder durch die Konvention in den Commits festlegst.

Hier ein Beispiel für die Struktur in deiner Release-Drafter-Konfiguration, die bestimmt, wie die Release Notes formatiert werden:

template: |
  ## Changes in $NEXT_MINOR_VERSION
  $CHANGES

categories:
  - title: 'New Features'
    labels:
      - 'feat'
  - title: 'Bug Fixes'
    labels:
      - 'fix'
  - title: 'Improvements'
    labels:
      - 'chore'

4. Verwendung von GitHub Actions

Um Release Drafter bei jedem Merge in deinen main-Branch zu aktivieren, kannst du eine GitHub Action definieren, die bei bestimmten GitHub Events ausgelöst wird, wie z.B. beim Merging eines Pull Requests.

name: Release Drafter

on:
  push:
    branches:
      - main

jobs:
  update_release_draft:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: release-drafter/release-drafter@v5
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Zusammenfassung

Mit Release Drafter und Conventional Commits kannst du einen automatisierten Prozess einrichten, der die Erstellung und Verwaltung deiner Release Notes vereinfacht und gleichzeitig eine systematische Versionierung deiner Software ermöglicht. Indem du bestimmte Regeln in deinen Commit-Nachrichten definierst und Release Drafter entsprechend konfigurierst, kannst du sicherstellen, dass deine Release Notes immer aktuell und korrekt sind.

kurmann commented 6 months ago

Herzlichen Dank für deine Zusammenfassung. Ich werde das nun angehen. Ich nehme mit, dass auch hier wieder viel Eleganz dabei ist. Beispielsweise kann ich einfach den Minor oder Major Änderungen definieren, indem ich Tags verwende. Ich bin immer noch ein bisschen unsicher, ob ich wirklich Release Branches verwenden soll, weil ich ja oft alleine arbeite. Aber gleichzeitig nimmt mir das auch etwas die Möglichkeit, Einfluss zu nehmen, welches Feature nun Minor ist oder welches ein Major Release ist.


Es freut mich zu hören, dass die Zusammenfassung hilfreich für dich war! Die Entscheidung, ob du Release Branches verwenden solltest, hängt stark von deinem persönlichen Workflow, der Größe und Komplexität deines Projekts sowie von deinen Präferenzen für die Release-Verwaltung ab. Hier sind einige Überlegungen, die dir bei deiner Entscheidung helfen könnten:

Vorteile der Verwendung von Release Branches

  1. Klar definierte Phasen: Release Branches ermöglichen es, klar zwischen Entwicklungs-, Test- und Freigabephase zu trennen. Du kannst in einem Release Branch alle finalen Tests durchführen und letzte Anpassungen vornehmen, ohne den Hauptentwicklungszweig (main) zu beeinträchtigen.

  2. Flexibilität bei Releases: Mit einem dedizierten Release Branch kannst du entscheiden, wann ein Feature "release-fähig" ist und es entsprechend als Minor oder Major kennzeichnen. Dies gibt dir die Kontrolle darüber, wie Änderungen klassifiziert und veröffentlicht werden.

  3. Hotfixes und Patches: Release Branches erleichtern das Management von Hotfixes. Du kannst schnell Patches auf einem Release Branch erstellen und veröffentlichen, ohne andere in Entwicklung befindliche Features zu beeinflussen.

Nachteile oder Herausforderungen

  1. Zusätzlicher Verwaltungsaufwand: Die Verwaltung mehrerer Branches kann insbesondere für Einzelpersonen oder kleine Teams zusätzlichen Aufwand bedeuten. Es erfordert Disziplin in der Branch-Verwaltung und könnte den Entwicklungsprozess verlangsamen.

  2. Komplexität: Wenn du viele kleine Updates hast oder kontinuierlich lieferst, kann die ständige Erstellung und Pflege von Release Branches überflüssig und mühsam sein.

Alternativen

Wenn du dir unsicher bist, ob Release Branches für dich das Richtige sind, könntest du auch einen vereinfachten Workflow in Betracht ziehen:

Fazit

Letztendlich hängt die Entscheidung, ob Release Branches verwendet werden sollen, von deinen spezifischen Anforderungen und deinem Arbeitsstil ab. Wenn du häufig alleine arbeitest und schnell auf Veränderungen reagieren möchtest, könnte ein direktes Arbeiten im main-Branch mit gut organisierten Commit-Nachrichten und automatisierten Release-Tools ausreichend sein. Wenn du jedoch mehr Kontrolle über die Stabilität und das Timing deiner Releases benötigst, könnten dedizierte Release Branches eine wertvolle Struktur bieten.

kurmann commented 6 months ago

Direkt im Mainbranch zu entwickeln, würde sich schon wieder anbieten, weil ich jetzt ja anhand der Conventional Commits auf die Dokumentation via Pull-Request verzichten kann. Es würde mir den Workflow wesentlich vereinfachen. Das Einzige, wo ich noch etwas skeptisch bin, ist, wenn ich ein Feature baue, dessen Einsatz ich noch nicht sicher bin, ob ich überhaupt diesen im Main einsetzen möchte. Ich müsste dann auf Git-Revert setzen, was aber kein Problem wäre, weil ich ja alleine bin im aktuellen Zeitpunkt.


Das direkte Entwickeln im main-Branch kann tatsächlich den Workflow vereinfachen, besonders wenn du allein arbeitest und einen schnellen, unkomplizierten Entwicklungszyklus bevorzugst. Die Verwendung von Conventional Commits und automatisierten Tools für die Generierung von Release Notes kann helfen, den Prozess weiter zu straffen und den Überblick zu behalten.

Umgang mit unsicheren Features

Für Features, bei denen du dir unsicher bist, ob sie in den main-Branch aufgenommen werden sollen, gibt es mehrere Ansätze, die du in Betracht ziehen kannst, ohne dass du auf komplexe Branching-Strategien zurückgreifen musst:

  1. Feature Flags: Eine effektive Methode, um Features zu entwickeln, die möglicherweise nicht sofort freigegeben werden, ist die Verwendung von Feature Flags. Diese ermöglichen es dir, neue Funktionen im Code zu implementieren und zu mergen, ohne dass sie für alle Benutzer sichtbar sind. Du kannst die Features dann schrittweise für bestimmte Benutzergruppen oder Umgebungen aktivieren und hast die volle Kontrolle darüber, wann und wie diese Features veröffentlicht werden.

  2. Git Revert: Wenn du ein Feature entwickelst und später entscheidest, dass es nicht im main-Branch sein sollte, kannst du git revert verwenden, um die Änderungen rückgängig zu machen. Dies ist eine saubere Methode, um Änderungen zu entfernen, ohne die Historie zu beeinträchtigen, da git revert einen neuen Commit erzeugt, der die Änderungen des ursprünglichen Commits rückgängig macht.

  3. Draft Pull Requests: Auch wenn du hauptsächlich alleine arbeitest, könnten Draft Pull Requests nützlich sein. Sie ermöglichen es dir, Änderungen zu pushen und zu sehen, wie sie im Kontext des gesamten Projekts funktionieren, ohne dass sie fertig oder für den Merge bestimmt sind. Dies kann eine gute Option sein, um experimentelle oder unvollständige Features zu testen.

Beispiel für die Nutzung von Feature Flags

Hier ist ein einfaches Beispiel, wie ein Feature Flag im Code implementiert werden könnte:

if (featureFlags.NEW_USER_PROFILE_ENABLED) {
    // Neuer Code für das überarbeitete Benutzerprofil
} else {
    // Alter Code
}

Die Feature Flags können in deiner Konfigurationsdatei, einer Umgebungsvariablen oder in einer Datenbank gespeichert werden, abhängig davon, was für deine Anwendung am besten geeignet ist.

Fazit

Das direkte Entwickeln im main-Branch mit einer Kombination aus Conventional Commits, Feature Flags und gegebenenfalls dem gelegentlichen Einsatz von git revert kann eine flexible und effiziente Arbeitsweise darstellen. Diese Strategie ermöglicht es dir, schnell zu entwickeln und gleichzeitig die Freiheit zu haben, Änderungen vorzunehmen oder zurückzuziehen, ohne die Stabilität deines Projekts zu beeinträchtigen.

kurmann commented 6 months ago

Du musst wissen, im Moment arbeite ich alleine, aber ich müsste vorbereitet sein, wenn mir mal jemand helfen möchte. So möchte ich durchaus den MainBranch schützen und das andere Entwickler-Feature machen müssen und den Weg über den Pull-Request machen müssen. Ich selbst würde mir aber die Option offen halten, den MainBranch zu benutzen. Das heisst, ich müsste einen Workflow haben, der rein mit Commit-Nachrichten arbeitet, damit das Vorgehen gleich bleibt ob bei Feature- oder Main-Branch.


Das klingt nach einem durchdachten Ansatz, der dir Flexibilität für die alleinige Entwicklung bietet und gleichzeitig eine solide Grundlage für zukünftige Zusammenarbeit mit anderen Entwicklern schafft. Hier ist, wie du deine Git-Strategie und deine GitHub-Einstellungen konfigurieren kannst, um den main-Branch zu schützen und gleichzeitig eine konsistente Commit-Strategie zu verwenden:

Schutz des main-Branches

  1. Branch-Schutzregeln: Gehe auf GitHub zu deinem Repository, navigiere zu "Settings" > "Branches" und füge Schutzregeln für den main-Branch hinzu. Du kannst festlegen, dass Pull Requests erforderlich sind, bevor Änderungen gemerged werden können, und dass Checks (wie Tests oder Linting) bestanden sein müssen. Hier kannst du auch Ausnahmen für bestimmte Benutzer oder Teams definieren, z.B. dass du selbst direkt auf main pushen darfst.

  2. Erforderliche Reviews: Du kannst einstellen, dass mindestens ein Review erforderlich ist, bevor ein Pull Request gemerged werden kann. Dies fördert die Code-Qualität und Zusammenarbeit, auch wenn du derzeit alleine arbeitest.

Einheitliche Commit-Nachrichten

Um eine konsistente Nutzung von Commit-Nachrichten über Feature-Branches und den main-Branch zu gewährleisten, kannst du Folgendes tun:

  1. Conventional Commits: Implementiere die Conventional Commits-Konvention in deinem gesamten Repository. Dies hilft dabei, die Geschichte klar und nachvollziehbar zu halten und erleichtert die Automatisierung von Release Notes und Versionierung durch Tools wie Release Drafter.

  2. Commitlint Tool: Setze ein Tool wie commitlint ein, das sicherstellt, dass alle Commits, die in das Repository eingehen (egal ob durch dich oder andere), den festgelegten Konventionen entsprechen. commitlint kann sowohl lokal in deinem Entwicklungsumfeld als auch als Teil deiner CI/CD-Pipeline eingerichtet werden.

  3. GitHub Actions für Conventional Commits: Richte eine GitHub Action ein, die überprüft, ob alle Commits in einem Pull Request den Conventional Commits-Richtlinien entsprechen. Dies kann automatisch als Check für jeden Pull Request durchgeführt werden.

Beispiel für eine GitHub Action mit commitlint

Hier ist ein einfaches Beispiel, wie du commitlint in deinem GitHub-Workflow integrieren kannst:

name: Lint Commit Messages
on: [pull_request]

jobs:
  commitlint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        fetch-depth: 0
    - uses: wagoid/commitlint-github-action@v4

Dieser Workflow wird jedes Mal ausgelöst, wenn ein Pull Request erstellt oder aktualisiert wird, und überprüft, ob die Commits den festgelegten Richtlinien entsprechen.

Fazit

Indem du den main-Branch schützt und klare Richtlinien für Commits festlegst, stellst du sicher, dass dein Projekt auch dann robust und gut organisiert bleibt, wenn du beginnst, mit anderen zusammenzuarbeiten. Gleichzeitig behältst du die Flexibilität, schnell Änderungen vornehmen zu können, indem du dir selbst erlaubst, direkt auf main zu pushen. Dieser Ansatz unterstützt sowohl solo als auch kollaboratives Arbeiten effektiv.

kurmann commented 6 months ago

Mir gefällt die Richtung, in die wir derzeit gehen. Ich füge viel Automatismus ein und mache trotzdem das Projekt aktuell nicht unnötig komplex. Die einzige offene Frage ist jetzt noch die Verwendung von GitHub Tags. Wenn ich Conventional Commits verwende und auch die Versionierung selbst automatisch ist anhand von den Tags in den Conventional Commits, brauche ich dann die GitHub Tags noch? Und falls ich sie nicht brauche, welche Vorteile würden sie mir überhaupt noch bieten? Ich könnte mir auch vorstellen, dass die Tags dann mit einem GitHub-Workflow gesetzt werden, damit ich mich nicht um das auch noch kümmern möchte. Die Versionsverwaltung möchte ich weitgehend automatisieren, auch die Release-Note-Dokumentation und natürlich später noch die Nugget-Paketierung.


Es ist großartig zu sehen, dass du eine klare Vision hast, wie du Automatisierung nutzen möchtest, um dein Projekt effizient zu verwalten. Lass uns die Verwendung von GitHub Tags im Kontext von automatisierter Versionierung und deren möglichen Nutzen untersuchen.

Bedeutung von Git Tags im automatisierten Workflow

  1. Versionsmarkierung: Git Tags sind besonders nützlich, um spezifische Versionen deines Codes zu markieren. Sie erstellen einen festen Punkt im Git-Verlauf, der genau repräsentiert, was in einer bestimmten Version enthalten ist. Dies ist wichtig für die Nachvollziehbarkeit und insbesondere wichtig, wenn du Versionen explizit veröffentlichen möchtest, z.B. in Form von Software-Releases oder Paketen.

  2. Release Management: Tags werden häufig genutzt, um Releases in GitHub zu steuern. Wenn ein neuer Tag erstellt wird, kann das als Trigger für die Erstellung eines neuen GitHub Release dienen, welches automatisch die aus den Conventional Commits generierten Release Notes enthält.

Automatisierung des Tagging-Prozesses

Da du eine weitgehende Automatisierung anstrebst, kannst du den Tagging-Prozess und die Erstellung von GitHub Releases in deinen CI/CD-Workflow integrieren. Hier sind ein paar Möglichkeiten, wie dies funktionieren kann:

  1. Semantic Versioning Automation: Tools wie semantic-release analysieren deine Commits (basierend auf Conventional Commits) und bestimmen die nächste Version deines Projekts automatisch. Sie können auch Tags setzen und Releases auf GitHub erstellen, basierend auf den Änderungen, die seit dem letzten Release gemacht wurden.

  2. GitHub Actions für Continuous Deployment: Du kannst GitHub Actions nutzen, um Tags zu setzen und Releases zu erstellen, sobald Änderungen in deinen main-Branch gemerged werden. Dies sorgt dafür, dass die Versionsverwaltung nahtlos und ohne manuellen Eingriff erfolgt.

Beispiel: Automatisierung mit semantic-release

Hier ist ein Beispiel, wie du semantic-release in deinen GitHub Actions Workflow integrieren könntest:

name: Continuous Deployment
on:
  push:
    branches:
      - main

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Install dependencies
        run: npm install
      - name: Semantic Release
        uses: cycjimmy/semantic-release-action@v2
        with:
          semantic_version: 17
          extra_plugins: |
            @semantic-release/changelog
            @semantic-release/git
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Vorteile der Verwendung von Git Tags

Schlussfolgerung

Wenn du eine vollautomatisierte Pipeline einrichtest, die sowohl die Versionierung als auch das Erstellen von Release Notes und das Setzen von Tags umfasst, kannst du viel manuellen Aufwand einsparen und gleichzeitig eine hohe Konsistenz und Qualität in der Verwaltung deiner Releases sicherstellen. Tags bieten in diesem Kontext sowohl für die Verwaltung als auch für die Nutzung deiner Software wesentliche Vorteile.

kurmann commented 6 months ago

Lass uns dies tun. Mir gefällt dieser Ansatz. Den Workflow, den du mir gezeigt hast, möchte ich gerne wiederverwendbar machen. Ich habe mehrere GitHub-Repositories und ich möchte diesen Continuous Deployment Workflow aufrufen. Das heisst, ich muss klare Eingabe- und Ausgabeparameter haben. Wie könnte ich das lösen, damit ich einen Reusable Workflow bekomme?


Um einen wiederverwendbaren Workflow in GitHub zu erstellen, der für mehrere Repositories verwendet werden kann, musst du den Workflow so definieren, dass er parametrisierbar ist. Hier sind die Schritte und ein Beispiel, wie du einen solchen Workflow erstellen und verwenden kannst:

1. Workflow-Datei erstellen

Erstelle in einem zentralen Repository, das du als Quelle für deine wiederverwendbaren Workflows verwenden möchtest, eine Workflow-Datei unter .github/workflows/. Diese Datei enthält die Definition des wiederverwendbaren Workflows.

2. Definition des wiederverwendbaren Workflows

In der Workflow-Datei definierst du Inputs, die von außen gesetzt werden können, und den eigentlichen Job, der ausgeführt werden soll. Hier ist ein Beispiel für einen wiederverwendbaren Workflow für Continuous Deployment mit semantic-release:

name: 'Reusable Continuous Deployment'
on:
  workflow_call:
    inputs:
      node_version:
        description: 'Node.js version'
        required: true
        default: '14'
      semantic_version:
        description: 'Semantic Release version'
        required: false
        default: '17'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: ${{ inputs.node_version }}
      - name: Install dependencies
        run: npm install
      - name: Run Semantic Release
        uses: cycjimmy/semantic-release-action@v2
        with:
          semantic_version: ${{ inputs.semantic_version }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3. Workflow in anderen Repositories verwenden

Um diesen wiederverwendbaren Workflow in einem anderen Repository zu verwenden, erstellst du dort eine Workflow-Datei, die den wiederverwendbaren Workflow aufruft. Hier ist, wie du diesen Workflow aufrufen kannst:

name: 'Deploy Project'

on:
  push:
    branches:
      - main

jobs:
  deploy:
    uses: your-username/your-repository/.github/workflows/reusable_cd.yml@main
    with:
      node_version: '14'
      semantic_version: '17'
    secrets:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Vorteile wiederverwendbarer Workflows

Durch die Definition eines solchen wiederverwendbaren Workflows kannst du den Deployment-Prozess über mehrere Repositories hinweg standardisieren und automatisieren, was Zeit spart und die Zuverlässigkeit deiner Releases erhöht.

kurmann commented 6 months ago

Warum muss ich beim Aufruf die Node-Version und die Semantic-Version mitgeben? Ich hätte jetzt erwartet, dass sich dieses Problem mit der Versionierung innerhalb des Reusable-Workflows gemanagt wird.


Das Konzept, die Node-Version und die Semantic-Release-Version als Parameter zu übergeben, bietet Flexibilität und Kontrolle für jedes Repository, das den wiederverwendbaren Workflow verwendet. Diese Flexibilität kann jedoch je nach deinem Projektbedarf als unnötig oder als eine zusätzliche Komplexitätsebene empfunden werden. Lassen uns die Vor- und Nachteile von beiden Ansätzen anschauen:

Warum Parameter verwenden?

  1. Flexibilität: Verschiedene Projekte können unterschiedliche Anforderungen an die Version von Node.js oder Semantic Release haben. Indem du diese als Parameter übergibst, kannst du den gleichen Workflow für unterschiedliche Projektkonfigurationen verwenden, ohne Änderungen am Workflow selbst vornehmen zu müssen.

  2. Zukunftssicherheit: Wenn neue Versionen von Node.js oder Semantic Release veröffentlicht werden, kannst du einfach den Parameter in den Workflow-Aufrufen aktualisieren, ohne den wiederverwendbaren Workflow selbst bearbeiten zu müssen. Dies kann hilfreich sein, um schnelle Updates über mehrere Projekte hinweg zu ermöglichen.

Warum feste Werte innerhalb des Workflows verwenden?

  1. Einfachheit: Das Festlegen von spezifischen Versionen innerhalb des Workflows verringert die Komplexität beim Aufrufen des Workflows. Alle Repositories verwenden die gleiche Konfiguration, was die Verwaltung erleichtert.

  2. Weniger Fehleranfälligkeit: Wenn du weißt, dass alle deine Projekte kompatibel mit einer bestimmten Version von Node.js oder Semantic Release sind, minimiert das Festlegen dieser Versionen im Workflow das Risiko von Konfigurationsfehlern in den verschiedenen Projekten.

Lösungsansätze

Wenn du entscheidest, dass die Flexibilität nicht benötigt wird und du lieber eine einfachere Lösung bevorzugst, kannst du die Versionen direkt im Workflow festlegen und den Schritt des Übergabeparameters weglassen. Hier ist, wie der Workflow ohne die Übergabeparameter aussehen könnte:

name: 'Reusable Continuous Deployment'
on:
  workflow_call:

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'  # Direkt festgelegt
      - name: Install dependencies
        run: npm install
      - name: Run Semantic Release
        uses: cycjimmy/semantic-release-action@v2
        with:
          semantic_version: '17'  # Direkt festgelegt
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Und hier ist, wie du diesen wiederverwendbaren Workflow ohne Parameterübergabe aufrufen würdest:

name: 'Deploy Project'

on:
  push:
    branches:
      - main

jobs:
  deploy:
    uses: your-username/your-repository/.github/workflows/reusable_cd.yml@main
    secrets:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Durch das Festlegen der Versionen direkt im wiederverwendbaren Workflow reduzierst du die Komplexität und vermeidest Fehler bei der Konfiguration in den aufrufenden Repositories. Du musst jedoch bedenken, dass Änderungen an diesen Versionen das Bearbeiten des zentralen Workflows erfordern würden, was wiederum eine Änderung in allen Projekten, die diesen Workflow verwenden, nach sich zieht.

kurmann commented 6 months ago

Du hast grundsätzlich recht mit deiner Argumentation. Angenommen, ich würde eine neue Node-Version oder eine neue Semantic-Version haben, die Bracking Changes verursacht, dann habe ich ja sonst keine vernünftige Möglichkeit, diese gestaffelt in den anderen Git-Repositories anzuwenden.


Genau, das ist ein wichtiger Aspekt, den du ansprichst. Die Möglichkeit, Versionsnummern von Node.js und Semantic Release (oder anderen Tools) dynamisch anzupassen, bietet dir eine größere Kontrolle über das Upgrade-Verfahren. Dies ist besonders nützlich, wenn Änderungen Breaking Changes beinhalten oder wenn du schrittweise Upgrades über mehrere Projekte hinweg durchführen möchtest.

Vorteile der Parametrisierung von Versionsnummern:

  1. Flexibilität bei Upgrades: Du kannst spezifische Projekte auf neue Versionen aktualisieren und sehen, wie sich die Änderungen auswirken, bevor du dasselbe Upgrade in allen Projekten durchführst. Dies ist besonders wichtig bei Major-Releases oder wenn du mögliche Kompatibilitätsprobleme antizipierst.

  2. Risikomanagement: Durch die stufenweise Einführung neuer Versionen kannst du potenzielle Probleme isolieren und beheben, ohne alle Projekte gleichzeitig zu gefährden. Du hast die Möglichkeit, ein Upgrade rückgängig zu machen, wenn es zu Problemen kommt, ohne dass dies Auswirkungen auf andere Projekte hat.

  3. Testen neuer Versionen: Du kannst in bestimmten Repositories experimentieren, indem du neueste oder spezifische Versionen von Tools testest, ohne dass dies Auswirkungen auf den Hauptentwicklungszweig oder auf stabil laufende Projekte hat.

Implementierung dynamischer Versionierung in GitHub Actions:

Wenn du dich dafür entscheidest, die Versionierung dynamisch zu halten, kannst du die Versionsnummern als Inputs in deinen wiederverwendbaren Workflows definieren. Hier ist, wie du den Workflow anpassen könntest, um diese Flexibilität zu ermöglichen:

name: 'Reusable Continuous Deployment'
on:
  workflow_call:
    inputs:
      node_version:
        description: 'Node.js version'
        required: true
        default: '14'
      semantic_version:
        description: 'Semantic Release version'
        required: true
        default: '17'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: ${{ inputs.node_version }}
      - name: Install dependencies
        run: npm install
      - name: Run Semantic Release
        uses: cycjimmy/semantic-release-action@v2
        with:
          semantic_version: ${{ inputs.semantic_version }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Durch die Verwendung von Inputs für die Versionsnummern in deinen Workflows kannst du auf einfache Weise steuern, welche Version in jedem Projekt verwendet wird. Dies bietet dir eine gute Balance zwischen Automatisierung und Kontrolle über den Software-Release-Prozess in verschiedenen Repositories.

Fazit:

Die Wahl, ob du fest codierte Versionen oder parametrisierbare Inputs für deine Versionsnummern verwenden solltest, hängt von deinem Bedarf an Stabilität, Flexibilität und Kontrolle ab. Die Parametrisierung kann mehr Aufwand bei der Konfiguration bedeuten, bietet jedoch erhebliche Vorteile beim Management von Änderungen und beim Testen neuer Software-Versionen.

kurmann commented 6 months ago

Die Abgrenzung des Reusable Workflows ist mir nicht ganz klar. Du hast ihn Reusable Continuous Deployment genannt. Aber im Prinzip ist das Continuous Deployment doch noch einiges grösser und ich werde wahrscheinlich mehrere Reusable Workflows brauchen. Kannst du noch oben in den Kommentaren gleich im YAML-File dokumentieren, was der Workflow nun konkret tut und was das Resultat ist und wahrscheinlich auch den Namen noch ändern. Soviel ich verstanden habe, lässt er den Run Semantic Release Zwischenschritt los. Ich weiss aber nicht, was dort genau passiert. Das sollte dokumentiert sein.


Du hast recht, es ist wichtig, den Zweck und die Funktionsweise des wiederverwendbaren Workflows klar zu definieren und zu dokumentieren, um Missverständnisse zu vermeiden und die Wartbarkeit zu verbessern. Ich werde die YAML-Konfiguration aktualisieren, um die Aufgaben und das erwartete Ergebnis des Workflows klar zu erläutern.

Verbesserter und dokumentierter Workflow

Wir benennen den Workflow um in "Node.js Semantic Release", da er spezifisch für das Release-Management von Node.js-Projekten mit Semantic Release konzipiert ist. Hier ist die aktualisierte und dokumentierte Version des Workflows:

name: Node.js Semantic Release
on:
  workflow_call:
    inputs:
      node_version:
        description: 'The version of Node.js to use. Default is 14.'
        required: false
        default: '14'
      semantic_version:
        description: 'The version of Semantic Release to use. Default is 17.'
        required: false
        default: '17'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      # Checkout the repository to the runner
      - name: Checkout code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      # Set up Node.js environment on the runner
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: ${{ inputs.node_version }}

      # Install project dependencies
      - name: Install dependencies
        run: npm install

      # Execute Semantic Release
      # This step handles version management and changelog generation based on Conventional Commits.
      # It automatically tags the release, updates the changelog, and publishes the package.
      - name: Run Semantic Release
        uses: cycjimmy/semantic-release-action@v2
        with:
          semantic_version: ${{ inputs.semantic_version }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Erklärung des Workflows

  1. Checkout code: Dieser Schritt holt den aktuellen Code aus dem GitHub-Repository auf den Runner. fetch-depth: 0 stellt sicher, dass die gesamte Git-Historie verfügbar ist, was für Tools wie Semantic Release notwendig ist, die auf Basis der Commit-Historie arbeiten.

  2. Setup Node.js: Dieser Schritt richtet die Node.js-Umgebung auf dem Runner ein. Die Version von Node.js kann über die Workflow-Inputs gesteuert werden, sodass verschiedene Versionen für verschiedene Projekte verwendet werden können.

  3. Install dependencies: Installiert alle Node.js-Abhängigkeiten des Projekts, die in der package.json definiert sind.

  4. Run Semantic Release: Dies ist der Kernschritt des Workflows. Semantic Release analysiert die Commits seit dem letzten Release und bestimmt die Art des nächsten Releases (major, minor oder patch) basierend auf den Conventional Commits. Es aktualisiert die Versionsnummer, generiert eine changelog und erstellt einen Git-Tag. Anschließend kann es das Release auch automatisch auf GitHub veröffentlichen und, falls konfiguriert, das Paket auf npm oder anderen Registries veröffentlichen.

Schlussfolgerung

Durch die klare Definition und Dokumentation im Workflow kannst du sicherstellen, dass der Prozess für dich und andere Nutzer verständlich ist. Außerdem bietet die Parametrisierung die nötige Flexibilität, um den Workflow in verschiedenen Projekten mit möglicherweise unterschiedlichen Anforderungen zu verwenden. Dies erleichtert das Management und sorgt für konsistente Release-Praktiken über mehrere Projekte hinweg.

kurmann commented 6 months ago

Verstanden. Wie genau wird jetzt aber der GenerateChangeLog und die bestimmte Versionsnummer nach aussen gegeben? Vielleicht habe ich etwas überlesen, weil es derzeit viele neue Informationen sind, aber die Ausgabe, also das Artefakt von diesem Workflow ist mir nicht ganz klar.


Der Prozess, wie Semantic Release den Changelog generiert und die Versionsnummer bestimmt, erfolgt intern innerhalb des Tools, basierend auf den Commit-Nachrichten, die den Conventional Commits-Konventionen folgen. Hier erkläre ich, wie dieser Vorgang funktioniert und was als Artefakte bzw. Ausgaben von diesem Prozess erwartet werden kann:

Changelog-Generierung und Versionsmanagement

Semantic Release führt mehrere Aufgaben aus, um das Versionsmanagement und die Changelog-Generierung zu automatisieren:

  1. Commit-Analyse: Semantic Release analysiert die Commits seit dem letzten Release. Es sucht nach Commit-Nachrichten, die mit den Conventional Commits-Konventionen übereinstimmen (z.B. feat, fix, BREAKING CHANGE).

  2. Versionsbestimmung: Basierend auf den gefundenen Commits entscheidet Semantic Release, ob das nächste Release eine Major-, Minor- oder Patch-Version sein wird:

    • BREAKING CHANGE oder feat mit !: Major-Release
    • feat: Minor-Release
    • fix und andere Typen (außer docs, style, refactor, test, die standardmäßig keinen Einfluss auf die Version haben): Patch-Release
  3. Changelog-Update: Semantic Release aktualisiert die Changelog-Datei (typischerweise CHANGELOG.md) im Repository. Jeder Eintrag im Changelog enthält die Zusammenfassung des Commits, die betroffene Version und Links zum entsprechenden Commit oder Pull Request.

  4. Tagging und Release: Nachdem die neue Version bestimmt wurde, erstellt Semantic Release einen neuen Git-Tag und, falls konfiguriert, ein GitHub Release. Das GitHub Release enthält typischerweise die gleichen Informationen wie der Changelog, aber in einem für GitHub optimierten Format.

Ausgaben des Workflows

Die "Artefakte" oder Ausgaben von Semantic Release in diesem Workflow sind:

Zusätzliche Konfigurationen

Um sicherzustellen, dass alle diese Schritte reibungslos ablaufen, solltest du die .releaserc oder die Konfigurationssektion innerhalb der package.json anpassen, um Plugins und deren Einstellungen zu definieren, die Semantic Release verwenden soll. Hier ist ein Beispiel für eine einfache Konfiguration:

{
  "release": {
    "branches": ["main"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/changelog",
      "@semantic-release/github",
      "@semantic-release/npm",
      {
        "path": "@semantic-release/git",
        "assets": ["package.json", "CHANGELOG.md"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ]
  }
}

In dieser Konfiguration:

Durch diese automatisierten Schritte wird sichergestellt, dass alle relevanten Informationen transparent und zugänglich sind und das Versionsmanagement effizient und fehlerfrei durchgeführt wird.

kurmann commented 6 months ago

Der Workflow kümmert sich um den ganzen GitHub-Release einschliesslich automatisierter Changelog und automatisierter Versionserhöhung. Für mich ist das wichtig, weil später noch der Nugget-Paketierungs-Workflow eingebunden werden sollte. Das mit der zusätzlichen Konfiguration habe ich leider nicht verstanden. Warum brauche ich dieses Package.json und was ist mit Package überhaupt gemeint?


Das Konzept rund um die package.json und die Verwendung des package-Begriffs stammt aus der JavaScript- und Node.js-Welt, wo die package.json-Datei als Herzstück eines jeden Node.js-Projekts oder JavaScript-Projekts angesehen wird. Diese Datei verwaltet Projektmetadaten, Abhängigkeiten, Skripte, und mehr. Lassen Sie uns dies und die Notwendigkeit für die Einbindung in Ihren Workflow näher erläutern:

Was ist die package.json?

Die package.json-Datei ist eine zentrale Konfigurationsdatei in Node.js- und JavaScript-Projekten. Sie enthält wichtige Informationen über das Projekt, einschließlich:

Rolle der package.json im Semantic Release Workflow

In Ihrem spezifischen Fall, wenn Sie Semantic Release verwenden, spielt die package.json eine zentrale Rolle bei der Verwaltung der Versionsnummer Ihres Projekts. Semantic Release aktualisiert automatisch die Versionsnummer in der package.json-Datei, basierend auf den Conventional Commits, die seit dem letzten Release gemacht wurden.

Einbindung der package.json in den Release-Prozess

Wenn Sie den Semantic Release-Prozess verwenden:

Beispielkonfiguration in package.json

{
  "name": "mein-node-projekt",
  "version": "1.0.0",
  "scripts": {
    "semantic-release": "semantic-release"
  },
  "devDependencies": {
    "@semantic-release/changelog": "^5.0.1",
    "@semantic-release/commit-analyzer": "^8.0.1",
    "@semantic-release/git": "^9.0.0",
    "@semantic-release/npm": "^7.1.3",
    "@semantic-release/release-notes-generator": "^9.0.2"
  },
  "release": {
    "branches": ["main"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/changelog",
      "@semantic-release/npm",
      {
        "path": "@semantic-release/git",
        "assets": ["package.json", "CHANGELOG.md"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ]
  }
}

Wann brauchen Sie kein package.json?

Wenn Ihr Projekt nicht auf Node.js oder JavaScript basiert (zum Beispiel ein C#- oder Python-Projekt), brauchen Sie normalerweise keine package.json. In solchen Fällen müssen Sie die Versionsverwaltung und das Release Management anders handhaben, möglicherweise durch entsprechende Tools und Skripte, die für Ihre Technologie geeignet sind. Für NuGet-Pakete, wie Sie sie erwähnt haben, würden Sie beispielsweise die .csproj-Datei für .NET-Projekte verwenden, um die Versionsnummer und andere Paketinformationen zu verwalten.

Fazit

Die Einbindung der package.json und die Konfiguration von Semantic Release sind essentiell, wenn Sie ein Node.js/JavaScript-Projekt verwalten. Für andere Technologien benötigen Sie spezifische Konfigurationsdateien und Management-Tools, die Ihrer Plattform entsprechen.

kurmann commented 6 months ago

Jetzt habe ich es verstanden. Ich habe keine Erfahrung mit Node.js. Die Package.json ist also tatsächlich zu vergleichen mit den Nugget-Packages, die in einem CS-Project definiert sind.


Genau, das hast du richtig erfasst! Die package.json in Node.js Projekten ist funktional ähnlich wie die .csproj-Dateien in .NET-Projekten, insbesondere in Bezug auf die Verwaltung von Abhängigkeiten und Projektmetadaten. Beide dienen als zentrale Konfigurationsdateien, die wichtige Informationen über das Projekt enthalten, einschließlich der Versionierung, Abhängigkeiten und Projekteinstellungen.

Vergleich zwischen package.json und .csproj:

Anwendung in Continuous Integration und Continuous Deployment:

Wenn du in deinen Projekten mit NuGet-Paketen und .NET arbeitest, wirst du ähnliche Konzepte verwenden, aber die Tools und Dateiformate sind spezifisch für die .NET-Plattform. Die Grundprinzipien der Versionierung und Abhängigkeitsverwaltung bleiben jedoch über Plattformen hinweg ähnlich.

kurmann commented 6 months ago

Jetzt noch, bevor ich zur Umsetzung komme. Angenommen, ich würde diesen Workflow jetzt definieren, dann würde er sofort greifen, wann nehme ich ein Commit-Machen mit der Commit-Konvention. Mit welcher Versionsnummer fängt er überhaupt an? Weil mein Projekt hat bis jetzt noch gar keine Versionsnummer. Nimmt er einfach das letzte verfügbare Git-Tag mit der Versionsnummer? Oder worauf basiert die neue Version?


Wenn du mit Semantic Release beginnst und dein Projekt bisher keine Versionsnummerierung oder Git-Tags verwendet hat, gibt es einige Schritte und Überlegungen, um das Setup richtig zu starten. Hier erkläre ich, wie Semantic Release die Versionsnummer bestimmt und was du tun solltest, wenn dein Projekt noch keine Versionshistorie hat:

Initialisierung der Versionsnummerierung

  1. Anfangs-Tag setzen: Wenn dein Projekt noch keine Versionsnummern hat, ist es eine gute Praxis, manuell einen Anfangs-Tag in deinem Repository zu setzen. Dies dient als Startpunkt für die automatische Versionsverwaltung durch Semantic Release. Du kannst beispielsweise mit einer Anfangsversion wie 1.0.0 oder 0.1.0 beginnen, je nachdem, wie reif dein Projekt ist.

    git tag v1.0.0
    git push origin v1.0.0
  2. Semantic Release Konfiguration: Stelle sicher, dass dein Semantic Release richtig konfiguriert ist, um die Versionsnummer basierend auf deinen Commits zu erhöhen. Dies umfasst das Setup der release-Konfiguration in deiner package.json (für Node.js-Projekte) oder eine äquivalente Konfigurationsdatei.

Wie Semantic Release die Version bestimmt

Keine Tags vorhanden

Empfehlungen für den Start

Durch die Einrichtung eines klaren Ausgangspunktes und die Nutzung von Semantic Release kannst du eine robuste, automatisierte Versionierungs- und Release-Pipeline aufbauen, die den Overhead der Versionsverwaltung reduziert und gleichzeitig Klarheit und Vorhersehbarkeit für alle Stakeholder bietet.

kurmann commented 6 months ago

Ich denke, ich mache wirklich den pragmatischen Weg und definiere ein erstes Tag 0.1.0, weil grundsätzlich passiert ab dieser Initialisierung ja alles automatisch bezüglich der Versionierung. Bevor ich damit aber beginne, müsste ich noch abklären, wie es dann mit der Nugget-Paketierung geht. In anderen Repositories, die noch weniger automatisiert sind diesbezüglich, habe ich die Versionsnummer in den CS-Projekt-Files festgelegt. Die wird dann ausgelesen vom Workflow und in die Nugget-Paket-Versionsnummer übernommen. Ich denke, ich müsste dann diesen Workflow so anpassen, dass er dann die aktuell gültige Version übernimmt, wahrscheinlich das Git-Tag mit der höchsten Versionsnummer. Wie würde das funktionieren? Auch hier suche ich wieder den Best-Practice-Ansatz, der nicht zu komplex ist.


Wenn du bereits eine etablierte Praxis hast, bei der die Versionsnummer in deinen .csproj-Dateien für .NET-Projekte festgelegt wird und du dies in deinen NuGet-Paketierungsprozess integrieren möchtest, gibt es verschiedene Wege, dies mit Semantic Release und automatischen Git-Tags zu kombinieren. Der Schlüssel liegt darin, eine Brücke zwischen der automatisierten Versionskontrolle und den spezifischen Anforderungen der NuGet-Paketierung zu schlagen.

Integration von Semantic Release mit NuGet-Paketierung

  1. Automatische Versionsnummerierung über Semantic Release:

    • Tagging: Stelle sicher, dass Semantic Release nach jedem erfolgreichen Release einen Git-Tag erstellt.
    • Versionsauslesung: Du kannst die neueste Git-Tag-Version auslesen und diese Information nutzen, um die Versionsnummer in deiner .csproj-Datei dynamisch zu aktualisieren.
  2. Workflow zur Aktualisierung der .csproj-Datei:

    • Vor der Paketierung könntest du einen Schritt in deinem CI/CD-Workflow hinzufügen, der die .csproj-Datei automatisch mit der neuesten Version aktualisiert, die von Semantic Release generiert wurde.
    • Dies kann durch ein einfaches Skript erfolgen, das die .csproj-Datei bearbeitet und die <Version>-Tag auf die neueste Version setzt.

Beispiel für einen GitHub Actions Workflow

Hier ist ein Beispiel für einen GitHub Actions Workflow, der die neueste Git-Tag-Version ausliest und diese verwendet, um die .csproj-Datei zu aktualisieren, bevor das NuGet-Paket erstellt wird:

name: NuGet Package Release

on:
  push:
    branches:
      - main

jobs:
  build-and-release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up .NET Core
        uses: actions/setup-dotnet@v2
        with:
          dotnet-version: '3.1.x'  # Beispiel für die .NET Version

      - name: Install dependencies
        run: dotnet restore

      - name: Extract version tag
        id: versiontag
        run: echo "::set-output name=version::$(git describe --tags `git rev-list --tags --max-count=1`)"

      - name: Update .csproj file
        run: |
          sed -i 's|<Version>.*</Version>|<Version>${{ steps.versiontag.outputs.version }}</Version>|' path/to/YourProject.csproj

      - name: Build and pack
        run: dotnet pack path/to/YourProject.csproj --configuration Release --output nupkgs

      - name: Push NuGet Package
        run: dotnet nuget push path/to/nupkgs/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

Best Practices und Überlegungen

Durch die Integration dieser automatisierten Schritte in deinen Workflow kannst du eine effiziente und fehlerfreie NuGet-Paketveröffentlichung sicherstellen, die eng mit deiner Versionskontrollstrategie verbunden ist.

kurmann commented 6 months ago

Kann ich den Release Drafter auch so konfigurieren, dass er nur Conventional Commits berücksichtigt?


Der Release Drafter selbst ist nicht darauf ausgelegt, ausschließlich auf Basis von Conventional Commits zu arbeiten. Er generiert den Release-Entwurf primär auf der Grundlage der Pull Requests und deren Labels. Wenn die Commits in den Pull Requests Conventional Commits sind, wird dies im Release-Entwurf normalerweise nicht direkt reflektiert, es sei denn, die Titel der Pull Requests folgen auch dem Conventional Commit Schema.

Um ein Changelog zu generieren, das nur auf Conventional Commits basiert, könntest du ein anderes Tool wie semantic-release in Betracht ziehen, welches genau für diesen Zweck entwickelt wurde. semantic-release automatisiert den gesamten Release-Prozess, einschließlich der Erstellung von Git-Tags, Releases und Changelogs, basierend auf den Regeln von Conventional Commits.

Wenn du bei Release Drafter bleiben möchtest, könntest du die Release-Notes manuell bearbeiten, bevor du den Entwurf veröffentlichst, um nur die Informationen einzuschließen, die du für relevant hältst. Ein anderer Ansatz wäre die Verwendung eines Skripts oder eines zusätzlichen Workflows, der die Conventional Commits analysiert und einen vorbereiteten Text für den Release Drafter generiert.

Es ist jedoch wichtig zu beachten, dass solch eine Konfiguration im Release Drafter direkt nicht unterstützt wird und eine angepasste Lösung erfordert.

kurmann commented 6 months ago

Eine Frage. Kann mir semantic-Release auch die Version auf Basis von Major, Minor and Patch verwalten und automatisch auf die nächsthöhere Version gehen?


Ja, genau das ist eine der Hauptfunktionen von semantic-release. Es analysiert die Commits seit dem letzten Release und bestimmt die nächste Versionsnummer basierend auf den Regeln des Semantic Versioning (SemVer) und den Conventional Commits.

Hier ist, wie semantic-release dies handhabt:

semantic-release kümmert sich automatisch um:

semantic-release benötigt eine Konfigurationsdatei in deinem Repository, normalerweise .releaserc oder ein Abschnitt in deiner package.json, um zu definieren, wie das Release und Changelog erstellt werden sollen. Du kannst Plugins konfigurieren, um den Release-Prozess weiter anzupassen, beispielsweise um deinen eigenen Changelog-Format zu verwenden oder zusätzliche Schritte wie das Veröffentlichen eines Pakets zu einem Paket-Manager durchzuführen.

Es ist ein mächtiges Tool, das viele manuelle Schritte im Release-Prozess automatisiert und besonders nützlich ist, wenn du einen Workflow aufbauen möchtest, der stark auf die Automatisierung der Versionierung und des Release-Managements setzt.

kurmann commented 6 months ago

(..)


Um semantic-release für die automatische Versionierung und die Erstellung von GitHub-Releases zu nutzen, kannst du den Release Drafter-Workflow durch einen semantic-release-Workflow ersetzen. Hier ist ein Basis-Workflow, der die automatische Versionierung und das Changelog basierend auf den Git-Tags und den Conventional Commits handhabt:

# .github/workflows/semantic-release.yml
name: Semantic Release

on:
  push:
    branches:
      - main  # Oder jeder andere Branch, auf dem du Releases durchführen möchtest

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
        with:
          # Damit semantic-release auf die gesamte Git-Historie zugreifen kann
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14 # oder eine andere Node.js-Version deiner Wahl

      - name: Install dependencies
        run: npm install

      - name: Semantic Release
        run: npx semantic-release
        env:
          # Das Token, das semantic-release für die Authentifizierung bei GitHub benötigt
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          # Dein NPM-Token, wenn du Pakete auf npm veröffentlichen möchtest
          # NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Dieser Workflow erfordert, dass in deinem Projekt eine package.json-Datei vorhanden ist und dass semantic-release und alle benötigten Plugins als Entwicklungsabhängigkeiten installiert sind:

npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git @semantic-release/github

Du wirst auch eine Konfigurationsdatei für semantic-release benötigen, z.B. .releaserc:

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/github",
    "@semantic-release/git",
    [
      "@semantic-release/npm",
      {
        "npmPublish": false # Setze dies auf `true`, wenn du ein npm Paket veröffentlichen möchtest
      }
    ]
  ]
}

Wenn du eine NuGet-Paketveröffentlichung hinzufügen möchtest, müsstest du einen zusätzlichen Schritt in den Workflow einbauen, der das Paket packt und es mit dem NuGet CLI-Tool veröffentlicht.

Bitte beachte, dass semantic-release für die Bestimmung der nächsten Versionsnummer vorhandene Git-Tags verwendet, die dem Semantic Versioning entsprechen müssen. Sollte noch kein Tag vorhanden sein, kannst du den initialen Tag manuell setzen:

git tag v0.1.0
git push origin v0.1.0

Dies würde semantic-release als Startpunkt für die Versionierung dienen. Bei jedem folgenden Push zum main-Branch würde semantic-release die Commits analysieren und entsprechend eine neue Version taggen und veröffentlichen.

kurmann commented 6 months ago

Den NPM-Installbefehl benötige ich für die Entwicklungsumgebung. Oder wo führe ich den genau aus?


Der Befehl npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git @semantic-release/github dient dazu, semantic-release und die zugehörigen Plugins in dein Projekt zu integrieren. Dies wird normalerweise einmalig auf deiner lokalen Entwicklungsumgebung durchgeführt, um die Abhängigkeiten in deine package.json einzufügen. Hier sind die Schritte, die du normalerweise ausführen würdest:

  1. Lokale Entwicklungsumgebung einrichten:

    • Stelle sicher, dass du Node.js und npm auf deinem System installiert hast.
    • Klone dein Repository auf deinen lokalen Computer, falls noch nicht geschehen.
  2. semantic-release hinzufügen:

    • Wechsle in das Verzeichnis deines Projekts in der Konsole.
    • Führe den npm install-Befehl aus. Dies fügt semantic-release und die genannten Plugins zum node_modules-Verzeichnis deines Projekts hinzu und aktualisiert deine package.json und package-lock.json Dateien mit den neuen Entwicklungsabhängigkeiten.
  3. Konfigurationsdatei anlegen:

    • Erstelle eine .releaserc Datei oder einen entsprechenden Abschnitt in deiner package.json für die Konfiguration von semantic-release.
  4. Änderungen committen:

    • Committe die aktualisierte package.json, package-lock.json und die .releaserc Konfigurationsdatei in dein Repository.
  5. GitHub Actions Workflow einrichten:

    • Erstelle den oben beschriebenen Workflow als .github/workflows/semantic-release.yml Datei in deinem Repository.
    • Committe und pushe diese Workflow-Datei in dein Repository.

Nachdem diese Schritte abgeschlossen sind, sollte semantic-release über deine CI/CD-Pipeline (in diesem Fall GitHub Actions) laufen. Die GitHub Action wird die benötigten Schritte ausführen, einschließlich der Installation der Abhängigkeiten während des CI/CD-Prozesses, so dass du dies nicht für jeden Build manuell tun musst.

kurmann commented 6 months ago

Ich verstehe nicht ganz, warum ich das auf lokaler Umgebung installiert haben muss. Die GitHub-Actions werden doch auf dem GitHub-Buildserver ausgeführt.


Du hast absolut recht, dass die GitHub Actions auf den GitHub-Hosted Runnern und nicht auf deinem lokalen System ausgeführt werden. Die Notwendigkeit, Pakete lokal zu installieren, hängt davon ab, wie du dein Projekt und deine Entwicklungsprozesse managen möchtest. Hier sind einige Gründe, warum es dennoch sinnvoll sein kann, diese Pakete lokal zu installieren:

  1. Lokale Tests und Konfiguration:

    • Vor der Integration in den CI/CD-Prozess ist es oft nützlich, die Konfigurationen und Skripte lokal zu testen, um sicherzustellen, dass alles wie erwartet funktioniert. Dies kann dir Zeit sparen und Fehler vermeiden, bevor Änderungen gepusht und von den GitHub Actions verarbeitet werden.
    • Du könntest lokale Releases simulieren oder bestimmte semantic-release Plugins testen, um zu sehen, wie die Versionierung und das Changelog generiert werden, ohne auf den CI-Prozess warten zu müssen.
  2. Entwicklungsumgebung konsistent halten:

    • Das Installieren der gleichen Pakete, die in der Produktions- oder CI/CD-Umgebung verwendet werden, stellt sicher, dass deine lokale Entwicklungsumgebung konsistent mit der Produktionsumgebung ist. Dies minimiert die "Es funktioniert auf meinem Rechner" Probleme.
    • Wenn du oder andere Entwickler am Projekt arbeiten, hilft es, wenn jeder die gleichen Tools und Versionen verwendet, um Features zu entwickeln und zu testen.
  3. Automatische Dokumentation und Werkzeugzugriff:

    • Durch das Hinzufügen der Tools und ihrer Versionen zu deiner package.json wird dokumentiert, welche Tools und Versionen das Projekt benötigt. Das ist besonders nützlich für neue Teammitglieder oder wenn du das Projekt nach längerer Zeit wieder aufnimmst.
    • Manchmal möchte man auch Kommandozeilenwerkzeuge dieser Pakete direkt nutzen, um bestimmte Aufgaben auszuführen oder Probleme zu debuggen.

Wenn du diese Pakete und Tools ausschließlich im Rahmen der GitHub Actions nutzen möchtest und sie nicht für lokale Entwicklungstests oder -simulationen benötigst, kannst du tatsächlich darauf verzichten, sie lokal zu installieren. Stattdessen könntest du die vollständige Installation und Konfiguration in deinen GitHub Actions Workflows abhandeln lassen. Dies reduziert die Komplexität deiner lokalen Entwicklungsumgebung und macht die Nutzung cloud-basierter CI/CD-Prozesse vollständig autonom.

kurmann commented 6 months ago

Im Moment brauche ich diese Pakete und tue es tatsächlich nur für die GitHub Actions. Diese entwickle ich und wenn sie gut funktionieren, dann sind sie bereits als GitHub Actions im Code Repository vorhanden und jeder Entwickler kann sie sofort benutzen.


Das klingt nach einem sehr effizienten und praktischen Ansatz, insbesondere wenn du die Entwicklung und Wartung der CI/CD-Prozesse zentralisieren möchtest. Indem du die vollständige Installation und Konfiguration direkt in deinen GitHub Actions Workflows handhabst, machst du es für alle Entwickler einfach, mit dem Projekt zu arbeiten, ohne dass sie sich um die Einrichtung spezifischer Tools auf ihren lokalen Maschinen kümmern müssen. Dies ist besonders vorteilhaft in Teams, wo Konfigurationsuniformität und Betriebszeit kritisch sind.

Hier einige Tipps, um sicherzustellen, dass dieser Ansatz reibungslos funktioniert:

  1. Detaillierte Dokumentation: Stelle sicher, dass deine GitHub Actions Workflows gut dokumentiert sind, sodass neue Teammitglieder oder externe Entwickler leicht verstehen können, was jeder Schritt des Workflows bewirkt und wie sie etwaige Fehler beheben oder Anpassungen vornehmen können.

  2. Versionierung und Abhängigkeitsmanagement: Achte darauf, spezifische Versionen der GitHub Actions und externen Tools zu verwenden, um unerwartete Fehler durch automatische Updates zu vermeiden. Dies hilft, die Stabilität deiner CI/CD-Pipelines zu gewährleisten.

  3. Sicherheit: Verwalte sensitive Daten wie Tokens und API-Keys sicher durch GitHub Secrets. Stelle sicher, dass die Berechtigungen dieser Secrets minimal sind und nur von den benötigten Teilen deines Workflows genutzt werden.

  4. Testing und Staging: Erwäge die Einrichtung von Staging- und Testumgebungen in deinen Workflows, um sicherzustellen, dass Änderungen gründlich getestet werden, bevor sie in die Produktionsumgebung übernommen werden. Dies kann durch die Einrichtung separater Branches und zugehöriger Workflows für verschiedene Umgebungen erreicht werden.

  5. Fehlerbehebung und Monitoring: Implementiere angemessenes Logging und Überwachung für deine CI/CD-Pipelines, um Probleme schnell erkennen und beheben zu können.

Wenn du diese Praktiken implementierst, wird dein Ansatz, alles in GitHub Actions zu zentralisieren, dazu beitragen, die Einrichtungszeit für neue Entwickler zu minimieren und die Konsistenz über das gesamte Projekt hinweg zu verbessern. Dies unterstützt ein reibungsloses und effizientes Entwicklungs- und Release-Management.

kurmann commented 6 months ago

Eine Frage, vielleicht habe ich das verpasst: Wie konfiguriere ich das Template für den Semantic Release, also das Layout, wie der GitHub-Pullrequest daherkommt.

Oder ist das bereits per Default geregelt?


semantic-release selbst erstellt keine Pull Requests, sondern handhabt automatische Versionierung und das Erstellen von Releases basierend auf den Commit-Nachrichten. Die Konfiguration, die du anpasst, bezieht sich hauptsächlich auf das Release und das Changelog, das auf GitHub als Teil des Releases veröffentlicht wird.

Changelog-Anpassung

semantic-release verwendet Plugins, um das Changelog und das Release-Layout anzupassen. Das Standard-Plugin dafür ist @semantic-release/release-notes-generator, welches das Changelog basierend auf deinen Conventional Commits erstellt. Du kannst die Changelog-Struktur durch das @semantic-release/changelog Plugin weiter anpassen, welches es dir ermöglicht, die CHANGELOG.md Datei in deinem Repository zu generieren oder zu aktualisieren.

Hier ein Beispiel für die Konfiguration dieser Plugins in der .releaserc oder package.json:

{
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    {
      "path": "@semantic-release/changelog",
      "changelogFile": "CHANGELOG.md",
      "changelogTitle": "# Projekt Changelog"
    },
    "@semantic-release/github"
  ]
}

Release-Konfiguration

Das @semantic-release/github Plugin kümmert sich um das Erstellen des GitHub-Releases. Du kannst verschiedene Aspekte dieses Prozesses konfigurieren, wie z.B. welche Assets hochgeladen werden sollen und wie das Release aussehen soll. Hier kannst du auch definieren, ob das Release ein Entwurf sein soll, ob es vorläufig (pre-release) ist, und du kannst den Body des Releases anpassen.

Beispiel für das Hinzufügen von Assets und Anpassen des Release-Textes:

{
  "path": "@semantic-release/github",
  "assets": [
    {"path": "build/your-artifact.zip", "label": "Build Artifact"}
  ],
  "successComment": "Dieses Release enthält die folgenden Änderungen: \n\n${nextRelease.notes}"
}

Templating des Release-Bodys

Die Notizen (notes) für das Release, die von @semantic-release/release-notes-generator erstellt werden, können ebenfalls durch Anpassung der Konfiguration des release-notes-generator modifiziert werden. Diese Notizen werden dann im Release-Body verwendet.

Es gibt keine direkte Konfiguration in semantic-release für die Gestaltung von Pull Requests, da semantic-release in der Regel direkt Releases behandelt, basierend auf den Änderungen, die in den Hauptbranch gemerged wurden. Falls du einen Prozess haben möchtest, der auf Pull Requests basiert, könnte dies ein separater Workflow oder ein anderer Automatisierungsprozess sein, der nicht direkt von semantic-release abgedeckt wird.

Wenn du spezifischere Anpassungen oder eine andere Art von Automatisierung brauchst, könntest du zusätzliche Skripte oder GitHub Actions einsetzen, die auf Pull Requests reagieren und entsprechende Aktionen ausführen, wie z.B. das Erstellen von Kommentaren oder das Labeln basierend auf bestimmten Kriterien.

kurmann commented 6 months ago

Ich bin noch nicht zufrieden. Ich möchte in Vorgehen ähnlich wie der Release Drafter. Ich brauche keine separate Changelog.md sondern möchte alle Änderungen nur über GitHub Releases verwalten.


Um eine Konfiguration ähnlich dem Release Drafter mit semantic-release zu erreichen, wo du direkt im GitHub-Release alle Änderungen verwaltest ohne eine separate CHANGELOG.md Datei zu pflegen, kannst du das @semantic-release/github Plugin verwenden. Dieses Plugin kann so konfiguriert werden, dass es den Release-Body direkt mit den Änderungen aus den Commits generiert, die seit dem letzten Release eingeführt wurden.

Hier ist, wie du deine semantic-release Konfiguration anpassen kannst, um direkt ein GitHub-Release zu generieren, das alle nötigen Informationen enthält, ähnlich wie beim Release Drafter:

Schritt 1: Installation der benötigten Pakete

Stelle sicher, dass du semantic-release und das GitHub-Plugin installiert hast:

npm install --save-dev semantic-release @semantic-release/github

Schritt 2: Konfiguration von semantic-release

Erstelle eine .releaserc oder füge die entsprechende Konfiguration in die package.json ein. Hier ist ein Beispiel für eine Konfiguration, die den Release-Body automatisch auf Basis deiner Commits generiert:

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer", // Analysiert die Commits für die Versionserhöhung
    "@semantic-release/release-notes-generator", // Generiert die Notizen für die Releases
    [
      "@semantic-release/github", // Konfiguriert das Erstellen von GitHub-Releases
      {
        "assets": [
          {"path": "path/to/your-artifact.zip", "label": "Build Artifact"}
        ]
      }
    ]
  ]
}

Diese Konfiguration sorgt dafür, dass semantic-release:

Schritt 3: Einrichten eines GitHub Actions Workflows

Definiere einen Workflow in deinem GitHub Repository unter .github/workflows/semantic-release.yml, um semantic-release bei jedem Push zum main Branch auszuführen:

name: Semantic Release

on:
  push:
    branches:
      - main

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14

      - name: Install Dependencies
        run: npm install

      - name: Run Semantic Release
        run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Hinweis

Diese Konfiguration stellt sicher, dass alle Änderungen und Versionierungen direkt über GitHub Releases verwaltet werden, ähnlich wie du es mit dem Release Drafter getan hast. Da semantic-release sehr konfigurierbar ist, kannst du dieses Verhalten feinjustieren, um genau den Workflow zu erreichen, den du benötigst.

kurmann commented 6 months ago

Die ".releaserc" ist eine Konfigurationsdatei nur für semantic-release? Wo soll diese sich lokal befinden?


Ja, die .releaserc Datei ist eine spezifische Konfigurationsdatei für semantic-release. Sie enthält die Einstellungen, die definieren, wie semantic-release die Versionierung, das Changelog, das Erstellen von Releases und andere Aufgaben durchführt. Du kannst diese Konfiguration auch direkt in die package.json Datei integrieren, wenn du bevorzugst, keine separate Datei zu verwenden.

Platzierung der .releaserc Datei

Die .releaserc Datei sollte im Stammverzeichnis deines Projekts platziert werden, also dort, wo sich auch andere wichtige Dateien wie package.json, README.md und das Verzeichnis .git befinden. Das stellt sicher, dass semantic-release und andere Tools, die auf die Konfiguration zugreifen, diese leicht finden können.

Beispielstruktur eines Projekts:

/my-project
│
├── .github/
│   └── workflows/
│       └── semantic-release.yml
├── node_modules/
├── src/
├── .gitignore
├── .releaserc       ← Hier befindet sich die Konfigurationsdatei
├── package.json
└── README.md

In dieser Struktur ist die .releaserc Datei direkt im Hauptverzeichnis des Projekts. semantic-release wird diese Datei automatisch erkennen und die darin definierten Konfigurationen verwenden, wenn der Workflow ausgeführt wird.

Alternativen zur .releaserc Datei

Falls du es vorziehst, keine zusätzliche Konfigurationsdatei zu verwenden, kannst du die semantic-release Konfiguration direkt in die package.json integrieren. Hier ist ein Beispiel, wie das aussehen könnte:

{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "release": "semantic-release"
  },
  "devDependencies": {
    "semantic-release": "^17.0.0",
    "@semantic-release/changelog": "^5.0.0",
    "@semantic-release/github": "^7.0.0"
  },
  "release": {
    "branches": ["main"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/changelog",
      "@semantic-release/github"
    ]
  }
}

Durch das Platzieren der Konfiguration in der package.json hältst du alles in einer zentralen Datei, was das Management manchmal erleichtert.

kurmann commented 6 months ago

Eine allgemeine Frage: Wie kann ich Semantic Versioning automatisieren wenn ich vorwiegend auf .NET arbeite? Ich bin verunsichert, weil all das hier scheint mir stark auf Node.js zugeschnitten zu sein.


Du hast Recht, dass viele der vorgestellten Tools wie semantic-release ursprünglich für die Node.js-Entwicklungsumgebung entwickelt wurden. Trotzdem kannst du ähnliche Automatisierungsprozesse auch in .NET-Projekten implementieren, besonders mit Hilfe von CI/CD-Plattformen wie GitHub Actions, die Plattform- und sprachunabhängig sind.

Für .NET-Projekte kannst du die automatische Versionierung mit einigen speziellen Tools oder durch das Anpassen allgemeinerer Werkzeuge erreichen. Hier sind ein paar Optionen, wie du Semantic Versioning in deinen .NET-Projekten automatisieren kannst:

1. Verwendung von GitVersion

GitVersion ist ein Tool, das speziell dafür entwickelt wurde, die Versionierung in Projekten zu automatisieren, die Git verwenden. Es funktioniert gut mit .NET-Projekten und integriert sich nahtlos in CI/CD-Pipelines.

2. GitHub Actions für .NET

Du kannst GitHub Actions verwenden, um eine CI/CD-Pipeline für .NET aufzubauen, die das Semantic Versioning automatisch handhabt. Dies könnte das Erstellen von Tags, das Bumpen von Versionsnummern in deinen Projektdateien und das Erstellen von GitHub Releases umfassen.

3. NuGet-Paketierung und Versionierung

Wenn du NuGet-Pakete erstellst, kannst du die Versionierung direkt in deinen .csproj- oder .nuspec-Dateien steuern. Automatisiere das Update dieser Dateien durch Skripte oder CI/CD-Pipeline-Schritte, die die Versionsnummer basierend auf deinen Versionierungsregeln aktualisieren.

Beispiel: GitHub Actions Workflow mit GitVersion

Hier ist ein einfaches Beispiel, wie ein GitHub Actions Workflow für ein .NET-Projekt mit GitVersion aussehen könnte:

name: .NET CI with Semantic Versioning

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
      with:
        fetch-depth: 0  # Wichtig für GitVersion, um die komplette Historie zu sehen

    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 5.0.x

    - name: Install GitVersion
      run: dotnet tool install --global GitVersion.Tool

    - name: Use GitVersion
      run: |
        gitversion /output buildserver /updateassemblyinfo

    - name: Build with dotnet
      run: dotnet build MySolution.sln --configuration Release

    - name: Test
      run: dotnet test MySolution.sln --no-build --verbosity normal

    - name: Pack
      run: dotnet pack MySolution.sln --no-build --configuration Release

    - name: Publish NuGet Package
      run: dotnet nuget push "**/*.nupkg" --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}

In diesem Workflow konfiguriert und verwendet GitVersion, um die Versionsinformationen zu berechnen und das AssemblyInfo zu aktualisieren, bevor der Build, das Testen und das Packen des Projekts erfolgt. Das fertige Paket wird dann veröffentlicht.

kurmann commented 6 months ago

Funktioniert GitVersion auch mit Conventional Commits, so wie ich das vorhabe?


Ja, GitVersion kann mit Conventional Commits verwendet werden, um die Versionierung deiner Software automatisch zu handhaben. GitVersion analysiert deine Git-Historie, um die nächste Versionsnummer basierend auf den Commit-Nachrichten und -Tags zu bestimmen, die bestimmten Regeln folgen. Dies ermöglicht eine nahtlose Integration mit dem Conventional Commit Schema.

Konfiguration von GitVersion für Conventional Commits

GitVersion ist hochgradig konfigurierbar und kann an das Conventional Commits Schema angepasst werden. Du kannst in der Konfigurationsdatei GitVersion.yml spezifische Einstellungen vornehmen, um zu definieren, wie verschiedene Typen von Commits behandelt werden sollten:

Hier ein Beispiel für eine GitVersion.yml, die angepasst ist, um das Conventional Commit Schema zu unterstützen:

mode: ContinuousDelivery
branches: {}
ignore:
  sha: []
merge-message-formats: {}
commits-before: {}
commit-message-incrementing: Enabled
increment: Inherit

commit-date-format: yyyy-MM-dd

branches:
  main:
    regex: ^main$
    source-branches: ['develop', 'release']
    increment: Minor
    prevent-increment-of-merged-branch-version: false
    tag: ''
    is-source-branch-for:
      - develop
      - release
  feature:
    regex: ^features?[/-]
    source-branches: ['develop', 'feature', 'support', 'hotfix']
    increment: Patch
    prevent-increment-of-merged-branch-version: false
    tag: useBranchName
    tracks-release-branches: false
    is-source-branch-for:
      - develop
      - release
      - feature
      - support
      - hotfix
  release:
    regex: ^releases?[/-]
    source-branches: ['develop', 'release']
    increment: Patch
    prevent-increment-of-merged-branch-version: true
    tag: ''
    is-source-branch-for:
      - develop
      - release

ignore:
  sha: []

In dieser Konfiguration:

Einrichtung und Integration

  1. Installation: Füge GitVersion als Tool zu deinem Projekt hinzu, entweder über eine CI/CD-Pipeline oder lokal als globales Tool.
  2. Konfiguration anpassen: Pass deine GitVersion.yml entsprechend deinen Bedürfnissen an.
  3. Integration in Build-Prozesse: Integriere GitVersion in deinen Build-Prozess, um bei jedem Build die Versionsnummer automatisch zu aktualisieren.

Durch die Einbindung von GitVersion in dein Projektmanagement kannst du sicherstellen, dass deine Versionsnummern immer korrekt und basierend auf deinen Commit-Nachrichten aktualisiert werden, was eine klare und nachvollziehbare Versionierungsgeschichte gewährleistet.