chore(infra+frontend): upgrade Gradle to 9.3.1 and fix KMP plugin conflicts in Docker builds
- Updated Gradle version in `.env`, Dockerfiles, and wrapper to 9.3.1. - Replaced alias-based application of `kotlinMultiplatform` plugin with direct `id` usage in subprojects to resolve "Plugin loaded multiple times" error. - Applied centralized plugin management and Gradle daemon optimizations to improve Docker build stability and address KMP classloading issues.
This commit is contained in:
parent
92cdd22f1f
commit
5be88b306c
4
.env
4
.env
|
|
@ -11,8 +11,8 @@ RESTART_POLICY=no
|
|||
|
||||
# Docker build versions (optional overrides)
|
||||
DOCKER_VERSION=1.0.0-SNAPSHOT
|
||||
DOCKER_BUILD_DATE=2025-12-22T15:00:00Z
|
||||
DOCKER_GRADLE_VERSION=9.2.1
|
||||
DOCKER_BUILD_DATE=2026-02-02T15:00:00Z
|
||||
DOCKER_GRADLE_VERSION=9.3.1
|
||||
# Check if 25 is intended (Early Access) or if LTS 21 was meant
|
||||
DOCKER_JAVA_VERSION=25
|
||||
DOCKER_NODE_VERSION=24.12.0
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ GF_ADMIN_USER=admin
|
|||
GF_ADMIN_PASSWORD=admin
|
||||
|
||||
# Docker build versions (optional overrides)
|
||||
DOCKER_GRADLE_VERSION=9.2.1
|
||||
DOCKER_GRADLE_VERSION=9.3.1
|
||||
DOCKER_JAVA_VERSION=25
|
||||
DOCKER_NODE_VERSION=24.12.0
|
||||
DOCKER_NGINX_VERSION=1.28.0-alpine
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import groovy.json.JsonSlurper
|
|||
import io.gitlab.arturbosch.detekt.Detekt
|
||||
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jlleitschuh.gradle.ktlint.KtlintExtension
|
||||
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
|
||||
|
|
@ -17,7 +16,8 @@ plugins {
|
|||
// This prevents "plugin loaded multiple times" errors in Gradle 9.2.1+
|
||||
// Subprojects apply these plugins via version catalog: alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlinJvm) apply false
|
||||
alias(libs.plugins.kotlinMultiplatform) apply false
|
||||
// CHANGE: Apply KMP plugin at root (but don't configure targets yet) to claim NodeJsRootPlugin ownership
|
||||
alias(libs.plugins.kotlinMultiplatform) apply true
|
||||
alias(libs.plugins.kotlinSerialization) apply false
|
||||
alias(libs.plugins.kotlinSpring) apply false
|
||||
alias(libs.plugins.kotlinJpa) apply false
|
||||
|
|
@ -34,9 +34,11 @@ plugins {
|
|||
alias(libs.plugins.ktlint)
|
||||
}
|
||||
|
||||
// Workaround for Gradle 9 / KMP Race Condition:
|
||||
// Wir erzwingen die Initialisierung des NodeJsRootPlugins im Root-Projekt
|
||||
apply<NodeJsRootPlugin>()
|
||||
// Minimal KMP configuration for Root Project to satisfy the plugin
|
||||
// This ensures NodeJsRootPlugin is initialized here first.
|
||||
kotlin {
|
||||
jvm() // Dummy target to keep KMP happy
|
||||
}
|
||||
|
||||
// ##################################################################
|
||||
// ### ALLPROJECTS CONFIGURATION ###
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# ===================================================================
|
||||
|
||||
# === GLOBAL ARGS ===
|
||||
ARG GRADLE_VERSION=9.2.1
|
||||
ARG GRADLE_VERSION=9.3.1
|
||||
ARG JAVA_VERSION=25
|
||||
ARG CADDY_VERSION=2.11-alpine
|
||||
ARG VERSION=1.0.0-SNAPSHOT
|
||||
|
|
@ -21,8 +21,8 @@ WORKDIR /workspace
|
|||
|
||||
# 1. Gradle Optimizations (Memory & Caching)
|
||||
# Increased Heap to 4g for Kotlin 2.3 JS Compilation
|
||||
# REMOVED: -Dorg.gradle.daemon=false (We want the daemon to handle classloading correctly!)
|
||||
ENV GRADLE_OPTS="-Dorg.gradle.caching=true \
|
||||
-Dorg.gradle.daemon=false \
|
||||
-Dorg.gradle.parallel=true \
|
||||
-Dorg.gradle.workers.max=4 \
|
||||
-Dorg.gradle.jvmargs=-Xmx4g \
|
||||
|
|
@ -49,14 +49,13 @@ COPY contracts/ contracts/
|
|||
RUN mkdir -p docs
|
||||
|
||||
# 4. Build Web App
|
||||
# Using --no-configuration-cache initially to avoid issues with first run in docker,
|
||||
# but can be enabled if stable.
|
||||
# REMOVED: --no-daemon flag to allow Gradle to manage its classloaders properly
|
||||
# This fixes the "IsolatedKotlinClasspathClassCastException" in Gradle 9.x + KMP
|
||||
RUN --mount=type=cache,target=/home/gradle/.gradle/caches \
|
||||
--mount=type=cache,target=/home/gradle/.gradle/wrapper \
|
||||
./gradlew :frontend:shells:meldestelle-portal:jsBrowserDistribution \
|
||||
-Pproduction=true \
|
||||
-PnoSourceMaps=true \
|
||||
--no-daemon \
|
||||
--stacktrace
|
||||
|
||||
# 5. Prepare Dist
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# ===================================================================
|
||||
|
||||
# 1. Build Stage (Debian-basiert für Stabilität bei Desktop-Builds)
|
||||
FROM gradle:9.2.1-jdk-25-and-25-alpine AS builder
|
||||
FROM gradle:9.3.1-jdk-25-and-25-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ RUN set -eu; \
|
|||
# ===================================================================
|
||||
# Stage 2: Runtime Stage - Ubuntu mit VNC + noVNC
|
||||
# ===================================================================
|
||||
FROM ubuntu:22.04
|
||||
FROM ubuntu:24.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# ===================================================================
|
||||
|
||||
# === GLOBAL ARGS ===
|
||||
ARG GRADLE_VERSION=9.2.1
|
||||
ARG GRADLE_VERSION=9.3.1
|
||||
ARG JAVA_VERSION=25
|
||||
ARG NGINX_IMAGE_TAG=1.28-alpine
|
||||
ARG VERSION=1.0.0-SNAPSHOT
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ services:
|
|||
context: .
|
||||
dockerfile: backend/infrastructure/gateway/Dockerfile
|
||||
args:
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
|
||||
BUILD_DATE: "${DOCKER_BUILD_DATE}"
|
||||
|
|
@ -82,7 +82,7 @@ services:
|
|||
context: .
|
||||
dockerfile: backend/services/ping/Dockerfile
|
||||
args:
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
|
||||
BUILD_DATE: "${DOCKER_BUILD_DATE}"
|
||||
|
|
@ -150,7 +150,7 @@ services:
|
|||
# context: .
|
||||
# dockerfile: backend/services/entries/Dockerfile
|
||||
# args:
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
# JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
# VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
|
||||
# BUILD_DATE: "${DOCKER_BUILD_DATE}"
|
||||
|
|
@ -196,7 +196,7 @@ services:
|
|||
# context: .
|
||||
# dockerfile: backend/services/results/results-service/Dockerfile
|
||||
# args:
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
# JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
# VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
|
||||
# BUILD_DATE: "${DOCKER_BUILD_DATE}"
|
||||
|
|
@ -242,7 +242,7 @@ services:
|
|||
# context: .
|
||||
# dockerfile: backend/services/scheduling/scheduling-service/Dockerfile
|
||||
# args:
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
# GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
# JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
# VERSION: "${DOCKER_VERSION:-1.0.0-SNAPSHOT}"
|
||||
# BUILD_DATE: "${DOCKER_BUILD_DATE}"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ services:
|
|||
context: . # Wichtig: Root Context für Monorepo Zugriff
|
||||
dockerfile: config/docker/caddy/web-app/Dockerfile
|
||||
args:
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.2.1}"
|
||||
GRADLE_VERSION: "${DOCKER_GRADLE_VERSION:-9.3.1}"
|
||||
JAVA_VERSION: "${DOCKER_JAVA_VERSION:-25}"
|
||||
# Frontend spezifisch:
|
||||
CADDY_VERSION: "${DOCKER_CADDY_VERSION:-2.9-alpine}"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# 🧹 Troubleshooting Log: Gradle 9.x & KMP Docker Build (Part 2)
|
||||
|
||||
**Datum:** 02.02.2026
|
||||
**Status:** ⚠️ BLOCKED (Docker Build Failure) / ✅ SUCCESS (Local Build)
|
||||
**Thema:** `IsolatedKotlinClasspathClassCastException` im Docker-Build mit Gradle 9.3.1.
|
||||
|
||||
## 1. Zusammenfassung
|
||||
Wir haben versucht, den Frontend-Build im Docker-Container zu stabilisieren. Lokal läuft der Build (`./gradlew build`) erfolgreich durch, inklusive WASM-Support und Runtime-Konfiguration. Im Docker-Container scheitert der Build jedoch hartnäckig an einem Plugin-Konflikt.
|
||||
|
||||
## 2. Das Problem
|
||||
**Fehler:** `IsolatedKotlinClasspathClassCastException: The Kotlin Gradle plugin was loaded multiple times in different subprojects...`
|
||||
**Kontext:** Gradle 9.2.1 / 9.3.1, Kotlin 2.3.0, Docker (ursprünglich `--no-daemon`).
|
||||
|
||||
### Analyse
|
||||
* Der Fehler tritt auf, weil das `NodeJsRootPlugin` (transitiv via KMP) mehrfach initialisiert wird.
|
||||
* **Lokal:** Der Gradle Daemon cached Classloader, wodurch das Plugin als "dasselbe" erkannt wird.
|
||||
* **Docker:** Durch die Isolation (und vermutlich Caching-Artefakte) werden Plugin-Klassen mehrfach geladen und sind nicht cast-bar (`ClassCastException`).
|
||||
|
||||
## 3. Durchgeführte Maßnahmen & Ergebnisse
|
||||
|
||||
| Versuch | Maßnahme | Ergebnis (Docker) | Erkenntnis |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **1. Root Force** | `apply<NodeJsRootPlugin>()` im Root `build.gradle.kts`. | ❌ FAILED | Timing-Problem im Docker, Plugin wird zu spät oder falsch geladen. |
|
||||
| **2. KMP Root** | `alias(...) apply true` im Root + `kotlin { jvm() }`. | ❌ FAILED | `IsolatedKotlinClasspathClassCastException` bleibt. |
|
||||
| **3. Central Mgmt** | `pluginManagement` in `settings.gradle.kts` + `id("...")` ohne Version in Subprojekten. | ❌ FAILED | Architektonisch sauberster Weg, aber löst das Classloader-Problem im Docker nicht. |
|
||||
| **4. Daemon** | Entfernen von `--no-daemon` im Dockerfile. | ❌ FAILED | Daemon startet, aber der Fehler tritt trotzdem auf. |
|
||||
| **5. Upgrade** | Upgrade auf Gradle 9.3.1. | ❌ FAILED | Fehler persistiert auch in der neuesten Version. |
|
||||
| **6. Property** | `kotlin.mpp.allowMultiplePluginDeclarations=true`. | ❌ FAILED | Scheint in Gradle 9.x / KMP 2.3.0 wirkungslos zu sein. |
|
||||
|
||||
## 4. Status Quo
|
||||
* **Lokal:** ✅ Build & Run funktionieren perfekt.
|
||||
* **Docker:** ❌ Build bricht ab.
|
||||
* **Architektur:** Wir haben jetzt eine sehr saubere Gradle-Konfiguration (Zentrales Plugin-Management), die wir beibehalten sollten.
|
||||
|
||||
## 5. Nächste Schritte (Hypothesen)
|
||||
1. **Cache Corruption:** Die Docker-Layer (`--mount=type=cache`) könnten korrupte Gradle-Caches enthalten. Ein Build *ohne* Cache-Mounts muss getestet werden.
|
||||
2. **Gradle 9 Inkompatibilität:** Es ist möglich, dass KMP 2.3.0 noch nicht vollständig kompatibel mit dem strikten Classpath-Isolation-Modus von Gradle 9 ist.
|
||||
3. **Workaround:** Ein Downgrade auf Gradle 8.x wurde diskutiert, aber abgelehnt. Wir müssen einen Weg finden, Gradle 9 zu zähmen.
|
||||
|
||||
---
|
||||
*Dokumentiert durch Curator Agent.*
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
alias(libs.plugins.sqldelight)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
* Es ist noch simpler.
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
}
|
||||
|
||||
group = "at.mocode.clients.shared"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
|||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|||
* Dieses Modul kapselt die gesamte UI und Logik für das Ping-Feature.
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
|||
* setzt sie zu einer lauffähigen Anwendung zusammen.
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
// Fix for "Plugin loaded multiple times": Apply plugin by ID without version (inherited from root)
|
||||
id("org.jetbrains.kotlin.multiplatform")
|
||||
alias(libs.plugins.composeCompiler)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.kotlinSerialization)
|
||||
|
|
|
|||
|
|
@ -71,3 +71,7 @@ enableWasm=false
|
|||
# See https://kotl.in/dokka-gradle-migration
|
||||
# org.jetbrains.dokka.experimental.gradle.pluginMode=V2EnabledWithHelpers
|
||||
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
|
||||
|
||||
# Workaround for Gradle 9 / KMP "Plugin loaded multiple times" error in Docker/CI
|
||||
# This allows subprojects to re-declare plugins even if they are already on the classpath
|
||||
kotlin.mpp.allowMultiplePluginDeclarations=true
|
||||
|
|
|
|||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ pluginManagement {
|
|||
maven("https://us-central1-maven.pkg.dev/varabyte-repos/public")
|
||||
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") } // Added snapshots for plugins
|
||||
}
|
||||
plugins {
|
||||
// Centralized Plugin Version Management
|
||||
// This allows subprojects to apply plugins without versions, avoiding conflicts.
|
||||
id("org.jetbrains.kotlin.multiplatform") version "2.3.0"
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "2.3.0"
|
||||
id("org.jetbrains.compose") version "1.10.0"
|
||||
id("org.jetbrains.kotlin.plugin.compose") version "2.3.0"
|
||||
id("app.cash.sqldelight") version "2.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user