dev.sunnyday.test.impact.plugin.TestImpactPlugin.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of test-impact-plugin Show documentation
Show all versions of test-impact-plugin Show documentation
Skip test runtime of unchanged gradle modules
package dev.sunnyday.test.impact.plugin
import dev.sunnyday.test.impact.plugin.domain.graph.ProjectGraphResolver
import dev.sunnyday.test.impact.plugin.extension.TestImpactExtension
import dev.sunnyday.test.impact.plugin.task.testimpact.TestImpactTask
import dev.sunnyday.test.impact.plugin.task.testimpact.TestImpactTaskOutput
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import java.io.File
class TestImpactPlugin : Plugin {
override fun apply(target: Project) {
PluginApplier(target).apply()
}
private class PluginApplier(
private val target: Project
) {
private val extension = registerExtension()
private val startParameterTaskNamesProvider by lazy { target.provider { target.gradle.startParameter.taskNames } }
private val graphResolverProvider by lazy { target.provider { ProjectGraphResolver(target) } }
private val testImpactTaskOutputProvider by lazy {
target.provider {
TestImpactTaskOutput(
getTestImpactOutputFile()
)
}
}
private val testImpactTaskProvider by lazy {
target.tasks.register("testImpact", TestImpactTask::class.java) {
group = "verification"
projectName = target.name
if (!(isWrapperTask() || isGradleStartedForTestImpact())) {
throw IllegalStateException(
"""
Currently :testImpact allowed to run only as a gradle start task.
Current start tasks: ${target.gradle.startParameter.taskNames}"
""".trimIndent()
)
}
changedFiles = extension.changesSource.getChangedFiles()
inputImpactGraph = graphResolverProvider.get().getProjectsGraph()
taskOutput = testImpactTaskOutputProvider.get()
}
}
fun apply() {
if (!isGradleStartedForTestImpact()) {
return
}
target.gradle.projectsEvaluated {
buildGraph()
buildTestImpactTasksGraph()
}
}
private fun registerExtension(): TestImpactExtension {
return target.extensions.create("testImpact", TestImpactExtension::class.java)
}
private fun buildGraph() {
val graphResolver = graphResolverProvider.get()
iterateOverProjects(graphResolver::onProjectEvaluated)
graphResolver.markGraphCompleted()
}
private fun buildTestImpactTasksGraph() {
iterateOverProjects { project ->
val projectTestTasks = extension.testTaskNameProvider.getTestTasks(project)
projectTestTasks.forEach { testTask ->
project.tasks.findByName(testTask)
?.let(::setupTestTaskDependency)
}
}
}
private fun setupTestTaskDependency(testTask: Task) {
val testImpactTask = testImpactTaskProvider.get()
testTask.apply {
dependsOn(testImpactTask.path)
val testImpactTaskOutputProvider = testImpactTaskOutputProvider
val testProjectPath = testTask.project.path
setOnlyIf {
val testTaskOutputGraph = testImpactTaskOutputProvider.get()
.readImpactGraph()
testTaskOutputGraph.getProjectByProjectPath(testProjectPath).hasChanges
}
doFirst {
// TODO: setup tests filter
}
}
val startTasks = startParameterTaskNamesProvider.get()
if (startTasks.last() == getTestImpactStartTaskName()) {
testImpactTask.finalizedBy(testTask.path)
}
}
private fun iterateOverProjects(action: (Project) -> Unit) {
val projectsQueue = ArrayDeque()
projectsQueue.add(target)
while (projectsQueue.isNotEmpty()) {
val project = projectsQueue.removeFirst()
action.invoke(project)
project.childProjects.values.forEach(projectsQueue::add)
}
}
private fun isGradleStartedForTestImpact(): Boolean {
return startParameterTaskNamesProvider.get().contains(getTestImpactStartTaskName())
}
private fun getTestImpactStartTaskName(): String {
return if (target.rootProject === target) "testImpact" else "${target.path}:testImpact"
}
private fun isWrapperTask(): Boolean {
return startParameterTaskNamesProvider.get() == listOf("wrapper")
}
private fun getTestImpactOutputFile(): File {
return File(target.layout.buildDirectory.get().asFile, "tmp/testImpact/output.txt")
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy