Skip to content

Commit

Permalink
Implemented the use of the full path to the project for the exclusion
Browse files Browse the repository at this point in the history
Fixes #151
  • Loading branch information
shanshin committed Apr 25, 2022
1 parent e1f3fbc commit 997a217
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 32 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -332,7 +332,7 @@ kover {
intellijEngineVersion.set("1.0.656") // change version of IntelliJ agent and reporter
jacocoEngineVersion.set("0.8.7") // change version of JaCoCo agent and reporter
generateReportOnCheck = true // false to do not execute `koverMergedReport` task before `check` task
disabledProjects = setOf() // setOf("project-name") to disable coverage for project with name `project-name`
disabledProjects = setOf() // setOf("project-name") or setOf(":project-name") to disable coverage for project with path `:project-name` (`:` for the root project)
instrumentAndroidPackage = false // true to instrument packages `android.*` and `com.android.*`
runAllTestsForProjectTask = false // true to run all tests in all projects if `koverHtmlReport`, `koverXmlReport`, `koverReport`, `koverVerify` or `check` tasks executed on some project
}
Expand All @@ -349,7 +349,7 @@ kover {
intellijEngineVersion.set('1.0.656') // change version of IntelliJ agent and reporter
jacocoEngineVersion.set('0.8.7') // change version of JaCoCo agent and reporter
generateReportOnCheck = true // false to do not execute `koverMergedReport` task before `check` task
disabledProjects = [] // ["project-name"] to disable coverage for project with name `project-name`
disabledProjects = [] // ["project-name"] or [":project-name"] to disable coverage for project with path `:project-name` (`:` for the root project)
instrumentAndroidPackage = false // true to instrument packages `android.*` and `com.android.*`
runAllTestsForProjectTask = false // true to run all tests in all projects if `koverHtmlReport`, `koverXmlReport`, `koverReport`, `koverVerify` or `check` tasks executed on some project
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
@@ -1,4 +1,4 @@
version=0.5.0
version=0.5.1-SNAPSHOT
group=org.jetbrains.kotlinx

kotlin.code.style=official
Expand Up @@ -145,4 +145,33 @@ internal class MultiProjectTests : BaseGradleScriptTest() {
}
}
}

@Test
fun testDisableSubprojectByPath() {
builder("Testing disabling one of subproject by path")
.sources("multiproject-user")
.subproject(subprojectName) {
sources("multiproject-common")
}
.configKover { disabledProjects += ":$subprojectName" }
.build()
.run("build", "koverReport") {
checkDefaultBinaryReport()
checkDefaultMergedReports()
checkDefaultReports()
xml(defaultMergedXmlReport()) {
classCounter("org.jetbrains.UserClass").assertFullyCovered()

// classes from disabled project should not be included in the merged report
classCounter("org.jetbrains.CommonClass").assertAbsent()
classCounter("org.jetbrains.CommonInternalClass").assertAbsent()
}

subproject(subprojectName) {
checkDefaultBinaryReport(false)
checkDefaultMergedReports(false)
checkDefaultReports(false)
}
}
}
}
54 changes: 42 additions & 12 deletions src/main/kotlin/kotlinx/kover/KoverPlugin.kt
Expand Up @@ -55,7 +55,8 @@ class KoverPlugin : Plugin<Project> {

private fun Project.applyToProject(providers: BuildProviders, agents: Map<CoverageEngine, CoverageAgent>) {
val projectProviders =
providers.projects[name] ?: throw GradleException("Kover: Providers for project '$name' was not found")
providers.projects[path]
?: throw GradleException("Kover: Providers for project '$name' ('$path') was not found")

val xmlReportTask = createKoverProjectTask(
XML_REPORT_TASK_NAME,
Expand Down Expand Up @@ -165,10 +166,10 @@ class KoverPlugin : Plugin<Project> {

task.group = VERIFICATION_GROUP

providers.projects.forEach { (projectName, m) ->
task.binaryReportFiles.put(projectName, NestedFiles(task.project.objects, m.reports))
task.srcDirs.put(projectName, NestedFiles(task.project.objects, m.sources))
task.outputDirs.put(projectName, NestedFiles(task.project.objects, m.output))
providers.projects.forEach { (projectPath, m) ->
task.binaryReportFiles.put(projectPath, NestedFiles(task.project.objects, m.reports))
task.srcDirs.put(projectPath, NestedFiles(task.project.objects, m.sources))
task.outputDirs.put(projectPath, NestedFiles(task.project.objects, m.output))
}

task.coverageEngine.set(providers.engine)
Expand Down Expand Up @@ -199,8 +200,8 @@ class KoverPlugin : Plugin<Project> {
task.mustRunAfter(xmlReportTask)
task.mustRunAfter(htmlReportTask)

task.xmlFiles[proj.name] = xmlReportTask.xmlReportFile
task.htmlDirs[proj.name] = htmlReportTask.htmlReportDir
task.xmlFiles[proj.path] = xmlReportTask.xmlReportFile
task.htmlDirs[proj.path] = htmlReportTask.htmlReportDir
}
}
}
Expand Down Expand Up @@ -244,6 +245,9 @@ class KoverPlugin : Plugin<Project> {
extension.coverageEngine.set(CoverageEngine.INTELLIJ)
extension.intellijEngineVersion.set(defaultIntellijVersion.toString())
extension.jacocoEngineVersion.set(defaultJacocoVersion)

afterEvaluate(CollectDisabledProjectsPathsAction(extension))

return extension
}

Expand Down Expand Up @@ -279,7 +283,7 @@ class KoverPlugin : Plugin<Project> {
}
val targetErrorProvider = project.layout.buildDirectory.file("kover/errors/$name.log").map { it.asFile }

doFirst(BinaryReportCleanupAction(project.name, providers.koverExtension, taskExtension))
doFirst(BinaryReportCleanupAction(project.path, providers.koverExtension, taskExtension))
doLast(MoveIntellijErrorLogAction(sourceErrorProvider, targetErrorProvider))
}
}
Expand All @@ -289,7 +293,7 @@ class KoverPlugin : Plugin<Project> {
For this reason, before starting the tests, it is necessary to clear the file from the results of previous runs.
*/
private class BinaryReportCleanupAction(
private val projectName: String,
private val projectPath: String,
private val koverExtensionProvider: Provider<KoverExtension>,
private val taskExtension: KoverTaskExtension
) : Action<Task> {
Expand All @@ -302,7 +306,7 @@ private class BinaryReportCleanupAction(

if (!taskExtension.isDisabled
&& !koverExtension.isDisabled
&& !koverExtension.disabledProjects.contains(projectName)
&& !koverExtension.disabledProjectsPaths.contains(projectPath)
&& koverExtension.coverageEngine.get() == CoverageEngine.INTELLIJ
) {
// IntelliJ engine expected empty file for parallel test execution.
Expand All @@ -312,6 +316,32 @@ private class BinaryReportCleanupAction(
}
}

private class CollectDisabledProjectsPathsAction(
private val koverExtension: KoverExtension,
) : Action<Project> {
override fun execute(project: Project) {
val allProjects = project.allprojects
val paths = allProjects.associate { it.name to mutableListOf<String>() }
allProjects.forEach { paths.getValue(it.name) += it.path }

val result: MutableSet<String> = mutableSetOf()

koverExtension.disabledProjects.map {
if (it.startsWith(':')) {
result += it
} else {
val projectPaths = paths[it] ?: return@map
if (projectPaths.size > 1) {
throw GradleException("Cover configuring error: ambiguous name of the excluded project '$it': suitable projects with paths $projectPaths")
}
result += projectPaths
}
}

koverExtension.disabledProjectsPaths = result
}
}

private class MoveIntellijErrorLogAction(
private val sourceFile: Provider<File>,
private val targetFile: Provider<File>
Expand All @@ -333,7 +363,7 @@ private class CoverageArgumentProvider(
@get:Input val excludeAndroidPackage: Provider<Boolean>
) : CommandLineArgumentProvider, Named {

private val projectName: String = task.project.name
private val projectPath: String = task.project.path

@Internal
override fun getName(): String {
Expand All @@ -345,7 +375,7 @@ private class CoverageArgumentProvider(

if (taskExtension.isDisabled
|| koverExtensionValue.isDisabled
|| koverExtensionValue.disabledProjects.contains(projectName)
|| koverExtensionValue.disabledProjectsPaths.contains(projectPath)
) {
return mutableListOf()
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/kotlinx/kover/Providers.kt
Expand Up @@ -15,7 +15,7 @@ internal fun Project.createProviders(agents: Map<CoverageEngine, CoverageAgent>)
val projects: MutableMap<String, ProjectProviders> = mutableMapOf()

allprojects {
projects[it.name] = ProjectProviders(
projects[it.path] = ProjectProviders(
it.provider { it.files(if (runAllTests()) allBinaryReports() else it.binaryReports(this)) },
it.provider { if (runAllTests()) allTestTasks() else it.testTasks(this) },
it.provider { it.collectDirs(this).first },
Expand Down Expand Up @@ -108,7 +108,7 @@ private fun Project.collectDirs(root: Project): Pair<FileCollection, FileCollect

private fun Project.isDisabled(root: Project): Boolean {
val koverExtension = root.extensions.getByType(KoverExtension::class.java)
return koverExtension.isDisabled || koverExtension.disabledProjects.contains(name)
return koverExtension.isDisabled || koverExtension.disabledProjectsPaths.contains(path)
}

private fun Project.runAllTests(): Boolean {
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/kotlinx/kover/api/KoverExtension.kt
Expand Up @@ -58,6 +58,12 @@ open class KoverExtension(objects: ObjectFactory) {
*/
@get:Input
public var runAllTestsForProjectTask: Boolean = false

/**
* Specifies the projects to be disabled from instrumentation and reportings.
*/
@get:Internal
internal var disabledProjectsPaths: Set<String> = emptySet()
}

public enum class CoverageEngine {
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/kotlinx/kover/engines/commons/Reports.kt
Expand Up @@ -30,3 +30,5 @@ internal fun String.wildcardsToRegex(): String {

return builder.toString()
}

internal val ONE_HUNDRED = 100.toBigDecimal()
Expand Up @@ -189,9 +189,9 @@ private fun Task.checkRule(counters: Map<VerificationValueType, Int>, rule: Veri

val ruleName = if (rule.name != null) "'${rule.name}' " else ""
return if (boundsViolations.size > 1) {
"Rule ${ruleName}violated for '${project.name}':" + boundsViolations.joinToString("\n ", "\n ")
"Rule ${ruleName}violated for '${project.path}':" + boundsViolations.joinToString("\n ", "\n ")
} else if (boundsViolations.size == 1) {
"Rule ${ruleName}violated for '${project.name}': ${boundsViolations[0]}"
"Rule ${ruleName}violated for '${project.path}': ${boundsViolations[0]}"
} else {
null
}
Expand Down
8 changes: 5 additions & 3 deletions src/main/kotlin/kotlinx/kover/engines/jacoco/JacocoReports.kt
Expand Up @@ -6,6 +6,8 @@ package kotlinx.kover.engines.jacoco

import groovy.lang.*
import kotlinx.kover.api.*
import kotlinx.kover.engines.commons.*
import kotlinx.kover.engines.commons.ONE_HUNDRED
import kotlinx.kover.engines.commons.Report
import org.gradle.api.*
import org.gradle.api.file.*
Expand Down Expand Up @@ -40,7 +42,7 @@ private fun Task.callJacocoAntReportTask(
invokeWithBody("executiondata") {
project.files(report.files).addToAntBuilder(this, "resources")
}
invokeWithBody("structure", mapOf("name" to project.name)) {
invokeWithBody("structure", mapOf("name" to project.path)) {
invokeWithBody("sourcefiles") {
project.files(sources).addToAntBuilder(this, "resources")
}
Expand Down Expand Up @@ -93,8 +95,8 @@ internal fun Task.jacocoVerification(
}
VerificationValueType.COVERED_LINES_PERCENTAGE -> {
limitArgs["value"] = "COVEREDRATIO"
min = min?.divide(BigDecimal(100))
max = max?.divide(BigDecimal(100))
min = min?.divide(ONE_HUNDRED)
max = max?.divide(ONE_HUNDRED)
}
}

Expand Down
12 changes: 9 additions & 3 deletions src/main/kotlin/kotlinx/kover/tasks/KoverCollectingTask.kt
Expand Up @@ -24,20 +24,26 @@ open class KoverCollectingTask : DefaultTask() {
it.into(outputDir)
xmlFiles.forEach { (p, f) ->
it.from(f) { c ->
c.rename { "$p.xml" }
c.rename { "${p.pathAsFilename()}.xml" }
}
}
}


htmlDirs.forEach { (p, d) ->
val name = p.pathAsFilename()

// delete directory for HTML reports so that the old reports do not overlap with the new ones
project.delete(outputDir.dir("html/$p"))
project.delete(outputDir.dir("html/$name"))

project.copy {
it.from(d)
it.into(outputDir.dir("html/$p"))
it.into(outputDir.dir("html/$name"))
}
}
}

private fun String.pathAsFilename(): String {
return if (this == ":") "_root_" else replace(':', '_')
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/kotlinx/kover/tasks/KoverHtmlReport.kt
Expand Up @@ -44,7 +44,7 @@ open class KoverMergedHtmlReportTask : KoverMergedTask() {

@CacheableTask
open class KoverHtmlReportTask : KoverProjectTask() {
private val projectName = project.name
private val projectPath = project.path

/**
* Specifies directory path of generated HTML report.
Expand Down Expand Up @@ -72,6 +72,6 @@ open class KoverHtmlReportTask : KoverProjectTask() {
classpath.get(),
)
}
logger.lifecycle("Kover: HTML report for '$projectName' file://${htmlDirFile.canonicalPath}/index.html")
logger.lifecycle("Kover: HTML report for '$projectPath' file://${htmlDirFile.canonicalPath}/index.html")
}
}
10 changes: 5 additions & 5 deletions src/main/kotlin/kotlinx/kover/tasks/KoverMergedTask.kt
Expand Up @@ -71,16 +71,16 @@ open class KoverMergedTask : DefaultTask() {
val sourcesMap = srcDirs.get()
val outputsMap = outputDirs.get()

val projectsNames = sourcesMap.keys
val projectsPaths = sourcesMap.keys

val reportFiles: MutableList<File> = mutableListOf()
val projects: MutableList<ProjectInfo> = mutableListOf()

projectsNames.map { projectName ->
reportFiles += binariesMap.getValue(projectName).files.get()
projectsPaths.map { projectPath ->
reportFiles += binariesMap.getValue(projectPath).files.get()
projects += ProjectInfo(
sources = sourcesMap.getValue(projectName).files.get(),
outputs = outputsMap.getValue(projectName).files.get()
sources = sourcesMap.getValue(projectPath).files.get(),
outputs = outputsMap.getValue(projectPath).files.get()
)
}

Expand Down

0 comments on commit 997a217

Please sign in to comment.