Closed kurmann closed 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:
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.
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.
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.
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.
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.
Ü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!
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:
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"
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:
Conventional Commits: Conventional Commit
im Command Palette (Cmd/Ctrl + Shift + P) ausführen.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.
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:
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.
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:
scope
eine Seite oder eine Funktion sein, wie login
, dashboard
, user-profile
.authentication-service
, product-controller
, database-utils
sein.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
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.
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.
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:
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.
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.
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.
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'
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 }}
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.
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:
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.
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.
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.
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.
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.
Wenn du dir unsicher bist, ob Release Branches für dich das Richtige sind, könntest du auch einen vereinfachten Workflow in Betracht ziehen:
Direkte Releases aus dem main
-Branch: Du könntest alle Änderungen direkt im main
-Branch entwickeln und von dort aus Releases erstellen. Dies kann durch klare Conventional Commits und automatisierte Tools wie Release Drafter unterstützt werden, um sicherzustellen, dass deine Release-Notes und Versionierungen korrekt sind.
Feature Flags: Eine weitere Möglichkeit, die Flexibilität in der Freigabe von Features zu erhöhen, ist die Verwendung von Feature Flags. Dies ermöglicht es dir, neue Funktionen im Code zu implementieren, aber sie für Benutzer verborgen zu halten, bis sie vollständig getestet sind und aktiviert werden sollen.
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.
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.
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:
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.
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.
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.
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.
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.
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:
main
-BranchesBranch-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.
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.
Um eine konsistente Nutzung von Commit-Nachrichten über Feature-Branches und den main
-Branch zu gewährleisten, kannst du Folgendes tun:
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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 }}
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.
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:
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.
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 }}
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 }}
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 }}
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.
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.
Install dependencies: Installiert alle Node.js-Abhängigkeiten des Projekts, die in der package.json
definiert sind.
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.
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.
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:
Semantic Release führt mehrere Aufgaben aus, um das Versionsmanagement und die Changelog-Generierung zu automatisieren:
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
).
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-Releasefeat
: Minor-Releasefix
und andere Typen (außer docs
, style
, refactor
, test
, die standardmäßig keinen Einfluss auf die Version haben): Patch-ReleaseChangelog-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.
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.
Die "Artefakte" oder Ausgaben von Semantic Release in diesem Workflow sind:
CHANGELOG.md
-Datei, die im Repository eingebunden und möglicherweise im GitHub Release angezeigt wird.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:
@semantic-release/changelog
aktualisiert die CHANGELOG.md
.@semantic-release/github
erstellt das GitHub Release.@semantic-release/git
pusht die Änderungen inklusive der aktualisierten CHANGELOG.md
und der package.json
mit der neuen Versionsnummer zurück ins Repository.Durch diese automatisierten Schritte wird sichergestellt, dass alle relevanten Informationen transparent und zugänglich sind und das Versionsmanagement effizient und fehlerfrei durchgeführt wird.
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:
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:
package.json
im Semantic Release WorkflowIn 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.
package.json
in den Release-ProzessWenn Sie den Semantic Release-Prozess verwenden:
package.json
und verwendet diese aktualisierte Version für das Git-Tagging und das Erstellen des GitHub Releases.release
-Konfiguration in der package.json
gesteuert werden.package.json
konfiguriert werden, um den Release-Prozess weiter anzupassen.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}"
}
]
}
}
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.
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.
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.
package.json
und .csproj
:Versionierung: In einer .csproj
-Datei wird die Version eines NuGet-Pakets oft im <Version>
Tag angegeben. Ähnlich wird in der package.json
die Version des Projekts unter dem Schlüssel version
gespeichert.
Abhängigkeiten verwalten: In der package.json
werden Abhängigkeiten in den dependencies
und devDependencies
Abschnitten gelistet. In .csproj
Dateien werden Abhängigkeiten (z.B. andere NuGet-Pakete) innerhalb des <ItemGroup>
Tags unter <PackageReference>
aufgeführt.
Skripte und Befehle: Die package.json
kann Skripte unter dem Schlüssel scripts
definieren, die dann mit npm run <script-name>
ausgeführt werden können. Im .NET-Ökosystem können ähnliche Aufgaben durch MSBuild-Skripte oder externe Build-Tools wie Cake oder FAKE gehandhabt werden.
Weitere Konfigurationen: Beide Dateiformate erlauben es, zusätzliche Konfigurationseinstellungen für das Projekt und die Build-Umgebung festzulegen. In .csproj
kann dies auch die Konfiguration von Projekt-eigenen Eigenschaften wie Target Frameworks und andere Build-bezogene Einstellungen umfassen.
.NET-Projekte (C#): In CI/CD Pipelines, die .NET-Projekte bauen, wird oft MSBuild oder das dotnet CLI-Tool verwendet, um das Projekt zu kompilieren, Tests auszuführen und Pakete zu packen. Die Versionsnummer kann dynamisch während des Builds gesetzt werden, indem man die Version
-Eigenschaft in der .csproj
-Datei anpasst oder durch spezielle Build-Tools wie GitVersion.
Node.js-Projekte: In Node.js-Projekten kann eine CI/CD-Pipeline das NPM oder Yarn Tool verwenden, um Abhängigkeiten zu installieren, Tests zu laufen und das Projekt zu bauen. Tools wie semantic-release
automatisieren die Versionierung und das Changelog-Management basierend auf Commit-Nachrichten.
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.
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:
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
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.
v1.2.3
), um die aktuelle Version des Projekts zu bestimmen und zu entscheiden, wie die nächste Version basierend auf den neuen Commits sein soll.feat:
beginnt und keinen Breaking Change enthält, zu einer Minor-Version-Erhöhung führen.1.0.0
beginnen, wenn es so eingestellt ist, dass es keine Tags findet und annimmt, dass das Projekt bei einer grundlegenden "ersten öffentlichen Release" beginnt.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.
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.
Automatische Versionsnummerierung über Semantic Release:
Workflow zur Aktualisierung der .csproj-Datei:
.csproj
-Datei automatisch mit der neuesten Version aktualisiert, die von Semantic Release generiert wurde.<Version>
-Tag auf die neueste Version setzt.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
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.
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.
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:
fix
(oder Aliase dafür) gekennzeichnet sind und keine Breaking Changes oder Features beinhalten.feat
(oder Aliase dafür) gekennzeichnet sind und keine Breaking Changes beinhalten.BREAKING CHANGE
-Footer gekennzeichnet sind oder die eine !
nach dem Typ/Skop-Bereich des Conventional Commits Message Formats enthalten.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.
(..)
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.
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:
Lokale Entwicklungsumgebung einrichten:
semantic-release
hinzufügen:
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.Konfigurationsdatei anlegen:
.releaserc
Datei oder einen entsprechenden Abschnitt in deiner package.json
für die Konfiguration von semantic-release
.Änderungen committen:
package.json
, package-lock.json
und die .releaserc
Konfigurationsdatei in dein Repository.GitHub Actions Workflow einrichten:
.github/workflows/semantic-release.yml
Datei in deinem 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.
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:
Lokale Tests und Konfiguration:
semantic-release
Plugins testen, um zu sehen, wie die Versionierung und das Changelog generiert werden, ohne auf den CI-Prozess warten zu müssen.Entwicklungsumgebung konsistent halten:
Automatische Dokumentation und Werkzeugzugriff:
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.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.
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:
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.
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.
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.
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.
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.
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.
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"
]
}
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}"
}
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.
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:
Stelle sicher, dass du semantic-release
und das GitHub-Plugin installiert hast:
npm install --save-dev semantic-release @semantic-release/github
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
:
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 }}
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.
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.
.releaserc
DateiDie .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.
/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.
.releaserc
DateiFalls 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.
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:
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.
GitVersion.yml
Datei in deinem Repository, wo du das Versionsschema definieren und anpassen kannst.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.
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.
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.
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.
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:
BREAKING CHANGE:
), oder durch die Verwendung eines !
direkt nach dem Typ/Scope.feat
(für neue Features) beginnen, können automatisch eine Minor-Version hochzählen.fix
beginnen, können automatisch eine Patch-Version hochzählen.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:
increment
: Steuert, wie die Version basierend auf dem Commit-Typ erhöht wird.commit-message-incrementing
: Aktiviert das Hochzählen der Version basierend auf den Commit-Nachrichten.regex
) für Branch-Namen definieren, wie Branches benannt sein müssen, um erkannt zu werden.GitVersion.yml
entsprechend deinen Bedürfnissen an.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.
Vorabdiskussion:
2