diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f65a3502..07991d6e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,15 +4,39 @@ jobs: gradle-build: runs-on: ubuntu-latest steps: - - name: git clone - uses: actions/checkout@v3.5.2 - - name: Set up JDK - uses: actions/setup-java@v3.11.0 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 17 - - name: gradle build - id: gradle - uses: gradle/gradle-build-action@v2.4.2 + java-version-file: gradle/jdk-version.txt + - uses: gradle/actions/setup-gradle@v3 + - run: "./gradlew qualityCheck" + env: + BUILD_CACHE_USER: ${{ secrets.BUILD_CACHE_USER }} + BUILD_CACHE_PWD: ${{ secrets.BUILD_CACHE_PWD }} + - run: "./gradlew test" + env: + BUILD_CACHE_USER: ${{ secrets.BUILD_CACHE_USER }} + BUILD_CACHE_PWD: ${{ secrets.BUILD_CACHE_PWD }} + - run: "./gradlew endToEndTest" + env: + BUILD_CACHE_USER: ${{ secrets.BUILD_CACHE_USER }} + BUILD_CACHE_PWD: ${{ secrets.BUILD_CACHE_PWD }} + - run: "./gradlew endToEndTestSlow" + env: + BUILD_CACHE_USER: ${{ secrets.BUILD_CACHE_USER }} + BUILD_CACHE_PWD: ${{ secrets.BUILD_CACHE_PWD }} + - run: "./gradlew cyclonedxBom" + env: + BUILD_CACHE_USER: ${{ secrets.BUILD_CACHE_USER }} + BUILD_CACHE_PWD: ${{ secrets.BUILD_CACHE_PWD }} + - uses: DependencyTrack/gh-upload-sbom@v3 with: - arguments: build \ No newline at end of file + apiKey: ${{ secrets.DEPENDENCYTRACK_APIKEY }} + bomFilename: "gradle/aggregation/build/reports/sbom/bom.xml" + serverHostname: "212.132.95.131" + port: "8091" + protocol: "http" + projectName: "gradle-project-setup-howto" + projectVersion: ${{ github.ref_name }} + autoCreate: true diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 23408f89..252db1e7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,32 +1,27 @@ -plugins { - id("org.example.application") -} +plugins { id("org.example.gradle.component.java-application") } -application { - mainClass.set("org.example.product.app.Application") -} +application { mainClass = "org.example.product.app.Application" } +// Complicated notation for 'capabilities' - upvote: https://github.com/gradle/gradle/issues/25629 dependencies { - providedCompile("jakarta.servlet:jakarta.servlet-api") - - implementation(project(":bespin")) - implementation(project(":corellia")) - implementation(project(":kamino")) - implementation(project(":kashyyyk")) - implementation(project(":naboo")) - implementation(project(":tatooine")) - implementation("com.google.inject.extensions:guice-servlet") - implementation("com.google.inject:guice") - implementation("org.slf4j:slf4j-api") - - mockApiImplementation(project(path)) - mockApiImplementation("com.google.guava:guava") + implementation(projects.bespin) + implementation(projects.corellia) + implementation(projects.kamino) + implementation(projects.kashyyyk) + implementation(projects.naboo) + implementation(projects.tatooine) + implementation(libs.guice) + implementation(libs.guice.servlet) + implementation(libs.slf4j.api) + runtimeOnly(libs.slf4j.simple) + providedCompile(libs.jakarta.servlet.api) - testImplementation("org.junit.jupiter:junit-jupiter-api") + endToEndTestImplementation(projects.app) { capabilities { requireCapability("${project.group}:$name-mock-api") } } + endToEndTestImplementation(libs.guava) + endToEndTestImplementation(libs.junit.jupiter.api) - endToEndTestImplementation(project(path)) { capabilities { requireCapabilities("${project.group}:${project.name}-mock-api") } } - endToEndTestImplementation("com.google.guava:guava") - endToEndTestImplementation("org.junit.jupiter:junit-jupiter-api") + mockApiImplementation(projects.app) + mockApiImplementation(libs.guava) - runtimeOnly("org.slf4j:slf4j-simple") + testImplementation(libs.junit.jupiter.api) } diff --git a/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemQuickTest.java b/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemQuickTest.java index 5fe8176e..859672c7 100644 --- a/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemQuickTest.java +++ b/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemQuickTest.java @@ -1,11 +1,11 @@ package org.example.product.app.endtoend; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.google.common.collect.ImmutableList; import org.example.product.app.mock.api.MockServer; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - public class SystemQuickTest { @Test diff --git a/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemTest.java b/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemTest.java index e73a0507..dc60b833 100644 --- a/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemTest.java +++ b/app/src/endToEndTest/java/org/example/product/app/endtoend/SystemTest.java @@ -1,12 +1,12 @@ package org.example.product.app.endtoend; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.google.common.collect.ImmutableList; import org.example.product.app.mock.api.MockServer; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - @Tag("slow") public class SystemTest { diff --git a/app/src/main/java/org/example/product/app/AppServlet.java b/app/src/main/java/org/example/product/app/AppServlet.java index 8bcf5a8e..030cc158 100644 --- a/app/src/main/java/org/example/product/app/AppServlet.java +++ b/app/src/main/java/org/example/product/app/AppServlet.java @@ -1,11 +1,11 @@ package org.example.product.app; +import java.io.IOException; +import java.io.PrintWriter; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; @WebServlet("/check") public class AppServlet extends HttpServlet { @@ -17,4 +17,4 @@ public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOExce pw.println(""); pw.close(); } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/example/product/app/MainModule.java b/app/src/main/java/org/example/product/app/MainModule.java index bf72c41a..f2ca6595 100644 --- a/app/src/main/java/org/example/product/app/MainModule.java +++ b/app/src/main/java/org/example/product/app/MainModule.java @@ -2,6 +2,7 @@ import com.google.inject.Guice; import com.google.inject.servlet.SessionScoped; +import java.io.IOException; import org.example.product.bespin.BespinModule; import org.example.product.kamino.KaminoModule; import org.example.product.kashyyyk.KashyyykModule; @@ -10,8 +11,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; - @SessionScoped public class MainModule { diff --git a/app/src/mockApi/java/org/example/product/app/mock/api/MockServer.java b/app/src/mockApi/java/org/example/product/app/mock/api/MockServer.java index e27e4d6e..7f0567b6 100644 --- a/app/src/mockApi/java/org/example/product/app/mock/api/MockServer.java +++ b/app/src/mockApi/java/org/example/product/app/mock/api/MockServer.java @@ -9,5 +9,4 @@ public ImmutableList get() { new MainModule(); return ImmutableList.of("a", "b", "x", "y"); } - } diff --git a/app/src/test/java/org/example/product/app/test/AppTest.java b/app/src/test/java/org/example/product/app/test/AppTest.java index 3f7db204..2902a371 100644 --- a/app/src/test/java/org/example/product/app/test/AppTest.java +++ b/app/src/test/java/org/example/product/app/test/AppTest.java @@ -1,9 +1,9 @@ package org.example.product.app.test; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; + public class AppTest { @Test diff --git a/bespin/build.gradle.kts b/bespin/build.gradle.kts index 4baa51fa..53b8cedd 100644 --- a/bespin/build.gradle.kts +++ b/bespin/build.gradle.kts @@ -1,13 +1,11 @@ -plugins { - id("org.example.java-library") -} +plugins { id("org.example.gradle.component.java-library") } +// For isolated-projects, use 'requireCapability' notation instead of testFixtures(...) dependencies { - api(project(":corellia")) - - implementation(project(":coruscant")) - implementation("org.apache.velocity:velocity-engine-core") + api(projects.corellia) + implementation(projects.coruscant) + implementation(libs.velocity.engine.core) - testImplementation(testFixtures(project(":corellia"))) - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(projects.corellia) { capabilities { requireCapability("${project.group}:$name-test-fixtures") } } + testImplementation(libs.junit.jupiter.api) } diff --git a/bespin/src/main/java/org/example/product/bespin/BespinModule.java b/bespin/src/main/java/org/example/product/bespin/BespinModule.java index 539fa80e..c0d3ccca 100644 --- a/bespin/src/main/java/org/example/product/bespin/BespinModule.java +++ b/bespin/src/main/java/org/example/product/bespin/BespinModule.java @@ -1,11 +1,10 @@ package org.example.product.bespin; -import org.example.product.corellia.CorelliaModule; -import org.example.product.coruscant.CoruscantModule; -import org.apache.velocity.io.VelocityWriter; - import java.io.FileWriter; import java.io.IOException; +import org.apache.velocity.io.VelocityWriter; +import org.example.product.corellia.CorelliaModule; +import org.example.product.coruscant.CoruscantModule; public class BespinModule { diff --git a/bespin/src/test/java/org/example/product/bespin/test/BespinModuleTest.java b/bespin/src/test/java/org/example/product/bespin/test/BespinModuleTest.java index a0b0a3ae..5ff0f403 100644 --- a/bespin/src/test/java/org/example/product/bespin/test/BespinModuleTest.java +++ b/bespin/src/test/java/org/example/product/bespin/test/BespinModuleTest.java @@ -1,10 +1,10 @@ package org.example.product.bespin.test; +import static org.junit.jupiter.api.Assertions.assertEquals; + import org.example.product.corellia.fixtures.CorelliaModuleFixture; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - public class BespinModuleTest { @Test diff --git a/build.gradle.kts b/build.gradle.kts index 42b87b3a..5d2d2ce0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ plugins { - id("org.example.root") + id("org.example.gradle.base.lifecycle.root") + id("org.example.gradle.check.dependencies.root") + id("org.example.gradle.check.format-gradle.root") } \ No newline at end of file diff --git a/corellia/build.gradle.kts b/corellia/build.gradle.kts index 9dc20254..6c1be5b6 100644 --- a/corellia/build.gradle.kts +++ b/corellia/build.gradle.kts @@ -1,15 +1,15 @@ plugins { - id("org.example.java-library-with-test-fixtures") + id("org.example.gradle.component.java-library") + id("org.example.gradle.feature.test-fixtures") } dependencies { - api("org.apache.poi:poi") + api(libs.poi) + implementation(libs.commons.io) + implementation(libs.poi.ooxml) - implementation("commons-io:commons-io") - implementation("org.apache.poi:poi-ooxml") + testImplementation(libs.junit.jupiter.api) - testFixturesApi("com.google.code.findbugs:jsr305") - testFixturesApi("com.google.guava:guava") - - testImplementation("org.junit.jupiter:junit-jupiter-api") + testFixturesApi(libs.guava) + testFixturesApi(libs.jsr305) } diff --git a/gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/MD5DirectoryChecksum.kt b/corellia/src/main/java/MD5DirectoryChecksum.kt similarity index 98% rename from gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/MD5DirectoryChecksum.kt rename to corellia/src/main/java/MD5DirectoryChecksum.kt index bfd8f6d4..56441a54 100644 --- a/gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/MD5DirectoryChecksum.kt +++ b/corellia/src/main/java/MD5DirectoryChecksum.kt @@ -1,5 +1,3 @@ -package org.example.application.tasks - import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty diff --git a/corellia/src/main/java/org/example/product/corellia/CorelliaModule.java b/corellia/src/main/java/org/example/product/corellia/CorelliaModule.java index cea2154c..c810764a 100644 --- a/corellia/src/main/java/org/example/product/corellia/CorelliaModule.java +++ b/corellia/src/main/java/org/example/product/corellia/CorelliaModule.java @@ -1,10 +1,9 @@ package org.example.product.corellia; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ooxml.POIXMLDocument; -import org.apache.commons.io.input.NullInputStream; - import java.io.IOException; +import org.apache.commons.io.input.NullInputStream; +import org.apache.poi.ooxml.POIXMLDocument; +import org.apache.poi.ss.usermodel.Workbook; public class CorelliaModule { diff --git a/corellia/src/test/java/org/example/product/corellia/test/CorelliaModuleTest.java b/corellia/src/test/java/org/example/product/corellia/test/CorelliaModuleTest.java index 3c16fbfe..b27bf2d9 100644 --- a/corellia/src/test/java/org/example/product/corellia/test/CorelliaModuleTest.java +++ b/corellia/src/test/java/org/example/product/corellia/test/CorelliaModuleTest.java @@ -1,15 +1,14 @@ package org.example.product.corellia.test; +import static org.junit.jupiter.api.Assertions.assertEquals; + import org.example.product.corellia.fixtures.CorelliaModuleFixture; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - public class CorelliaModuleTest { @Test void testModule() { assertEquals(3, new CorelliaModuleFixture().threeModules().size()); } - } diff --git a/corellia/src/testFixtures/java/org/example/product/corellia/fixtures/CorelliaModuleFixture.java b/corellia/src/testFixtures/java/org/example/product/corellia/fixtures/CorelliaModuleFixture.java index 74dfd7e4..722d46c8 100644 --- a/corellia/src/testFixtures/java/org/example/product/corellia/fixtures/CorelliaModuleFixture.java +++ b/corellia/src/testFixtures/java/org/example/product/corellia/fixtures/CorelliaModuleFixture.java @@ -2,12 +2,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.io.ByteProcessor; -import org.example.product.corellia.CorelliaModule; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.IOException; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.example.product.corellia.CorelliaModule; public class CorelliaModuleFixture implements ByteProcessor { public List threeModules() { diff --git a/coruscant/build.gradle.kts b/coruscant/build.gradle.kts index 8440f637..a05a605f 100644 --- a/coruscant/build.gradle.kts +++ b/coruscant/build.gradle.kts @@ -1,24 +1,24 @@ plugins { - id("org.example.java-library-published") + id("org.example.gradle.component.java-library") + id("org.example.gradle.feature.publish") } dependencies { - api("com.fasterxml.jackson.core:jackson-annotations") - api("com.fasterxml.jackson.core:jackson-databind") - api("com.google.guava:guava") - api("jakarta.inject:jakarta.inject-api") - api("org.json:json") - api("org.opensaml:opensaml") + api(libs.guava) + api(libs.jackson.annotations) + api(libs.jackson.databind) + api(libs.jakarta.inject.api) + api(libs.opensaml) + api(libs.org.json) + implementation(libs.httpcomponents.fluent.hc) + implementation(libs.jackson.core) + implementation(libs.jackson.datatype.json.org) + implementation(libs.jackson.datatype.jsr310) + implementation(libs.jakarta.activation) + implementation(libs.jakarta.mail.impl) + implementation(libs.org.reflections) + implementation(libs.slf4j.api) - implementation("com.fasterxml.jackson.core:jackson-core") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-json-org") - implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") - implementation("com.sun.activation:jakarta.activation") - implementation("com.sun.mail:jakarta.mail") - implementation("org.apache.httpcomponents:fluent-hc") - implementation("org.reflections:reflections") - implementation("org.slf4j:slf4j-api") - - testImplementation("org.assertj:assertj-core") - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(libs.assertj.core) + testImplementation(libs.junit.jupiter.api) } diff --git a/coruscant/src/main/java/org/example/product/coruscant/CoruscantModule.java b/coruscant/src/main/java/org/example/product/coruscant/CoruscantModule.java index fe2eb15f..1737838b 100644 --- a/coruscant/src/main/java/org/example/product/coruscant/CoruscantModule.java +++ b/coruscant/src/main/java/org/example/product/coruscant/CoruscantModule.java @@ -7,19 +7,6 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import org.apache.http.client.fluent.Request; -import org.json.JSONArray; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.reflections.Reflections; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.inject.Inject; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; -import javax.mail.util.ByteArrayDataSource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -27,6 +14,18 @@ import java.io.StringWriter; import java.io.Writer; import java.util.regex.Pattern; +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.inject.Inject; +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import javax.mail.util.ByteArrayDataSource; +import org.apache.http.client.fluent.Request; +import org.json.JSONArray; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.reflections.Reflections; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * I am published and therefore I have Javadoc! @@ -40,7 +39,7 @@ public class CoruscantModule { */ public CoruscantModule() { LOGGER.info("Coruscant Module created"); - try(InputStream hello = CoruscantModule.class.getResourceAsStream("hello.txt")) { + try (InputStream hello = CoruscantModule.class.getResourceAsStream("hello.txt")) { System.out.println(new BufferedReader(new InputStreamReader(hello)).readLine()); } catch (IOException e) { throw new RuntimeException(e); diff --git a/coruscant/src/main/java/org/example/product/coruscant/CoruscantModuleData.java b/coruscant/src/main/java/org/example/product/coruscant/CoruscantModuleData.java index 97e3f1b2..9a20d7bb 100644 --- a/coruscant/src/main/java/org/example/product/coruscant/CoruscantModuleData.java +++ b/coruscant/src/main/java/org/example/product/coruscant/CoruscantModuleData.java @@ -6,6 +6,4 @@ * I am data and I am published! */ @JsonIgnoreProperties(ignoreUnknown = true) -public class CoruscantModuleData { - -} +public class CoruscantModuleData {} diff --git a/coruscant/src/test/java/org/example/product/coruscant/test/CoruscantModuleTest.java b/coruscant/src/test/java/org/example/product/coruscant/test/CoruscantModuleTest.java index d7675bdb..92d25459 100644 --- a/coruscant/src/test/java/org/example/product/coruscant/test/CoruscantModuleTest.java +++ b/coruscant/src/test/java/org/example/product/coruscant/test/CoruscantModuleTest.java @@ -1,14 +1,13 @@ package org.example.product.coruscant.test; -import org.example.product.coruscant.CoruscantModule; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; - -import static org.assertj.core.api.Assertions.assertThat; +import org.example.product.coruscant.CoruscantModule; +import org.junit.jupiter.api.Test; public class CoruscantModuleTest { @@ -16,7 +15,7 @@ public class CoruscantModuleTest { void testCoruscantModule() throws IOException { assertThat(new CoruscantModule()).isNotEqualTo(null); - try(InputStream hello = CoruscantModuleTest.class.getResourceAsStream("testHello.txt")) { + try (InputStream hello = CoruscantModuleTest.class.getResourceAsStream("testHello.txt")) { String message = new BufferedReader(new InputStreamReader(hello)).readLine(); assertThat(message).isEqualTo("TEST HELLO!"); } diff --git a/gradle.properties b/gradle.properties index 5221002f..029dcc69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,11 @@ # Configure the Grade Daemon - memory and same encoding on all machines org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -# activate Gradle configuration cache - instantly start builds that ran before, full parellilsm +# activate Gradle configuration cache - instantly start builds that ran before, full parallelism org.gradle.configuration-cache=true +dependency.analysis.autoapply=false +# 'isolated-projects' can be activated when removing 'org.cyclonedx.bom' +# org.gradle.unsafe.isolated-projects=true # activate Gradle build cache - switch between branches/commits without rebuilding every time org.gradle.caching=true diff --git a/gradle/aggregation/build.gradle.kts b/gradle/aggregation/build.gradle.kts new file mode 100644 index 00000000..09809fd9 --- /dev/null +++ b/gradle/aggregation/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("org.example.gradle.report.code-coverage") + id("org.example.gradle.report.plugin-analysis") + id("org.example.gradle.report.sbom") +} + +dependencies { + implementation(projects.app) +} diff --git a/gradle/jdk-version.txt b/gradle/jdk-version.txt new file mode 100644 index 00000000..b5045cc4 --- /dev/null +++ b/gradle/jdk-version.txt @@ -0,0 +1 @@ +21 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..a215eb81 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,33 @@ +[libraries] +assertj-core = { module = "org.assertj:assertj-core", version = "3.22.0" } +commons-io = { module = "commons-io:commons-io" } +guava = { module = "com.google.guava:guava" } +guice = { module = "com.google.inject:guice", version = "5.1.0" } +guice-servlet = { module = "com.google.inject.extensions:guice-servlet" } +httpcomponents-fluent-hc = { module = "org.apache.httpcomponents:fluent-hc", version = "4.5.13" } +jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations" } +jackson-core = { module = "com.fasterxml.jackson.core:jackson-core", version = "2.13.5" } +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind" } +jackson-datatype-json-org = { module = "com.fasterxml.jackson.datatype:jackson-datatype-json-org" } +jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" } +jakarta-activation = { module = "com.sun.activation:jakarta.activation", version = "1.2.2" } +jakarta-inject-api = { module = "jakarta.inject:jakarta.inject-api", version = "1.0.5" } +jakarta-mail-impl = { module = "com.sun.mail:jakarta.mail", version = "1.6.7" } +jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version = "4.0.4" } +jsr305 = { module = "com.google.code.findbugs:jsr305" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version = "5.8.2" } +opensaml = { module = "org.opensaml:opensaml", version = "2.6.4" } +org-json = { module = "org.json:json" } +org-reflections = { module = "org.reflections:reflections", version = "0.9.11" } +poi = { module = "org.apache.poi:poi", version = "5.2.2" } +poi-ooxml = { module = "org.apache.poi:poi-ooxml" } +resteasy-core = { module = "org.jboss.resteasy:resteasy-core", version = "4.7.6.Final" } +resteasy-guice = { module = "org.jboss.resteasy:resteasy-guice" } +resteasy-jackson2-provider = { module = "org.jboss.resteasy:resteasy-jackson2-provider" } +slf4j-api = { module = "org.slf4j:slf4j-api", version = "1.7.36"} +slf4j-simple = { module = "org.slf4j:slf4j-simple" } +solr-solrj = { module = "org.apache.solr:solr-solrj", version = "7.7.3" } +typesafeconfig-guice = { module = "com.github.racc:typesafeconfig-guice", version = "0.1.0" } +velocity-engine-core = { module = "org.apache.velocity:velocity-engine-core", version = "2.3" } +zookeeper = { module = "org.apache.zookeeper:zookeeper", version = "3.8.0" } +zookeeper-jute = { module = "org.apache.zookeeper:zookeeper-jute" } \ No newline at end of file diff --git a/gradle/meta-plugins/build-parameters-plugins/build.gradle.kts b/gradle/meta-plugins/build-parameters-plugins/build.gradle.kts deleted file mode 100644 index ee8509ef..00000000 --- a/gradle/meta-plugins/build-parameters-plugins/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("org.gradlex.build-parameters") version "1.4.3" -} - -group = "org.example" - -buildParameters { - pluginId("org.example.build-parameters") - bool("ci") { - defaultValue.set(false) - fromEnvironment() - } - group("catalina") { - string("home") { - fromEnvironment() - description.set("Root of the Tomcat installation") - } - } -} diff --git a/gradle/meta-plugins/plugin-analysis-plugins/build.gradle.kts b/gradle/meta-plugins/plugin-analysis-plugins/build.gradle.kts deleted file mode 100644 index 2ae4b073..00000000 --- a/gradle/meta-plugins/plugin-analysis-plugins/build.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -plugins { - `kotlin-dsl` -} - -group = "org.example" \ No newline at end of file diff --git a/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org.example.plugin-analysis.gradle.kts b/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org.example.plugin-analysis.gradle.kts deleted file mode 100644 index a6633b6f..00000000 --- a/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org.example.plugin-analysis.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -import org.example.pluginanalysis.PluginApplicationOrderAnalysis - -tasks.register("analysePluginApplicationOrder") { - group = "help" - - pluginSrcFolders.from(subprojects.map { it.layout.projectDirectory.dir("src/main/kotlin") }) - pluginApplicationDiagram.set(layout.buildDirectory.file("reports/plugins/plugin-application-order.puml")) -} \ No newline at end of file diff --git a/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org/example/pluginanalysis/PluginApplicationOrderAnalysis.kt b/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org/example/pluginanalysis/PluginApplicationOrderAnalysis.kt deleted file mode 100644 index d6071d4a..00000000 --- a/gradle/meta-plugins/plugin-analysis-plugins/src/main/kotlin/org/example/pluginanalysis/PluginApplicationOrderAnalysis.kt +++ /dev/null @@ -1,71 +0,0 @@ -package org.example.pluginanalysis - -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction -import java.io.File - -abstract class PluginApplicationOrderAnalysis : DefaultTask() { - - @get:InputFiles - abstract val pluginSrcFolders : ConfigurableFileCollection - - @get:OutputFile - abstract val pluginApplicationDiagram: RegularFileProperty - - @TaskAction - fun analyse() { - val pluginDependencies = pluginSrcFolders.associate { srcFolder -> - val pluginProjectName = srcFolder.parentFile.parentFile.parentFile.name - pluginProjectName to (srcFolder.listFiles() ?: emptyArray()).filter { - it.name.endsWith(".gradle.kts") - }.associate { pluginFile -> - val pluginId = pluginFile.name.replaceFirst(".gradle.kts", "") - val shortenedPluginId = shorten(pluginId) - shortenedPluginId to pluginsBlock(pluginFile.readText()).lines().filter { it.contains("id(") }.map { - shorten(it.substring(it.indexOf("id(\"") + 4, it.indexOf("\")"))) - } - } - }.filter { it.value.isNotEmpty() } - - val lineBreak = "\n " - pluginApplicationDiagram.get().asFile.writeText(""" - @startuml - - ${pluginDependencies.map { (projectName, pluginIds) -> - "package \"$projectName\" {$lineBreak" + - pluginIds.keys.joinToString("") { "agent \"$it\"$lineBreak" } + - "$lineBreak}" - }.joinToString(lineBreak)} - - ${pluginDependencies.values.fold(emptyMap>()) { a, b -> a + b }.filter { - it.value.isNotEmpty() - }.map { - (from, to) -> to.joinToString("") { "\"$from\" --down--> \"$it\"$lineBreak" } - }.joinToString(lineBreak)} - - @enduml - """.trimIndent()) - - logger.lifecycle("Diagram: ${pluginApplicationDiagram.get().asFile.absolutePath}") - } - - private fun pluginsBlock(script: String) = script.indexOf("}").let { - when(it) { - -1 -> "" - else -> script.substring(0, it) - } - } - - private fun shorten(pluginId: String) = pluginId.split(".").let { segments -> - when (segments.size) { - 1 -> segments.single() - else -> segments.subList(0, segments.size - 1).map { it.first() } - .joinToString(".", "", ".") + segments.last() - } - - } -} \ No newline at end of file diff --git a/gradle/meta-plugins/settings-plugins/build.gradle.kts b/gradle/meta-plugins/settings-plugins/build.gradle.kts deleted file mode 100644 index f5c6502c..00000000 --- a/gradle/meta-plugins/settings-plugins/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(project(":build-parameters-plugins")) - implementation("com.gradle:gradle-enterprise-gradle-plugin:3.15.1") -} diff --git a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.gradle-enterprise.settings.gradle.kts b/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.gradle-enterprise.settings.gradle.kts deleted file mode 100644 index b5ef95d8..00000000 --- a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.gradle-enterprise.settings.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -import buildparameters.BuildParametersExtension - -plugins { - // Use the Gradle Enterprise plugin to publish Build Scan to https://scans.gradle.com - id("com.gradle.enterprise") - id("org.example.build-parameters") -} - -// Configure the Gradle Enterprise plugin -gradleEnterprise { - buildScan { - // You may remove this check to publish build scans for every build (preferred, if there are no concerns) - if (the().ci) { - publishAlways() - } - termsOfServiceUrl = "https://gradle.com/terms-of-service" - termsOfServiceAgree = "yes" - } -} diff --git a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.project-structure.settings.gradle.kts b/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.project-structure.settings.gradle.kts deleted file mode 100644 index fcf1797b..00000000 --- a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.project-structure.settings.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -// Include all subfolders that contain a 'build.gradle.kts' as subprojects -rootDir.listFiles()?.filter { File(it, "build.gradle.kts").exists() }?.forEach { subproject -> - include(subproject.name) -} diff --git a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.repositories.settings.gradle.kts b/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.repositories.settings.gradle.kts deleted file mode 100644 index 3c184c9d..00000000 --- a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.repositories.settings.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -pluginManagement { - // Get community plugins from the Gradle Plugin Portal - repositories.gradlePluginPortal() - - // Get our own convention plugins from 'gradle/plugins' - if (File(rootDir, "gradle/plugins").exists()) { - includeBuild("gradle/plugins") - } - // If not the main build, 'plugins' is located next to the build (e.g. gradle/settings) - if (File(rootDir, "../plugins").exists()) { - includeBuild("../plugins") - } -} - -dependencyResolutionManagement { - // Get components from Maven Central - repositories.mavenCentral() - // In the main build, find the platform in 'gradle/platform' - if (File(rootDir, "gradle/platform").exists()) { - includeBuild("gradle/platform") - } -} diff --git a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.settings.settings.gradle.kts b/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.settings.settings.gradle.kts deleted file mode 100644 index 3ac0503d..00000000 --- a/gradle/meta-plugins/settings-plugins/src/main/kotlin/org.example.settings.settings.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -plugins { - id("org.example.gradle-enterprise") - id("org.example.project-structure") - id("org.example.repositories") -} diff --git a/gradle/meta-plugins/settings.gradle.kts b/gradle/meta-plugins/settings.gradle.kts deleted file mode 100644 index 5d527fc6..00000000 --- a/gradle/meta-plugins/settings.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -dependencyResolutionManagement { - repositories.gradlePluginPortal() -} - -include("build-parameters-plugins", "plugin-analysis-plugins", "settings-plugins") diff --git a/gradle/platform/build.gradle.kts b/gradle/platform/build.gradle.kts deleted file mode 100644 index 6f5ff217..00000000 --- a/gradle/platform/build.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ -plugins { - id("org.example.platform") -} - -dependencies { - api(platform("com.fasterxml.jackson:jackson-bom:2.13.2.20220328")) - api(platform("com.google.inject:guice-bom:5.1.0")) - api(platform("org.apache.httpcomponents:httpcomponents-client:4.5.13")) { because ("see HttpComponentsPlatformRule") } // Parent as Anchor for Alignment BOM - api(platform("org.apache.poi:poi:5.2.2")) { because ("see PoiPlatformRule") } // Central component as Anchor for Alignment BOM - api(platform("org.jboss.resteasy:resteasy-bom:4.7.6.Final")) { (this as ExternalModuleDependency).version { reject("[5.0.0.Final,)") } } - api(platform("org.junit:junit-bom:5.7.2")) { (this as ExternalModuleDependency).version { reject("[5.8.0,)") } } // Do not Upgrade to 5.8: https://github.com/gradle/gradle/issues/18627 - api(platform("org.mockito:mockito-bom:4.5.1")) - api(platform("org.slf4j:slf4j-parent:1.7.36")) { because ("see Slf4jPlatformRule") } // Parent as Anchor for Alignment BOM -} - -dependencies.constraints { - api("com.github.racc:typesafeconfig-guice:0.1.0") - api("com.sun.activation:jakarta.activation:1.2.2") { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs - api("com.sun.mail:jakarta.mail:1.6.7") { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs - api("jakarta.inject:jakarta.inject-api:1.0.5") { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs - api("jakarta.servlet:jakarta.servlet-api:4.0.4") { version { reject("[5.0.0,)") } } // Stay Tomcat 8 compatible - api("org.apache.commons:commons-lang3:3.9") - api("org.apache.solr:solr-solrj:7.7.3") { version { reject("[8.0.0,)") } } // API changes in 8 require production code changes - api("org.apache.velocity:velocity-engine-core:2.3") - api("org.apache.zookeeper:zookeeper:3.8.0") - api("org.assertj:assertj-core:3.22.0") - api("org.opensaml:opensaml:2.6.4") - api("org.reflections:reflections:0.9.11") { version { reject("[0.9.12,)") } } // Upgrade breaks 'com.github.racc:typesafeconfig-guice' -} diff --git a/gradle/platform/settings.gradle.kts b/gradle/platform/settings.gradle.kts deleted file mode 100644 index 9cfb420c..00000000 --- a/gradle/platform/settings.gradle.kts +++ /dev/null @@ -1,6 +0,0 @@ -pluginManagement { - includeBuild("../meta-plugins") -} -plugins { - id("org.example.settings") -} diff --git a/gradle/plugins/base-plugins/build.gradle.kts b/gradle/plugins/base-plugins/build.gradle.kts deleted file mode 100644 index cd774386..00000000 --- a/gradle/plugins/base-plugins/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation(project(":dependency-analysis-plugins")) - implementation(project(":dependency-rules-plugins")) -} diff --git a/gradle/plugins/base-plugins/src/main/kotlin/org.example.base.gradle.kts b/gradle/plugins/base-plugins/src/main/kotlin/org.example.base.gradle.kts deleted file mode 100644 index 15df32b4..00000000 --- a/gradle/plugins/base-plugins/src/main/kotlin/org.example.base.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - id("base") - id("org.example.dependency-rules") -} - -// Set the group (some components will be published) -group = "org.example.product" - -// Set the version from 'version.txt' -version = providers.fileContents( - rootProject.layout.projectDirectory.file("gradle/version.txt")).asText.getOrElse("") diff --git a/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts b/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts deleted file mode 100644 index e5b2c3d4..00000000 --- a/gradle/plugins/base-plugins/src/main/kotlin/org.example.platform.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id("java-platform") - id("org.example.base") - id("org.example.dependency-analysis-platform") -} - -// Depend on other Platforms/BOMs to align versions for libraries that consist of multiple components (like Jackson) -javaPlatform.allowDependencies() diff --git a/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts b/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts deleted file mode 100644 index d4e13ba3..00000000 --- a/gradle/plugins/base-plugins/src/main/kotlin/org.example.root.gradle.kts +++ /dev/null @@ -1,58 +0,0 @@ -plugins { - id("lifecycle-base") - id("org.example.dependency-analysis-root") -} - -// Configure the ':tasks' task of the root project to only show -// the main lifecycle tasks as entry points to the build -val mainBuildGroup = "main build" -tasks.named("tasks") { - displayGroup = mainBuildGroup -} - -tasks.named("build") { - group = mainBuildGroup - description = "Complete build of all modules and the application" - dependsOn(subprojects.map { ":${it.name}:$name" }) -} - -tasks.register("compileAll") { - group = mainBuildGroup - description = "Complete build of all modules and the application" - dependsOn(subprojects.map { ":${it.name}:$name" }) -} - -tasks.named("check") { - group = mainBuildGroup - description = "Runs all checks and produces test summary and code coverage reports" - dependsOn(subprojects.map { ":${it.name}:$name" }) - dependsOn(gradle.includedBuild("platform").task(":check")) - doLast { - println("Unit test summary: app/build/reports/tests/unit-test/aggregated-results/index.html") - println("Unit test code coverage: app/build/reports/jacoco/testCodeCoverageReport/html/index.html") - } -} - -tasks.register("run") { - group = mainBuildGroup - description = "Build and run as standalone application" - dependsOn(":app:$name") -} - -tasks.register("deployWebApp") { - group = mainBuildGroup - description = "Deploy web app into local Tomcat found via CATALINA_HOME" - dependsOn(":app:$name") -} - -tasks.register("checkForDependencyVulnerabilities") { - group = mainBuildGroup - description = "Check current dependencies for known vulnerabilities" - dependsOn(":app:dependencyCheckAnalyze") -} - -tasks.register("checkForDependencyVersionUpgrades") { - group = mainBuildGroup - description = "Check for version upgrades (runs weekly on CI)" - dependsOn(gradle.includedBuild("platform").task(":$name")) -} diff --git a/gradle/plugins/build.gradle.kts b/gradle/plugins/build.gradle.kts index 5a4984ec..2e1a8efb 100644 --- a/gradle/plugins/build.gradle.kts +++ b/gradle/plugins/build.gradle.kts @@ -1,3 +1,20 @@ -plugins { - id("org.example.plugin-analysis") -} \ No newline at end of file +plugins { `kotlin-dsl` } + +repositories { gradlePluginPortal() } + +dependencies { + implementation("com.autonomousapps:dependency-analysis-gradle-plugin:1.32.0") + implementation("com.diffplug.spotless:spotless-plugin-gradle:6.25.0") + implementation("com.gradle:develocity-gradle-plugin:3.17.2") + implementation("io.fuchs.gradle.classpath-collision-detector:classpath-collision-detector:0.3") + implementation("org.cyclonedx:cyclonedx-gradle-plugin:1.8.2") + implementation("org.gradlex:jvm-dependency-conflict-resolution:2.1.1") +} + +testing.suites.named("test") { + useJUnitJupiter() + dependencies { + implementation("org.junit.jupiter:junit-jupiter-params") + implementation("org.assertj:assertj-core:3.26.0") + } +} diff --git a/gradle/plugins/dependency-analysis-plugins/build.gradle.kts b/gradle/plugins/dependency-analysis-plugins/build.gradle.kts deleted file mode 100644 index e24ad2cc..00000000 --- a/gradle/plugins/dependency-analysis-plugins/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation("com.autonomousapps:dependency-analysis-gradle-plugin") -} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts deleted file mode 100644 index 3da50ad1..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-platform.gradle.kts +++ /dev/null @@ -1,79 +0,0 @@ -import org.example.dependencyanalysis.DependencyFormatCheck -import org.example.dependencyanalysis.DependencyVersionUpgradesCheck -import org.example.dependencyanalysis.PlatformVersionConsistencyCheck - -plugins { - id("java-platform") -} - -val checkDependencyFormatting = tasks.register("checkDependencyFormatting") { - group = LifecycleBasePlugin.VERIFICATION_GROUP - - buildFilePath.set(project.buildFile.absolutePath) - shouldNotHaveVersions.set(false) - declaredDependencies.put("api", provider { configurations.api.get().dependencies.map { d -> d.toDeclaredString() } }) - declaredDependencies.put("runtime", provider { configurations.runtime.get().dependencies.map { d -> d.toDeclaredString() } }) - declaredConstraints.put("api", provider { configurations.api.get().dependencyConstraints.map { d -> d.toDeclaredString() } }) - declaredConstraints.put("runtime", provider { configurations.runtime.get().dependencyConstraints.map { d -> d.toDeclaredString() } }) -} - -val latestReleases = configurations.dependencyScope("dependencyVersionUpgrades") { - withDependencies { - add(project.dependencies.platform(project(project.path))) - configurations.api.get().dependencies.forEach { - add(project.dependencies.platform("${it.group}:${it.name}:latest.release") { isTransitive = false }) - } - configurations.api.get().dependencyConstraints.forEach { - add(project.dependencies.create("${it.group}:${it.name}:latest.release") { isTransitive = false }) - } - } -} -val latestReleasesPath = configurations.resolvable("latestReleasesPath") { - attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) - attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) - extendsFrom(latestReleases.get()) -} -tasks.register("checkForDependencyVersionUpgrades") { - group = HelpTasksPlugin.HELP_GROUP - projectName.set(project.name) - apiDependencies.set(configurations.api.get().dependencies.map { "${it.group}:${it.name}:${it.version}" }) - apiDependencyConstraints.set(configurations.api.get().dependencyConstraints.map { "${it.group}:${it.name}:${it.version}" }) - latestReleasesResolutionResult.set(latestReleasesPath.map { it.incoming.resolutionResult.allComponents }) -} - -// Install a task that checks the consistency of the platform against the resolution result of the product -val product = configurations.dependencyScope("product").get() -dependencies { - product(platform(project(path))) -} -val purePlatformVersions = configurations.dependencyScope("purePlatformVersions") { - withDependencies { - add(project.dependencies.platform(project(project.path))) - // Create a dependency for eac constraint defined in the platform (this is to check for unused entries) - configurations.api.get().dependencyConstraints.forEach { constraint -> - add(project.dependencies.create("${constraint.group}:${constraint.name}") { isTransitive = false }) - } - } -} -val fullProductRuntimeClasspath = configurations.resolvable("fullProductRuntimeClasspath") { - attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) - attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) - extendsFrom(product) -} -val purePlatformVersionsPath = configurations.resolvable("purePlatformVersionsPath") { - attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) - attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) - extendsFrom(purePlatformVersions.get()) -} -tasks.register("checkPlatformVersionConsistency") { - group = HelpTasksPlugin.HELP_GROUP - productClasspath.set(fullProductRuntimeClasspath.map { it.incoming.resolutionResult.allComponents }) - classpathFromPlatform.set(purePlatformVersionsPath.map { it.incoming.resolutionResult.allComponents }) -} - -tasks.check { - dependsOn(checkDependencyFormatting) -} - -fun Dependency.toDeclaredString() = "$group:$name:$version" -fun DependencyConstraint.toDeclaredString() = "$group:$name:$version" diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts deleted file mode 100644 index 96da16fc..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-project.gradle.kts +++ /dev/null @@ -1,40 +0,0 @@ -import com.autonomousapps.DependencyAnalysisSubExtension -import org.example.dependencyanalysis.DependencyFormatCheck -import org.example.dependencyanalysis.DependencyScopeCheck - -plugins { - id("java") -} - -val checkDependencyFormatting = tasks.register("checkDependencyFormatting") { - group = LifecycleBasePlugin.VERIFICATION_GROUP - - buildFilePath.set(project.buildFile.absolutePath) - shouldNotHaveVersions.set(true) - sourceSets.all { - declaredDependencies.put(implementationConfigurationName, provider { configurations.getByName(implementationConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) - declaredDependencies.put(runtimeOnlyConfigurationName, provider { configurations.getByName(runtimeOnlyConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) - declaredDependencies.put(compileOnlyConfigurationName, provider { configurations.getByName(compileOnlyConfigurationName).dependencies.map { d -> d.toDeclaredString() } }) - declaredDependencies.put(apiConfigurationName, provider { configurations.findByName(apiConfigurationName)?.dependencies?.map { d -> d.toDeclaredString() } ?: emptyList() }) - declaredDependencies.put(compileOnlyApiConfigurationName, provider { configurations.findByName(compileOnlyApiConfigurationName)?.dependencies?.map { d -> d.toDeclaredString() } ?: emptyList() }) - } -} - -val checkDependencyScopes = tasks.register("checkDependencyScopes") { - group = LifecycleBasePlugin.VERIFICATION_GROUP - shouldRunAfter(checkDependencyFormatting) -} - -tasks.check { - dependsOn(checkDependencyFormatting) - dependsOn(checkDependencyScopes) -} - -plugins.withId("com.autonomousapps.dependency-analysis") { - extensions.getByType().registerPostProcessingTask(checkDependencyScopes) -} - -fun Dependency.toDeclaredString() = when(this) { - is ProjectDependency -> ":$name" - else -> "$group:$name${if (version == null) "" else ":$version"}" -} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts deleted file mode 100644 index 47951078..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org.example.dependency-analysis-root.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - id("com.autonomousapps.dependency-analysis") -} - -// Lifecycle task to check dependency scopes in all subprojects -tasks.register("checkDependencyScopes") { - group = LifecycleBasePlugin.VERIFICATION_GROUP - description = "Check all dependency scopes (api vs implementation) and find unused dependencies" - dependsOn(subprojects.map { "${it.path}:checkDependencyScopes"}) -} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt deleted file mode 100644 index 7ce8d58e..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyFormatCheck.kt +++ /dev/null @@ -1,81 +0,0 @@ -package org.example.dependencyanalysis - -import org.gradle.api.DefaultTask -import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction - -/** - * Check that 'dependencies' are defined in alphabetical order and without version. - */ -abstract class DependencyFormatCheck : DefaultTask() { - - @get:Input - abstract val buildFilePath : Property - - @get:Input - abstract val declaredDependencies : MapProperty> // Map of 'scope' to 'coordinates' - - @get:Input - abstract val declaredConstraints : MapProperty> // Map of 'scope' to 'coordinates' - - @get:Input - abstract val shouldNotHaveVersions : Property - - @TaskAction - fun check() { - declaredDependencies.get().forEach { (scope, dependencies) -> - if (shouldNotHaveVersions.get()) { - dependencies.forEach { coordinates -> - if (coordinates.count { it == ':' } == 2 && !coordinates.startsWith("org.jetbrains.kotlin:kotlin-stdlib:")) { - throw RuntimeException(""" - ${buildFilePath.get()} - - Dependencies with versions are not allowed. Please declare the dependency as follows: - - ${scope}("${coordinates.substring(0, coordinates.lastIndexOf(':'))}") - - All versions must be declared in 'gradle/platform'. - If the version is not yet defined there, add the following to 'gradle/platform/build.gradle.kts': - - api("$coordinates") - """.trimIndent()) - } - } - } - - val declaredInBuildFile = dependencies.filter { - // Ignore dependencies that are defined in our plugins - it !in listOf( - "org.example.product:platform", - "org.slf4j:slf4j-simple", - "org.junit.jupiter:junit-jupiter-engine", - "org.junit.jupiter:junit-jupiter") - } - val sortedProject = declaredInBuildFile.filter { it.startsWith(":") }.sorted() - val sortedExternal = declaredInBuildFile.filter { !it.startsWith(":") }.sorted() - if (declaredInBuildFile != sortedProject + sortedExternal) { - throw RuntimeException(""" - ${buildFilePath.get()} - - $scope dependencies are not declared in alphabetical order. Please use this order: - ${sortedProject.joinToString("\n ") {"${scope}(project(\"${it}\"))"}} - ${sortedExternal.joinToString("\n ") {"${scope}(\"${it}\")"}} - """.trimIndent()) - } - } - - declaredConstraints.get().forEach { (scope, constraints) -> - val sortedConstraints = constraints.sorted() - if (constraints != sortedConstraints) { - throw RuntimeException(""" - ${buildFilePath.get()} - - $scope dependency constraints are not declared in alphabetical order. Please use this order: - ${sortedConstraints.joinToString("\n ") {"${scope}(\"${it}\")"}} - """.trimIndent()) - } - } - } -} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt deleted file mode 100644 index c1a2c1aa..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyScopeCheck.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.example.dependencyanalysis - -import com.autonomousapps.AbstractPostProcessingTask -import com.autonomousapps.model.Advice -import com.autonomousapps.model.ProjectCoordinates -import org.gradle.api.tasks.TaskAction - -/** - * Task that uses the 'com.autonomousapps.dependency-analysis' plugin to find unused dependencies and check - * 'api' vs. 'implementation' scopes. - */ -abstract class DependencyScopeCheck : AbstractPostProcessingTask() { - - @TaskAction - fun check() { - val projectAdvice = projectAdvice().dependencyAdvice - if (projectAdvice.isNotEmpty()) { - val toAdd = projectAdvice.filter { it.toConfiguration != null && it.toConfiguration != "runtimeOnly" } - .map { it.declaration(it.toConfiguration) }.sorted() - val toRemove = - projectAdvice.filter { it.fromConfiguration != null }.map { it.declaration(it.fromConfiguration) } - .sorted() - - throw RuntimeException( - """ - ${projectAdvice().projectPath.substring(1)}/build.gradle.kts - - Please add the following dependency declarations: - ${toAdd.joinToString("\n ") { it }} - - Please remove the following dependency declarations: - ${toRemove.joinToString("\n ") { it }} - """.trimIndent() - ) - } - } - - private fun Advice.declaration(conf: String?) = - if (coordinates is ProjectCoordinates) "${conf}(project(\"${coordinates.identifier}\"))" - else "${conf}(\"${coordinates.identifier}\")" -} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt b/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt deleted file mode 100644 index 1f6b32b1..00000000 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/DependencyVersionUpgradesCheck.kt +++ /dev/null @@ -1,58 +0,0 @@ -package org.example.dependencyanalysis - -import org.gradle.api.DefaultTask -import org.gradle.api.artifacts.result.ResolvedComponentResult -import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction - -/** - * Checks if new versions are available for what is declared in the platform. - */ -abstract class DependencyVersionUpgradesCheck : DefaultTask() { - - @get:Internal - abstract val projectName: Property - - @get:Internal - abstract val apiDependencies: SetProperty - - @get:Internal - abstract val apiDependencyConstraints: SetProperty - - @get:Internal - abstract val latestReleasesResolutionResult: SetProperty - - @TaskAction - fun check() { - val platformDependencyUpgrades = apiDependencies.get().filter { declared -> declared.resolvedVersion() != declared.version() } - val constraintUpgrades = apiDependencyConstraints.get().filter { declared -> declared.resolvedVersion() != declared.version() } - if (platformDependencyUpgrades.isNotEmpty() || constraintUpgrades.isNotEmpty()) { - throw RuntimeException(""" - ${projectName.get()}/build.gradle.kts - - The following dependency versions should be upgraded in 'gradle/platform/build.gradle.kts' (dependencies {} block): - - ${platformDependencyUpgrades.joinToString("\n ") { "api(platform(\"${it.ga()}:${it.resolvedVersion()}\"))" }} - - The following dependency versions should be upgraded in 'gradle/platform/build.gradle.kts' (dependencies.constraints {} block): - - ${constraintUpgrades.joinToString("\n ") { "api(\"${it.ga()}:${it.resolvedVersion()}\")" }} - - If we cannot perform an upgrade, please add a '{ version { reject("...") } }' statement and a comment - for the versions we cannot support at the moment. - """.trimIndent()) - } - } - - private fun String.ga() = substring(0, lastIndexOf(":")) - - private fun String.version() = substring(lastIndexOf(":") + 1) - - private fun String.resolvedVersion() = - latestReleasesResolutionResult.get().find { - it.moduleVersion!!.module.toString() == ga() - }?.moduleVersion?.version ?: version() // if no fitting version could be determined, return the declared one - -} diff --git a/gradle/plugins/dependency-rules-plugins/build.gradle.kts b/gradle/plugins/dependency-rules-plugins/build.gradle.kts deleted file mode 100644 index 405c8e41..00000000 --- a/gradle/plugins/dependency-rules-plugins/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation("dev.jacomet.gradle.plugins:logging-capabilities") - implementation("org.gradlex:java-ecosystem-capabilities") -} diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org.example.dependency-rules.gradle.kts b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org.example.dependency-rules.gradle.kts deleted file mode 100644 index 15db5440..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org.example.dependency-rules.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -import org.example.metadatarules.fixdependencies.TypesafeConfigGuiceRule -import org.example.metadatarules.status.ComponentStatusRule -import org.example.metadatarules.versionalignment.HttpComponentsPlatformRule -import org.example.metadatarules.versionalignment.PoiPlatformRule -import org.example.metadatarules.versionalignment.Slf4jPlatformRule -import org.example.metadatarules.versionalignment.ParentPomAsPlatformRule - -plugins { - id("dev.jacomet.logging-capabilities") - id("org.gradlex.java-ecosystem-capabilities") -} - -// Configure logging capabilities plugin to default to Slf4JSimple -loggingCapabilities.enforceSlf4JSimple() - -dependencies.components { - // Versions that are not final get the 'integration' status - all() - - // Fix dependencies - withModule(TypesafeConfigGuiceRule.TYPESAFE_CONFIG_GUICE_MODULE) - - // Define 'Alignment Platforms' (platforms for multi-component libraries without published BOM) - withModule(HttpComponentsPlatformRule.HTTP_COMPONENTS_CLIENT) - withModule(PoiPlatformRule.POI_COMMON) - withModule(Slf4jPlatformRule.SLF4J_PARENT) - - // Make parents usable as pure 'Alignment Platforms' - remove all constraints that do not concern the alignment - withModule(HttpComponentsPlatformRule.HTTP_COMPONENTS_CLIENT) - withModule(Slf4jPlatformRule.SLF4J_PARENT) -} diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/fixdependencies/TypesafeConfigGuiceRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/fixdependencies/TypesafeConfigGuiceRule.kt deleted file mode 100644 index c9ef41c3..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/fixdependencies/TypesafeConfigGuiceRule.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.example.metadatarules.fixdependencies - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Removes the 'no_aop' classifier from the Guice dependency, because it - * no longer exists with Guice 5.0 to which we upgrade the dependency. - */ -@CacheableRule -abstract class TypesafeConfigGuiceRule : ComponentMetadataRule { - companion object { - const val TYPESAFE_CONFIG_GUICE_MODULE = "com.github.racc:typesafeconfig-guice" - } - - override fun execute(context: ComponentMetadataContext) { - context.details.allVariants { - withDependencies { - removeIf { it.group == "com.google.inject" } - add("com.google.inject:guice") - } - } - } -} diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/status/ComponentStatusRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/status/ComponentStatusRule.kt deleted file mode 100644 index 3e5d1d7f..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/status/ComponentStatusRule.kt +++ /dev/null @@ -1,29 +0,0 @@ -package org.example.metadatarules.status - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Make sure versions that are not final released have a different status than 'release'. - * Otherwise, they will be considered when asking for the 'latest.release' version. - * - * (POM metadata does not support the 'status' concept and thus Gradle assumes everything is a 'release' by default) - */ -@CacheableRule -abstract class ComponentStatusRule : ComponentMetadataRule { - override fun execute(context: ComponentMetadataContext) { - val version = context.details.id.version - val lcVersion = version.lowercase() - if (lcVersion.contains("alpha") - || lcVersion.contains("-b") - || lcVersion.contains("beta") - || lcVersion.contains("cr") - || lcVersion.contains("m") - || lcVersion.contains("rc") - || lcVersion.startsWith("200")) { - - context.details.status = "integration" - } - } -} diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/HttpComponentsPlatformRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/HttpComponentsPlatformRule.kt deleted file mode 100644 index d894f351..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/HttpComponentsPlatformRule.kt +++ /dev/null @@ -1,42 +0,0 @@ -package org.example.metadatarules.versionalignment - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Extend the Parent POM 'httpcomponents-client' with constraints so that it can be used as platform - * to align the versions of all 'org.apache.httpcomponents' components. - * - * See: - * https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcomponents-client/4.5.13/httpcomponents-client-4.5.13.pom - * - * - * httpclient - * httpmime - * fluent-hc - * httpclient-cache - * httpclient-win - * httpclient-osgi - * - */ -@CacheableRule -abstract class HttpComponentsPlatformRule : ComponentMetadataRule { - companion object { - const val HTTP_COMPONENTS_CLIENT = "org.apache.httpcomponents:httpcomponents-client" - } - - override fun execute(context: ComponentMetadataContext) { - val version = context.details.id.version - context.details.allVariants { - withDependencyConstraints { - add("org.apache.httpcomponents:httpclient:$version") - add("org.apache.httpcomponents:httpmime:$version") - add("org.apache.httpcomponents:fluent-hc:$version") - add("org.apache.httpcomponents:httpclient-cache:$version") - add("org.apache.httpcomponents:httpclient-win:$version") - add("org.apache.httpcomponents:httpclient-osgi:$version") - } - } - } -} \ No newline at end of file diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/ParentPomAsPlatformRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/ParentPomAsPlatformRule.kt deleted file mode 100644 index 95427191..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/ParentPomAsPlatformRule.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.example.metadatarules.versionalignment - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Sometime libraries consisting of multiple components do not offer a BOM but have - * a 'Parent POM' that contains the information for alignment. - * However, these often also contain constraints on other components that we do not - * want to include. This Rule removes these additional constraints. - */ -@CacheableRule -abstract class ParentPomAsPlatformRule : ComponentMetadataRule { - override fun execute(context: ComponentMetadataContext) { - val group = context.details.id.group - context.details.allVariants { - withDependencyConstraints { - removeAll { it.group != group } - } - } - } -} diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/PoiPlatformRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/PoiPlatformRule.kt deleted file mode 100644 index 46482edb..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/PoiPlatformRule.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.example.metadatarules.versionalignment - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Extend the central 'poi' component with constraints so that it can be used as platform - * to align the versions of all 'org.apache.poi' components. - * - * See: - * https://repo1.maven.org/maven2/org/apache/poi/poi/5.2.0/poi-5.2.0.pom - */ -@CacheableRule -abstract class PoiPlatformRule : ComponentMetadataRule { - companion object { - const val POI_COMMON = "org.apache.poi:poi" - } - - override fun execute(context: ComponentMetadataContext) { - val version = context.details.id.version - context.details.allVariants { - withDependencyConstraints { - add("org.apache.poi:poi-excelant:$version") - add("org.apache.poi:poi-ooxml:$version") - add("org.apache.poi:poi-scratchpad:$version") - } - } - } -} \ No newline at end of file diff --git a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/Slf4jPlatformRule.kt b/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/Slf4jPlatformRule.kt deleted file mode 100644 index ea067f38..00000000 --- a/gradle/plugins/dependency-rules-plugins/src/main/kotlin/org/example/metadatarules/versionalignment/Slf4jPlatformRule.kt +++ /dev/null @@ -1,40 +0,0 @@ -package org.example.metadatarules.versionalignment - -import org.gradle.api.artifacts.CacheableRule -import org.gradle.api.artifacts.ComponentMetadataContext -import org.gradle.api.artifacts.ComponentMetadataRule - -/** - * Extend the Parent POM 'slf4j-parent' with constraints so that it can be used as platform - * to align the versions of all 'org.slf4j' components. - * - * See: - * https://repo1.maven.org/maven2/org/slf4j/slf4j-parent/1.7.36/slf4j-parent-1.7.36.pom - */ -@CacheableRule -abstract class Slf4jPlatformRule : ComponentMetadataRule { - companion object { - const val SLF4J_PARENT = "org.slf4j:slf4j-parent" - } - - override fun execute(context: ComponentMetadataContext) { - val version = context.details.id.version - context.details.allVariants { - withDependencyConstraints { - add("org.slf4j:slf4j-api:$version") - add("org.slf4j:slf4j-simple:$version") - add("org.slf4j:slf4j-nop:$version") - add("org.slf4j:slf4j-jdk14:$version") - add("org.slf4j:slf4j-log4j12:$version") - add("org.slf4j:slf4j-reload4j:$version") - add("org.slf4j:slf4j-jcl:$version") - add("org.slf4j:slf4j-android:$version") - add("org.slf4j:slf4j-ext:$version") - add("org.slf4j:jcl-over-slf4j:$version") - add("org.slf4j:log4j-over-slf4j:$version") - add("org.slf4j:jul-to-slf4j:$version") - add("org.slf4j:osgi-over-slf4j:$version") - } - } - } -} \ No newline at end of file diff --git a/gradle/plugins/java-application-plugins/build.gradle.kts b/gradle/plugins/java-application-plugins/build.gradle.kts deleted file mode 100644 index 20df9997..00000000 --- a/gradle/plugins/java-application-plugins/build.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation(project(":java-base-plugins")) - implementation("org.example:build-parameters-plugins") - implementation("org.owasp:dependency-check-gradle") - implementation("io.fuchs.gradle.classpath-collision-detector:classpath-collision-detector") -} diff --git a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.application.gradle.kts b/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.application.gradle.kts deleted file mode 100644 index cf394666..00000000 --- a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.application.gradle.kts +++ /dev/null @@ -1,47 +0,0 @@ -import org.example.application.tasks.MD5DirectoryChecksum -import org.example.application.tasks.VersionXml - -plugins { - id("org.example.java") - id("application") // For stand-alone application packaging - id("jacoco-report-aggregation") // get and aggregated coverage report for all tests - id("test-report-aggregation") // get and aggregated result report for all tests - id("org.example.war") // For web application packaging/deployment - id("org.example.end2end-testing") - id("io.fuchs.gradle.classpath-collision-detector") - id("org.owasp.dependencycheck") -} - -configurations.aggregateTestReportResults { - shouldResolveConsistentlyWith(configurations.appRuntimeClasspath.get()) -} -configurations.aggregateCodeCoverageReportResults { - shouldResolveConsistentlyWith(configurations.appRuntimeClasspath.get()) -} - -// Generate additional resources required at application runtime -val generateVersionXml = tasks.register("generateVersionXml") { - mainVersion.set(providers.fileContents( - rootProject.layout.projectDirectory.file("gradle/version.txt")).asText) - xmlFile.set(layout.buildDirectory.file("generated-resources/xml/version.xml")) -} -val resourcesChecksum = tasks.register("resourcesChecksum") { - inputDirectory.set(layout.projectDirectory.dir("src/main/resources")) - checksumFile.set(layout.buildDirectory.file("generated-resources/md5/resources.MD5")) -} - -tasks.processResources { - from(generateVersionXml) - from(resourcesChecksum) -} - -dependencyCheck { - scanConfigurations = listOf(configurations.runtimeClasspath.get().name) - autoUpdate = false -} - -tasks.check { - dependsOn(tasks.testAggregateTestReport) - dependsOn(tasks.testCodeCoverageReport) - dependsOn(tasks.detectCollisions) -} diff --git a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.end2end-testing.gradle.kts b/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.end2end-testing.gradle.kts deleted file mode 100644 index d91b118c..00000000 --- a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.end2end-testing.gradle.kts +++ /dev/null @@ -1,33 +0,0 @@ -plugins { - id("org.example.java") -} - -// Specific API fixtures used for testing without live service -val mockApi = sourceSets.create("mockApi") -java.registerFeature(mockApi.name) { - usingSourceSet(mockApi) -} - -// end-to-end tests located in the :app project -testing.suites.create("endToEndTest") { - useJUnitJupiter("") - targets.all { - testTask { - options { - this as JUnitPlatformOptions - excludeTags("slow") - } - } - tasks.check { - dependsOn(testTask) - } - } -} - -// Add a second task for the endToEndTest suite (not yet supported by suites directly) -tasks.register("endToEndTestSlow") { - testClassesDirs = sourceSets["endToEndTest"].output.classesDirs - classpath = sourceSets["endToEndTest"].runtimeClasspath - group = LifecycleBasePlugin.VERIFICATION_GROUP - useJUnitPlatform { includeTags("slow") } -} diff --git a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.war.gradle.kts b/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.war.gradle.kts deleted file mode 100644 index be5f514d..00000000 --- a/gradle/plugins/java-application-plugins/src/main/kotlin/org.example.war.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id("war") - id("org.example.java") - id("org.example.build-parameters") -} - -// The war plugin used 'providedRuntime' / 'providedCompile' to resolve dependencies for packaging the WAR file -configurations.providedCompile { - shouldResolveConsistentlyWith(configurations.appRuntimeClasspath.get()) -} -configurations.providedRuntime { - shouldResolveConsistentlyWith(configurations.appRuntimeClasspath.get()) -} - -tasks.register("deployWebApp") { - group = "distribution" - description = "Deploy web app into local Tomcat found via CATALINA_HOME" - from(tasks.war) { - into("webapps") - } - into(buildParameters.catalina.home) -} diff --git a/gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/VersionXml.kt b/gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/VersionXml.kt deleted file mode 100644 index 0a1e8ef4..00000000 --- a/gradle/plugins/java-application-plugins/src/main/kotlin/org/example/application/tasks/VersionXml.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.example.application.tasks - -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -/** - * Encodes the current product version in an XML format used at application runtime. - */ -abstract class VersionXml : DefaultTask() { - - @get:Input - abstract val mainVersion: Property - - @get:OutputFile - abstract val xmlFile: RegularFileProperty - - @TaskAction - fun generate() { - xmlFile.get().asFile.writeText( - "" - ) - } -} diff --git a/gradle/plugins/java-base-plugins/build.gradle.kts b/gradle/plugins/java-base-plugins/build.gradle.kts deleted file mode 100644 index 2ce9b700..00000000 --- a/gradle/plugins/java-base-plugins/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation(project(":base-plugins")) -} diff --git a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.consistent-resolution.gradle.kts b/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.consistent-resolution.gradle.kts deleted file mode 100644 index 4fc15b53..00000000 --- a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.consistent-resolution.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -plugins { - id("java-base") -} - -// Expose the ':app' project runtime classpath in every project -val app = configurations.dependencyScope("app") { - withDependencies { - // Depend on ':app' and with this on all its (transitive) dependencies - add(project.dependencies.create(project(":app"))) - // Get our own version information from the platform project - add(project.dependencies.create(project.dependencies.platform("org.example.product:platform"))) - } -} -val appRuntimeClasspath = configurations.resolvable("appRuntimeClasspath") { - description = "Runtime classpath of the complete application" - extendsFrom(app.get()) - attributes { - // We want the runtime classpath represented by Usage.JAVA_RUNTIME - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) - } -} - -// Every compile classpath and runtime classpath uses the versions of the -sourceSets.all { - configurations[compileClasspathConfigurationName].shouldResolveConsistentlyWith(appRuntimeClasspath.get()) - configurations[runtimeClasspathConfigurationName].shouldResolveConsistentlyWith(appRuntimeClasspath.get()) - // Source sets without production code (tests / fixtures) are allowed to have dependencies that are - // not part of the consistent resolution result and might need additional version information - if (this != sourceSets["main"]) { - dependencies.add(implementationConfigurationName, dependencies.platform("org.example.product:platform")) - } -} diff --git a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts b/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts deleted file mode 100644 index ee8824fa..00000000 --- a/gradle/plugins/java-base-plugins/src/main/kotlin/org.example.java.gradle.kts +++ /dev/null @@ -1,39 +0,0 @@ -plugins { - id("java") - id("jacoco") // Record test coverage data during test execution - id("org.example.base") - id("org.example.consistent-resolution") - id("org.example.dependency-analysis-project") -} - -// Configure Java compilation on java {} extension or directly on 'JavaCompile' tasks -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(17)) -} -tasks.withType().configureEach { - options.encoding = "UTF-8" -} - -// Configure details for *all* test executions directly on 'Test' task -tasks.withType().configureEach { - useJUnitPlatform() // Use JUnit 5 as test framework - maxParallelForks = 4 - - testLogging.showStandardStreams = true - - maxHeapSize = "1g" - systemProperty("file.encoding", "UTF-8") -} - -// Configure common test runtime dependencies for *all* projects -dependencies { - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - testRuntimeOnly("org.slf4j:slf4j-simple") -} - -// Add a 'compileAll' task to run all of Java compilation in one go -tasks.register("compileAll") { - group = LifecycleBasePlugin.BUILD_GROUP - description = "Compile all Java code (use to prime the build cache for CI pipeline)" - dependsOn(tasks.withType()) -} diff --git a/gradle/plugins/java-library-plugins/build.gradle.kts b/gradle/plugins/java-library-plugins/build.gradle.kts deleted file mode 100644 index 4aaf9877..00000000 --- a/gradle/plugins/java-library-plugins/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - `kotlin-dsl` -} - -dependencies { - implementation(platform(project(":plugins-platform"))) - - implementation(project(":java-base-plugins")) -} diff --git a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-published.gradle.kts b/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-published.gradle.kts deleted file mode 100644 index 4b6a639a..00000000 --- a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-published.gradle.kts +++ /dev/null @@ -1,35 +0,0 @@ -plugins { - id("maven-publish") - id("org.example.java-library") -} - -// Publish with sources and Javadoc -java { - withSourcesJar() - withJavadocJar() -} - -// Configure details of Javadoc generation -tasks.javadoc { - (options as StandardJavadocDocletOptions).apply { - memberLevel = JavadocMemberLevel.PUBLIC - isAuthor = true - } -} - -publishing.publications.create("mavenJava") { - from(components["java"]) - - // We use consistent resolution + a platform for controlling versions - // -> Publish the versions that are the result of the consistent resolution - versionMapping { - allVariants { - fromResolutionResult() - } - } -} - -// The repository to publish to -publishing.repositories { - maven("/tmp/my-repo") -} diff --git a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-with-test-fixtures.gradle.kts b/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-with-test-fixtures.gradle.kts deleted file mode 100644 index 79940f87..00000000 --- a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library-with-test-fixtures.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -plugins { - id("org.example.java-library") - id("java-test-fixtures") -} diff --git a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library.gradle.kts b/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library.gradle.kts deleted file mode 100644 index c89bd437..00000000 --- a/gradle/plugins/java-library-plugins/src/main/kotlin/org.example.java-library.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -plugins { - id("java-library") - id("org.example.java") -} diff --git a/gradle/plugins/plugins-platform/build.gradle.kts b/gradle/plugins/plugins-platform/build.gradle.kts deleted file mode 100644 index ba662629..00000000 --- a/gradle/plugins/plugins-platform/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - id("java-platform") -} - -dependencies.constraints { - api("com.autonomousapps:dependency-analysis-gradle-plugin:1.27.0") - api("dev.jacomet.gradle.plugins:logging-capabilities:0.11.1") - api("io.fuchs.gradle.classpath-collision-detector:classpath-collision-detector:0.3") - api("org.gradlex:java-ecosystem-capabilities:1.3.1") - api("org.owasp:dependency-check-gradle:9.0.2") -} diff --git a/gradle/plugins/settings.gradle.kts b/gradle/plugins/settings.gradle.kts deleted file mode 100644 index a7ec1ee2..00000000 --- a/gradle/plugins/settings.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -pluginManagement { - includeBuild("../meta-plugins") -} -plugins { - id("org.example.settings") -} - -dependencyResolutionManagement { - repositories.gradlePluginPortal() - includeBuild("../meta-plugins") // for 'build-parameters' -} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.base.dependency-rules.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.base.dependency-rules.gradle.kts new file mode 100644 index 00000000..078d0a9c --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.base.dependency-rules.gradle.kts @@ -0,0 +1,44 @@ +plugins { id("org.gradlex.jvm-dependency-conflict-resolution") } + +jvmDependencyConflicts { + // Configure build wide consistent resolution. That is, the versions that are used on the + // runtime classpath of the web applications should also be used in all other places + // (e.g. also when compiling a project at the bottom of the dependency graph that does not + // see most of the other dependencies that may influence the version choices). + consistentResolution { + platform(":versions") + providesVersions(":aggregation") + } + + // Configure logging capabilities plugin to default to Slf4JSimple + logging { enforceSlf4JSimple() } + + patch { + module("com.github.racc:typesafeconfig-guice") { + // remove and re-add due to 'no_aop' classifier + removeDependency("com.google.inject:guice") + addApiDependency("com.google.inject:guice") + } + + align( + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpmime", + "org.apache.httpcomponents:fluent-hc", + "org.apache.httpcomponents:httpclient-cache", + "org.apache.httpcomponents:httpclient-win", + "org.apache.httpcomponents:httpclient-osgi" + ) + align( + "org.apache.poi:poi", + "org.apache.poi:poi-excelant", + "org.apache.poi:poi-ooxml", + "org.apache.poi:poi-scratchpad" + ) + align("com.google.inject.extensions:guice-servlet", "com.google.inject:guice") + align( + "org.jboss.resteasy:resteasy-core", + "org.jboss.resteasy:resteasy-guice", + "org.jboss.resteasy:resteasy-jackson2-provider" + ) + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.base.identity.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.base.identity.gradle.kts new file mode 100644 index 00000000..e9c4fd6f --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.base.identity.gradle.kts @@ -0,0 +1,7 @@ +plugins { id("org.gradle.base") } + +// Set the group (some components will be published) +group = "org.example.product" + +// Set the version from 'version.txt' +version = providers.fileContents(isolated.rootProject.projectDirectory.file("gradle/version.txt")).asText.getOrElse("") diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.gradle.kts new file mode 100644 index 00000000..2292aeb7 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.gradle.kts @@ -0,0 +1,13 @@ +plugins { id("org.gradle.base") } + +tasks.register("qualityCheck") { + group = "build" + description = "Runs checks (without executing tests)" +} + +tasks.register("qualityGate") { + group = "build" + description = "Runs checks and auto-corrects (without executing tests)" +} + +tasks.check { dependsOn(tasks.named("qualityCheck")) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.root.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.root.gradle.kts new file mode 100644 index 00000000..26fbd373 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.base.lifecycle.root.gradle.kts @@ -0,0 +1,10 @@ +plugins { + id("org.gradle.base") + id("org.example.gradle.base.lifecycle") +} + +// Configure the 'tasks' task such that when you run './gradlew' without arguments you see only the +// tasks of the 'build' group, which are the tasks for daily development. +defaultTasks("tasks") + +tasks.named("tasks") { displayGroup = "build" } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.gradle.kts new file mode 100644 index 00000000..f6330b2c --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.gradle.kts @@ -0,0 +1,18 @@ +import com.autonomousapps.tasks.ProjectHealthTask + +plugins { + id("org.gradle.java") + id("com.autonomousapps.dependency-analysis") + id("io.fuchs.gradle.classpath-collision-detector") + id("org.example.gradle.base.lifecycle") +} + +tasks.named("qualityCheck") { + dependsOn(tasks.detectCollisions) + dependsOn(tasks.withType()) +} + +tasks.named("qualityGate") { + dependsOn(tasks.detectCollisions) + dependsOn(tasks.withType()) +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.root.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.root.gradle.kts new file mode 100644 index 00000000..2fd1238c --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.dependencies.root.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("org.gradle.base") + id("com.autonomousapps.dependency-analysis") +} + +// Configure the dependency analysis plugin to fail if issues are found +dependencyAnalysis { issues { all { onAny { severity("fail") } } } } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.gradle.kts new file mode 100644 index 00000000..1ceb7ebc --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.gradle.kts @@ -0,0 +1,17 @@ +import com.hedera.gradle.spotless.SortDependenciesStep + +plugins { + id("com.diffplug.spotless") + id("org.example.gradle.base.lifecycle") +} + +spotless { + kotlinGradle { + ktfmt().kotlinlangStyle().configure { it.setMaxWidth(500) } + addStep(SortDependenciesStep.create()) + } +} + +tasks.named("qualityCheck") { dependsOn(tasks.spotlessCheck) } + +tasks.named("qualityGate") { dependsOn(tasks.spotlessApply) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.root.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.root.gradle.kts new file mode 100644 index 00000000..dd641626 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-gradle.root.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("com.diffplug.spotless") + id("org.example.gradle.base.lifecycle") +} + +spotless { + kotlinGradle { + ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } + target("gradle/plugins/src/main/**/*.gradle.kts") + } + kotlin { + ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } + target("gradle/plugins/src/main/**/*.kt") + } +} + +tasks.named("qualityCheck") { dependsOn(tasks.spotlessCheck) } + +tasks.named("qualityGate") { dependsOn(tasks.spotlessApply) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-java.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-java.gradle.kts new file mode 100644 index 00000000..16ca55c9 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.format-java.gradle.kts @@ -0,0 +1,17 @@ +plugins { + id("com.diffplug.spotless") + id("org.example.gradle.base.lifecycle") +} + +spotless { + java { + importOrder() + removeUnusedImports() + cleanthat() + palantirJavaFormat() + } +} + +tasks.named("qualityCheck") { dependsOn(tasks.spotlessCheck) } + +tasks.named("qualityGate") { dependsOn(tasks.spotlessApply) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.check.platform.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.check.platform.gradle.kts new file mode 100644 index 00000000..309269dd --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.check.platform.gradle.kts @@ -0,0 +1,46 @@ +import org.example.gradle.tasks.PlatformVersionConsistencyCheck + +plugins { + id("org.gradle.java-platform") + id("org.example.gradle.base.lifecycle") +} + +// Install a task that checks the consistency of the platform against the resolution result of the +// product +val product = configurations.dependencyScope("product").get() + +dependencies { product(platform(project(path))) } + +val purePlatformVersions = + configurations.dependencyScope("purePlatformVersions") { + withDependencies { + add(project.dependencies.platform(project(project.path))) + // Create a dependency for eac constraint defined in the platform (this is to check for + // unused entries) + configurations.api.get().dependencyConstraints.forEach { constraint -> + add(project.dependencies.create("${constraint.group}:${constraint.name}") { isTransitive = false }) + } + } + } +val fullProductRuntimeClasspath = + configurations.resolvable("fullProductRuntimeClasspath") { + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + extendsFrom(product) + } +val purePlatformVersionsPath = + configurations.resolvable("purePlatformVersionsPath") { + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) + extendsFrom(purePlatformVersions.get()) + } + +tasks.register("checkPlatformVersionConsistency") { + group = HelpTasksPlugin.HELP_GROUP + productClasspath = fullProductRuntimeClasspath.map { it.incoming.resolutionResult.allComponents } + classpathFromPlatform = purePlatformVersionsPath.map { it.incoming.resolutionResult.allComponents } +} + +// TODO check/repair: dependsOn(checkPlatformVersionConsistency) +// tasks.named("qualityCheck") +// tasks.named("qualityGate") diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-application.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-application.gradle.kts new file mode 100644 index 00000000..115b2759 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-application.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("org.gradle.application") + id("org.example.gradle.base.dependency-rules") + id("org.example.gradle.base.identity") + id("org.example.gradle.base.lifecycle") + id("org.example.gradle.check.dependencies") + id("org.example.gradle.check.format-gradle") + id("org.example.gradle.check.format-java") + id("org.example.gradle.feature.checksum") + id("org.example.gradle.feature.compile") + id("org.example.gradle.feature.end2end-testing") + id("org.example.gradle.feature.javadoc") + id("org.example.gradle.feature.test") + id("org.example.gradle.feature.war") +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-library.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-library.gradle.kts new file mode 100644 index 00000000..85fe8b8f --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.component.java-library.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("org.gradle.java-library") + id("org.example.gradle.base.dependency-rules") + id("org.example.gradle.base.identity") + id("org.example.gradle.base.lifecycle") + id("org.example.gradle.check.dependencies") + id("org.example.gradle.check.format-gradle") + id("org.example.gradle.check.format-java") + id("org.example.gradle.feature.compile") + id("org.example.gradle.feature.javadoc") + id("org.example.gradle.feature.test") +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.dependencies.platform.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.dependencies.platform.gradle.kts new file mode 100644 index 00000000..67809921 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.dependencies.platform.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("org.gradle.java-platform") + id("org.example.gradle.base.dependency-rules") + id("org.example.gradle.base.lifecycle") + id("org.example.gradle.check.format-gradle") +} + +// Allow upgrading/downgrading (transitive) versions via catalog by adding strict constraints +dependencies.constraints { + val libs = versionCatalogs.named("libs") + val catalogEntries = libs.libraryAliases.map { libs.findLibrary(it).get().get() } + catalogEntries.forEach { entry -> + val version = entry.version + if (version != null) { + api(entry) { version { strictly(version) } } + } + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.build-cache.settings.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.build-cache.settings.gradle.kts new file mode 100644 index 00000000..e6ef79ba --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.build-cache.settings.gradle.kts @@ -0,0 +1,12 @@ +buildCache { + remote { + url = uri("https://gradle.onepiece.software:5071/cache/") + if (providers.environmentVariable("CI").getOrElse("false").toBoolean()) { + isPush = true + credentials { + username = providers.environmentVariable("BUILD_CACHE_USER").get() + password = providers.environmentVariable("BUILD_CACHE_PWD").get() + } + } + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.checksum.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.checksum.gradle.kts new file mode 100644 index 00000000..30cc55ad --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.checksum.gradle.kts @@ -0,0 +1,11 @@ +import org.example.gradle.tasks.MD5DirectoryChecksum + +plugins { id("org.gradle.java") } + +// Generate additional resources required at application runtime +tasks.register("resourcesChecksum") { + inputDirectory = layout.projectDirectory.dir("src/main/resources") + checksumFile = layout.buildDirectory.file("generated-resources/md5/resources.MD5") +} + +tasks.processResources { from(tasks.named("resourcesChecksum")) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.compile.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.compile.gradle.kts new file mode 100644 index 00000000..31d6d27d --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.compile.gradle.kts @@ -0,0 +1,55 @@ +plugins { + id("org.gradle.java") + id("org.example.gradle.base.lifecycle") +} + +// Configure which JDK and Java version to build with. The version is defined in +// 'gradle/jdk-version.txt' so that GitHub actions can also pick it up from there. +java { + toolchain.languageVersion = + JavaLanguageVersion.of( + providers + .fileContents(isolated.rootProject.projectDirectory.file("gradle/jdk-version.txt")) + .asText + .get() + .trim() + ) +} + +// Configuration to make the build reproducible. This means we override settings that are, by +// default, platform dependent (e.g. different default encoding on Windows and Unix systems). +tasks.withType().configureEach { + options.apply { + isFork = true + encoding = "UTF-8" + compilerArgs.add("-implicit:none") + compilerArgs.add("-Werror") + compilerArgs.add("-Xlint:all,-serial") + } +} + +tasks.withType().configureEach { + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + filePermissions { unix("0664") } + dirPermissions { unix("0775") } +} + +// Publish/build with sources +java { withSourcesJar() } + +// Tweak 'lifecycle tasks': These are the tasks in the 'build' group that are used in daily +// development. Under normal circumstances, these should be all the tasks developers needs +// in their daily work. +tasks.named("qualityCheck") { dependsOn(tasks.withType()) } + +tasks.named("qualityGate") { dependsOn(tasks.withType()) } + +// Clear tasks group 'build' from clutter for a clean set of tasks to be used in daily work +tasks.buildDependents { setGroup(null) } + +tasks.buildNeeded { setGroup(null) } + +tasks.jar { setGroup(null) } + +sourceSets.all { tasks.named(classesTaskName) { group = null } } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.develocity.settings.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.develocity.settings.gradle.kts new file mode 100644 index 00000000..c5d6f957 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.develocity.settings.gradle.kts @@ -0,0 +1,12 @@ +plugins { id("com.gradle.develocity") } + +// Configure Build Scans (local builds have to opt-in via --scan) +develocity { + buildScan { + termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use" + termsOfUseAgree = "yes" + if (!providers.environmentVariable("CI").getOrElse("false").toBoolean()) { + publishing.onlyIf { false } // only publish with explicit '--scan' + } + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.end2end-testing.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.end2end-testing.gradle.kts new file mode 100644 index 00000000..596b1118 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.end2end-testing.gradle.kts @@ -0,0 +1,32 @@ +plugins { id("org.gradle.java") } + +// Specific API fixtures used for testing without live service +val mockApi = sourceSets.create("mockApi") + +java.registerFeature(mockApi.name) { usingSourceSet(mockApi) } + +tasks.named("mockApiJar") { group = null } + +// end-to-end tests +testing.suites.create("endToEndTest") { + targets.named("endToEndTest") { + testTask { + group = "build" + options { + this as JUnitPlatformOptions + excludeTags("slow") + } + } + tasks.check { dependsOn(testTask) } + } + // Add a second task for the endToEndTest suite + targets.register("endToEndTestSlow") { + testTask { + group = "build" + options { + this as JUnitPlatformOptions + includeTags("slow") + } + } + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.javadoc.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.javadoc.gradle.kts new file mode 100644 index 00000000..d503913d --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.javadoc.gradle.kts @@ -0,0 +1,12 @@ +plugins { id("org.gradle.java") } + +// Publish/build with Javadoc +java { withJavadocJar() } + +tasks.withType().configureEach { + options { + this as StandardJavadocDocletOptions + encoding = "UTF-8" + addStringOption("Xwerror", "-Xdoclint:all,-missing") + } +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.project-structure.settings.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.project-structure.settings.gradle.kts new file mode 100644 index 00000000..982a5b16 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.project-structure.settings.gradle.kts @@ -0,0 +1,18 @@ +// Include all subfolders that contain a 'build.gradle.kts' as subprojects +rootDir + .listFiles() + ?.filter { File(it, "build.gradle.kts").exists() } + ?.forEach { subproject -> include(subproject.name) } + +// Platform project +include(":versions") + +project(":versions").projectDir = file("gradle/versions") + +// Aggregation and analysis project to create reports about the whole software (coverage, SBOM, ...) +include(":aggregation") + +project(":aggregation").projectDir = file("gradle/aggregation") + +// Allow local projects to be referred to by accessor +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.publish.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.publish.gradle.kts new file mode 100644 index 00000000..2a39c976 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.publish.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("org.gradle.java") + id("org.gradle.maven-publish") +} + +// Publish with sources and Javadoc +java { + withSourcesJar() + withJavadocJar() +} + +tasks.named("sourcesJar") { group = null } + +tasks.named("javadocJar") { group = null } + +publishing.publications.create("mavenJava") { + from(components["java"]) + + // We use consistent resolution + a platform for controlling versions + // -> Publish the versions that are the result of the consistent resolution + versionMapping { allVariants { fromResolutionResult() } } +} + +// The repository to publish to +publishing.repositories { maven("/tmp/my-repo") } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.repositories.settings.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.repositories.settings.gradle.kts new file mode 100644 index 00000000..235b9daf --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.repositories.settings.gradle.kts @@ -0,0 +1,9 @@ +pluginManagement { + // Get community plugins from the Gradle Plugin Portal + repositories.gradlePluginPortal() +} + +dependencyResolutionManagement { + // Get components from Maven Central + repositories.mavenCentral() +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test-fixtures.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test-fixtures.gradle.kts new file mode 100644 index 00000000..82efceb9 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test-fixtures.gradle.kts @@ -0,0 +1,3 @@ +plugins { id("org.gradle.java-test-fixtures") } + +tasks.testFixturesJar { setGroup(null) } diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test.gradle.kts new file mode 100644 index 00000000..d201ce4e --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.test.gradle.kts @@ -0,0 +1,23 @@ +plugins { + id("org.gradle.jacoco") // Record test coverage data during test execution + id("org.gradle.java") +} + +// Configure details for *all* test executions directly on 'Test' task +tasks.test { + group = "build" + + useJUnitPlatform() // Use JUnit 5 as test framework + maxParallelForks = 4 + + testLogging.showStandardStreams = true + + maxHeapSize = "1g" + systemProperty("file.encoding", "UTF-8") +} + +// Configure common test runtime dependencies for *all* projects +dependencies { + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + testRuntimeOnly("org.slf4j:slf4j-simple") +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.feature.war.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.war.gradle.kts new file mode 100644 index 00000000..53477adf --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.feature.war.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("org.gradle.war") + id("org.example.gradle.base.dependency-rules") +} + +tasks.war { setGroup(null) } + +// The war plugin used 'providedRuntime' / 'providedCompile' to resolve dependencies for packaging +// the WAR file +configurations.providedCompile { shouldResolveConsistentlyWith(configurations["mainRuntimeClasspath"]) } + +configurations.providedRuntime { shouldResolveConsistentlyWith(configurations["mainRuntimeClasspath"]) } + +tasks.register("deployWebApp") { + group = "distribution" + description = "Deploy web app into local Tomcat found via CATALINA_HOME" + from(tasks.war) { into("webapps") } + into(providers.gradleProperty("catalinaHome").orElse(providers.environmentVariable("CATALINA_HOME"))) +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.report.code-coverage.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.report.code-coverage.gradle.kts new file mode 100644 index 00000000..359ee1eb --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.report.code-coverage.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("org.gradle.jacoco-report-aggregation") + id("org.gradle.java") + id("org.example.gradle.base.dependency-rules") + id("org.example.gradle.base.lifecycle") +} + +tasks.check { + // Generate report when running 'check' + dependsOn(tasks.testCodeCoverageReport) +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.report.plugin-analysis.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.report.plugin-analysis.gradle.kts new file mode 100644 index 00000000..23f6ea1d --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.report.plugin-analysis.gradle.kts @@ -0,0 +1,9 @@ +import org.example.gradle.tasks.PluginApplicationOrderAnalysis + +// Parse '*.gradle.kts' files and create a PlantUML diagram based on the application order +tasks.register("analysePluginApplicationOrder") { + group = "help" + + pluginSrcFolders.from(project.layout.projectDirectory.dir("../plugins/src/main/kotlin")) + pluginApplicationDiagram = layout.buildDirectory.file("reports/plugins/plugin-application-order.puml") +} diff --git a/gradle/plugins/src/main/kotlin/org.example.gradle.report.sbom.gradle.kts b/gradle/plugins/src/main/kotlin/org.example.gradle.report.sbom.gradle.kts new file mode 100644 index 00000000..a3d68307 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org.example.gradle.report.sbom.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("org.gradle.java") + id("org.cyclonedx.bom") +} + +// Generate a Software Bill of Materials for the software product +tasks.cyclonedxBom { + notCompatibleWithConfigurationCache("https://github.com/CycloneDX/cyclonedx-gradle-plugin/issues/193") + includeConfigs.add(configurations.runtimeClasspath.name) + destination = layout.buildDirectory.dir("reports/sbom").get().asFile +} diff --git a/gradle/plugins/src/main/kotlin/org/example/gradle/spotless/SortDependenciesStep.kt b/gradle/plugins/src/main/kotlin/org/example/gradle/spotless/SortDependenciesStep.kt new file mode 100644 index 00000000..f0ad9b73 --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org/example/gradle/spotless/SortDependenciesStep.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.gradle.spotless + +import com.diffplug.spotless.FormatterFunc +import com.diffplug.spotless.FormatterStep +import java.util.Locale + +class SortDependenciesStep : java.io.Serializable { + companion object { + fun create(): FormatterStep { + return FormatterStep.create( + "SortDependenciesStep", + SortDependenciesStep(), + SortDependenciesStep::toFormatter + ) + } + } + + fun toFormatter(): FormatterFunc { + return FormatterFunc { unixStr -> + val lines = unixStr.split('\n') + val blockStartIndex = + lines.indexOfFirst { it.startsWith("dependencies {") || it.startsWith("dependencies.constraints {") } + if (blockStartIndex == -1) { + unixStr // no 'dependencies {} block' + } else { + val blockEndIndex = blockStartIndex + lines.subList(blockStartIndex, lines.size).indexOf("}") + val declarations = + lines.subList(blockStartIndex + 1, blockEndIndex).filter { it.contains("(") }.map { parse(it) } + val comparator = + Comparator { a, b -> + when { + a.sourceSet.compareTo(b.sourceSet) != 0 -> a.sourceSet.compareTo(b.sourceSet) + a.scope.ordinal != b.scope.ordinal -> a.scope.ordinal.compareTo(b.scope.ordinal) + a.isProject && !b.isProject -> -1 + !a.isProject && b.isProject -> 1 + else -> a.line.compareTo(b.line) + } + } + + val sourceSetStartLines = + declarations + .filter { it.sourceSet.isNotEmpty() } + .map { DependencyDeclaration(it.sourceSet, Scope.Api, false, "") } + .distinct() + val sorted = (declarations + sourceSetStartLines).sortedWith(comparator).map { it.line } + val blockStart = lines.subList(0, blockStartIndex + 1) + val blockEnd = lines.subList(blockEndIndex, lines.size) + + (blockStart + sorted + blockEnd).joinToString("\n") + } + } + } + + private fun parse(line: String): DependencyDeclaration { + val fullScope = line.trim().substring(0, line.trim().indexOf("(")) + var scope = Scope.Api + var sourceSet = "" + val isProject = line.contains("(projects.") + val isThirdParty = line.contains("(libs.") + + if (!isProject && !isThirdParty) { + println("WARN: Discouraged dependency notation: ${line.trim()}") + } + + Scope.values().forEach { scopeCandidate -> + if (fullScope == scopeCandidate.name.replaceFirstChar { it.lowercase(Locale.getDefault()) }) { + scope = scopeCandidate + sourceSet = "" + } + if (fullScope.endsWith(scopeCandidate.name)) { + scope = scopeCandidate + sourceSet = fullScope.substring(0, fullScope.length - scopeCandidate.name.length) + } + } + return DependencyDeclaration(sourceSet, scope, isProject, line) + } + + private enum class Scope { + Api, + Implementation, + CompileOnlyApi, + CompileOnly, + RuntimeOnly, + ProvidedCompile, + ProvidedRuntime, + AnnotationProcessor + } + + private data class DependencyDeclaration( + val sourceSet: String, + val scope: Scope, + val isProject: Boolean, + val line: String + ) +} diff --git a/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/MD5DirectoryChecksum.kt b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/MD5DirectoryChecksum.kt new file mode 100644 index 00000000..fce3cd7d --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/MD5DirectoryChecksum.kt @@ -0,0 +1,75 @@ +package org.example.gradle.tasks + +import java.io.File +import java.nio.file.Files +import java.security.DigestInputStream +import java.security.MessageDigest +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +/** + * Gradle task based on 'Checksum' Ant Task but stripped down to what we need in this build. + * + * See: https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/taskdefs/Checksum.java + */ +abstract class MD5DirectoryChecksum : DefaultTask() { + + @get:InputDirectory abstract val inputDirectory: DirectoryProperty + + @get:OutputFile abstract val checksumFile: RegularFileProperty + + @TaskAction + fun generateChecksum() { + val messageDigest = MessageDigest.getInstance("MD5") + + val allDigests = mutableMapOf() + val bufSize = 8 * 1024 + val buf = ByteArray(bufSize) + + val folder = inputDirectory.get().asFile + folder + .walkTopDown() + .filter { it.isFile } + .forEach { + messageDigest.reset() + val fis = Files.newInputStream(it.toPath()) + val dis = DigestInputStream(fis, messageDigest) + while (dis.read(buf, 0, bufSize) != -1) { + // Empty statement + } + dis.close() + fis.close() + val fileDigest = messageDigest.digest() + allDigests[it] = fileDigest + } + // Calculate the total checksum + // Convert the keys (source files) into a sorted array. + val keyArray = allDigests.keys.sortedBy { it.relativeTo(folder).path } + + // Loop over the checksums and generate a total hash. + messageDigest.reset() + keyArray.forEach { + // Add the digest for the file content + val digest = allDigests.getValue(it) + messageDigest.update(digest) + + // Add the file path + val fileName = it.relativeTo(folder).path.replace(File.separatorChar, '/') + messageDigest.update(fileName.toByteArray()) + } + checksumFile.get().asFile.writeText(createDigestString(messageDigest.digest())) + } + + private fun createDigestString(fileDigest: ByteArray): String { + val byteMask = 0xFF + val checksumSb = StringBuilder() + for (digestByte in fileDigest) { + checksumSb.append(String.format("%02x", byteMask and digestByte.toInt())) + } + return checksumSb.toString() + } +} diff --git a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PlatformVersionConsistencyCheck.kt similarity index 54% rename from gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt rename to gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PlatformVersionConsistencyCheck.kt index dda68726..7148ba3d 100644 --- a/gradle/plugins/dependency-analysis-plugins/src/main/kotlin/org/example/dependencyanalysis/PlatformVersionConsistencyCheck.kt +++ b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PlatformVersionConsistencyCheck.kt @@ -1,4 +1,4 @@ -package org.example.dependencyanalysis +package org.example.gradle.tasks import org.gradle.api.DefaultTask import org.gradle.api.artifacts.component.ModuleComponentSelector @@ -14,36 +14,40 @@ import org.gradle.api.tasks.TaskAction */ abstract class PlatformVersionConsistencyCheck : DefaultTask() { - @get:Internal - abstract val productClasspath: SetProperty + @get:Internal abstract val productClasspath: SetProperty - @get:Internal - abstract val classpathFromPlatform: SetProperty + @get:Internal abstract val classpathFromPlatform: SetProperty @TaskAction fun check() { - val publishedCategory = Attribute.of( Category.CATEGORY_ATTRIBUTE.name, String::class.java) + val publishedCategory = Attribute.of(Category.CATEGORY_ATTRIBUTE.name, String::class.java) val resolvedToDeclaredVersions = - productClasspath.get().filter { it.moduleVersion?.group != "org.example.product" }.associate { cpEntry -> - cpEntry.moduleVersion to cpEntry.dependents.find { - it.from.variants.any { variant -> - variant.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name == Category.REGULAR_PLATFORM - || variant.attributes.getAttribute(publishedCategory) == Category.REGULAR_PLATFORM - } - }?.let { - (it.requested as ModuleComponentSelector).version + productClasspath + .get() + .filter { it.moduleVersion?.group != "org.example.product" } + .associate { cpEntry -> + cpEntry.moduleVersion to + cpEntry.dependents + .find { + it.from.variants.any { variant -> + variant.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name == + Category.REGULAR_PLATFORM || + variant.attributes.getAttribute(publishedCategory) == Category.REGULAR_PLATFORM + } + } + ?.let { (it.requested as ModuleComponentSelector).version } } - } - - val unnecessaryEntries = classpathFromPlatform.get().filter { platformEntry -> - productClasspath.get().none { platformEntry.moduleVersion?.module == it.moduleVersion?.module } - } + val unnecessaryEntries = + classpathFromPlatform.get().filter { platformEntry -> + productClasspath.get().none { platformEntry.moduleVersion?.module == it.moduleVersion?.module } + } val missingEntries = resolvedToDeclaredVersions.filter { it.value == null }.map { it.key } val wrongEntries = resolvedToDeclaredVersions.filter { it.value != null && it.key?.version != it.value } if (unnecessaryEntries.isNotEmpty() || missingEntries.isNotEmpty() || wrongEntries.isNotEmpty()) { - throw RuntimeException(""" + throw RuntimeException( + """ The following entries are not used in production code: ${unnecessaryEntries.joinToString("\n ") { "api(\"${it.moduleVersion}\")" }} @@ -56,8 +60,9 @@ abstract class PlatformVersionConsistencyCheck : DefaultTask() { ${wrongEntries.keys.joinToString("\n ") { "api(\"${it}\") - currently declared '${wrongEntries[it]}'" }} - """.trimIndent()) + """ + .trimIndent() + ) } } } - diff --git a/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PluginApplicationOrderAnalysis.kt b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PluginApplicationOrderAnalysis.kt new file mode 100644 index 00000000..a2603c7a --- /dev/null +++ b/gradle/plugins/src/main/kotlin/org/example/gradle/tasks/PluginApplicationOrderAnalysis.kt @@ -0,0 +1,71 @@ +package org.example.gradle.tasks + +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction + +abstract class PluginApplicationOrderAnalysis : DefaultTask() { + + @get:InputFiles abstract val pluginSrcFolders: ConfigurableFileCollection + + @get:OutputFile abstract val pluginApplicationDiagram: RegularFileProperty + + @TaskAction + fun analyse() { + val pluginDependencies = + pluginSrcFolders + .associate { srcFolder -> + val pluginProjectName = srcFolder.parentFile.parentFile.parentFile.name + pluginProjectName to + (srcFolder.listFiles() ?: emptyArray()) + .filter { it.name.endsWith(".gradle.kts") } + .associate { pluginFile -> + val pluginId = pluginFile.name.replaceFirst(".gradle.kts", "") + pluginId to + pluginsBlock(pluginFile.readText()) + .lines() + .filter { it.contains("id(") } + .map { it.substring(it.indexOf("id(\"") + 4, it.indexOf("\")")) } + } + } + .filter { it.value.isNotEmpty() } + + val lineBreak = "\n " + pluginApplicationDiagram + .get() + .asFile + .writeText( + """ + @startuml + + ${pluginDependencies.map { (projectName, pluginIds) -> + "package \"$projectName\" {$lineBreak" + + pluginIds.keys.joinToString("") { "agent \"$it\"$lineBreak" } + + "$lineBreak}" + }.joinToString(lineBreak)} + + ${pluginDependencies.values.fold(emptyMap>()) { a, b -> a + b }.filter { + it.value.isNotEmpty() + }.map { + (from, to) -> to.joinToString("") { "\"$from\" --down--> \"$it\"$lineBreak" } + }.joinToString(lineBreak)} + + @enduml + """ + .trimIndent() + ) + + logger.lifecycle("Diagram: ${pluginApplicationDiagram.get().asFile.absolutePath}") + } + + private fun pluginsBlock(script: String) = + script.indexOf("}").let { + when (it) { + -1 -> "" + else -> script.substring(0, it) + } + } +} diff --git a/gradle/plugins/src/test/kotlin/org/example/gradle/test/ConventionPluginTest.kt b/gradle/plugins/src/test/kotlin/org/example/gradle/test/ConventionPluginTest.kt new file mode 100644 index 00000000..c8bf944d --- /dev/null +++ b/gradle/plugins/src/test/kotlin/org/example/gradle/test/ConventionPluginTest.kt @@ -0,0 +1,121 @@ +package org.example.gradle.test + +import org.assertj.core.api.Assertions.assertThat +import org.example.gradle.test.fixtures.GradleProject +import org.gradle.testkit.runner.TaskOutcome.SUCCESS +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import java.io.File + +class ConventionPluginTest { + + @ParameterizedTest + @MethodSource("pluginIds") + fun `each plugin can be applied individually without error`(pluginId: String) { + val p = GradleProject() + when { + pluginId.endsWith(".settings") -> p.settingsFile("""plugins { id("${pluginId.substringBeforeLast(".settings")}") }""") + pluginId.endsWith(".root") -> p.rootBuildFile("""plugins { id("${pluginId.substringBeforeLast(".settings")}") }""") + else -> p.withMinimalStructure().moduleBuildFile("""plugins { id("$pluginId") }""") + } + + val result = p.help() + + assertThat(result.task(":help")!!.outcome).isEqualTo(SUCCESS) + + } + + @Test + fun `qualityGate sorts dependencies of a library`() { + val p = GradleProject().withMinimalStructure() + p.catalog(""" + [libraries] + resteasy-core = { module = "org.jboss.resteasy:resteasy-core", version = "4.7.6.Final" } + resteasy-jackson2-provider = { module = "org.jboss.resteasy:resteasy-jackson2-provider" } + guice = { module = "com.google.inject:guice", version = "5.1.0" } + """.trimIndent()) + val buildFile = p.moduleBuildFile(""" + plugins { + id("org.example.gradle.component.java-library") + } + + dependencies { + implementation(libs.resteasy.jackson2.provider) + api(libs.resteasy.core) + implementation(libs.guice) + } + """.trimIndent()) + p.file("module/src/main/java/foo/Bar.java", """ + package foo; + public class Bar { + private org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider a; + private com.google.inject.Guice b; + public org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap c; + } + """.trimIndent()) + + p.qualityGate() + + assertThat(buildFile).hasContent(""" + plugins { id("org.example.gradle.component.java-library") } + + dependencies { + api(libs.resteasy.core) + implementation(libs.guice) + implementation(libs.resteasy.jackson2.provider) + } + """.trimIndent()) + } + + @Test + fun `qualityGate fails for wrong dependency scopes`() { + val p = GradleProject().withMinimalStructure() + p.catalog(""" + [libraries] + resteasy-core = { module = "org.jboss.resteasy:resteasy-core", version = "4.7.6.Final" } + resteasy-jackson2-provider = { module = "org.jboss.resteasy:resteasy-jackson2-provider" } + guice = { module = "com.google.inject:guice", version = "5.1.0" } + """.trimIndent()) + val buildFile = p.moduleBuildFile(""" + plugins { + id("org.example.gradle.component.java-library") + } + + dependencies { + implementation(libs.resteasy.jackson2.provider) + api(libs.resteasy.core) + implementation(libs.guice) + } + """.trimIndent()) + p.file("module/src/main/java/foo/Bar.java", """ + package foo; + public class Bar { + private org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap c; + } + """.trimIndent()) + + val result = p.failQualityGate() + + assertThat(result.output).contains(""" + Unused dependencies which should be removed: + implementation(libs.guice) + + Existing dependencies which should be modified to be as indicated: + implementation(libs.resteasy.core) (was api) + + Dependencies which should be removed or changed to runtime-only: + runtimeOnly(libs.resteasy.jackson2.provider) (was implementation) + """.trimIndent()) + } + + companion object { + @JvmStatic + fun pluginIds(): Array { + val pluginList = File("src/main/kotlin").listFiles()!!.filter { it.isFile }.map { + it.name.substringBeforeLast(".gradle.kts") + } + return pluginList.toTypedArray() + } + } +} \ No newline at end of file diff --git a/gradle/plugins/src/test/kotlin/org/example/gradle/test/fixtures/GradleProject.kt b/gradle/plugins/src/test/kotlin/org/example/gradle/test/fixtures/GradleProject.kt new file mode 100644 index 00000000..688e783c --- /dev/null +++ b/gradle/plugins/src/test/kotlin/org/example/gradle/test/fixtures/GradleProject.kt @@ -0,0 +1,89 @@ +package org.example.gradle.test.fixtures + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import java.io.File +import java.lang.management.ManagementFactory +import java.nio.file.Files + +/** + * Access to a minimal project inside a temporary folder. + * The project contain files that are expected to exist in our setup. + */ +class GradleProject { + + private val projectDir: File = Files.createTempDirectory("gradle-build").toFile() + private val settingsFile = file("settings.gradle.kts", "") + private val rootBuildFile = file("build.gradle.kts") + private val catalog = file("gradle/libs.versions.toml") + private val platform = file("gradle/versions/build.gradle.kts") + private val reports = file("gradle/reports/build.gradle.kts") + private val appBuildFile = file("app/build.gradle.kts") + private val moduleBuildFile = file("module/build.gradle.kts") + private val jdkVersionFile = file("gradle/jdk-version.txt") + + fun withMinimalStructure(): GradleProject { + settingsFile.writeText(""" + plugins { + id("org.example.gradle.feature.repositories") + id("org.example.gradle.feature.project-structure") + } + rootProject.name = "test-project" + """.trimIndent()) + rootBuildFile.writeText(""" + plugins { + id("org.example.gradle.check.dependencies.root") + } + """.trimIndent()) + platform.writeText("""plugins { id("org.example.gradle.dependencies.platform") }""") + reports.writeText("") + catalog(""" + [libraries] + foo = { module = "foo:bar" } + """.trimIndent()) + jdkVersionFile.writeText("21") + appBuildFile.writeText("""plugins { id("org.example.gradle.component.java-application") }""") + file("app/src/main/resources").mkdirs() + return this + } + + fun settingsFile(content: String) = settingsFile.also { + it.writeText(content) + } + + + fun rootBuildFile(content: String) = rootBuildFile.also { + it.writeText(content) + } + + fun moduleBuildFile(content: String) = moduleBuildFile.also { + it.writeText(content) + } + + fun catalog(content: String) = catalog.also { + it.writeText(content) + } + + fun file(path: String, content: String? = null) = File(projectDir, path).also { + it.parentFile.mkdirs() + if (content != null) { + it.writeText(content) + } + } + + fun help(): BuildResult = runner(listOf("help")).build() + + fun build(): BuildResult = runner(listOf("build")).build() + + fun qualityGate(): BuildResult = runner(listOf("qualityGate")).build() + + fun failQualityGate(): BuildResult = runner(listOf("qualityGate")).buildAndFail() + + private fun runner(args: List) = GradleRunner.create() + .forwardOutput() + .withPluginClasspath() + .withProjectDir(projectDir) + .withArguments(args + listOf("--configuration-cache", "-s", "--warning-mode=all")) + .withDebug(ManagementFactory.getRuntimeMXBean().inputArguments.toString().contains("-agentlib:jdwp")) + +} \ No newline at end of file diff --git a/gradle/versions/build.gradle.kts b/gradle/versions/build.gradle.kts new file mode 100644 index 00000000..1fdfa089 --- /dev/null +++ b/gradle/versions/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { id("org.example.gradle.dependencies.platform") } + +// Reject versions that should not be upgraded beyond a certain point. +// This makes Dependabot PR builds fail that attempt to update these. +dependencies.constraints { + api(libs.jakarta.activation) { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs + api(libs.jakarta.inject.api) { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs + api(libs.jakarta.mail.impl) { version { reject("[2.0.0,)") } } // Upgrade to 2.x requires newer Jakarta APIs + api(libs.jakarta.servlet.api) { version { reject("[5.0.0,)") } } // Stay Tomcat 8 compatible + api(libs.org.reflections) { version { reject("[0.9.12,)") } } // Upgrade breaks 'com.github.racc:typesafeconfig-guice' + api(libs.resteasy.core) { version { reject("[5.0.0.Final,)") } } + api(libs.solr.solrj) { version { reject("[8.0.0,)") } } // API changes in 8 require production code changes +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd491..e6441136 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e093..a4413138 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-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..b740cf13 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/gradlew.bat b/gradlew.bat index 6689b85b..7101f8e4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/kamino/build.gradle.kts b/kamino/build.gradle.kts index b1f90536..f91f9481 100644 --- a/kamino/build.gradle.kts +++ b/kamino/build.gradle.kts @@ -1,13 +1,13 @@ plugins { - id("org.example.java-library-published") + id("org.example.gradle.component.java-library") + id("org.example.gradle.feature.publish") } dependencies { - api(project(":coruscant")) - api("org.jboss.resteasy:resteasy-core") + api(projects.coruscant) + api(libs.resteasy.core) + implementation(libs.resteasy.guice) + implementation(libs.resteasy.jackson2.provider) - implementation("org.jboss.resteasy:resteasy-guice") - implementation("org.jboss.resteasy:resteasy-jackson2-provider") - - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(libs.junit.jupiter.api) } diff --git a/kamino/src/main/java/org/example/product/kamino/KaminoModule.java b/kamino/src/main/java/org/example/product/kamino/KaminoModule.java index 8823220c..e9b559b2 100644 --- a/kamino/src/main/java/org/example/product/kamino/KaminoModule.java +++ b/kamino/src/main/java/org/example/product/kamino/KaminoModule.java @@ -26,10 +26,8 @@ public class KaminoModule { * @return all the important Classes */ public Class[] info() { - return new Class[]{ - ResteasyBootstrap.class, - ResteasyJackson2Provider.class, - GuiceResteasyBootstrapServletContextListener.class + return new Class[] { + ResteasyBootstrap.class, ResteasyJackson2Provider.class, GuiceResteasyBootstrapServletContextListener.class }; } } diff --git a/kamino/src/test/java/org/example/product/kamino/test/KaminoModuleTest.java b/kamino/src/test/java/org/example/product/kamino/test/KaminoModuleTest.java index 4d276e34..b950e1df 100644 --- a/kamino/src/test/java/org/example/product/kamino/test/KaminoModuleTest.java +++ b/kamino/src/test/java/org/example/product/kamino/test/KaminoModuleTest.java @@ -1,9 +1,9 @@ package org.example.product.kamino.test; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; + public class KaminoModuleTest { @Test diff --git a/kashyyyk/build.gradle.kts b/kashyyyk/build.gradle.kts index d2295a9d..114edba6 100644 --- a/kashyyyk/build.gradle.kts +++ b/kashyyyk/build.gradle.kts @@ -1,13 +1,10 @@ -plugins { - id("org.example.java-library") -} +plugins { id("org.example.gradle.component.java-library") } dependencies { - api(project(":naboo")) - api(project(":tatooine")) - - implementation(project(":bespin")) - implementation(project(":kamino")) + api(projects.naboo) + api(projects.tatooine) + implementation(projects.bespin) + implementation(projects.kamino) - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(libs.junit.jupiter.api) } diff --git a/kashyyyk/src/main/java/org/example/product/kashyyyk/KashyyykModule.java b/kashyyyk/src/main/java/org/example/product/kashyyyk/KashyyykModule.java index aeca593f..270acedd 100644 --- a/kashyyyk/src/main/java/org/example/product/kashyyyk/KashyyykModule.java +++ b/kashyyyk/src/main/java/org/example/product/kashyyyk/KashyyykModule.java @@ -1,19 +1,18 @@ package org.example.product.kashyyyk; -import org.example.product.bespin.BespinModule; -import org.example.product.kamino.KaminoModule; -import org.example.product.naboo.NabooModule; -import org.example.product.tatooine.TatooineModule; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import org.example.product.bespin.BespinModule; +import org.example.product.kamino.KaminoModule; +import org.example.product.naboo.NabooModule; +import org.example.product.tatooine.TatooineModule; public class KashyyykModule { public KashyyykModule() { - try(InputStream hello = KashyyykModule.class.getResourceAsStream("hello.txt")) { + try (InputStream hello = KashyyykModule.class.getResourceAsStream("hello.txt")) { String message = new BufferedReader(new InputStreamReader(hello)).readLine(); System.out.println(message); } catch (IOException e) { diff --git a/kashyyyk/src/test/java/org/example/product/kashyyyk/KashyyykModuleTest.java b/kashyyyk/src/test/java/org/example/product/kashyyyk/KashyyykModuleTest.java index 4a243929..35fc5056 100644 --- a/kashyyyk/src/test/java/org/example/product/kashyyyk/KashyyykModuleTest.java +++ b/kashyyyk/src/test/java/org/example/product/kashyyyk/KashyyykModuleTest.java @@ -1,14 +1,13 @@ package org.example.product.kashyyyk; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; public class KashyyykModuleTest { @@ -17,7 +16,7 @@ void testModule() throws IOException { KashyyykModule module = new KashyyykModule(); assertSame(5, module.calculateSomethingImportant()); - try(InputStream hello = KashyyykModuleTest.class.getResourceAsStream("testHello.txt")) { + try (InputStream hello = KashyyykModuleTest.class.getResourceAsStream("testHello.txt")) { String message = new BufferedReader(new InputStreamReader(hello)).readLine(); assertEquals("TEST HELLO!", message); } diff --git a/naboo/build.gradle.kts b/naboo/build.gradle.kts index 24eb9267..7dcf241a 100644 --- a/naboo/build.gradle.kts +++ b/naboo/build.gradle.kts @@ -1,10 +1,8 @@ -plugins { - id("org.example.java-library") -} +plugins { id("org.example.gradle.component.java-library") } dependencies { - implementation("org.apache.solr:solr-solrj") - implementation("org.apache.zookeeper:zookeeper-jute") + implementation(libs.solr.solrj) + implementation(libs.zookeeper.jute) - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(libs.junit.jupiter.api) } diff --git a/naboo/src/main/java/org/example/product/naboo/NabooModule.java b/naboo/src/main/java/org/example/product/naboo/NabooModule.java index f5f82acb..97cf5e11 100644 --- a/naboo/src/main/java/org/example/product/naboo/NabooModule.java +++ b/naboo/src/main/java/org/example/product/naboo/NabooModule.java @@ -1,23 +1,20 @@ package org.example.product.naboo; +import java.util.Collections; import org.apache.jute.Utils; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; -import java.util.Collections; - public class NabooModule { public NabooModule() { dive(); } - public NabooModule(int importantNumber) { - - } + public NabooModule(int importantNumber) {} private int dive() { SolrParams params = new MapSolrParams(Collections.singletonMap("a1", "")); - return Utils.compareBytes(params.get("a1").getBytes(), 0, 0, new byte[0],0,0); + return Utils.compareBytes(params.get("a1").getBytes(), 0, 0, new byte[0], 0, 0); } } diff --git a/naboo/src/test/java/org/example/product/naboo/test/NabooModuleTest.java b/naboo/src/test/java/org/example/product/naboo/test/NabooModuleTest.java index 0e1dc27e..3d03b600 100644 --- a/naboo/src/test/java/org/example/product/naboo/test/NabooModuleTest.java +++ b/naboo/src/test/java/org/example/product/naboo/test/NabooModuleTest.java @@ -1,9 +1,9 @@ package org.example.product.naboo.test; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; + public class NabooModuleTest { @Test diff --git a/settings.gradle.kts b/settings.gradle.kts index 14163a0b..b2e93475 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,11 @@ pluginManagement { - includeBuild("gradle/meta-plugins") + includeBuild("gradle/plugins") } plugins { - id("org.example.settings") + id("org.example.gradle.feature.build-cache") + id("org.example.gradle.feature.develocity") + id("org.example.gradle.feature.project-structure") + id("org.example.gradle.feature.repositories") } rootProject.name = "gradle-project-setup-howto" diff --git a/tatooine/build.gradle.kts b/tatooine/build.gradle.kts index 8663b146..e2b62ea9 100644 --- a/tatooine/build.gradle.kts +++ b/tatooine/build.gradle.kts @@ -1,11 +1,8 @@ -plugins { - id("org.example.java-library") -} +plugins { id("org.example.gradle.component.java-library") } dependencies { - api("com.github.racc:typesafeconfig-guice") - - implementation("org.apache.zookeeper:zookeeper") + api(libs.typesafeconfig.guice) + implementation(libs.zookeeper) - testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation(libs.junit.jupiter.api) } diff --git a/tatooine/src/main/java/org/example/product/tatooine/TatooineModuleConfig.java b/tatooine/src/main/java/org/example/product/tatooine/TatooineModuleConfig.java index 971e0f65..383f5631 100644 --- a/tatooine/src/main/java/org/example/product/tatooine/TatooineModuleConfig.java +++ b/tatooine/src/main/java/org/example/product/tatooine/TatooineModuleConfig.java @@ -19,5 +19,4 @@ public int getVal2() { public TatooineModuleConfig provide() { return new TatooineModuleConfig(); } - } diff --git a/tatooine/src/test/java/org/example/product/tatooine/test/TatooineModuleTest.java b/tatooine/src/test/java/org/example/product/tatooine/test/TatooineModuleTest.java index be7a1ccb..231556de 100644 --- a/tatooine/src/test/java/org/example/product/tatooine/test/TatooineModuleTest.java +++ b/tatooine/src/test/java/org/example/product/tatooine/test/TatooineModuleTest.java @@ -1,9 +1,9 @@ package org.example.product.tatooine.test; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertSame; +import org.junit.jupiter.api.Test; + public class TatooineModuleTest { @Test