import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.kotlin.jvm) alias(libs.plugins.kotlin.spring) alias(libs.plugins.spring.boot) alias(libs.plugins.vaadin) alias(libs.plugins.native) apply false } group = "de.hoennig" version = "0.1.75-SNAPSHOT" repositories { mavenCentral() } kotlin { jvmToolchain(25) compilerOptions { jvmTarget = JvmTarget.JVM_21 } } val schemaGenerator by sourceSets.creating dependencies { implementation(platform(libs.spring.boot.bom)) implementation(platform(libs.vaadin.bom)) implementation(libs.vaadin.core) implementation("com.vaadin:vaadin-spring") implementation("org.springframework.boot:spring-boot-starter-webmvc") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.springframework.boot:spring-boot-starter-jdbc") implementation("org.springframework.boot:spring-boot-starter-liquibase") implementation(libs.h2) implementation(libs.liquibase) implementation(libs.jooq) implementation("nl.martijndwars:web-push:5.1.2") { isTransitive = false } implementation("org.bitbucket.b_c:jose4j:0.9.6") implementation("org.bouncycastle:bcprov-jdk18on:1.85.2") implementation("org.springframework.security:spring-security-config") implementation("org.springframework.security:spring-security-web") testImplementation("org.springframework.security:spring-security-test") testImplementation(libs.jooq) add(schemaGenerator.implementationConfigurationName, platform(libs.spring.boot.bom)) add(schemaGenerator.implementationConfigurationName, libs.h2) add(schemaGenerator.implementationConfigurationName, libs.liquibase) add(schemaGenerator.implementationConfigurationName, libs.jooq.codegen) testImplementation(libs.h2) testImplementation(libs.liquibase) testImplementation("org.springframework:spring-jdbc") testImplementation("org.springframework.data:spring-data-jdbc") testImplementation(platform(libs.spring.boot.bom)) testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation(platform(libs.cucumber.bom)) testImplementation("io.cucumber:cucumber-java") testImplementation("io.cucumber:cucumber-junit-platform-engine") testImplementation("org.junit.platform:junit-platform-suite") testImplementation(libs.playwright) testRuntimeOnly("org.junit.platform:junit-platform-launcher") } tasks.withType().configureEach { options.release.set(21) } tasks.test { useJUnitPlatform() environment("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "1") if (providers.gradleProperty("production").map(String::toBoolean).getOrElse(false)) { systemProperty("vaadin.productionMode", "true") } systemProperty("cucumber.junit-platform.discovery.as-root-engine", "false") systemProperty("cucumber.publish.enabled", "false") doFirst { systemProperty("prototype.testClasspath", sourceSets.test.get().runtimeClasspath.asPath) } } tasks.processTestResources { from("gherkin") { into("gherkin") } } springBoot { buildInfo { properties { excludes.set(setOf("time")) } } } vaadin { // Include custom service-worker changes even when the UI import graph is unchanged. forceProductionBuild = true productionMode = providers.gradleProperty("production").map(String::toBoolean).getOrElse(false) } if (providers.gradleProperty("native").map(String::toBoolean).getOrElse(false)) { apply(plugin = "org.graalvm.buildtools.native") configure { binaries { named("main") { imageName.set("werkjournal") buildArgs.add("-march=compatibility") buildArgs.add("-J-Xmx" + providers.gradleProperty("nativeHeap").getOrElse("4g")) buildArgs.add("--parallelism=" + providers.gradleProperty("nativeThreads").getOrElse("2")) } } } } tasks.bootJar { archiveFileName.set("werkjournal.jar") } // Generate from a disposable H2 database migrated by the same Liquibase SQL. val generatedPrototypeJooq = layout.buildDirectory.dir("generated/jooq-prototype") val generatePrototypeJooq by tasks.registering(JavaExec::class) { dependsOn(tasks.named(schemaGenerator.classesTaskName)) classpath = schemaGenerator.runtimeClasspath mainClass.set("de.hoennig.werkjournal.codegen.GeneratePrototypeKt") javaLauncher.set(javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(25)) }) maxHeapSize = "256m" val schema = layout.projectDirectory.file("src/test/resources/db/prototype/initial.sql") val database = layout.buildDirectory.dir("jooq-prototype-database") inputs.file(schema) outputs.dir(generatedPrototypeJooq) args(schema.asFile.absolutePath, database.get().file("schema").asFile.absolutePath, generatedPrototypeJooq.get().asFile.absolutePath) doFirst { delete(database, generatedPrototypeJooq) database.get().asFile.mkdirs() } } kotlin.sourceSets.named("test") { kotlin.srcDir(generatedPrototypeJooq) } tasks.named("compileTestKotlin") { dependsOn(generatePrototypeJooq) } val generatedJooq = layout.buildDirectory.dir("generated/jooq") val generateJooq by tasks.registering(JavaExec::class) { dependsOn(tasks.named(schemaGenerator.classesTaskName)) classpath = schemaGenerator.runtimeClasspath mainClass.set("de.hoennig.werkjournal.codegen.GeneratePrototypeKt") javaLauncher.set(javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(25)) }) maxHeapSize = "256m" val schema = layout.projectDirectory.file("src/main/resources/db/changelog.sql") val database = layout.buildDirectory.dir("jooq-database") inputs.file(schema) outputs.dir(generatedJooq) args(schema.asFile.absolutePath, database.get().file("schema").asFile.absolutePath, generatedJooq.get().asFile.absolutePath, "de.hoennig.werkjournal.persistence.generated", "APP_USER|CUSTOMER|WORK_PROJECT|WORK_ENTRY|WORK_MUTATION|HABIT|HABIT_DAY|HABIT_LIMIT|HABIT_MUTATION|ACCOUNT_DEFAULTS|DAY_OFF|ACCOUNT_INVITATION|ADMISSION_CONTROL|DEVICE_LOGIN|PUSH_SUBSCRIPTION|REMINDER_DELIVERY") doFirst { delete(database, generatedJooq); database.get().asFile.mkdirs() } } kotlin.sourceSets.named("main") { kotlin.srcDir(generatedJooq) } tasks.named("compileKotlin") { dependsOn(generateJooq) } // Tool-only classpath: installing browser binaries must not compile the application. val browserTools by configurations.creating dependencies { browserTools(libs.playwright) } tasks.register("installBrowsers") { classpath = browserTools mainClass.set("com.microsoft.playwright.CLI") args("install", "chromium", "firefox") } // Production acceptance must run after JVM tests and packaging, not inside test. tasks.register("productionAcceptance") { dependsOn(tasks.test, tasks.named("bootJar")) classpath = sourceSets.test.get().runtimeClasspath mainClass.set("io.cucumber.core.cli.Main") args("--glue", "de.hoennig.werkjournal.acceptance.production", "--tags", "@WJ-020", "--plugin", "json:build/reports/cucumber/production.json", "gherkin/ops-tests.feature") systemProperty("cucumber.publish.enabled", "false") } // Repeat the implemented browser scenarios in the second supported desktop engine. tasks.register("firefoxAcceptance") { dependsOn(tasks.test, tasks.named("bootJar")) classpath = sourceSets.test.get().runtimeClasspath mainClass.set("io.cucumber.core.cli.Main") args("--glue", "de.hoennig.werkjournal.acceptance.browser", "--tags", providers.gradleProperty("browserTags").getOrElse("@browser"), "--plugin", "json:build/reports/cucumber/firefox.json", "gherkin/ux-tests.feature", "gherkin/habit-tests.feature", "gherkin/work-tests.feature", "gherkin/identity-tests.feature") systemProperty("werkjournal.test.browser", "firefox") systemProperty("cucumber.publish.enabled", "false") environment("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "1") }