145 lines
12 KiB
Markdown
145 lines
12 KiB
Markdown
# Versionierung und Releases
|
|
|
|
## Normaler Ablauf
|
|
|
|
Entwicklung erfolgt auf `dev`. Ein Push nach `main` ist die bewusste Freigabe zum Veröffentlichen. Der Workflow `.gitea/workflows/build-push.yaml` startet automatisch, prüft die Commit-Nachrichten und Release-Tests, baut alle sechs Images und veröffentlicht bei relevanten Änderungen einen Gitea-Release.
|
|
|
|
Nach abgeschlossener Entwicklung in einem sauberen Checkout:
|
|
|
|
```bash
|
|
git switch dev
|
|
git pull --ff-only origin dev
|
|
npm ci --ignore-scripts
|
|
npm test
|
|
npm run release:preview
|
|
git push origin dev
|
|
git switch main
|
|
git pull --ff-only origin main
|
|
git merge --no-ff dev -m "chore(release): merge dev into main"
|
|
git push origin main
|
|
git switch dev
|
|
```
|
|
|
|
Alternativ einen Pull Request von `dev` nach `main` mit einem normalen Merge übernehmen. Der Merge-Commit selbst wird bei der Versionsberechnung übersprungen; die enthaltenen `feat:`-/`fix:`-Commits bestimmen das Release. Bei Squash-Merges muss die Squash-Nachricht die größte Änderung einschließlich etwaiger Breaking Changes ausdrücken.
|
|
|
|
Es ist kein separater Versions-Commit erforderlich. `npm run release:preview` ist eine lokale, schreibfreie Vorschau; vorher mit `git fetch origin --tags` die Release-Tags aktualisieren. Ein Push, der nur Wartungsänderungen enthält, erzeugt nach dem ersten Release keine neue Version.
|
|
|
|
Ein manueller Start ist zusätzlich unter Gitea → Actions → Build and Release FEDEO → Run workflow möglich. Wähle `main` für einen Release und `dev` für einen Entwicklungsbuild. Dieser Start verwendet dieselbe Pipeline und dieselbe automatisch berechnete Version. `npm run release:ci` ist ausschließlich für die CI vorgesehen.
|
|
|
|
## Versionsregeln
|
|
|
|
Die Pipeline nutzt die fest gepinnten Pakete `@semantic-release/commit-analyzer` und `@semantic-release/release-notes-generator` mit dem Conventional-Commits-Preset. Der Veröffentlichungsablauf ist auf Gitea 1.25.3 abgestimmt.
|
|
|
|
| Commit | Bedeutung | Release |
|
|
| --- | --- | --- |
|
|
| `fix(scope): …` | Fehlerkorrektur | Patch |
|
|
| `perf(scope): …` | Leistungsverbesserung | Patch |
|
|
| `feat(scope): …` | Neue Funktion | Minor |
|
|
| `feat(scope)!: …` / `BREAKING CHANGE: …` | Inkompatible Änderung | Major |
|
|
| `docs:`, `test:`, `refactor:`, `build:`, `ci:`, `chore:`, `style:` | Wartung ohne Breaking Change | Keiner |
|
|
| `revert: …` mit Git-Revert-Information | Zurücknahme bereits ausgelieferter Änderungen | Patch |
|
|
|
|
Es zählt der höchste erforderliche Sprung seit dem letzten stabilen Tag `vMAJOR.MINOR.PATCH`. Eine Änderung und ihr vollständiger Git-Revert innerhalb desselben Release-Bereichs heben sich auf. Selbst verfasste Nachrichten müssen dem Schema entsprechen; echte Merge-Commits und automatisch generierte Git-Reverts werden gesondert behandelt.
|
|
|
|
Der erste Release heißt `3.0.0`. `bootstrapCommit` in `release.config.json` begrenzt die Prüfung und die erste Änderungsliste auf die Einführung dieser Versionierung. Ältere Commits werden weder umgeschrieben noch nachträglich klassifiziert. Den Ausgangscommit nach Einführung nicht ändern.
|
|
|
|
## Versionen und Artefakte
|
|
|
|
Backend, Frontend, Dokumentation, Website und zentrale Dienste werden als gemeinsamer FEDEO-Stand gebaut. Die Produktversion stammt aus Git und wird beim Build eingebettet. Backend-/Frontend-Paketversionen dienen nicht als Release-Quelle.
|
|
|
|
- Stabile Images: `…/backend:3.2.0`, `…/backend:v3.2.0` und `…/backend:sha-<vollständiger Commit>`; entsprechend für alle sechs Komponenten.
|
|
- Bewegliche Kanäle: `latest` und `main` zeigen nach erfolgreicher Veröffentlichung auf denselben Release.
|
|
- Entwicklung: `dev` sowie unveränderliche `dev-sha-<vollständiger Commit>-<UUID>`-Images. Alle Komponenten eines erfolgreichen Laufs erhalten denselben Snapshot-Tag. Auch eine Wiederholung desselben Commits baut einen eigenen Snapshot. Die eingebettete Entwicklungsversion enthält Commit-Anzahl und Commit-ID.
|
|
- Release-Builds erhalten zunächst einen eindeutigen temporären `build-<UUID>`-Tag. Diese Tags können später nach einer Aufbewahrungsfrist bereinigt werden; stabile Versionen und deren Digests müssen erhalten bleiben.
|
|
- Release-Dateien: `CHANGELOG.md`, `release-manifest.json`, `docker-compose.selfhost.yml`, `.env.example`, `selfhost-install.sh`, `selfhost-setup.sh` und `SHA256SUMS`.
|
|
|
|
Das Manifest dokumentiert die Image-Digests, den Commit und SHA-256-Prüfsummen aller enthaltenen SQL-Migrationen. Es beschreibt den ausgelieferten Migrationsstand; den tatsächlich angewendeten Stand einer Installation bestimmt deren Datenbank.
|
|
|
|
Mobile-App und Device-Agent behalten ihre eigenen bestehenden Versionsreihen. Ihre Paketversionen und die lokale iOS-Buildnummer werden im Manifest festgehalten. Die iOS-Buildnummer aus einer externen EAS-Ausführung kann davon abweichen. Ein Server-Release startet keine App-Store-Veröffentlichung und behauptet keine automatisch geprüfte Kompatibilität mit unabhängig veröffentlichten Clients. Inkompatible API-Änderungen gehören als Breaking Change mit betroffenen Client-Versionen und Upgrade-Anleitung in die Release Notes.
|
|
|
|
## Laufende Version abfragen
|
|
|
|
Im Frontend steht die Version unten in der Seitenleiste; der Tooltip enthält den Commit. Die Backend-Version ist öffentlich über diesen Endpunkt abrufbar:
|
|
|
|
```bash
|
|
curl https://app.example.com/backend/version
|
|
```
|
|
|
|
Beispiel: `{"product":"FEDEO","version":"3.2.0","revision":"<Commit-ID>"}`. Die zentrale Instanzmeldung verwendet dieselbe Backend-Version. Bei lokalen Builds ohne Build-Argumente lautet die Version `0.0.0-dev`.
|
|
|
|
## Gitea einmalig vorbereiten
|
|
|
|
Der vorhandene Actions-Runner benötigt Docker mit Buildx und Netzwerkzugriff auf npm, Basis-Images und die Registry. Alle Images werden wie der bisherige Backend-Build für `linux/amd64` erzeugt. Eine zusätzliche ARM-Variante ist ein eigener Ausbau.
|
|
|
|
Unter Repository → Settings → Actions → Variables bzw. Secrets:
|
|
|
|
- `CI_TOKEN`: Token des Registry-Benutzers `flfeders`, mindestens mit `write:package`. Die Registry-Anmeldung verwendet wie die bisherigen Build-Workflows vorrangig `vars.CI_TOKEN`; `secrets.CI_TOKEN` dient als Rückfallwert. Für eine spätere Umstellung auf ein Secret die gleichnamige Variable entfernen.
|
|
- Optional `RELEASE_TOKEN` als Secret oder Variable: Token mit `write:repository` für Release-API und Git-Tags sowie zum Erzeugen/Löschen des temporären Sperr-Branches `automation/release-lock`. Nur `main` benötigt diese Rechte. Die Reihenfolge für Git-Anmeldung und Release-API ist `secrets.RELEASE_TOKEN`, `vars.RELEASE_TOKEN`, `vars.CI_TOKEN`, `secrets.CI_TOKEN`. Ohne separates Release-Token benötigt der verwendete `CI_TOKEN` zusätzlich diese Rechte.
|
|
|
|
Auf `dev` nutzt der Checkout wie die bisherigen Workflows den normalen Job-Token zum Lesen. Entwicklungsbuilds pushen keine Git-Refs und rufen die Release-API nicht auf; der Registry-Token benötigt dafür keine Repository-Schreibrechte.
|
|
|
|
Der Release-Token-Benutzer muss die entsprechenden Repository-Rechte haben. Geschützte Tags `v*` müssen ihn zulassen; `automation/release-lock` muss durch ihn erzeugt und entfernt werden können. Die Pipeline benötigt keine Schreibrechte auf den Inhalt von `main`. Ein 403 beim Anlegen der Main-Sperre führt vor dem Image-Build zum Abbruch mit einem Hinweis auf die fehlenden Rechte.
|
|
|
|
`dev` mit der neuen Konfiguration zu pushen prüft zunächst den Entwicklungsbuild. Erst die bewusste Übernahme nach `main` erstellt den ersten stabilen Release. Release-Erstellung und Deployment haben eigene Auslöser: Server werden durch diese Pipeline nicht neu gestartet.
|
|
|
|
## Veröffentlichungsreihenfolge und Wiederaufnahme
|
|
|
|
Gitea 1.25 ignoriert das Workflow-Feld `concurrency`. Deshalb reserviert der Runner für Releases auf `main` atomar einen Git-Branch per leerem `--force-with-lease`. Ein zweiter Release-Runner wartet bis zu zwei Stunden, ohne die Sperre zu übernehmen. Veraltete Main-Läufe werden vor dem Build übersprungen, wenn bereits ein neuerer Main-Commit vorhanden ist; dessen Lauf enthält alle ausstehenden Änderungen.
|
|
|
|
Entwicklungsbuilds benötigen keine Git-Sperre. Parallele Läufe bauen unabhängige Snapshot-Tags. Nach dem vollständigen Build wird vor jeder Aktualisierung eines `dev`-Images geprüft, ob der Commit noch der aktuelle Stand von `origin/dev` ist. Ein erkennbar veralteter Lauf beendet die Aktualisierung. Diese Prüfung und die Registry-Aktualisierung sind nicht atomar; für einen festen Stand aller Komponenten denselben vollständigen Snapshot-Tag oder einen stabilen Release verwenden.
|
|
|
|
1. Vollständigen Commit und Tags laden, Commit-Nachrichten prüfen, Version berechnen.
|
|
2. Alle sechs Images aus diesem Checkout mit Lockfiles bauen. Der Backend-Build führt zusätzlich seine Tests aus. Vorher laufen die Release-Tests in einem eigenen Job.
|
|
3. Gitea-Entwurf erzeugen und Dateien hochladen, zuerst das Manifest mit den gebauten Digests.
|
|
4. Unveränderliche Image-Tags auf diese Digests setzen. Ein vorhandener abweichender Digest führt zum Abbruch.
|
|
5. Release veröffentlichen; Gitea erzeugt dabei den Git-Tag auf dem konkreten Commit.
|
|
6. `latest` und `main` auf die veröffentlichten Images umstellen, anschließend die Sperre entfernen.
|
|
|
|
Bei einem Release-Fehler den fehlgeschlagenen Workflow **am ursprünglichen Commit erneut ausführen**. Ein vorhandenes Manifest wird weiterverwendet; veröffentlichte Versionen werden nicht neu gebaut. Auch eine unterbrochene Aktualisierung von `latest` lässt sich so vervollständigen. Die Registry bietet keine gemeinsame Transaktion über mehrere Images: deshalb verwendet Selfhosting feste Versionen und das Manifest die exakten Digests.
|
|
|
|
Ein anderer noch offener Release-Entwurf blockiert einen neuen Release. Zuerst den ursprünglichen Lauf wiederaufnehmen; anschließend den aktuellen Main-Lauf erneut starten. Releases oder Versionstags nicht löschen, um einen fehlgeschlagenen Lauf zu überspringen.
|
|
|
|
Nach einem hart abgebrochenen Runner kann die Sperre bestehen bleiben. Zuerst in Actions sicherstellen, dass der zugehörige Lauf wirklich beendet ist. Danach ausschließlich dessen Sperre mit dem zuvor gelesenen Commit als Lease entfernen:
|
|
|
|
```bash
|
|
git ls-remote origin refs/heads/automation/release-lock
|
|
# Die ausgegebene Commit-ID anstelle von LOCK_SHA einsetzen:
|
|
git push --force-with-lease=refs/heads/automation/release-lock:LOCK_SHA origin :refs/heads/automation/release-lock
|
|
```
|
|
|
|
Keine aktive Sperre löschen. Der Lease verhindert, dass zwischenzeitlich eine andere Sperre entfernt wird. Entwicklungsbuilds erzeugen keine Sperre und können direkt erneut gestartet werden.
|
|
|
|
## Selfhosting und Updates
|
|
|
|
Für eine Installation eines bereits veröffentlichten Releases, hier beispielhaft `3.0.0`:
|
|
|
|
```bash
|
|
curl -fsSL https://git.federspiel.tech/flfeders/FEDEO/releases/download/v3.0.0/selfhost-install.sh -o /tmp/fedeo-install.sh
|
|
bash /tmp/fedeo-install.sh --simple --start
|
|
```
|
|
|
|
Dieser versionierte Installer lädt die Betriebsdateien vom zugehörigen Git-Tag und schreibt `FEDEO_VERSION=3.0.0` in die neue `.env`. Vorhandene Installationen behalten ihren bisherigen Kanal, bis `FEDEO_VERSION` bewusst geändert wird. Die Dateien im Entwicklungszweig verwenden weiterhin `dev` als Rückfallwert.
|
|
|
|
Bei einem Update:
|
|
|
|
1. Release Notes und Migrationshinweise lesen. Konsistentes Datenbankbackup (z. B. `pg_dump`) sowie Datei-/Objektspeicher und Konfiguration sichern. Ein TAR des laufenden PostgreSQL-Datenverzeichnisses ist kein verlässliches Datenbankbackup.
|
|
2. Die benötigten Betriebsdateien vom gewünschten Release herunterladen; bestehende `.env` und Daten behalten. Downloads mit dessen `SHA256SUMS` überprüfen.
|
|
3. In `/opt/fedeo/.env` die feste Zielversion setzen, z. B. `FEDEO_VERSION=3.2.0`.
|
|
4. Images laden und Dienste neu erstellen:
|
|
|
|
```bash
|
|
docker compose --env-file /opt/fedeo/.env -f /opt/fedeo/docker-compose.yml pull
|
|
docker compose --env-file /opt/fedeo/.env -f /opt/fedeo/docker-compose.yml up -d
|
|
curl https://app.example.com/backend/version
|
|
```
|
|
|
|
Das Backend führt standardmäßig Vorwärtsmigrationen beim Start aus. Ein Downgrade der Images setzt die Datenbank nicht zurück. Zur vorherigen Version nur bei nachgewiesener Schema-Kompatibilität wechseln oder das passende Backup in einem geplanten Wiederherstellungsablauf einspielen.
|
|
|
|
## Technische Referenzen
|
|
|
|
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
|
|
- [semantic-release Commit-Analyse](https://github.com/semantic-release/commit-analyzer)
|
|
- [Gitea 1.25 Actions-Einschränkungen](https://docs.gitea.com/1.25/usage/actions/comparison/)
|
|
- [Gitea 1.25 API](https://docs.gitea.com/api/1.25/)
|
|
- [Codex-Projektanweisungen mit AGENTS.md](https://learn.chatgpt.com/docs/agent-configuration/agents-md)
|