diff --git a/docs/website/overrides/main.html b/docs/website/overrides/main.html
new file mode 100644
index 0000000..bc1e8e6
--- /dev/null
+++ b/docs/website/overrides/main.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+
+{% block htmltitle %}
+ {% if page.toc | first is defined %}
+
{{ page.toc.items[0].title }} - {{ config.site_name }}
+ {% else %}
+ {{ super() }}
+ {% endif %}
+{% endblock %}
--
2.51.2
From ad6351a11e32669a0c0fb3d986e2247a8c00f903 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 11 Feb 2026 09:20:23 +0100
Subject: [PATCH 02/24] upgrade: OpenSavvy Containers 0.8.5
---
.gitlab-ci.main.kts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/.gitlab-ci.main.kts b/.gitlab-ci.main.kts
index fc2cf2c..1800401 100755
--- a/.gitlab-ci.main.kts
+++ b/.gitlab-ci.main.kts
@@ -7,8 +7,10 @@ import opensavvy.gitlab.ci.*
import opensavvy.gitlab.ci.Environment.EnvironmentTier.Development
import opensavvy.gitlab.ci.script.shell
-// https://gitlab.com/opensavvy/automation/containers/-/releases
-val ciContainers = "0.8.4"
+/**
+ * [OpenSavvy's CI container images](https://gitlab.com/opensavvy/automation/containers/-/releases)
+ */
+val ciContainers = "0.8.5"
/**
* The URL of the website built by /docs/website.
--
2.51.2
From 566fbf66182b25a2b62d4a18f8699a65af0b1526 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 19:36:35 +0100
Subject: [PATCH 03/24] build(idea): Add run configuration to run only JVM
tests
---
.idea/runConfigurations/Check__JVM_only_.xml | 28 ++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 .idea/runConfigurations/Check__JVM_only_.xml
diff --git a/.idea/runConfigurations/Check__JVM_only_.xml b/.idea/runConfigurations/Check__JVM_only_.xml
new file mode 100644
index 0000000..026288f
--- /dev/null
+++ b/.idea/runConfigurations/Check__JVM_only_.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+ true
+ false
+ false
+
+
+
\ No newline at end of file
--
2.51.2
From a1f3dae33619468c70468b6d743fb554f28e2a4a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:12:26 +0100
Subject: [PATCH 04/24] upgrade: Kotlin 2.3.0
---
gradle.properties | 3 ++-
gradle/common.versions.toml | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/gradle.properties b/gradle.properties
index 9f2627a..55c1ee1 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -24,7 +24,8 @@ buildCacheUrl=https://gradle.canet.dev
# Configuration on demand allows Gradle to only configure projects which take part in the build.
# See https://docs.gradle.org/current/userguide/multi_project_configuration_and_execution.html#sec:configuration_on_demand
-org.gradle.configureondemand=true
+# TODO Disabled until https://youtrack.jetbrains.com/issue/KT-52074
+org.gradle.configureondemand=false
# Enables cross-compilation for Kotlin Multiplatform.
# This device will attempt to compile all configured Kotlin Native platforms,
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 8a4885e..f9c7937 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -5,7 +5,7 @@
[versions]
# https://kotlinlang.org/docs/releases.html#release-details
-kotlin = "2.2.21"
+kotlin = "2.3.0"
# https://github.com/google/ksp/releases
ksp = "2.3.2"
--
2.51.2
From 98ed08921933500fd4c5360070242300686ecd68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:12:35 +0100
Subject: [PATCH 05/24] upgrade: KSP 2.3.4
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index f9c7937..8dafc9a 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -8,7 +8,7 @@
kotlin = "2.3.0"
# https://github.com/google/ksp/releases
-ksp = "2.3.2"
+ksp = "2.3.4"
# https://github.com/JetBrains/compose-multiplatform/releases
compose = "1.8.2"
--
2.51.2
From a38c15ec8b72b7b8bd5280ee68fc1fc9c752b463 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:12:43 +0100
Subject: [PATCH 06/24] upgrade: Compose 1.10.0
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 8dafc9a..e927654 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -11,7 +11,7 @@ kotlin = "2.3.0"
ksp = "2.3.4"
# https://github.com/JetBrains/compose-multiplatform/releases
-compose = "1.8.2"
+compose = "1.10.0"
# https://github.com/kotest/kotest/releases
kotest = "6.0.4"
--
2.51.2
From 057a36800cc3a27e149b859f35479b47a8d21417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:12:54 +0100
Subject: [PATCH 07/24] upgrade: TestBalloon 0.8.0
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index e927654..c14ba19 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -17,7 +17,7 @@ compose = "1.10.0"
kotest = "6.0.4"
# https://github.com/infix-de/testBalloon/releases
-testBalloon = "0.7.1-K2.2.21"
+testBalloon = "0.8.0-K2.3.0"
# https://gitlab.com/opensavvy/groundwork/pedestal/-/releases
pedestal = "3.1.1"
--
2.51.2
From 820649dd45f28c3c8ab54238dc306b55666c8306 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:13:02 +0100
Subject: [PATCH 08/24] upgrade: Pedestal 3.2.0
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index c14ba19..e5f9057 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -20,7 +20,7 @@ kotest = "6.0.4"
testBalloon = "0.8.0-K2.3.0"
# https://gitlab.com/opensavvy/groundwork/pedestal/-/releases
-pedestal = "3.1.1"
+pedestal = "3.2.0"
# https://prepared.opensavvy.dev/news
prepared = "2.2.0"
--
2.51.2
From 6369bea9b2874c0f784edb03fe2af89d0050ba30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:13:10 +0100
Subject: [PATCH 09/24] upgrade: Prepared 2.3.0
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index e5f9057..1631355 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -23,7 +23,7 @@ testBalloon = "0.8.0-K2.3.0"
pedestal = "3.2.0"
# https://prepared.opensavvy.dev/news
-prepared = "2.2.0"
+prepared = "2.3.0"
# https://spine.opensavvy.dev/news
spine = "0.9.0"
--
2.51.2
From a3a27cc244e44752dc215af217ae3a63b1b269b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 21 Jan 2026 20:13:21 +0100
Subject: [PATCH 10/24] upgrade: NodeJS 24.13.0
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 1631355..8a74a7a 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -35,7 +35,7 @@ ktmongo = "0.25.1"
jetbrains-annotations = "26.0.2-1"
# https://nodejs.org/en/download
-nodejs = "24.12.0"
+nodejs = "24.13.0"
[plugins]
kotlin = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
--
2.51.2
From 903f3adf73ed7687716ec2b71adaec568b3a8189 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Tue, 27 Jan 2026 16:25:50 +0100
Subject: [PATCH 11/24] upgrade: Kotest 6.1.1
---
gradle/common.versions.toml | 3 ++-
gradle/templates/template-app/build.gradle.kts | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 8a74a7a..09803cb 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -14,7 +14,7 @@ ksp = "2.3.4"
compose = "1.10.0"
# https://github.com/kotest/kotest/releases
-kotest = "6.0.4"
+kotest = "6.1.1"
# https://github.com/infix-de/testBalloon/releases
testBalloon = "0.8.0-K2.3.0"
@@ -57,6 +57,7 @@ testBalloon = { id = "de.infix.testBalloon", version.ref = "testBalloon" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit5 = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "kotlin" }
+kotest-framework = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" }
kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotest-assertions-collections = { module = "io.kotest:kotest-assertions-collections", version.ref = "kotest" }
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
diff --git a/gradle/templates/template-app/build.gradle.kts b/gradle/templates/template-app/build.gradle.kts
index a8ceed2..3c4b0e8 100644
--- a/gradle/templates/template-app/build.gradle.kts
+++ b/gradle/templates/template-app/build.gradle.kts
@@ -48,5 +48,6 @@ kotlin {
sourceSets.commonTest.dependencies {
implementation(libsCommon.opensavvy.prepared.kotest)
+ implementation(libsCommon.kotest.framework)
}
}
--
2.51.2
From de22f3cfd2b05f60f0d1b95fa4d6bd9516550b70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Tue, 27 Jan 2026 16:26:10 +0100
Subject: [PATCH 12/24] upgrade: TestBalloon 0.8.2
---
gradle/common.versions.toml | 4 +++-
gradle/templates/template-lib/build.gradle.kts | 1 +
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 09803cb..7ae16a2 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -17,7 +17,7 @@ compose = "1.10.0"
kotest = "6.1.1"
# https://github.com/infix-de/testBalloon/releases
-testBalloon = "0.8.0-K2.3.0"
+testBalloon = "0.8.2-K2.3.0"
# https://gitlab.com/opensavvy/groundwork/pedestal/-/releases
pedestal = "3.2.0"
@@ -62,6 +62,8 @@ kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref =
kotest-assertions-collections = { module = "io.kotest:kotest-assertions-collections", version.ref = "kotest" }
kotest-property = { module = "io.kotest:kotest-property", version.ref = "kotest" }
+testBalloon = { module = "de.infix.testBalloon:testBalloon-framework-core", version.ref = "testBalloon" }
+
jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" }
opensavvy-pedestal-progress = { module = "dev.opensavvy.pedestal:progress", version.ref = "pedestal" }
diff --git a/gradle/templates/template-lib/build.gradle.kts b/gradle/templates/template-lib/build.gradle.kts
index 0e03cb8..cff2ec6 100644
--- a/gradle/templates/template-lib/build.gradle.kts
+++ b/gradle/templates/template-lib/build.gradle.kts
@@ -43,6 +43,7 @@ kotlin {
sourceSets.commonTest.dependencies {
implementation(libsCommon.opensavvy.prepared.testBalloon)
+ implementation(libsCommon.testBalloon)
implementation(libsCommon.kotlin.test)
}
}
--
2.51.2
From 78612f8bc871da6418fbd75ac879392959497ccd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Tue, 27 Jan 2026 22:59:36 +0100
Subject: [PATCH 13/24] build(gradle): Use bundles to facilitate using
TestBalloon and Kotest
---
gradle/common.versions.toml | 15 +++++++++++++++
gradle/templates/template-app/build.gradle.kts | 3 +--
gradle/templates/template-lib/build.gradle.kts | 4 +---
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 7ae16a2..e79d1fb 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -106,3 +106,18 @@ opensavvy-ktmongo-driver-coroutines = { module = "dev.opensavvy.ktmongo:driver-c
opensavvy-ktmongo-driver-coroutines-kmongo = { module = "dev.opensavvy.ktmongo:driver-coroutines-kmongo", version.ref = "ktmongo" }
[bundles]
+# A bundle of dependencies to use Prepared with the TestBalloon runner.
+# Requires applying the plugin 'libsCommon.plugins.testBalloon'.
+testBalloon = [
+ "opensavvy-prepared-testBalloon",
+ "testBalloon", # Force the version of the TestBalloon accompanying library to match the plugin's
+ "kotlin-test", # Force the Kotlin stdlib to match the KGP version, important on JS
+]
+
+# A bundle of dependencies to use Prepared with the Kotest runner.
+# Requires applying the plugins 'libsCommon.plugins.kotest' and 'libsCommon.plugins.ksp'.
+kotest = [
+ "opensavvy-prepared-kotest",
+ "kotest-framework",
+ "kotest-assertions",
+]
diff --git a/gradle/templates/template-app/build.gradle.kts b/gradle/templates/template-app/build.gradle.kts
index 3c4b0e8..c5517bf 100644
--- a/gradle/templates/template-app/build.gradle.kts
+++ b/gradle/templates/template-app/build.gradle.kts
@@ -47,7 +47,6 @@ kotlin {
}
sourceSets.commonTest.dependencies {
- implementation(libsCommon.opensavvy.prepared.kotest)
- implementation(libsCommon.kotest.framework)
+ implementation(libsCommon.bundles.kotest)
}
}
diff --git a/gradle/templates/template-lib/build.gradle.kts b/gradle/templates/template-lib/build.gradle.kts
index cff2ec6..5040e16 100644
--- a/gradle/templates/template-lib/build.gradle.kts
+++ b/gradle/templates/template-lib/build.gradle.kts
@@ -42,9 +42,7 @@ kotlin {
}
sourceSets.commonTest.dependencies {
- implementation(libsCommon.opensavvy.prepared.testBalloon)
- implementation(libsCommon.testBalloon)
- implementation(libsCommon.kotlin.test)
+ implementation(libsCommon.bundles.testBalloon)
}
}
--
2.51.2
From 9001322d0512d6c0d904cc0e69231fc646fdedb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 11 Feb 2026 09:15:31 +0100
Subject: [PATCH 14/24] upgrade: Gradle Conventions 2.3.1
---
gradle/conventions/settings.gradle.kts | 2 +-
settings.gradle.kts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/gradle/conventions/settings.gradle.kts b/gradle/conventions/settings.gradle.kts
index f74bd11..90bd5ec 100644
--- a/gradle/conventions/settings.gradle.kts
+++ b/gradle/conventions/settings.gradle.kts
@@ -48,7 +48,7 @@ pluginManagement {
}
plugins {
- id("dev.opensavvy.conventions.settings") version "2.2.0"
+ id("dev.opensavvy.conventions.settings") version "2.3.1"
}
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 09ecbe9..a442d7b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -55,7 +55,7 @@ pluginManagement {
}
plugins {
- id("dev.opensavvy.conventions.settings") version "2.2.0"
+ id("dev.opensavvy.conventions.settings") version "2.3.1"
}
include(
--
2.51.2
From acb94f972fa408fc9103ee7543f419e7faf8849b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 11 Feb 2026 09:17:14 +0100
Subject: [PATCH 15/24] upgrade(gradle): Automatically run the build with a
Java 25 JDK
---
gradle/gradle-daemon-jvm.properties | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties
index c5df377..c0f7bef 100644
--- a/gradle/gradle-daemon-jvm.properties
+++ b/gradle/gradle-daemon-jvm.properties
@@ -1,11 +1,12 @@
#This file is generated by updateDaemonJvm
-toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/6d0adbce30460017fe61d2993dfa663e/redirect
-toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/50f16d2dc2bb80a421afc1af38fc92e3/redirect
-toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/6d0adbce30460017fe61d2993dfa663e/redirect
-toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/50f16d2dc2bb80a421afc1af38fc92e3/redirect
-toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/4f4ebe4f162f6deb29540c4ebe629d79/redirect
-toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/79d5995ef1c3e4df39a3b2f545cada5e/redirect
-toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/6d0adbce30460017fe61d2993dfa663e/redirect
-toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/50f16d2dc2bb80a421afc1af38fc92e3/redirect
-toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/61fdd87038cf8b094dadad8566609a29/redirect
-toolchainVersion=24
+toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
+toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
+toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
+toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
+toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/d4fd992c9557644e637ebe98263e0ae7/redirect
+toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/faa12903720d410b387cc69ccafb1a74/redirect
+toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/1630f7ebef05444cb27a2709ea0249b3/redirect
+toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/cd495626d2ee49a75447e3fdc6afb287/redirect
+toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/8e1d9ee5d0f13e442218f6884a306da1/redirect
+toolchainVendor=ADOPTIUM
+toolchainVersion=25
--
2.51.2
From 90efe09c65cde94fad5450dad1e62b83ec60c655 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Wed, 11 Feb 2026 14:35:43 +0100
Subject: [PATCH 16/24] build(gradle): Increase the maximum heap & metaspace
sizes
---
gradle.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle.properties b/gradle.properties
index 55c1ee1..1757137 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -50,5 +50,5 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
kotlin.js.yarn=false
# System resource usage
-org.gradle.jvmargs=-Xmx3g -Xms200m -XX:MaxMetaspaceSize=512m -XX:+UseCompressedOops -XX:+UseG1GC -XX:NewRatio=3 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:G1PeriodicGCInterval=60000 -XX:-G1PeriodicGCInvokesConcurrent
+org.gradle.jvmargs=-Xmx4g -Xms200m -XX:MaxMetaspaceSize=640m -XX:+UseCompressedOops -XX:+UseG1GC -XX:NewRatio=3 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:G1PeriodicGCInterval=60000 -XX:-G1PeriodicGCInvokesConcurrent
kotlin.daemon.jvmargs=-Xmx3g -Xms128m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -XX:NewRatio=2 -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=40 -XX:G1PeriodicGCInterval=15000 -XX:-G1PeriodicGCInvokesConcurrent
--
2.51.2
From ddba7a26405bc20344b24d839396cb96d82d386d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Fri, 13 Feb 2026 18:38:57 +0100
Subject: [PATCH 17/24] upgrade: Kotest 6.1.3
---
gradle/common.versions.toml | 2 +-
gradle/templates/template-app/build.gradle.kts | 5 +++++
.../template-app/src/commonTest/kotlin/HelloWorldKotest.kt | 7 +++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index e79d1fb..4a00b0e 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -14,7 +14,7 @@ ksp = "2.3.4"
compose = "1.10.0"
# https://github.com/kotest/kotest/releases
-kotest = "6.1.1"
+kotest = "6.1.3"
# https://github.com/infix-de/testBalloon/releases
testBalloon = "0.8.2-K2.3.0"
diff --git a/gradle/templates/template-app/build.gradle.kts b/gradle/templates/template-app/build.gradle.kts
index c5517bf..4d3eb76 100644
--- a/gradle/templates/template-app/build.gradle.kts
+++ b/gradle/templates/template-app/build.gradle.kts
@@ -50,3 +50,8 @@ kotlin {
implementation(libsCommon.bundles.kotest)
}
}
+
+tasks.withType {
+ // Kotest doesn't report test correctly as of now
+ failOnNoDiscoveredTests = false
+}
diff --git a/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt b/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
index b54c189..714df6c 100644
--- a/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
+++ b/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
@@ -1,5 +1,6 @@
package opensavvy.playground.core
+import io.kotest.core.spec.style.FunSpec
import opensavvy.prepared.runner.kotest.PreparedSpec
class HelloWorldKotestTest : PreparedSpec({
@@ -9,3 +10,9 @@ class HelloWorldKotestTest : PreparedSpec({
check("Hello World!" == message)
}
})
+
+class FooTest : FunSpec({
+ test("test") {
+ check(true)
+ }
+})
--
2.51.2
From e251e62883d4f504af091035e61d4769bd3d43e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Fri, 13 Feb 2026 18:42:19 +0100
Subject: [PATCH 18/24] upgrade: Prepared 2.3.1
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 4a00b0e..f39a1f3 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -23,7 +23,7 @@ testBalloon = "0.8.2-K2.3.0"
pedestal = "3.2.0"
# https://prepared.opensavvy.dev/news
-prepared = "2.3.0"
+prepared = "2.3.1"
# https://spine.opensavvy.dev/news
spine = "0.9.0"
--
2.51.2
From 3dd824bb8e30c7ad70d409d9285f969a26ea76df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Fri, 13 Feb 2026 18:43:34 +0100
Subject: [PATCH 19/24] upgrade: Spine 0.9.1
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index f39a1f3..591d365 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -26,7 +26,7 @@ pedestal = "3.2.0"
prepared = "2.3.1"
# https://spine.opensavvy.dev/news
-spine = "0.9.0"
+spine = "0.9.1"
# https://ktmongo.opensavvy.dev/news
ktmongo = "0.25.1"
--
2.51.2
From 99efdbb6d8c2795189fd2e5d3642ada96896db03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Fri, 13 Feb 2026 18:43:45 +0100
Subject: [PATCH 20/24] upgrade: KtMongo 0.26.1
---
gradle/common.versions.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/common.versions.toml b/gradle/common.versions.toml
index 591d365..e3e477d 100644
--- a/gradle/common.versions.toml
+++ b/gradle/common.versions.toml
@@ -29,7 +29,7 @@ prepared = "2.3.1"
spine = "0.9.1"
# https://ktmongo.opensavvy.dev/news
-ktmongo = "0.25.1"
+ktmongo = "0.26.1"
# https://github.com/JetBrains/java-annotations/releases
jetbrains-annotations = "26.0.2-1"
--
2.51.2
From 43ef50cb391f52e042f1d9c1354bc78f55f22fe5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Sun, 15 Feb 2026 12:17:08 +0100
Subject: [PATCH 21/24] ci(gitlab): Test that our tests can deal with Unicode
characters in test names
---
.../src/commonTest/kotlin/HelloWorldKotest.kt | 5 +++++
.../src/commonTest/kotlin/HelloWorldTest.kt | 11 -----------
.../kotlin/HelloWorldTestBalloonTest.kt | 18 ++++++++++++++++++
3 files changed, 23 insertions(+), 11 deletions(-)
delete mode 100644 gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTest.kt
create mode 100644 gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTestBalloonTest.kt
diff --git a/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt b/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
index 714df6c..eaf764c 100644
--- a/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
+++ b/gradle/templates/template-app/src/commonTest/kotlin/HelloWorldKotest.kt
@@ -9,6 +9,11 @@ class HelloWorldKotestTest : PreparedSpec({
@Suppress("SimplifyBooleanWithConstants") // The compiler knows this test will always succeed
check("Hello World!" == message)
}
+
+ test("Yay • \u2606\u2606\u2606\u2606 Unicode!") {
+ // This test verifies that our CI is able to handle Unicode characters in test names.
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/580885
+ }
})
class FooTest : FunSpec({
diff --git a/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTest.kt b/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTest.kt
deleted file mode 100644
index 23918b6..0000000
--- a/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTest.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package opensavvy.playground.core
-
-import opensavvy.prepared.runner.testballoon.preparedSuite
-
-val HelloWorldTest by preparedSuite {
-
- test("Hello world!") {
- @Suppress("SimplifyBooleanWithConstants") // The compiler knows this test will always succeed
- check("Hello World!" == message)
- }
-}
diff --git a/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTestBalloonTest.kt b/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTestBalloonTest.kt
new file mode 100644
index 0000000..e6a9052
--- /dev/null
+++ b/gradle/templates/template-lib/src/commonTest/kotlin/HelloWorldTestBalloonTest.kt
@@ -0,0 +1,18 @@
+package opensavvy.playground.core
+
+import opensavvy.prepared.runner.testballoon.preparedSuite
+
+val HelloWorldTestBalloonTest by preparedSuite {
+
+ test("Hello world!") {
+ @Suppress("SimplifyBooleanWithConstants") // The compiler knows this test will always succeed
+ check("Hello World!" == message)
+ }
+
+ suite("Nested suite with Unicode \u2606") {
+ test("Yay • \u2606\u2606\u2606\u2606 Unicode!") {
+ // This test verifies that our CI is able to handle Unicode characters in test names.
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/580885
+ }
+ }
+}
--
2.51.2
From 79dbdf5ff83ec689a15eb8c7c71d401359846104 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Mon, 16 Feb 2026 15:27:20 +0100
Subject: [PATCH 22/24] ci(gitlab): Strip non-latin-1 characters from test
report names on non-JVM platforms
This is a workaround for https://gitlab.com/gitlab-org/gitlab/-/issues/580885.
---
.gitlab-ci.main.kts | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/.gitlab-ci.main.kts b/.gitlab-ci.main.kts
index b4874bf..f68ca4d 100755
--- a/.gitlab-ci.main.kts
+++ b/.gitlab-ci.main.kts
@@ -24,6 +24,33 @@ val siteUrl = "\$CI_PAGES_URL"
fun Job.opensavvyImage(name: String) =
image("registry.gitlab.com/opensavvy/automation/containers/$name", ciContainers)
+// region GitLab
+
+/**
+ * Renames all JUnit XML test reports to remove non-latin-1 characters, because GitLab crashes in their presence.
+ *
+ * See [GITLAB-580885](https://gitlab.com/gitlab-org/gitlab/-/issues/580885).
+ */
+fun Job.stripUnicodeTestReports() {
+ afterScript {
+ // language="Shell Script"
+ shell($$"""
+ find . -path '*/build/test-results/*/TEST-*.xml' -print0 |
+ grep -zP '[^\x00-\x{00FF}]' |
+ while IFS= read -r -d '' f; do
+ d="$(dirname "$f")"
+ b="$(basename "$f")"
+ nb=$(printf '%s' "$b" | LC_ALL=C sed -E \
+ -e 's/[\xc4-\xdf][\x80-\xbf]/-/g' \
+ -e 's/[\xe0-\xef][\x80-\xbf]{2}/-/g' \
+ -e 's/[\xf0-\xf4][\x80-\xbf]{3}/-/g')
+ mv -- "$f" "$d/$nb"
+ done
+ """.trimIndent())
+ }
+}
+
+// endregion
// region Kotlin Multiplatform
fun Job.jvm() {
@@ -34,16 +61,22 @@ fun Job.jvm() {
fun Job.jsBrowser() {
useGradle()
opensavvyImage("chromium")
+
+ stripUnicodeTestReports()
}
fun Job.jsNode() {
useGradle()
opensavvyImage("nodejs")
+
+ stripUnicodeTestReports()
}
fun Job.nativeLinuxX64() {
useGradle()
opensavvyImage("java")
+
+ stripUnicodeTestReports()
}
fun Job.nativeIosArm64() {
--
2.51.2
From d441674c3f997bef1605b9bcdef4a83c68bd19c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Sat, 14 Feb 2026 19:15:18 +0100
Subject: [PATCH 23/24] build: Replace JVM toolchains by Tapmoc
---
vite-base/build.gradle.kts | 4 ++--
vite-kotlin/build.gradle.kts | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/vite-base/build.gradle.kts b/vite-base/build.gradle.kts
index cc01327..f256aea 100644
--- a/vite-base/build.gradle.kts
+++ b/vite-base/build.gradle.kts
@@ -31,8 +31,8 @@ library {
}
}
-kotlin {
- jvmToolchain(11)
+tapmoc {
+ java(11)
}
afterEvaluate {
diff --git a/vite-kotlin/build.gradle.kts b/vite-kotlin/build.gradle.kts
index 8b3b2e5..1a30365 100644
--- a/vite-kotlin/build.gradle.kts
+++ b/vite-kotlin/build.gradle.kts
@@ -44,8 +44,8 @@ library {
}
}
-kotlin {
- jvmToolchain(11)
+tapmoc {
+ java(11)
}
afterEvaluate {
--
2.51.2
From c59488899ab027ea057c9a6cd63effe9aa1af3ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?=
Date: Sun, 15 Feb 2026 11:33:06 +0100
Subject: [PATCH 24/24] test(kotlin): Add a long string to the generated Wasm
files
Before this commit, the generated file was 3927 bytes. However, Vite now inlines files smaller than 4096 bytes. Because of that, there wasn't a .wasm file at the end of the test, and it failed.
With this commit, we voluntarily increase the size of the file by a lot, to ensure it is always generated.
This is a better approach than modifying the assertion because this test is meant to be simple verification of whether our configuration of Vite is correct. If in some situations Vite is able to optimize the program further, that's great but doesn't matter for what we want to test.
---
vite-kotlin/src/test/kotlin/WasmJS.kt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/vite-kotlin/src/test/kotlin/WasmJS.kt b/vite-kotlin/src/test/kotlin/WasmJS.kt
index b1f141e..b7a192b 100644
--- a/vite-kotlin/src/test/kotlin/WasmJS.kt
+++ b/vite-kotlin/src/test/kotlin/WasmJS.kt
@@ -14,6 +14,8 @@ val WasmJS by preparedSuite(preparedConfig = CoroutineTimeout(10.minutes)) {
val simpleBuild by createBuild("app")
val app by prepared { gradle.project("app") }
+ val longString = "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"
+
test("Pure WasmJS") {
simpleBuild()
@@ -56,6 +58,7 @@ val WasmJS by preparedSuite(preparedConfig = CoroutineTimeout(10.minutes)) {
main().writeText("""
fun main() {
println("Hello world!")
+ println("$longString")
}
""".trimIndent())
@@ -137,6 +140,7 @@ val WasmJS by preparedSuite(preparedConfig = CoroutineTimeout(10.minutes)) {
main().writeText("""
fun main() {
println("Hello world!")
+ println("$longString")
}
""".trimIndent())