diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5268f21 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,50 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### Git ### +.git +.gitignore + +### Docker ### +.dockerignore +Dockerfile + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..91ab9ec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM eclipse-temurin:21-jdk-alpine AS build + +WORKDIR /root/app + +# Download Gradle +COPY ./gradle ./gradle +COPY ./gradlew ./ +RUN ./gradlew --no-daemon --info --stacktrace + +# Download Dependencies +COPY ./buildSrc ./buildSrc +COPY ./settings.gradle.kts ./ +COPY ./bot-api/build.gradle.kts ./bot-api/ +COPY ./bot-database/build.gradle.kts ./bot-database/ +COPY ./management/build.gradle.kts ./management/ +COPY ./server/build.gradle.kts ./server/ +COPY ./bots/ping-bot/build.gradle.kts ./bots/ping-bot/ +COPY ./bots/pizza-bot/build.gradle.kts ./bots/pizza-bot/ +RUN ./gradlew deps --no-daemon --info --stacktrace + +# Build Application +COPY . . +RUN ./gradlew build :server:jlink --no-daemon --info --stacktrace + +FROM alpine:3.19.1 + +WORKDIR /opt/chat/ +COPY --from=build /root/app/server/build/dist/jre /opt/chat/ + +ENV JAVA_HOME="/opt/chat" +ENV JAVA_OPTS="--enable-preview" +ENV CHAT_BOT_CONFIG="file:/etc/chat/config.json" +ENTRYPOINT $JAVA_HOME/bin/java $JAVA_OPTS --module eu.jonahbauer.chat.server diff --git a/bot-api/build.gradle.kts b/bot-api/build.gradle.kts index 219585e..3aa0986 100644 --- a/bot-api/build.gradle.kts +++ b/bot-api/build.gradle.kts @@ -20,12 +20,12 @@ java { } } -val configApi by configurations val configCompileOnly by configurations +val configCompileOnlyApi by configurations val configAnnotationProcessor by configurations dependencies { - api(libs.annotations) + compileOnlyApi(libs.annotations) api(project(path)) { capabilities { requireCapability("${project.group}:${project.name}-config") @@ -33,8 +33,8 @@ dependencies { } implementation(libs.gson) - configApi(libs.annotations) configCompileOnly(libs.lombok) + configCompileOnlyApi(libs.annotations) configAnnotationProcessor(libs.lombok) } diff --git a/bot-database/build.gradle.kts b/bot-database/build.gradle.kts index 8eccf32..535079b 100644 --- a/bot-database/build.gradle.kts +++ b/bot-database/build.gradle.kts @@ -7,7 +7,7 @@ group = "eu.jonahbauer.chat" version = "0.1.0-SNAPSHOT" dependencies { - api(libs.annotations) + compileOnlyApi(libs.annotations) implementation(libs.sqlite) implementation(libs.hikari) implementation(libs.slf4j) diff --git a/buildSrc/src/main/kotlin/chat-bot.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/chat-bot.java-conventions.gradle.kts index 22ead73..301537e 100644 --- a/buildSrc/src/main/kotlin/chat-bot.java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/chat-bot.java-conventions.gradle.kts @@ -35,6 +35,15 @@ tasks.withType { jvmArgs("--enable-preview") } +tasks.register("deps") { + group = "build" + description = "resolves all resolvable configurations" + + doLast { + configurations.filter { it.isCanBeResolved }.forEach { it.resolve() } + } +} + val application = extensions.findByType() application?.apply { applicationDefaultJvmArgs = listOf("--enable-preview") diff --git a/buildSrc/src/main/kotlin/eu/jonahbauer/chat/build/jlink/JLinkTask.kt b/buildSrc/src/main/kotlin/eu/jonahbauer/chat/build/jlink/JLinkTask.kt new file mode 100644 index 0000000..8680db7 --- /dev/null +++ b/buildSrc/src/main/kotlin/eu/jonahbauer/chat/build/jlink/JLinkTask.kt @@ -0,0 +1,68 @@ +package eu.jonahbauer.chat.build.jlink + +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.plugins.internal.JavaPluginHelper +import org.gradle.api.provider.ListProperty +import org.gradle.api.tasks.* +import org.gradle.api.tasks.internal.JavaExecExecutableUtils +import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.jvm.toolchain.internal.JavaExecutableUtils +import org.gradle.kotlin.dsl.getByType + +abstract class JLinkTask : DefaultTask() { + @get:OutputDirectory + abstract val output : DirectoryProperty + + @get:InputFile + abstract val executable : RegularFileProperty + + @get:InputFiles + abstract val modulePath : ConfigurableFileCollection + + @get:Input + abstract val modules : ListProperty + + @get:Input + abstract val options : ListProperty + + init { + group = "distribution" + description = "assembles a modular runtime image using jlink" + + output.convention(project.layout.buildDirectory.dir("dist/jre")) + modules.convention(listOf("ALL-MODULE-PATH")) + + if (project.pluginManager.hasPlugin("java")) { + val feature = JavaPluginHelper.getJavaComponent(project).mainFeature + modulePath.from(feature.runtimeClasspathConfiguration) + modulePath.from(feature.jarTask) + + val toolchains = project.extensions.getByType(JavaToolchainService::class) + val java = project.extensions.getByType(JavaPluginExtension::class) + + executable.convention(toolchains.launcherFor(java.toolchain) + .map { it.metadata.installationPath } + .map { it.dir("bin").file("jlink") }) + } + } + + @TaskAction + fun execute() { + val args = options.get() + listOf( + "--module-path", modulePath.asPath, + "--output", output.get().asFile.path, + "--add-modules", modules.get().joinToString(",") + ) + val executable = executable.get().asFile.path + + project.delete(output) + project.exec { + this.executable = executable + this.args = args + } + } +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f20ff05..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-rc-4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/server/build.gradle.kts b/server/build.gradle.kts index 55ca829..bb2fe68 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -1,12 +1,16 @@ +import eu.jonahbauer.chat.build.jlink.JLinkTask + plugins { id("chat-bot.java-conventions") - application } group = "eu.jonahbauer.chat" version = "0.1.0-SNAPSHOT" -val bots = project(":bots").subprojects +val bot : Configuration by configurations.creating +configurations.runtimeOnly { + extendsFrom(bot) +} dependencies { implementation(project(":bot-api")) @@ -16,13 +20,27 @@ dependencies { runtimeOnly(libs.logback) - bots.forEach { - implementation(project(it.path)) + project.project(":bots").subprojects.forEach { + bot(project(it.path)) } } -application { - mainClass.set("eu.jonahbauer.chat.server.Main") - mainModule.set("eu.jonahbauer.chat.server") - applicationDefaultJvmArgs = listOf("--enable-preview") -} \ No newline at end of file +tasks.named("compileJava") { + options.javaModuleMainClass = "eu.jonahbauer.chat.server.Main" +} + +tasks.register("jlink") { + modules = listOf("ALL-MODULE-PATH", "jdk.crypto.ec") + options = listOf("--no-header-files", "--no-man-pages", "--strip-debug", "--compress=zip-6") +} + +tasks.register("run") { + group = "application" + description = "runs the application using the custom runtime image" + + executable = project.layout.buildDirectory.file("dist/jre/bin/java").get().asFile.path + args("--enable-preview", "-m", "eu.jonahbauer.chat.server") + + dependsOn(tasks.named("jlink")) +} +