diff --git a/README.md b/README.md index 3f02197..7b598ea 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ and [Kover](https://github.com/Kotlin/kotlinx-kover). - Integrates with test frameworks like [JUnit5](https://junit.org/junit5/), [Spock](https://spockframework.org/) and [Kotest](https://kotest.io/). -- Compatible with [gradle configuration cache](https://docs.gradle.org/current/userguide/configuration_cache.html). +- Compatible with [gradle configuration cache](https://docs.gradle.org/current/userguide/configuration_cache.html) + and [lazy task configuration](https://docs.gradle.org/current/userguide/lazy_configuration.html). ## Using the plugin diff --git a/src/integration/kotlin/com/coditory/gradle/integration/CommandLineTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/CommandLineTest.kt index 7e378db..58fff32 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/CommandLineTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/CommandLineTest.kt @@ -42,7 +42,7 @@ class CommandLineTest { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/JUnitBasicTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/JUnitBasicTest.kt index 1720669..a57e846 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/JUnitBasicTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/JUnitBasicTest.kt @@ -41,7 +41,7 @@ class JUnitBasicTest { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/JUnitClasspathTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/JUnitClasspathTest.kt index 55b10d9..1d2356e 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/JUnitClasspathTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/JUnitClasspathTest.kt @@ -35,7 +35,7 @@ class JUnitClasspathTest { integrationImplementation("com.google.code.gson:gson:${Versions.gson}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/JacocoBasedTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/JacocoBasedTest.kt index 531b280..073d1d4 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/JacocoBasedTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/JacocoBasedTest.kt @@ -30,7 +30,7 @@ class JacocoBasedTest { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/KotestBasicTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/KotestBasicTest.kt index 143b280..6444a6c 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/KotestBasicTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/KotestBasicTest.kt @@ -43,7 +43,7 @@ class KotestBasicTest { testImplementation("io.kotest:kotest-runner-junit5:${Versions.kotest}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/KotestClasspathTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/KotestClasspathTest.kt index dc43fd8..cda2046 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/KotestClasspathTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/KotestClasspathTest.kt @@ -37,7 +37,7 @@ class KotestClasspathTest { integrationImplementation("com.google.code.gson:gson:${Versions.gson}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/KotlinInternalScopeTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/KotlinInternalScopeTest.kt index 347cfd0..e970e5f 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/KotlinInternalScopeTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/KotlinInternalScopeTest.kt @@ -30,7 +30,7 @@ class KotlinInternalScopeTest { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/LazyTaskRegisteringTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/LazyTaskRegisteringTest.kt new file mode 100644 index 0000000..556d07c --- /dev/null +++ b/src/integration/kotlin/com/coditory/gradle/integration/LazyTaskRegisteringTest.kt @@ -0,0 +1,46 @@ +package com.coditory.gradle.integration + +import com.coditory.gradle.integration.base.TestProjectBuilder +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.AutoClose +import org.junit.jupiter.api.Test + +class LazyTaskRegisteringTest { + companion object { + const val TEST_CONFIG_LOG = "Long running configuration..." + + @AutoClose + private val project = TestProjectBuilder + .project(LazyTaskRegisteringTest::class.simpleName!!) + .withBuildGradleKts( + """ + plugins { + id("jacoco") + id("com.coditory.integration-test") + } + + repositories { + mavenCentral() + } + + dependencies { + testImplementation("org.junit.jupiter:junit-jupiter-api:${Versions.junit}") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") + } + + tasks.withType().configureEach { + println("$TEST_CONFIG_LOG") + } + """, + ) + .build() + } + + @Test + fun `should register test tasks in a lazy manner`() { + // when + val result = project.runGradle(listOf("clean")) + // then + assertThat(result.output).doesNotContain(TEST_CONFIG_LOG) + } +} diff --git a/src/integration/kotlin/com/coditory/gradle/integration/LombokTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/LombokTest.kt index 4c8447a..9e03af0 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/LombokTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/LombokTest.kt @@ -33,7 +33,7 @@ class LombokTest { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junit}") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/integration/kotlin/com/coditory/gradle/integration/PlatformDependencyTest.kt b/src/integration/kotlin/com/coditory/gradle/integration/PlatformDependencyTest.kt index 3bc5e3a..c40137d 100644 --- a/src/integration/kotlin/com/coditory/gradle/integration/PlatformDependencyTest.kt +++ b/src/integration/kotlin/com/coditory/gradle/integration/PlatformDependencyTest.kt @@ -31,7 +31,7 @@ class PlatformDependencyTest { integrationImplementation("org.springframework.boot:spring-boot-starter-test") } - tasks.withType { + tasks.withType().configureEach { useJUnitPlatform() testLogging { events("passed", "failed", "skipped") diff --git a/src/main/kotlin/com/coditory/gradle/integration/JacocoTaskConfiguration.kt b/src/main/kotlin/com/coditory/gradle/integration/JacocoTaskConfiguration.kt index 0d7544a..ac3aa5a 100644 --- a/src/main/kotlin/com/coditory/gradle/integration/JacocoTaskConfiguration.kt +++ b/src/main/kotlin/com/coditory/gradle/integration/JacocoTaskConfiguration.kt @@ -8,20 +8,27 @@ import org.gradle.testing.jacoco.tasks.JacocoReport internal object JacocoTaskConfiguration { fun apply(project: Project) { - if (project.pluginManager.hasPlugin("jacoco")) { - var dstFile: String? = null - project.tasks.named(INTEGRATION) { task -> - val jacocoTaskExtension = task.extensions.getByType(JacocoTaskExtension::class.java) - dstFile = jacocoTaskExtension.destinationFile?.path - } - if (dstFile != null) { - project.tasks.withType(JacocoReport::class.java) { task -> - task.executionData(dstFile) - task.mustRunAfter(INTEGRATION) - } - project.tasks.withType(JacocoCoverageVerification::class.java) { task -> - task.mustRunAfter(INTEGRATION) - } + if (!project.pluginManager.hasPlugin("jacoco")) return + project.tasks.withType(JacocoCoverageVerification::class.java).configureEach { task -> + task.mustRunAfter(INTEGRATION) + } + project.tasks.withType(JacocoReport::class.java).configureEach { task -> + task.mustRunAfter(INTEGRATION) + } + // execute only if integration test and jacoco are on the execution path + // to preserve lazy task configuration + project.gradle.taskGraph.whenReady { + val names = project.gradle.taskGraph.allTasks.map { it.name } + if (names.contains("jacocoTestReport") && names.contains(INTEGRATION)) { + project.tasks.withType(JacocoReport::class.java) + .named("jacocoTestReport") { reportTask -> + val jacocoTaskExtension = + project.tasks.getByName(INTEGRATION).extensions.getByType(JacocoTaskExtension::class.java) + val dstFile = jacocoTaskExtension.destinationFile?.path + if (dstFile != null) { + reportTask.executionData(dstFile) + } + } } } } diff --git a/src/main/kotlin/com/coditory/gradle/integration/TestAllTaskConfiguration.kt b/src/main/kotlin/com/coditory/gradle/integration/TestAllTaskConfiguration.kt index a8e6a96..f56cc01 100644 --- a/src/main/kotlin/com/coditory/gradle/integration/TestAllTaskConfiguration.kt +++ b/src/main/kotlin/com/coditory/gradle/integration/TestAllTaskConfiguration.kt @@ -3,18 +3,20 @@ package com.coditory.gradle.integration import com.coditory.gradle.integration.IntegrationTestPlugin.Companion.INTEGRATION_TEST import com.coditory.gradle.integration.IntegrationTestPlugin.Companion.TEST_ALL_TASK_NAME import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.tasks.testing.Test import org.gradle.language.base.plugins.LifecycleBasePlugin internal object TestAllTaskConfiguration { fun apply(project: Project, config: IntegrationTestPluginConfig) { - val testAllTask = project.tasks.create(TEST_ALL_TASK_NAME) - testAllTask.description = "Runs all test suites." - testAllTask.group = LifecycleBasePlugin.VERIFICATION_GROUP - testAllTask.enabled = config.allTestTaskEnabled - project.tasks.withType(Test::class.java).forEach { - testAllTask.dependsOn(it.name) + project.tasks.register(TEST_ALL_TASK_NAME) { testAllTask: Task -> + testAllTask.description = "Runs all test suites." + testAllTask.group = LifecycleBasePlugin.VERIFICATION_GROUP + testAllTask.enabled = config.allTestTaskEnabled + project.tasks.withType(Test::class.java).names.forEach { + testAllTask.dependsOn(it) + } + testAllTask.dependsOn(INTEGRATION_TEST) } - testAllTask.dependsOn(INTEGRATION_TEST) } } diff --git a/src/main/kotlin/com/coditory/gradle/integration/TestSuitesConfiguration.kt b/src/main/kotlin/com/coditory/gradle/integration/TestSuitesConfiguration.kt index 251ccbc..5599971 100644 --- a/src/main/kotlin/com/coditory/gradle/integration/TestSuitesConfiguration.kt +++ b/src/main/kotlin/com/coditory/gradle/integration/TestSuitesConfiguration.kt @@ -3,6 +3,7 @@ package com.coditory.gradle.integration import com.coditory.gradle.integration.IntegrationTestPlugin.Companion.INTEGRATION import com.coditory.gradle.integration.IntegrationTestPlugin.Companion.INTEGRATION_TEST import org.gradle.api.Project +import org.gradle.api.Task import org.gradle.api.attributes.TestSuiteType import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPluginExtension @@ -70,17 +71,19 @@ internal object TestSuitesConfiguration { } private fun setupTestTask(project: Project, config: IntegrationTestPluginConfig) { - val integrationTestTask = project.tasks.create(INTEGRATION_TEST) - integrationTestTask.description = "Runs integration test suites." - integrationTestTask.group = LifecycleBasePlugin.VERIFICATION_GROUP - integrationTestTask.enabled = config.integrationTestsEnabled - integrationTestTask.dependsOn(INTEGRATION) - project.tasks.getByName(JavaBasePlugin.CHECK_TASK_NAME) - .dependsOn(INTEGRATION_TEST) - project.tasks.getByName(JavaBasePlugin.CHECK_TASK_NAME) - .dependsOn(INTEGRATION) - project.tasks.getByName(INTEGRATION) - .enabled = config.integrationTestsEnabled + project.tasks.register(INTEGRATION_TEST) { integrationTestTask: Task -> + integrationTestTask.description = "Runs integration test suites." + integrationTestTask.group = LifecycleBasePlugin.VERIFICATION_GROUP + integrationTestTask.enabled = config.integrationTestsEnabled + integrationTestTask.dependsOn(INTEGRATION) + } + project.tasks.named(JavaBasePlugin.CHECK_TASK_NAME) { checkTask -> + checkTask.dependsOn(INTEGRATION_TEST) + checkTask.dependsOn(INTEGRATION) + } + project.tasks.named(INTEGRATION) { integrationTask -> + integrationTask.enabled = config.integrationTestsEnabled + } } private fun configureKotlinCompilation(project: Project) { diff --git a/src/test/kotlin/com/coditory/gradle/integration/JacocoConfigurationTest.kt b/src/test/kotlin/com/coditory/gradle/integration/JacocoConfigurationTest.kt deleted file mode 100644 index 38451a8..0000000 --- a/src/test/kotlin/com/coditory/gradle/integration/JacocoConfigurationTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.coditory.gradle.integration - -import com.coditory.gradle.integration.base.TestProject -import com.coditory.gradle.integration.base.TestProjectBuilder.Companion.project -import org.assertj.core.api.Assertions.assertThat -import org.gradle.api.plugins.JavaPlugin -import org.gradle.testing.jacoco.plugins.JacocoPlugin -import org.gradle.testing.jacoco.tasks.JacocoReport -import org.junit.jupiter.api.Test - -class JacocoConfigurationTest { - private val project: TestProject = project() - .withPlugins(JavaPlugin::class, JacocoPlugin::class, IntegrationTestPlugin::class) - .build() - - @Test - fun `should register integrationTest exec files in jacoco report task`() { - val jacocoReportTask = project.tasks.getByName("jacocoTestReport") as JacocoReport - val executionData = jacocoReportTask.executionData - assertThat(executionData).isNotNull() - assertThat(executionData.asPath).isEqualTo( - project.toBuildPath( - "jacoco/test.exec", - "jacoco/integration.exec", - ), - ) - } -} diff --git a/src/test/kotlin/com/coditory/gradle/integration/base/TestProject.kt b/src/test/kotlin/com/coditory/gradle/integration/base/TestProject.kt index 3bf2fa0..357c89b 100644 --- a/src/test/kotlin/com/coditory/gradle/integration/base/TestProject.kt +++ b/src/test/kotlin/com/coditory/gradle/integration/base/TestProject.kt @@ -30,10 +30,11 @@ class TestProject(private val project: Project) : Project by project { } private fun gradleRunner(project: Project, arguments: List, gradleVersion: String? = null): GradleRunner { + // clean is required so tasks are not cached + val args = if (arguments.contains("clean")) arguments else listOf("clean") + arguments val builder = GradleRunner.create() .withProjectDir(project.projectDir) - // clean is required so tasks are not cached - .withArguments(listOf("clean") + arguments) + .withArguments(args) .withPluginClasspath() .forwardOutput() if (!gradleVersion.isNullOrBlank() && gradleVersion != "current") {