Gradle, js, single platform projects: create single test aggregator

Extract KotlinTestsRegistry service for customizing aggregated test tasks
naming.
This commit is contained in:
Sergey Rostov
2019-05-22 13:49:20 +03:00
parent a5664207d5
commit 22bc99f527
7 changed files with 131 additions and 111 deletions
@@ -30,9 +30,9 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_COMPILER_EMBEDDABLE
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_MODULE_GROUP
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import org.jetbrains.kotlin.gradle.utils.loadPropertyFromResources
import javax.inject.Inject
@@ -73,6 +73,8 @@ abstract class KotlinBasePluginWrapper(
project.kotlinExtension.sourceSets = kotlinSourceSetContainer(kotlinSourceSetFactory(project))
}
project.extensions.add(KotlinTestsRegistry.PROJECT_EXTENSION_NAME, createTestRegistry(project))
val plugin = getPlugin(project, kotlinGradleBuildServices)
setupAttributeMatchingStrategy(project)
@@ -80,6 +82,8 @@ abstract class KotlinBasePluginWrapper(
plugin.apply(project)
}
internal open fun createTestRegistry(project: Project) = KotlinTestsRegistry(project)
private fun setupAttributeMatchingStrategy(project: Project) = with(project.dependencies.attributesSchema) {
KotlinPlatformType.setupAttributesMatchingStrategy(this)
KotlinUsages.setupAttributesMatchingStrategy(this)
@@ -144,6 +148,8 @@ open class KotlinJsPluginWrapper @Inject constructor(
override val projectExtensionClass: KClass<out KotlinJsProjectExtension>
get() = KotlinJsProjectExtension::class
override fun createTestRegistry(project: Project) = KotlinTestsRegistry(project, "test")
}
open class KotlinMultiplatformPluginWrapper @Inject constructor(
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
import org.jetbrains.kotlin.gradle.testing.internal.registerTestTask
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.util.concurrent.Callable
@@ -383,7 +383,7 @@ abstract class KotlinTargetConfigurator<KotlinCompilationType : KotlinCompilatio
}
}
registerTestTask(testTask)
target.project.kotlinTestRegistry.registerTestTask(testTask)
}
private fun addJar(configuration: Configuration, jarArtifact: PublishArtifact) {
@@ -9,6 +9,7 @@ import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator.Companion.runTaskNameSuffix
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator.Companion.testTaskNameSuffix
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
@@ -17,20 +18,18 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsNodeDsl
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinBrowserJs
import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinNodeJs
import org.jetbrains.kotlin.gradle.testing.internal.allTestsTask
import org.jetbrains.kotlin.gradle.testing.internal.getOrCreateAggregatedTestTask
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
class KotlinJsTarget(project: Project, platformType: KotlinPlatformType) :
KotlinOnlyTarget<KotlinJsCompilation>(project, platformType), KotlinJsTargetDsl {
val testTaskName get() = lowerCamelCaseName(disambiguationClassifier, testTaskNameSuffix)
val testTask
get() = project.getOrCreateAggregatedTestTask(
val testTask: TaskHolder<KotlinTestReport>
get() = project.kotlinTestRegistry.getOrCreateAggregatedTestTask(
name = testTaskName,
description = "Run JS tests for all platforms",
reportName = "jsAll",
parent = project.allTestsTask.doGetTask()
description = "Run JS tests for all platforms"
)
val runTaskName get() = lowerCamelCaseName(disambiguationClassifier, runTaskNameSuffix)
@@ -17,8 +17,7 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
import org.jetbrains.kotlin.gradle.testing.internal.registerTestTask
import org.jetbrains.kotlin.gradle.testing.internal.registerTestTaskInAggregate
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.utils.addIfNotNull
abstract class KotlinJsSubTarget(
@@ -86,8 +85,7 @@ abstract class KotlinJsSubTarget(
testJs.configureConventions()
}
registerTestTaskInAggregate(testJs, target.testTask.doGetTask())
registerTestTask(testJs)
target.project.kotlinTestRegistry.registerTestTask(testJs, target.testTask.doGetTask())
project.whenEvaluated {
testJs.configure {
@@ -18,14 +18,13 @@ import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Exec
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
import org.jetbrains.kotlin.gradle.testing.internal.registerTestTask
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import java.io.File
import java.util.*
@@ -145,7 +144,7 @@ open class KotlinNativeTargetConfigurator(
testTask.configureConventions()
}
registerTestTask(testTask)
kotlinTestRegistry.registerTestTask(testTask)
} else {
tasks.create(taskName, Exec::class.java).apply {
group = RUN_GROUP
@@ -0,0 +1,112 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.testing.internal
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.testing.AbstractTestTask
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
import org.jetbrains.kotlin.gradle.tasks.locateTask
/**
* Internal service for creating aggregated test tasks and registering all test tasks.
* See [KotlinTestReport] for more details about aggregated test tasks.
*/
class KotlinTestsRegistry(val project: Project, val allTestsTaskName: String = "allTests") {
val allTestsTask: TaskHolder<KotlinTestReport>
get() = doGetOrCreateAggregatedTestTask(
name = allTestsTaskName,
description = "Runs the tests for all targets and create aggregated report"
) {
project.tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME)
.dependsOn(it.getTaskOrProvider())
}
fun registerTestTask(
taskHolder: TaskHolder<AbstractTestTask>,
aggregate: KotlinTestReport = allTestsTask.doGetTask()
) {
val project = taskHolder.project
project.tasks.getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(taskHolder.name)
project.cleanAllTestTask.dependsOn(cleanTaskName(taskHolder.name))
aggregate.dependsOn(taskHolder.name)
taskHolder.configure { task ->
aggregate.registerTestTask(task)
ijListenTestTask(task)
}
}
fun getOrCreateAggregatedTestTask(
name: String,
description: String,
parent: TaskHolder<KotlinTestReport>? = allTestsTask
): TaskHolder<KotlinTestReport> {
if (name == parent?.name) return parent
return doGetOrCreateAggregatedTestTask(name, description, parent?.doGetTask())
}
private fun doGetOrCreateAggregatedTestTask(
name: String,
description: String,
parent: KotlinTestReport? = null,
configure: (TaskHolder<KotlinTestReport>) -> Unit = {}
): TaskHolder<KotlinTestReport> {
val existed = project.locateTask<KotlinTestReport>(name)
if (existed != null) return existed
val reportName = name
val aggregate: TaskHolder<KotlinTestReport> = project.createOrRegisterTask(name) { aggregate ->
aggregate.description = description
aggregate.group = JavaBasePlugin.VERIFICATION_GROUP
aggregate.destinationDir = project.testReportsDir.resolve(reportName)
if (System.getProperty("idea.active") != null) {
aggregate.extensions.extraProperties.set("idea.internal.test", true)
}
project.gradle.taskGraph.whenReady { graph ->
aggregate.maybeOverrideReporting(graph)
}
parent?.addChild(aggregate)
}
parent?.dependsOn(aggregate.getTaskOrProvider())
configure(aggregate)
return aggregate
}
private fun cleanTaskName(taskName: String): String {
check(taskName.isNotEmpty())
return "clean" + taskName.capitalize()
}
private val Project.cleanAllTestTask: Task
get() {
val taskName = cleanTaskName(allTestsTask.name)
return tasks.findByName(taskName)
?: tasks.create(taskName, Task::class.java).also {
tasks.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME).dependsOn(it)
}
}
companion object {
const val PROJECT_EXTENSION_NAME = "kotlinTestRegistry"
}
}
internal val Project.kotlinTestRegistry: KotlinTestsRegistry
get() = extensions.getByName(KotlinTestsRegistry.PROJECT_EXTENSION_NAME) as KotlinTestsRegistry
@@ -1,94 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.testing.internal
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.testing.AbstractTestTask
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.plugin.TaskHolder
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
import org.jetbrains.kotlin.gradle.tasks.locateTask
internal val Project.allTestsTask: TaskHolder<KotlinTestReport>
get() = getOrCreateAggregatedTestTask(
name = "allTests",
description = "Runs the tests for all targets and create aggregated report",
reportName = "all"
) {
tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME)
.dependsOn(it.getTaskOrProvider())
}
internal fun Project.getOrCreateAggregatedTestTask(
name: String,
description: String,
reportName: String,
parent: KotlinTestReport? = null,
configure: (TaskHolder<KotlinTestReport>) -> Unit = {}
): TaskHolder<KotlinTestReport> {
val existed = locateTask<KotlinTestReport>(name)
if (existed != null) return existed
val aggregate: TaskHolder<KotlinTestReport> = createOrRegisterTask(name) { aggregate ->
aggregate.description = description
aggregate.group = JavaBasePlugin.VERIFICATION_GROUP
aggregate.destinationDir = testReportsDir.resolve(reportName)
if (System.getProperty("idea.active") != null) {
aggregate.extensions.extraProperties.set("idea.internal.test", true)
}
project.gradle.taskGraph.whenReady { graph ->
aggregate.maybeOverrideReporting(graph)
}
parent?.addChild(aggregate)
}
parent?.dependsOn(aggregate.getTaskOrProvider())
configure(aggregate)
return aggregate
}
private fun cleanTaskName(taskName: String): String {
check(taskName.isNotEmpty())
return "clean" + taskName.capitalize()
}
private val Project.cleanAllTestTask: Task
get() {
val taskName = cleanTaskName(allTestsTask.name)
return tasks.findByName(taskName)
?: tasks.create(taskName, Task::class.java).also {
tasks.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME).dependsOn(it)
}
}
@Suppress("UnstableApiUsage")
internal fun registerTestTask(taskHolder: TaskHolder<AbstractTestTask>) {
registerTestTaskInAggregate(taskHolder, taskHolder.project.allTestsTask.doGetTask())
}
internal fun registerTestTaskInAggregate(
taskHolder: TaskHolder<AbstractTestTask>,
allTests: KotlinTestReport
) {
val project = taskHolder.project
project.tasks.getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(taskHolder.name)
project.cleanAllTestTask.dependsOn(cleanTaskName(taskHolder.name))
allTests.dependsOn(taskHolder.name)
taskHolder.configure { task ->
allTests.registerTestTask(task)
ijListenTestTask(task)
}
}