diff --git a/README.md b/README.md index 5f17de0..12998a9 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ [![build](https://github.com/will-molloy/java-template/actions/workflows/build.yml/badge.svg?branch=main&event=push)](https://github.com/will-molloy/java-template/actions/workflows/build.yml) [![codecov](https://codecov.io/gh/will-molloy/java-template/branch/main/graph/badge.svg)](https://codecov.io/gh/will-molloy/java-template) -template repo for Java projects using Gradle +template repo for Java/Kotlin projects using Gradle ## Features - JDK 21 ([Amazon Corretto](https://aws.amazon.com/corretto/)) -- Gradle 8 +- [Gradle 8](https://github.com/gradle/gradle) with Kotlin DSL - [GitHub Actions](https://github.com/features/actions) CI/CD -- Automatic code formatting via [Spotless](https://github.com/diffplug/spotless) +- Automatic code formatting via [Spotless](https://github.com/diffplug/spotless) ([`google-java-format`](https://github.com/google/google-java-format) and [`ktlint`](https://github.com/pinterest/ktlint)) - Code style analysis via [Checkstyle](https://github.com/checkstyle/checkstyle) - Static analysis via [SpotBugs](https://spotbugs.github.io/) - Unit and integration test support via [JUnit 5](https://junit.org/junit5/) and [TestSets plugin](https://github.com/unbroken-dome/gradle-testsets-plugin) diff --git a/build.gradle.kts b/build.gradle.kts index 85d28d2..9117c35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,15 +5,17 @@ import com.github.spotbugs.snom.SpotBugsExtension import com.github.spotbugs.snom.SpotBugsTask import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension logger.quiet("Java version: ${JavaVersion.current()}") logger.quiet("Gradle version: ${gradle.gradleVersion}") plugins { id("java-library") - id("com.diffplug.gradle.spotless") version "6.25.0" apply (false) - id("com.github.spotbugs") version "6.0.15" apply (false) - id("com.asarkar.gradle.build-time-tracker") version "4.3.0" + kotlin("jvm") version libs.versions.kotlin + alias(libs.plugins.spotless) + alias(libs.plugins.spotbugs) + alias(libs.plugins.buildtimetracker) } allprojects { @@ -21,23 +23,39 @@ allprojects { repositories { mavenCentral() } -} -subprojects { apply(plugin = "java") configure { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } + apply(plugin = "kotlin") + configure { + jvmToolchain(21) + } + apply(plugin = "com.diffplug.spotless") configure { java { removeUnusedImports() googleJavaFormat() + trimTrailingWhitespace() + endWithNewline() + } + kotlin { + ktlint() + trimTrailingWhitespace() + endWithNewline() + } + kotlinGradle { + ktlint().editorConfigOverride(mapOf("ktlint_standard_no-empty-file" to "disabled")) + trimTrailingWhitespace() + endWithNewline() } } + // TODO this doesn't work on Kotlin, look into Detekt? apply(plugin = "checkstyle") configure { toolVersion = "10.12.0" @@ -68,17 +86,19 @@ subprojects { showExceptions = true showCauses = true showStackTraces = true - afterSuite(KotlinClosure2({ desc: TestDescriptor, result: TestResult -> - if (desc.parent == null) { - println( - "Results: ${result.resultType} " + + afterSuite( + KotlinClosure2({ desc: TestDescriptor, result: TestResult -> + if (desc.parent == null) { + println( + "Results: ${result.resultType} " + "(${result.testCount} test${if (result.testCount > 1) "s" else ""}, " + "${result.successfulTestCount} passed, " + "${result.failedTestCount} failed, " + - "${result.skippedTestCount} skipped)" - ) - } - })) + "${result.skippedTestCount} skipped)", + ) + } + }), + ) } finalizedBy(tasks.withType()) } @@ -102,20 +122,23 @@ subprojects { } dependencies { - implementation("org.apache.logging.log4j:log4j-core:2.23.1") - implementation("org.apache.logging.log4j:log4j-api:2.23.1") - implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.23.1") - implementation("com.github.spotbugs:spotbugs-annotations:4.8.5") - implementation("com.google.guava:guava:33.2.0-jre") + implementation(rootProject.libs.log4j.core) + implementation(rootProject.libs.log4j.api) + implementation(rootProject.libs.log4j.slf4j2) + implementation(rootProject.libs.spotbugs.annotations) + implementation(rootProject.libs.guava) - testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testImplementation("com.google.truth:truth:1.4.2") - testImplementation("org.mockito:mockito-core:5.12.0") - testImplementation("org.mockito:mockito-junit-jupiter:5.12.0") + testImplementation(rootProject.libs.junit) + testImplementation(rootProject.libs.truth) + testImplementation(rootProject.libs.mockito.core) + testImplementation(rootProject.libs.mockito.junit) configurations.all { - exclude("org.assertj") - exclude("junit") + exclude(group = "org.assertj") + exclude(group = "junit") + resolutionStrategy { + force("com.google.guava:guava:${rootProject.libs.versions.guava.get()}") // exclude android version + } } } } diff --git a/hello-world/build.gradle.kts b/example-java/build.gradle.kts similarity index 50% rename from hello-world/build.gradle.kts rename to example-java/build.gradle.kts index b3c0931..3ff8c1f 100644 --- a/hello-world/build.gradle.kts +++ b/example-java/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.unbroken-dome.test-sets") version "4.1.0" + alias(libs.plugins.testsets) } testSets { diff --git a/hello-world/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java b/example-java/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java similarity index 94% rename from hello-world/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java rename to example-java/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java index 4eb8f22..70ebbce 100644 --- a/hello-world/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java +++ b/example-java/src/integrationTest/java/com/willmolloy/HelloWorldIntegrationTest.java @@ -12,7 +12,7 @@ class HelloWorldIntegrationTest { @Test - void test() { + void test_hello() { assertThat(new HelloWorld().hello("world")).isEqualTo("Hello world!"); } } diff --git a/hello-world/src/main/java/com/willmolloy/HelloWorld.java b/example-java/src/main/java/com/willmolloy/HelloWorld.java similarity index 84% rename from hello-world/src/main/java/com/willmolloy/HelloWorld.java rename to example-java/src/main/java/com/willmolloy/HelloWorld.java index 82a20bc..9a5872a 100644 --- a/hello-world/src/main/java/com/willmolloy/HelloWorld.java +++ b/example-java/src/main/java/com/willmolloy/HelloWorld.java @@ -9,8 +9,7 @@ * @author Will Molloy */ class HelloWorld { - - private final Logger log = LogManager.getLogger(); + private static final Logger log = LogManager.getLogger(); String hello(String text) { log.debug("Hello {}!", text); diff --git a/hello-world/src/main/resources/log4j2.xml b/example-java/src/main/resources/log4j2.xml similarity index 95% rename from hello-world/src/main/resources/log4j2.xml rename to example-java/src/main/resources/log4j2.xml index ea3be10..e7e6d12 100644 --- a/hello-world/src/main/resources/log4j2.xml +++ b/example-java/src/main/resources/log4j2.xml @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/hello-world/src/test/java/com/willmolloy/HelloWorldTest.java b/example-java/src/test/java/com/willmolloy/HelloWorldTest.java similarity index 93% rename from hello-world/src/test/java/com/willmolloy/HelloWorldTest.java rename to example-java/src/test/java/com/willmolloy/HelloWorldTest.java index 4b7b1fb..2530f7b 100644 --- a/hello-world/src/test/java/com/willmolloy/HelloWorldTest.java +++ b/example-java/src/test/java/com/willmolloy/HelloWorldTest.java @@ -12,7 +12,7 @@ class HelloWorldTest { @Test - void test() { + void test_hello() { assertThat(new HelloWorld().hello("world")).isEqualTo("Hello world!"); } } diff --git a/example-kotlin/build.gradle.kts b/example-kotlin/build.gradle.kts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/example-kotlin/build.gradle.kts @@ -0,0 +1 @@ + diff --git a/example-kotlin/src/main/kotlin/com/willmolloy/HelloWorld.kt b/example-kotlin/src/main/kotlin/com/willmolloy/HelloWorld.kt new file mode 100644 index 0000000..a941572 --- /dev/null +++ b/example-kotlin/src/main/kotlin/com/willmolloy/HelloWorld.kt @@ -0,0 +1,12 @@ +package com.willmolloy + +/** + * Example main src. + * + * @author Will Molloy + */ +class HelloWorld { + fun hello(text: String): String { + return "Hello $text!" + } +} diff --git a/example-kotlin/src/test/kotlin/com/willmolloy/HelloWorldTest.kt b/example-kotlin/src/test/kotlin/com/willmolloy/HelloWorldTest.kt new file mode 100644 index 0000000..01488d0 --- /dev/null +++ b/example-kotlin/src/test/kotlin/com/willmolloy/HelloWorldTest.kt @@ -0,0 +1,14 @@ +package com.willmolloy + +import com.google.common.truth.Truth.assertThat +import org.junit.jupiter.api.Test + +/** + * Unit tests for [HelloWorld]. + */ +class HelloWorldTest { + @Test + fun `test hello`() { + assertThat(HelloWorld().hello("world")).isEqualTo("Hello world!") + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..d502398 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,27 @@ +[plugins] +spotless = { id = "com.diffplug.spotless", version = "6.25.0" } +spotbugs = { id = "com.github.spotbugs", version = "6.0.27" } +buildtimetracker = { id = "com.asarkar.gradle.build-time-tracker", version = "4.3.0" } +testsets = { id = "org.unbroken-dome.test-sets", version = "4.1.0" } + +[versions] +kotlin = "2.1.0" +log4j = "2.24.3" +spotbugs = "4.8.6" +guava = "33.4.0-jre" +# test libs +junit = "5.11.4" +truth = "1.4.4" +mockito = "5.14.2" + +[libraries] +spotbugs-annotations = { module = "com.github.spotbugs:spotbugs-annotations", version.ref = "spotbugs" } +log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } +log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } +log4j-slf4j2 = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version.ref = "log4j" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +# test libs +junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" } +truth = { module = "com.google.truth:truth", version.ref = "truth" } +mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } +mockito-junit = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } diff --git a/settings.gradle.kts b/settings.gradle.kts index bae30d9..09ecaa5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,2 +1,3 @@ rootProject.name = "java-template" -include("hello-world") +include("example-java") +include("example-kotlin")