diff --git a/README.md b/README.md index f5fd7b1..438097d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ plugin (https://github.com/scoverage/scalac-scoverage-plugin). * `excludedPackages = ` (default `not set`): Comma separated list of regexes for packages, classes and modules to exclude from coverage. +* `excludedSubProjects = ` (default `not set`): List of Gradle sub-projects to be excluded from the Scoverage parent project aggregation. Projects should be added using the standard Gradle project selector e.g. `excludedSubProjects = [ project(':parent:subproject') ]` + #### Multiple check tasks It is possible to configure multiple checks; for instance, one check for a statement rate and another for a branch rate: diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithPartialScoverageUseAndExcludedSubProjectTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithPartialScoverageUseAndExcludedSubProjectTest.java new file mode 100644 index 0000000..5d0d92c --- /dev/null +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithPartialScoverageUseAndExcludedSubProjectTest.java @@ -0,0 +1,23 @@ +package org.scoverage; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; + +public class ScalaMultiModuleWithPartialScoverageUseAndExcludedSubProjectTest extends ScoverageFunctionalTest { + + public ScalaMultiModuleWithPartialScoverageUseAndExcludedSubProjectTest() { + super("scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project"); + } + + @Test + public void reportScoverage() { + + AssertableBuildResult result = dryRun("clean", ScoveragePlugin.getREPORT_NAME()); + + assertFalse(result.getResult().getOutput().contains("Scala sub-project 'a' doesn't have Scoverage applied and will be ignored in parent project aggregation")); + result.assertTaskExists(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskExists("b:" + ScoveragePlugin.getREPORT_NAME()); + } + +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/a/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/a/build.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/a/src/main/scala/org/hello/a/WorldA.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/a/src/main/scala/org/hello/a/WorldA.scala new file mode 100644 index 0000000..c07f298 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/a/src/main/scala/org/hello/a/WorldA.scala @@ -0,0 +1,8 @@ +package org.hello.a + +class WorldA { + + def fooA(): String = { + "a" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/b/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/b/build.gradle new file mode 100644 index 0000000..e69de29 diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/b/src/main/scala/org/hello/b/WorldB.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/b/src/main/scala/org/hello/b/WorldB.scala new file mode 100644 index 0000000..83a8f32 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/b/src/main/scala/org/hello/b/WorldB.scala @@ -0,0 +1,8 @@ +package org.hello.b + +class WorldB { + + def fooB(): String = { + "b" + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/build.gradle new file mode 100644 index 0000000..5cc0f47 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala project that builds successfully and has modules which does not use scoverate plugin' + +allprojects { p -> + repositories { + mavenCentral() + } + + apply plugin: 'java' + apply plugin: 'scala' + + if (p.name != 'a') { + apply plugin: 'org.scoverage' + if (project.gradle.rootProject.name == p.name) { + scoverage { + excludedSubProjects = [project(':a')] + } + } + } + + dependencies { + + implementation group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + testImplementation group: 'org.junit.platform', name: 'junit-platform-runner' + + testImplementation group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } +} + +dependencies { + implementation project(':a') + implementation project(':b') +} diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/settings.gradle new file mode 100644 index 0000000..dd79722 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/settings.gradle @@ -0,0 +1 @@ +include 'a', 'b' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/src/main/scala/org/hello/World.scala b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/src/main/scala/org/hello/World.scala new file mode 100644 index 0000000..bf64f3e --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module-with-partial-scoverage-use-and-excluded-sub-project/src/main/scala/org/hello/World.scala @@ -0,0 +1,11 @@ +package org.hello + +import org.hello.a.WorldA +import org.hello.a.WorldB + +class World { + + def foo(): String = { + WorldA.foo() + WorldB.foo() + } +} \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index d2b5119..c15e249 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -35,6 +35,9 @@ class ScoverageExtension { /** regex for each excluded file */ final ListProperty excludedFiles + /** List of sub-projects excluded intentionally from aggregation */ + final ListProperty excludedSubProjects + /** Options for enabling and disabling output */ final Property coverageOutputCobertura final Property coverageOutputXML @@ -74,6 +77,9 @@ class ScoverageExtension { excludedFiles = project.objects.listProperty(String) excludedFiles.set([]) + excludedSubProjects = project.objects.listProperty(Project) + excludedSubProjects.set([]) + coverageOutputCobertura = project.objects.property(Boolean) coverageOutputCobertura.set(true) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index a6a33d2..08e8a73 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -293,12 +293,14 @@ class ScoveragePlugin implements Plugin { // define aggregation task if (!project.subprojects.empty) { project.gradle.projectsEvaluated { - project.subprojects.each { + def excludedSubProjectPaths = project.extensions.scoverage.excludedSubProjects.get().collect { it.getPath() } + def includedSubProjects = project.subprojects.findAll { !excludedSubProjectPaths.contains(it.getPath()) } + includedSubProjects.each { if (it.plugins.hasPlugin(ScalaPlugin) && !it.plugins.hasPlugin(ScoveragePlugin)) { it.logger.warn("Scala sub-project '${it.name}' doesn't have Scoverage applied and will be ignored in parent project aggregation") } } - def childReportTasks = project.subprojects.findResults { + def childReportTasks = includedSubProjects.findResults { it.tasks.find { task -> task.name == REPORT_NAME && task instanceof ScoverageAggregate }