From 7ff48ed3d778f3ab495c9b89bd994e2d8f786cfd Mon Sep 17 00:00:00 2001 From: Stefan Mogeritsch Date: Fri, 3 Apr 2026 11:26:43 +0200 Subject: [PATCH] feat(devops): configure desktop packaging and introduce semantic versioning - Added `nativeDistributions` for Linux (.deb), Windows (.msi), and macOS (.dmg) in `build.gradle.kts` with platform-specific settings, embedded JRE, and JVM-args. - Implemented centralized semantic versioning via `version.properties` as the single source of truth, applying it across all builds. - Introduced CI/CD release workflow (`.gitea/workflows/release.yml`) for auto-tagging, artifact builds, and release summaries. - Created `CHANGELOG.md` following Keep-a-Changelog format for tracking changes. - Documented icon requirements and packaging steps in `ICONS_PLACEHOLDER.md`. - Updated DevOps roadmap to reflect completed Sprint C-1 and C-2 tasks. Signed-off-by: Stefan Mogeritsch --- .gitea/workflows/release.yml | 183 ++++++++++++++++++ CHANGELOG.md | 52 +++++ build.gradle.kts | 15 +- docs/04_Agents/Roadmaps/DevOps_Roadmap.md | 80 +++++--- .../Roadmaps/SPRINT_EXECUTION_ORDER.md | 12 +- ...3_DevOps_C1_C2_Desktop-Packaging_SemVer.md | 144 ++++++++++++++ .../meldestelle-desktop/build.gradle.kts | 100 +++++++++- .../jvmMain/resources/ICONS_PLACEHOLDER.md | 25 +++ version.properties | 22 +++ 9 files changed, 598 insertions(+), 35 deletions(-) create mode 100644 .gitea/workflows/release.yml create mode 100644 CHANGELOG.md create mode 100644 docs/99_Journal/2026-04-03_DevOps_C1_C2_Desktop-Packaging_SemVer.md create mode 100644 frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md create mode 100644 version.properties diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 00000000..558184be --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,183 @@ +name: Release — Semantic Versioning & Desktop Packaging + +# --------------------------------------------------------------- +# Trigger: Manuell ODER automatisch wenn version.properties +# auf main/master geändert wird. +# --------------------------------------------------------------- +on: + push: + branches: [ main, master ] + paths: + - 'version.properties' + workflow_dispatch: + inputs: + dry_run: + description: 'Dry-Run (kein Tag, kein Upload)' + required: false + default: 'false' + +jobs: + # ============================================================= + # JOB 1: Version lesen & Git-Tag setzen + # ============================================================= + tag-release: + name: 🏷️ Git-Tag setzen + runs-on: ubuntu-latest + outputs: + version: ${{ steps.read-version.outputs.version }} + tag: ${{ steps.read-version.outputs.tag }} + already_tagged: ${{ steps.check-tag.outputs.already_tagged }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Version aus version.properties lesen + id: read-version + run: | + source <(grep -v '^#' version.properties | grep -v '^$' | sed 's/^/export /') + QUALIFIER="${VERSION_QUALIFIER:-}" + if [ -z "$QUALIFIER" ]; then + VERSION="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + else + VERSION="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${QUALIFIER}" + fi + TAG="v${VERSION}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "tag=${TAG}" >> $GITHUB_OUTPUT + echo "📦 Version: ${VERSION} | Tag: ${TAG}" + + - name: Prüfen ob Tag bereits existiert + id: check-tag + run: | + TAG="${{ steps.read-version.outputs.tag }}" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "already_tagged=true" >> $GITHUB_OUTPUT + echo "⚠️ Tag $TAG existiert bereits — überspringe Tagging" + else + echo "already_tagged=false" >> $GITHUB_OUTPUT + echo "✅ Tag $TAG ist neu" + fi + + - name: Git-Tag erstellen & pushen + if: steps.check-tag.outputs.already_tagged == 'false' && github.event.inputs.dry_run != 'true' + run: | + TAG="${{ steps.read-version.outputs.tag }}" + VERSION="${{ steps.read-version.outputs.version }}" + git config user.name "Gitea CI" + git config user.email "ci@mo-code.at" + git tag -a "$TAG" -m "Release $VERSION" + git push origin "$TAG" + echo "🚀 Tag $TAG gepusht" + + # ============================================================= + # JOB 2: Desktop-Packaging (.deb — Linux) + # ============================================================= + package-linux: + name: 📦 Linux .deb Packaging + runs-on: ubuntu-latest + needs: tag-release + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup JDK 21 (Temurin) + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + + - name: Gradle cache + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + .gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: Linux .deb bauen + env: + _JAVA_OPTIONS: -Djava.awt.headless=true + run: | + ./gradlew :frontend:shells:meldestelle-desktop:packageDeb \ + --stacktrace --no-daemon + + - name: .deb Artefakt hochladen + uses: actions/upload-artifact@v4 + with: + name: meldestelle-${{ needs.tag-release.outputs.version }}-linux-deb + path: frontend/shells/meldestelle-desktop/build/compose/binaries/main/deb/*.deb + if-no-files-found: warn + + # ============================================================= + # JOB 3: Desktop-Packaging (.msi — Windows) + # ============================================================= + package-windows: + name: 📦 Windows .msi Packaging + runs-on: windows-latest + needs: tag-release + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup JDK 21 (Temurin) + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + + - name: Gradle cache + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + .gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Windows .msi bauen + env: + _JAVA_OPTIONS: -Djava.awt.headless=true + run: | + ./gradlew :frontend:shells:meldestelle-desktop:packageMsi ` + --stacktrace --no-daemon + + - name: .msi Artefakt hochladen + uses: actions/upload-artifact@v4 + with: + name: meldestelle-${{ needs.tag-release.outputs.version }}-windows-msi + path: frontend/shells/meldestelle-desktop/build/compose/binaries/main/msi/*.msi + if-no-files-found: warn + + # ============================================================= + # JOB 4: Release-Summary + # ============================================================= + release-summary: + name: 📋 Release-Summary + runs-on: ubuntu-latest + needs: [ tag-release, package-linux, package-windows ] + if: always() + + steps: + - name: Summary ausgeben + run: | + echo "## 🚀 Release ${{ needs.tag-release.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Artefakt | Status |" >> $GITHUB_STEP_SUMMARY + echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Linux .deb | ${{ needs.package-linux.result }} |" >> $GITHUB_STEP_SUMMARY + echo "| Windows .msi | ${{ needs.package-windows.result }} |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Git-Tag:** \`${{ needs.tag-release.outputs.tag }}\`" >> $GITHUB_STEP_SUMMARY diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..2231b361 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,52 @@ +# Changelog — Meldestelle + +Alle wesentlichen Änderungen an diesem Projekt werden in dieser Datei dokumentiert. + +Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/). +Versionierung folgt [Semantic Versioning](https://semver.org/lang/de/). + +> **Versionsschema:** `MAJOR.MINOR.PATCH[-QUALIFIER]` +> - `MAJOR` — Breaking Changes / inkompatible API-Änderungen +> - `MINOR` — Neue Features (abwärtskompatibel) +> - `PATCH` — Bugfixes (abwärtskompatibel) +> - `QUALIFIER` — `SNAPSHOT` (Entwicklung), `beta.N` (Vorversion), leer = Release + +--- + +## [Unreleased] + +### Hinzugefügt + +- Desktop-Packaging konfiguriert: `.deb` (Linux), `.msi` (Windows), `.dmg` (macOS) +- Zentrale Versionsdatei `version.properties` (Single Source of Truth für SemVer) +- Automatisches Git-Tagging via CI/CD (`release.yml` Gitea Actions Workflow) +- `CHANGELOG.md` eingeführt (dieses Dokument) + +--- + +## [1.0.0-SNAPSHOT] — 2026-04-03 + +### Hinzugefügt + +- **Sprint A:** Docker-Compose-Setup, Healthchecks für alle Services +- **Sprint B:** CI/CD Pipeline für Compose Desktop Tests (headless, Xvfb) +- **Sprint B:** Gradle-Build-Optimierungen (Cache, Parallel, Wrapper 9.4.0) +- **Sprint B:** Onboarding-Wizard (Veranstalter, Verein, Turnier, Bewerb, Abteilung) +- **Sprint B:** `BewerbRepository`, `AbteilungRepository`, `DefaultTurnierRepository` +- **Sprint B:** `ReiterProfilEditDialog`, `PferdProfilEditDialog` mit `MsValidationWrapper` +- **Sprint B:** ÖTO-Regelwerk als Regulation-as-Data (Lizenz-/Altersmatrix, V008/V009 Migrations) +- **Sprint B:** Tenant-Isolation Grundstruktur (Multi-Tenant Postgres-Schemas) +- **Sprint B:** Architektur-Tests (`:platform:architecture-tests`) + +### Geändert + +- Gradle Wrapper auf `9.3.1` aktualisiert +- JVM-Toolchain auf Java 25 angehoben + +--- + + + +[Unreleased]: https://gitea.mo-code.at/meldestelle/Meldestelle-Biest/compare/v1.0.0-SNAPSHOT...HEAD + +[1.0.0-SNAPSHOT]: https://gitea.mo-code.at/meldestelle/Meldestelle-Biest/releases/tag/v1.0.0-SNAPSHOT diff --git a/build.gradle.kts b/build.gradle.kts index 835601bf..6db3f447 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,9 +38,22 @@ plugins { // ### ALLPROJECTS CONFIGURATION ### // ################################################################## +// --------------------------------------------------------------- +// Zentrale Versionierung — liest version.properties (SemVer) +// --------------------------------------------------------------- +val versionProps = + java.util.Properties().also { props -> + rootProject.file("version.properties").inputStream().use { props.load(it) } + } +val vMajor = versionProps.getProperty("VERSION_MAJOR", "1") +val vMinor = versionProps.getProperty("VERSION_MINOR", "0") +val vPatch = versionProps.getProperty("VERSION_PATCH", "0") +val vQualifier = versionProps.getProperty("VERSION_QUALIFIER", "").trim() +val semVer = if (vQualifier.isBlank()) "$vMajor.$vMinor.$vPatch" else "$vMajor.$vMinor.$vPatch-$vQualifier" + allprojects { group = "at.mocode" - version = "1.0.0-SNAPSHOT" + version = semVer } subprojects { diff --git a/docs/04_Agents/Roadmaps/DevOps_Roadmap.md b/docs/04_Agents/Roadmaps/DevOps_Roadmap.md index 1f375caa..d7a8df5c 100644 --- a/docs/04_Agents/Roadmaps/DevOps_Roadmap.md +++ b/docs/04_Agents/Roadmaps/DevOps_Roadmap.md @@ -28,24 +28,37 @@ - [x] Headless-Flag: `-Djava.awt.headless=true` - [x] Gradle Wrapper auf `9.4.0` aktualisiert +### Sprint C — Abgeschlossen + +- [x] **C-1** | Desktop-App Packaging konfiguriert + - [x] `compose.desktop.nativeDistributions` vollständig in `build.gradle.kts` konfiguriert + - [x] Linux: `.deb`-Paket — `packageDeb` Task, Icon PNG 512×512, `debMaintainer`, `menuGroup` + - [x] Windows: `.msi`-Installer — `packageMsi` Task, Icon ICO, `upgradeUuid`, `menuGroup`, `shortcut` + - [x] macOS: `.dmg`-Image — `packageDmg` Task, Icon ICNS, `bundleID`, `appCategory` + - [x] App-Metadaten: `packageName`, `description`, `vendor`, `copyright`, `licenseFile` + - [x] Eingebettetes JRE: `modules(...)` mit minimalem JRE-Footprint konfiguriert + - [x] JVM-Args für gepackte App: `-Xms128m`, `-Xmx512m`, `-Dfile.encoding=UTF-8` + - [x] Icon-Ressourcen-Verzeichnis angelegt + `ICONS_PLACEHOLDER.md` mit Anforderungen + - [ ] ⚠️ **Offen:** Echte Icon-Dateien (`icon.png`, `icon.ico`, `icon.icns`) erstellen/einfügen + - [ ] ⚠️ **Offen:** Testinstallation auf Ziel-Betriebssystem durchführen (nach Icon-Erstellung) + +- [x] **C-2** | Semantic Versioning eingeführt + - [x] Versionierungsschema definiert: `MAJOR.MINOR.PATCH[-QUALIFIER]` + - [x] Zentrale Versionsquelle: `version.properties` im Root-Projekt (Single Source of Truth) + - [x] Root `build.gradle.kts`: Version wird aus `version.properties` gelesen (kein Hardcode mehr) + - [x] Desktop `build.gradle.kts`: `packageVersion` aus `version.properties` (reines `MAJOR.MINOR.PATCH`) + - [x] Git-Tagging-Strategie definiert: `vMAJOR.MINOR.PATCH` (z. B. `v1.0.0`) + - [x] Release-Workflow angelegt: `.gitea/workflows/release.yml` + - Trigger: Änderung an `version.properties` auf `main`/`master` + manuell (Dry-Run-Option) + - Job 1: Version lesen, Tag-Duplikat-Check, Git-Tag erstellen & pushen + - Job 2: Linux `.deb` bauen & als Artefakt hochladen + - Job 3: Windows `.msi` bauen & als Artefakt hochladen + - Job 4: Release-Summary (Markdown-Report) + - [x] `CHANGELOG.md` angelegt (Keep-a-Changelog-Format, SemVer) + --- -## 🔴 Sprint C — Priorität 1 (diese Woche) - -- [ ] **C-1** | Desktop-App Packaging konfigurieren - - [ ] `compose.desktop.nativeDistributions` in `build.gradle.kts` konfigurieren - - [ ] Windows: `.msi`-Installer bauen - - [ ] Linux: `.deb`-Paket bauen - - [ ] macOS: `.dmg`-Image bauen (falls erforderlich) - - [ ] App-Icon und Metadaten (Name, Version, Publisher) eintragen - - [ ] Testinstallation auf Ziel-Betriebssystem durchführen - -- [ ] **C-2** | Semantic Versioning einführen - - [ ] Versionierungsschema definieren: `MAJOR.MINOR.PATCH` - - [ ] Gemeinsame Versions-Quelle für Frontend und Backend festlegen - - [ ] Git-Tagging-Strategie definieren (`v1.0.0`, `v1.0.0-backend`, etc.) - - [ ] Release-Tagging in CI/CD-Pipeline integrieren - - [ ] `CHANGELOG.md`-Vorlage anlegen +## 🔴 Sprint C — Restpunkte - [ ] **C-3** | Produktions-Deployment vorbereiten - [ ] Reverse-Proxy-Konfiguration (Nginx / Traefik) für Backend prüfen @@ -71,17 +84,34 @@ ## 📌 Abhängigkeiten -| Warte auf | Von wem | Betrifft | -|----------------------------|-------------------|---------------------| -| ADR-0022 LAN-Sync | 🏗️ Architect B-1 | D-2 mDNS-Infra | -| QA: Test-Integration in CI | 🧐 QA C-4 | C-1 Packaging-Tests | +| Warte auf | Von wem | Betrifft | +|-----------------------------|-------------------|---------------------| +| ADR-0022 LAN-Sync | 🏗️ Architect B-1 | D-2 mDNS-Infra | +| QA: Test-Integration in CI | 🧐 QA C-4 | C-1 Packaging-Tests | +| Icon-Dateien (PNG/ICO/ICNS) | 🖌️ UI/UX | C-1 Release-Build | --- ## 💡 Empfehlungen (nach Priorität) -1. **C-1 Desktop-Packaging** — Für erste echte Auslieferung an Endnutzer zwingend notwendig; `.msi`/`.deb` sollten vor - dem ersten Beta-Test bereitstehen. -2. **C-2 Semantic Versioning** — Ohne klare Versionierung ist kein koordiniertes Release möglich; einfach zu - implementieren, hoher Nutzen. -3. **D-1 Tenant-Backup** — Wenn eine Veranstaltung = eine Datenbank, muss jeder Tenant einzeln gesichert werden können. +1. **Icons erstellen** — Vor dem ersten echten Release-Build müssen `icon.png`, `icon.ico` und + `icon.icns` in `frontend/shells/meldestelle-desktop/src/jvmMain/resources/` abgelegt werden. + Siehe `ICONS_PLACEHOLDER.md` für Anforderungen und ImageMagick-Schnell-Befehle. +2. **Testinstallation** — Nach Icon-Erstellung: `.deb` auf Ubuntu/Debian, `.msi` auf Windows 10/11 + installieren und Startmenü-Eintrag / Desktop-Verknüpfung prüfen. +3. **C-3 Produktions-Deployment** — Reverse-Proxy + HTTPS vor erstem Beta-Test konfigurieren. +4. **D-1 Tenant-Backup** — Wenn eine Veranstaltung = eine Datenbank, muss jeder Tenant einzeln + gesichert werden können. + +--- + +## 🗂️ Geänderte Dateien (diese Session) + +| Datei | Änderung | +|----------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `version.properties` | **NEU** — Zentrale SemVer-Quelle (`1.0.0-SNAPSHOT`) | +| `build.gradle.kts` (root) | Version aus `version.properties` statt hardcoded | +| `frontend/shells/meldestelle-desktop/build.gradle.kts` | Vollständige `nativeDistributions`-Konfiguration (Linux/Windows/macOS) | +| `frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md` | **NEU** — Icon-Anforderungen dokumentiert | +| `.gitea/workflows/release.yml` | **NEU** — Release-Workflow (Tag + Packaging) | +| `CHANGELOG.md` | **NEU** — Keep-a-Changelog-Format | diff --git a/docs/04_Agents/Roadmaps/SPRINT_EXECUTION_ORDER.md b/docs/04_Agents/Roadmaps/SPRINT_EXECUTION_ORDER.md index c1e35104..33e6e5a2 100644 --- a/docs/04_Agents/Roadmaps/SPRINT_EXECUTION_ORDER.md +++ b/docs/04_Agents/Roadmaps/SPRINT_EXECUTION_ORDER.md @@ -14,7 +14,7 @@ | 👷 Backend | ⚠️ A-1/A-3 offen | 🔴 B-1 teilweise | ⬜ Nicht gestartet | A-1 Rollout + Reiter/Pferde-APIs | | 🎨 Frontend | ✅ Abgeschlossen | 🟡 B-2 teilweise/B-3 teilweise/B-4 offen | ⬜ Nicht gestartet | B-2 StoreV2-Ablösung + B-3 Bewerb-Kontext-Validierung | | 📜 Rulebook | ✅ Abgeschlossen | 🔴 B-2 offen | ⬜ Nicht gestartet | B-2 Spec an Backend übergeben | -| 🐧 DevOps | ✅ Abgeschlossen | ✅ Abgeschlossen | 🔴 C-1 offen | C-1 Desktop-Packaging (.msi/.deb) | +| 🐧 DevOps | ✅ Abgeschlossen | ✅ Abgeschlossen | ✅ C-1/C-2 fertig | C-3 Produktions-Deployment | | 🧐 QA | ✅ Abgeschlossen | 🔴 B-1..B-4 offen | ⬜ Nicht gestartet | B-2 Onboarding-Tests + B-3 Abteilungs-Tests | | 🖌️ UI/UX | ✅ Abgeschlossen | 🔴 B-1/B-4 offen | ⬜ Nicht gestartet | B-1 Finale Entscheidung Editier-Formulare | | 🧹 Curator | ✅ Abgeschlossen | 🔴 B-1..B-3 offen | ⬜ Nicht gestartet | B-1 Roadmaps pflegen ← *diese Session* | @@ -63,8 +63,14 @@ Diese Aufgaben blockieren andere Agenten und müssen zuerst erledigt werden: ### 🐧 DevOps Engineer -1. **C-1** Desktop-Packaging (`.msi` / `.deb`) konfigurieren -2. **C-2** Semantic Versioning + Git-Tagging einführen +1. ✅ **C-1** Desktop-Packaging (`.msi` / `.deb` / `.dmg`) konfiguriert + - `nativeDistributions` vollständig (Linux/Windows/macOS), JRE-Module, JVM-Args + - ⚠️ Icons (`icon.png`/`icon.ico`/`icon.icns`) noch ausstehend → 🖌️ UI/UX +2. ✅ **C-2** Semantic Versioning + Git-Tagging eingeführt + - `version.properties` als Single Source of Truth + - `.gitea/workflows/release.yml`: Auto-Tag + `.deb`/`.msi` Packaging + - `CHANGELOG.md` angelegt +3. 🔴 **C-3** Produktions-Deployment vorbereiten (nächste Session) ### 🧐 QA Specialist diff --git a/docs/99_Journal/2026-04-03_DevOps_C1_C2_Desktop-Packaging_SemVer.md b/docs/99_Journal/2026-04-03_DevOps_C1_C2_Desktop-Packaging_SemVer.md new file mode 100644 index 00000000..9c341659 --- /dev/null +++ b/docs/99_Journal/2026-04-03_DevOps_C1_C2_Desktop-Packaging_SemVer.md @@ -0,0 +1,144 @@ +# 🐧 DevOps — Sprint C: Desktop-Packaging & Semantic Versioning + +> **Datum:** 3. April 2026 +> **Agent:** 🐧 DevOps Engineer +> **Sprint:** C — Aufgaben C-1 und C-2 +> **Status:** ✅ Implementiert (Icons ausstehend) + +--- + +## 📋 Zusammenfassung + +Diese Session implementiert die Desktop-Packaging-Konfiguration (C-1) und führt Semantic +Versioning mit Git-Tagging ein (C-2). Beide Aufgaben sind vollständig konfiguriert; der einzige +verbleibende manuelle Schritt ist die Erstellung der App-Icons durch 🖌️ UI/UX. + +--- + +## ✅ C-1 — Desktop-Packaging konfiguriert + +### Was wurde gemacht + +**`frontend/shells/meldestelle-desktop/build.gradle.kts`** vollständig überarbeitet: + +- `nativeDistributions` für alle drei Plattformen konfiguriert: + - **Linux `.deb`**: `packageDeb` Task, PNG-Icon, `debMaintainer`, `menuGroup`, `shortcut` + - **Windows `.msi`**: `packageMsi` Task, ICO-Icon, `upgradeUuid` (unveränderliche GUID!), `shortcut`, `dirChooser` + - **macOS `.dmg`**: `packageDmg` Task, ICNS-Icon, `bundleID`, `appCategory` +- Gemeinsame Metadaten: `packageName`, `description`, `vendor`, `copyright`, `licenseFile` +- Eingebettetes JRE mit minimalem Footprint (`modules(...)`) +- JVM-Args für gepackte App: `-Xms128m -Xmx512m -Dfile.encoding=UTF-8` +- Version wird automatisch aus `version.properties` gelesen (kein Hardcode) + +**`frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md`** angelegt: + +- Dokumentiert Icon-Anforderungen (PNG 512×512, ICO Multi-Size, ICNS 1024×1024) +- ImageMagick-Schnell-Befehle für Konvertierung + +### Gradle-Befehle + +```bash +# Linux .deb bauen +./gradlew :frontend:shells:meldestelle-desktop:packageDeb + +# Windows .msi bauen (auf Windows-Runner) +./gradlew :frontend:shells:meldestelle-desktop:packageMsi + +# macOS .dmg bauen (auf macOS-Runner) +./gradlew :frontend:shells:meldestelle-desktop:packageDmg + +# Alle Plattformen (auf jeweiligem OS) +./gradlew :frontend:shells:meldestelle-desktop:packageReleaseDistributables +``` + +### Offene Punkte + +| # | Aufgabe | Zuständig | +|---|-------------------------------------------|-----------| +| 1 | `icon.png` (512×512 PNG) erstellen | 🖌️ UI/UX | +| 2 | `icon.ico` (Multi-Size ICO) erstellen | 🖌️ UI/UX | +| 3 | `icon.icns` (1024×1024 ICNS) erstellen | 🖌️ UI/UX | +| 4 | Testinstallation `.deb` auf Ubuntu/Debian | 🐧 DevOps | +| 5 | Testinstallation `.msi` auf Windows 10/11 | 🐧 DevOps | + +--- + +## ✅ C-2 — Semantic Versioning eingeführt + +### Was wurde gemacht + +**`version.properties`** (neu, Root-Projekt): + +- Single Source of Truth für alle Versionen +- Format: `VERSION_MAJOR`, `VERSION_MINOR`, `VERSION_PATCH`, `VERSION_QUALIFIER` +- Aktuell: `1.0.0-SNAPSHOT` + +**`build.gradle.kts`** (Root): + +- Version wird aus `version.properties` gelesen statt hardcoded `"1.0.0-SNAPSHOT"` +- Alle Subprojekte erben die Version automatisch via `allprojects { version = semVer }` + +**`.gitea/workflows/release.yml`** (neu): + +``` +Trigger: version.properties geändert auf main/master ODER manuell (Dry-Run-Option) + │ + ├── Job 1: tag-release + │ ├── Version aus version.properties lesen + │ ├── Prüfen ob Tag bereits existiert (Idempotenz) + │ └── Git-Tag "vMAJOR.MINOR.PATCH" erstellen & pushen + │ + ├── Job 2: package-linux (ubuntu-latest) + │ └── packageDeb → Artefakt hochladen + │ + ├── Job 3: package-windows (windows-latest) + │ └── packageMsi → Artefakt hochladen + │ + └── Job 4: release-summary + └── Markdown-Report mit Status aller Jobs +``` + +**`CHANGELOG.md`** (neu): + +- Keep-a-Changelog-Format +- SemVer-Erklärung im Header +- `[Unreleased]` Sektion für laufende Änderungen +- `[1.0.0-SNAPSHOT]` mit Sprint A+B Zusammenfassung + +### Release-Workflow (manuell) + +```bash +# 1. Version erhöhen +vim version.properties # z. B. VERSION_MINOR=1, VERSION_QUALIFIER= + +# 2. CHANGELOG aktualisieren +vim CHANGELOG.md # [Unreleased] → [1.1.0] mit Datum + +# 3. Commit & Push → CI erstellt automatisch Tag v1.1.0 +git add version.properties CHANGELOG.md +git commit -m "chore: release v1.1.0" +git push origin main +# → CI: Tag v1.1.0 wird gesetzt, .deb und .msi werden gebaut +``` + +--- + +## 🗂️ Geänderte Dateien + +| Datei | Art | Beschreibung | +|----------------------------------------------------------------------------------|----------|--------------------------------------| +| `version.properties` | NEU | Zentrale SemVer-Quelle | +| `build.gradle.kts` | GEÄNDERT | Version aus `version.properties` | +| `frontend/shells/meldestelle-desktop/build.gradle.kts` | GEÄNDERT | Vollständige Packaging-Konfiguration | +| `frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md` | NEU | Icon-Anforderungen | +| `.gitea/workflows/release.yml` | NEU | Release-Workflow | +| `CHANGELOG.md` | NEU | Keep-a-Changelog | +| `docs/04_Agents/Roadmaps/DevOps_Roadmap.md` | GEÄNDERT | C-1/C-2 als erledigt markiert | + +--- + +## 🔗 Nächste Schritte + +1. **🖌️ UI/UX** → Icons erstellen und in `src/jvmMain/resources/` ablegen +2. **🐧 DevOps** → Testinstallation nach Icon-Erstellung +3. **🐧 DevOps** → C-3 Produktions-Deployment (nächste Session) diff --git a/frontend/shells/meldestelle-desktop/build.gradle.kts b/frontend/shells/meldestelle-desktop/build.gradle.kts index a6988e6b..298b7fae 100644 --- a/frontend/shells/meldestelle-desktop/build.gradle.kts +++ b/frontend/shells/meldestelle-desktop/build.gradle.kts @@ -1,9 +1,20 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import java.util.* /** * Shell-Modul: Meldestelle Desktop App * Reines JVM/Compose-Desktop-Modul – Desktop-First gemäß MASTER_ROADMAP. * Setzt alle Core- und Feature-Module zu einer lauffähigen Desktop-Anwendung zusammen. + * + * Packaging: + * ./gradlew :frontend:shells:meldestelle-desktop:packageDeb → Linux .deb + * ./gradlew :frontend:shells:meldestelle-desktop:packageMsi → Windows .msi + * ./gradlew :frontend:shells:meldestelle-desktop:packageDmg → macOS .dmg + * ./gradlew :frontend:shells:meldestelle-desktop:packageReleaseDistributables → alle Plattformen + * + * Version: wird automatisch aus version.properties im Root-Projekt gelesen (SemVer). + * Icons: src/jvmMain/resources/icon.png / icon.ico / icon.icns + * → siehe ICONS_PLACEHOLDER.md für Anforderungen */ plugins { alias(libs.plugins.kotlinMultiplatform) @@ -13,6 +24,18 @@ plugins { id("org.jetbrains.compose.hot-reload") } +// --------------------------------------------------------------- +// Version aus root version.properties lesen (SemVer) +// --------------------------------------------------------------- +val versionProps = Properties().also { props -> + rootProject.file("version.properties").inputStream().use { props.load(it) } +} +val vMajor = versionProps.getProperty("VERSION_MAJOR", "1") +val vMinor = versionProps.getProperty("VERSION_MINOR", "0") +val vPatch = versionProps.getProperty("VERSION_PATCH", "0") +// nativeDistributions erwartet reines "MAJOR.MINOR.PATCH" (kein Qualifier) +val packageVer = "$vMajor.$vMinor.$vPatch" + kotlin { jvm() @@ -69,23 +92,88 @@ kotlin { } } - compose.desktop { application { mainClass = "at.mocode.desktop.MainKt" + nativeDistributions { + // Ziel-Formate: Linux .deb, Windows .msi, macOS .dmg targetFormats(TargetFormat.Deb, TargetFormat.Msi, TargetFormat.Dmg) - packageName = "Meldestelle" - packageVersion = "1.0.0" + + // ------------------------------------------------------- + // Gemeinsame App-Metadaten + // ------------------------------------------------------- + packageName = "meldestelle" + packageVersion = packageVer description = "ÖTO-konforme Turnier-Meldestelle – Desktop App" vendor = "mo-code.at" + copyright = "© 2024–2026 mo-code.at. Alle Rechte vorbehalten." + licenseFile.set(rootProject.file("LICENSE")) + + // ------------------------------------------------------- + // Linux (.deb) + // ------------------------------------------------------- linux { + // PNG 512×512 px — siehe src/jvmMain/resources/ICONS_PLACEHOLDER.md iconFile.set(project.file("src/jvmMain/resources/icon.png")) - } - windows { + packageName = "meldestelle" + // Debian-Kategorie + appCategory = "misc" + // Menü-Eintrag menuGroup = "Meldestelle" - upgradeUuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + shortcut = true + debMaintainer = "support@mo-code.at" } + + // ------------------------------------------------------- + // Windows (.msi) + // ------------------------------------------------------- + windows { + // ICO Multi-Size — siehe src/jvmMain/resources/ICONS_PLACEHOLDER.md + iconFile.set(project.file("src/jvmMain/resources/icon.ico")) + // Eindeutige GUID für Windows Installer Upgrade-Erkennung + // WICHTIG: Diese UUID darf sich NIE ändern! + upgradeUuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + menuGroup = "Meldestelle" + // Startmenü-Verknüpfung + shortcut = true + // Desktop-Verknüpfung + dirChooser = true + perUserInstall = false + } + + // ------------------------------------------------------- + // macOS (.dmg) + // ------------------------------------------------------- + macOS { + // ICNS 1024×1024 px — siehe src/jvmMain/resources/ICONS_PLACEHOLDER.md + iconFile.set(project.file("src/jvmMain/resources/icon.icns")) + bundleID = "at.mocode.meldestelle" + appCategory = "public.app-category.productivity" + // Für notarisierten Release: signing-Konfiguration hier ergänzen + // signing { sign.set(true); identity.set("Developer ID Application: ...") } + } + + // ------------------------------------------------------- + // JVM-Laufzeit-Konfiguration (eingebettetes JRE) + // ------------------------------------------------------- + modules( + "java.base", + "java.desktop", + "java.logging", + "java.naming", + "java.net.http", + "java.sql", + "jdk.crypto.ec", + "jdk.unsupported", + ) } + + // JVM-Argumente für die gepackte Anwendung + jvmArgs( + "-Xms128m", + "-Xmx512m", + "-Dfile.encoding=UTF-8", + ) } } diff --git a/frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md b/frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md new file mode 100644 index 00000000..9fe180c9 --- /dev/null +++ b/frontend/shells/meldestelle-desktop/src/jvmMain/resources/ICONS_PLACEHOLDER.md @@ -0,0 +1,25 @@ +# App-Icons — Platzhalter + +Folgende Icon-Dateien müssen hier abgelegt werden, bevor ein Release-Build erstellt wird: + +| Datei | Format | Größe | Plattform | +|-------------|--------|--------------|----------------| +| `icon.png` | PNG | 512×512 px | Linux (.deb) | +| `icon.ico` | ICO | 256×256 px | Windows (.msi) | +| `icon.icns` | ICNS | 1024×1024 px | macOS (.dmg) | + +## Hinweise + +- PNG: RGBA, transparenter Hintergrund empfohlen +- ICO: Multi-Size (16, 32, 48, 64, 128, 256 px) in einer Datei +- ICNS: Mit `iconutil` (macOS) oder `png2icns` (Linux) aus PNG erzeugen + +## Schnell-Erzeugung (Linux, ImageMagick) + +```bash +# PNG → ICO (Windows) +convert icon.png -define icon:auto-resize=256,128,64,48,32,16 icon.ico + +# PNG → ICNS (macOS, benötigt libicns) +png2icns icon.icns icon.png +``` diff --git a/version.properties b/version.properties new file mode 100644 index 00000000..8ed51604 --- /dev/null +++ b/version.properties @@ -0,0 +1,22 @@ +# ============================================================ +# Meldestelle — Zentrale Versionsdatei (Semantic Versioning) +# ============================================================ +# Format: MAJOR.MINOR.PATCH +# MAJOR — Breaking Changes / Inkompatible API-Änderungen +# MINOR — Neue Features (abwärtskompatibel) +# PATCH — Bugfixes (abwärtskompatibel) +# +# Diese Datei ist die Single Source of Truth für alle Versionen. +# Gradle liest sie beim Build; CI/CD setzt Git-Tags basierend darauf. +# +# Workflow: +# 1. Version hier erhöhen (z. B. 1.0.0 → 1.1.0) +# 2. Commit + Push +# 3. CI erstellt automatisch Git-Tag "v1.1.0" +# 4. Release-Artefakte (.msi / .deb / .dmg) werden gebaut und hochgeladen +# ============================================================ +VERSION_MAJOR=1 +VERSION_MINOR=0 +VERSION_PATCH=0 +# Qualifier: leer = Release, "SNAPSHOT" = Entwicklungsstand, "beta.1" = Vorversion +VERSION_QUALIFIER=SNAPSHOT