import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.gradle.api.tasks.testing.logging.TestExceptionFormat plugins { kotlin("jvm") version "2.4.10" kotlin("plugin.serialization") version "2.4.10" id("io.ktor.plugin") version "3.5.2" application jacoco } group = "com.osglab.account" version = "0.1.0" repositories { mavenCentral() } application { mainClass.set("io.ktor.server.netty.EngineMain") } val adminWebDirectory = layout.projectDirectory.dir("admin-web") val adminWebInstall = tasks.register("adminWebInstall") { workingDir(adminWebDirectory) inputs.files( adminWebDirectory.file("package.json"), adminWebDirectory.file("package-lock.json"), ) outputs.dir(adminWebDirectory.dir("node_modules")) commandLine("npm", "ci", "--no-audit", "--no-fund") } val adminWebBuild = tasks.register("adminWebBuild") { dependsOn(adminWebInstall) workingDir(adminWebDirectory) inputs.files( adminWebDirectory.file("index.html"), adminWebDirectory.file("tsconfig.json"), adminWebDirectory.file("vite.config.ts"), ) inputs.dir(adminWebDirectory.dir("src")) outputs.dir(adminWebDirectory.dir("dist")) commandLine("npm", "run", "build") } val adminWebTest = tasks.register("adminWebTest") { dependsOn(adminWebInstall) workingDir(adminWebDirectory) inputs.files( adminWebDirectory.file("tsconfig.json"), adminWebDirectory.file("vite.config.ts"), ) inputs.dir(adminWebDirectory.dir("src")) commandLine("npm", "run", "test") } val adminWebResources = tasks.register("adminWebResources") { dependsOn(adminWebBuild) from(adminWebDirectory.dir("dist")) into(layout.buildDirectory.dir("generated/admin-web/admin")) } sourceSets { main { resources.srcDir(layout.buildDirectory.dir("generated/admin-web")) } } kotlin { jvmToolchain(21) compilerOptions { jvmTarget.set(JvmTarget.JVM_21) freeCompilerArgs.add("-Xjsr305=strict") } } dependencies { val ktorVersion = "3.5.2" val exposedVersion = "1.4.0" val flywayVersion = "13.3.0" implementation("io.ktor:ktor-server-core-jvm:$ktorVersion") implementation("io.ktor:ktor-server-netty-jvm:$ktorVersion") implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktorVersion") implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktorVersion") implementation("io.ktor:ktor-server-auth-jvm:$ktorVersion") implementation("io.ktor:ktor-server-auth-jwt-jvm:$ktorVersion") implementation("io.ktor:ktor-server-status-pages-jvm:$ktorVersion") implementation("io.ktor:ktor-server-call-logging-jvm:$ktorVersion") { // Jansi is Windows-only console coloring here; excluding it keeps /tmp noexec-safe. exclude(group = "org.fusesource.jansi", module = "jansi") } implementation("io.ktor:ktor-server-rate-limit-jvm:$ktorVersion") implementation("io.ktor:ktor-server-websockets-jvm:$ktorVersion") implementation("io.ktor:ktor-server-forwarded-header-jvm:$ktorVersion") implementation("io.ktor:ktor-server-config-yaml-jvm:$ktorVersion") implementation("io.ktor:ktor-server-call-id-jvm:$ktorVersion") implementation("io.ktor:ktor-server-default-headers-jvm:$ktorVersion") implementation("io.ktor:ktor-server-compression-jvm:$ktorVersion") implementation("io.ktor:ktor-client-core-jvm:$ktorVersion") implementation("io.ktor:ktor-client-cio-jvm:$ktorVersion") implementation("io.ktor:ktor-client-content-negotiation-jvm:$ktorVersion") implementation("io.ktor:ktor-client-websockets-jvm:$ktorVersion") implementation("io.insert-koin:koin-ktor:4.2.2") implementation("io.insert-koin:koin-logger-slf4j:4.2.2") implementation("org.jetbrains.exposed:exposed-core:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion") implementation("com.zaxxer:HikariCP:7.1.0") implementation("com.mysql:mysql-connector-j:26.7.0") implementation("org.flywaydb:flyway-core:$flywayVersion") implementation("org.flywaydb:flyway-mysql:$flywayVersion") implementation("com.auth0:java-jwt:4.6.0") implementation("com.nimbusds:nimbus-jose-jwt:10.9.1") implementation("ch.veehait.devicecheck:devicecheck-appattest:0.9.6") implementation("org.bouncycastle:bcprov-jdk18on:1.85.2") implementation("com.upokecenter:cbor:4.5.6") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.11.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.11.0") implementation("ch.qos.logback:logback-classic:1.6.3") testImplementation("io.ktor:ktor-server-test-host-jvm:$ktorVersion") testImplementation("io.ktor:ktor-client-mock-jvm:$ktorVersion") testImplementation(kotlin("test")) testImplementation("io.kotest:kotest-runner-junit5-jvm:6.2.4") testImplementation("io.kotest:kotest-assertions-core-jvm:6.2.4") testImplementation("io.mockk:mockk-jvm:1.14.11") testImplementation("org.testcontainers:mysql:1.21.4") testImplementation("org.testcontainers:junit-jupiter:1.21.4") } tasks.test { dependsOn(adminWebTest) useJUnitPlatform() testLogging { events("failed", "skipped") exceptionFormat = TestExceptionFormat.FULL } finalizedBy(tasks.jacocoTestReport) } tasks.processResources { dependsOn(adminWebResources) } tasks.register("generateAdminCredentials") { group = "deployment" description = "Generate private admin bootstrap and operator handoff files" classpath = sourceSets["main"].runtimeClasspath mainClass.set("com.osglab.account.tools.AdminCredentialGenerator") } jacoco { toolVersion = "0.8.15" } tasks.jacocoTestReport { dependsOn(tasks.test) reports { xml.required.set(true) html.required.set(true) } } ktor { fatJar { archiveFileName.set("osg-account-server.jar") } }