diff --git a/documentation/build.gradle b/documentation/build.gradle index 01c67f967..cd3f823ef 100644 --- a/documentation/build.gradle +++ b/documentation/build.gradle @@ -101,30 +101,40 @@ asciidoctor { enabled = false } -def renderReferenceDocumentationTask = tasks.register( 'renderReferenceDocumentation', AsciidoctorTask ) { - description = 'Renders the Reference Documentation in HTML format using Asciidoctor.' - sourceDir = file( 'src/main/asciidoc/reference' ) +def renderReferenceDocumentationTask = tasks.register( "renderReferenceDocumentation", AsciidoctorTask ) { + description = "Renders the Reference Documentation in HTML format using Asciidoctor." + notCompatibleWithConfigurationCache( "AsciidoctorGradlePlugin does not support configuration cache yet" ) + + // use of provider to obtain info and cache the value + def versionFamily = providers.provider { project.projectVersion.family } + def fullVersion = providers.provider { project.version.toString() } + def asciidocReference = layout.projectDirectory.dir("src/main/asciidoc/reference") + + sourceDir = asciidocReference.asFile + sources { - include 'index.adoc' + include( "index.adoc" ) } resources { - from( sourceDir ) { - include 'images/**' - include 'css/**' + from( asciidocReference ) { + include( "images/**", "css/**" ) } } - outputDir = project.layout.buildDirectory.dir( "asciidoc/reference/html_single" ).get().asFile - options logDocuments: true + outputDir = layout.buildDirectory.dir("asciidoc/reference/html_single").get().asFile + + options( logDocuments: true ) - attributes icons: 'font', - 'source-highlighter': 'rouge', - experimental: true, - linkcss: true, - majorMinorVersion: project.projectVersion.family, - fullVersion: project.version.toString(), - docinfo: 'private' + attributes( + "icons": "font", + "source-highlighter": "rouge", + "experimental": true, + "linkcss": true, + "majorMinorVersion": versionFamily.get(), + "fullVersion": fullVersion.get(), + "docinfo": "private" + ) } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/gradle.properties b/gradle.properties index d098a7035..af06041aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,6 +5,14 @@ toolchain.compiler.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOf toolchain.javadoc.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 toolchain.launcher.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 +# asciidoctor gradle plugin don't support configuration cache +org.gradle.configuration-cache=true +org.gradle.configureondemand=true +# configuration of testcontainers need to be updated to prevent bind the same port +org.gradle.parallel=false +org.gradle.caching=true +org.gradle.daemon=true + # JDK auto-detection is not quite ready yet in Gradle 6.7. # On Fedora in particular, if you have the package java-1.8.0-openjdk-headless-1.8.0.265.b01-1.fc32.x86_64 installed, # Gradle will look for the Java binaries in /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.265.b01-1.fc32.x86_64/bin/java diff --git a/local-build-plugins/src/main/groovy/hr-print-resolved-version.gradle b/local-build-plugins/src/main/groovy/hr-print-resolved-version.gradle index 9dea09b82..ba44fadc2 100644 --- a/local-build-plugins/src/main/groovy/hr-print-resolved-version.gradle +++ b/local-build-plugins/src/main/groovy/hr-print-resolved-version.gradle @@ -1,31 +1,16 @@ +import org.hibernate.reactive.env.PrintResolvedVersionsTask + // Task to print the resolved versions of Hibernate ORM and Vert.x -tasks.register( "printResolvedVersions" ) { +tasks.register( "printResolvedVersions", PrintResolvedVersionsTask ) { + classpath.from( configurations.compileClasspath ) description = "Print the resolved hibernate-orm-core and vert.x versions" - doLast { - def hibernateCoreVersion = "n/a" - def vertxVersion = "n/a" - - // Resolve Hibernate Core and Vert.x versions from compile classpath - configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.each { artifact -> - if (artifact.moduleVersion.id.name == 'hibernate-core') { - hibernateCoreVersion = artifact.moduleVersion.id.version - } - if (artifact.moduleVersion.id.group == 'io.vertx' && artifact.moduleVersion.id.name == 'vertx-sql-client') { - vertxVersion = artifact.moduleVersion.id.version - } - } - - // Print the resolved versions - println "Resolved Hibernate ORM Core Version: ${hibernateCoreVersion}" - println "Resolved Vert.x SQL client Version: ${vertxVersion}" - } } // Make the version printing task run before tests and JavaExec tasks tasks.withType( Test ).configureEach { - dependsOn printResolvedVersions + dependsOn( tasks.named( "printResolvedVersions" ) ) } tasks.withType( JavaExec ).configureEach { - dependsOn printResolvedVersions + dependsOn( tasks.named( "printResolvedVersions" ) ) } \ No newline at end of file diff --git a/local-build-plugins/src/main/groovy/hr-test-containers.gradle b/local-build-plugins/src/main/groovy/hr-test-containers.gradle index fad66398f..1520dd753 100644 --- a/local-build-plugins/src/main/groovy/hr-test-containers.gradle +++ b/local-build-plugins/src/main/groovy/hr-test-containers.gradle @@ -1,79 +1,77 @@ -// Print a summary of the results of the tests (number of failures, successes and skipped) -def loggingSummary(db, result, desc) { - if ( !desc.parent ) { // will match the outermost suite - def output = "${db} results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)" - def repeatLength = output.length() + 1 - logger.lifecycle '\n' + ('-' * repeatLength) + '\n' + output + '\n' + ('-' * repeatLength) +import org.hibernate.reactive.env.TestDbTask + +def dbs = ['MariaDB', 'MySQL', 'PostgreSQL', 'DB2', 'CockroachDB', 'MSSQLServer', 'Oracle'] + +// create a task for each DB, now is static configure and not dynamic with rule pattern +// and run the tests on the selected db +// Example: +// gradlew testDbMySQL testDbDB2 +dbs.each { db -> + tasks.register( "testDb${db}", TestDbTask ) { + dbName = db + description = "Run tests for ${db}" } } -// Example: -// gradle test -Pdb=MySQL -test { - def selectedDb +// configure default task 'test' with same config of TestDbTask, with cache safe +tasks.named( "test", Test ).configure { t -> + def dbName = providers.gradleProperty( "db" ).orElse( "PostgreSQL" ) + def dockerEnabled = providers.gradleProperty( "docker" ).isPresent() + def includeTests = providers.gradleProperty( "includeTests" ).orNull + def showStandardStreams = providers.gradleProperty( "showStandardOutput" ).isPresent() - doFirst { - selectedDb = project.hasProperty( 'db' ) - ? project.properties['db'] - : 'PostgreSQL' - systemProperty 'db', selectedDb - } - afterSuite { desc, result -> - loggingSummary( selectedDb, result, desc ) + t.systemProperty( "db", dbName.get() ) + t.systemProperty( "docker", dockerEnabled ? "true" : "false" ) + t.systemProperty( "org.hibernate.reactive.common.InternalStateAssertions.ENFORCE", "true" ) + + if ( includeTests ) { + t.filter { f -> f.includeTestsMatching( includeTests ) } } -} -// Configuration for the tests -tasks.withType( Test ).configureEach { - defaultCharacterEncoding = "UTF-8" - useJUnitPlatform() - testLogging { - showStandardStreams = project.hasProperty('showStandardOutput') - showStackTraces = true - exceptionFormat = 'full' - displayGranularity = 1 - events = ['PASSED', 'FAILED', 'SKIPPED'] + t.defaultCharacterEncoding = "UTF-8" + t.useJUnitPlatform() + t.testLogging { + it.showStandardStreams = showStandardStreams + it.showStackTraces = true + it.exceptionFormat = 'full' + it.displayGranularity = 1 + it.events = ['PASSED', 'FAILED', 'SKIPPED'] } - systemProperty 'docker', project.hasProperty( 'docker' ) ? 'true' : 'false' - systemProperty 'org.hibernate.reactive.common.InternalStateAssertions.ENFORCE', 'true' - if ( project.hasProperty( 'includeTests' ) ) { - // Example: ./gradlew testAll -PincludeTests=DefaultPortTest - filter { - includeTestsMatching project.properties['includeTests'] ?: '*' as String + t.addTestListener( new TestListener() { + void beforeSuite(TestDescriptor suite) { + /* Do nothing */ } - } -} -def createTestDbTask(dbName) { - tasks.register( "testDb${dbName}", Test ) { - description = "Run tests for ${dbName}" + void beforeTest(TestDescriptor testDescriptor) { + /* Do nothing */ + } - doFirst() { - systemProperty 'db', dbName + void afterTest(TestDescriptor testDescriptor, TestResult result) { + /* Do nothing */ } - afterSuite { desc, result -> - loggingSummary( dbName, result, desc ) + + // Add afterSuite hook + void afterSuite(TestDescriptor desc, TestResult result) { + if ( !desc.parent ) { + def output = "${dbName.get()} results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)" + def line = '-' * (output.length() + 1) + logger.lifecycle( "\n${line}\n${output}\n${line}" ) + } } - } + } ) } -// Rule to recognize calls to testDb -// and run the tests on the selected db -// Example: -// gradle testDbMySQL testDbDB2 -tasks.addRule( "Pattern testDb" ) { String taskName -> - if ( taskName.startsWith( "testDb" ) ) { - def dbName = taskName.substring( "testDb".length() ) - createTestDbTask( dbName ) +// configure all testDbTask with docker and filter test +tasks.withType( TestDbTask ).configureEach { + dockerEnabled = project.hasProperty( 'docker' ) + if ( project.hasProperty( 'includeTests' ) ) { + includeTests = project.property( 'includeTests' ) } } -// The dbs we want to test when running testAll -def dbs = ['MariaDB', 'MySQL', 'PostgreSQL', 'DB2', 'CockroachDB', 'MSSQLServer', 'Oracle'] -dbs.forEach { createTestDbTask it } - +// task with all database tasks.register( "testAll", Test ) { description = "Run tests for ${dbs}" - dependsOn = dbs.collect( [] as HashSet ) { db -> "testDb${db}" } + dependsOn( dbs.collect { "testDb${it}" } ) } diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/PrintResolvedVersionsTask.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/PrintResolvedVersionsTask.java new file mode 100644 index 000000000..e890d3ae8 --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/PrintResolvedVersionsTask.java @@ -0,0 +1,36 @@ +package org.hibernate.reactive.env; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.TaskAction; + +import org.jetbrains.annotations.NotNull; + +@CacheableTask +public abstract class PrintResolvedVersionsTask extends DefaultTask { + + @Classpath + @NotNull + public abstract ConfigurableFileCollection getClasspath(); + + @TaskAction + public void printVersions() { + var hibernateCoreVersion = "n/a"; + var vertxVersion = "n/a"; + + for ( final var file : getClasspath().getFiles() ) { + String name = file.getName(); + if ( name.startsWith( "hibernate-core-" ) && name.endsWith( ".jar" ) ) { + hibernateCoreVersion = name.substring( "hibernate-core-".length(), name.length() - 4 ); + } + if ( name.startsWith( "vertx-sql-client-" ) && name.endsWith( ".jar" ) ) { + vertxVersion = name.substring( "vertx-sql-client-".length(), name.length() - 4 ); + } + } + + System.out.println( "Resolved Hibernate ORM Core Version: " + hibernateCoreVersion ); + System.out.println( "Resolved Vert.x SQL client Version: " + vertxVersion ); + } +} diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/TestDbTask.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/TestDbTask.java new file mode 100644 index 000000000..08aa55b36 --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/TestDbTask.java @@ -0,0 +1,146 @@ +package org.hibernate.reactive.env; + +import java.util.HashMap; +import java.util.Map; + +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.testing.Test; +import org.gradle.api.tasks.testing.TestDescriptor; +import org.gradle.api.tasks.testing.TestListener; +import org.gradle.api.tasks.testing.TestResult; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class TestDbTask extends Test { + + @NotNull + private String dbName = "PostgreSQL"; + private boolean dockerEnabled = false; + @Nullable + private String includeTests = null; + private boolean showStandardStreams = false; + + @Input + @Optional + @NotNull + public String getDbName() { + return dbName; + } + + public void setDbName(final @NotNull String dbName) { + this.dbName = dbName; + } + + @Input + public boolean isDockerEnabled() { + return dockerEnabled; + } + + public void setDockerEnabled(final boolean dockerEnabled) { + this.dockerEnabled = dockerEnabled; + } + + @Input + @Optional + @Nullable + public String getIncludeTests() { + return includeTests; + } + + public void setIncludeTests(final @Nullable String includeTests) { + this.includeTests = includeTests; + } + + @Input + public boolean isShowStandardStreams() { + return showStandardStreams; + } + + public void setShowStandardStreams(boolean showStandardStreams) { + this.showStandardStreams = showStandardStreams; + } + + @Input + public Map getCustomSystemProperties() { + final Map props = new HashMap<>(); + props.put("db", dbName); + props.put("docker", dockerEnabled ? "true" : "false"); + return props; + } + + public TestDbTask() { + // Default logging configuration + setDefaultCharacterEncoding( "UTF-8" ); + useJUnitPlatform(); + final var testLogging = getTestLogging(); + testLogging.setShowStandardStreams( showStandardStreams ); + testLogging.setShowStackTraces( true ); + testLogging.setExceptionFormat( "full" ); + testLogging.setDisplayGranularity( 1 ); + testLogging.events( "PASSED", "FAILED", "SKIPPED" ); + + // enforcing Hibernate internal state + systemProperty( "org.hibernate.reactive.common.InternalStateAssertions.ENFORCE", "true" ); + + addTestListener( new TestListener() { + + @Override + public void beforeSuite(TestDescriptor suite) { + /* Do nothing */ + } + + // Add afterSuite hook + @Override + public void afterSuite(TestDescriptor suite, TestResult result) { + logSummary( suite, result ); + } + + @Override + public void beforeTest(TestDescriptor testDescriptor) { + /* Do nothing */ + } + + @Override + public void afterTest(TestDescriptor testDescriptor, TestResult result) { + /* Do nothing */ + } + } ); + } + + @Override + public void executeTests() { + // Apply system properties before running + getCustomSystemProperties().forEach(this::systemProperty); + getTestLogging().setShowStandardStreams( showStandardStreams ); + + if ( includeTests != null && !includeTests.isEmpty() ) { + getFilter().includeTestsMatching( includeTests ); + } + + super.executeTests(); + } + + /** + * Print a summary of the results of the tests (number of failures, successes and skipped) + * + * @param desc the test descriptor + * @param result the test result + */ + private void logSummary(final @NotNull TestDescriptor desc, final @NotNull TestResult result) { + if ( desc.getParent() == null ) { // outermost suite + final var output = String.format( + "%s results: %s (%d tests, %d passed, %d failed, %d skipped)", + dbName, + result.getResultType(), + result.getTestCount(), + result.getSuccessfulTestCount(), + result.getFailedTestCount(), + result.getSkippedTestCount() + ); + final var line = "-".repeat( output.length() + 1 ); + getLogger().lifecycle( "\n{}\n{}\n{}", line, output, line ); + } + } +}