diff --git a/README.md b/README.md index 0d01c1b..5d0e083 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ You can find instructions on how to apply the plugin at: http://plugins.gradle. When applied on a project with sub-projects, the plugin will create the aggregation task `aggregateScoverage`, which will first generate reports for each project individually (including the parent project), and will then generate an aggregated result based on these reports. + + The plugin must be applied on a sub-project for it to be included in the aggregated; applying the plugin on a + project _does not_ automatically apply it on sub-projects. The aggregated report will override the parent-project specific report (`parent-project/build/reports/scoverage`). diff --git a/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java b/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java new file mode 100644 index 0000000..c3fdffa --- /dev/null +++ b/src/functionalTest/java/org.scoverage/MultiModulePluginNotConfiguredForScalaTest.java @@ -0,0 +1,38 @@ +package org.scoverage; + +import org.junit.Assert; +import org.junit.Test; + +public class MultiModulePluginNotConfiguredForScalaTest extends ScoverageFunctionalTest { + + public MultiModulePluginNotConfiguredForScalaTest() { + super("multi-module-plugin-not-configured-for-scala"); + } + + @Test + public void checkAndAggregateScoverage() throws Exception { + + AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), + ScoveragePlugin.getAGGREGATE_NAME()); + + result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("scala_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSkipped(ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("scala_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSkipped(ScoveragePlugin.getAGGREGATE_NAME()); + + assertReportDirsEmpty(); + + Assert.assertTrue(result.getResult().getOutput().contains("Scala sub-project 'scala_only' doesn't have Scoverage applied")); + Assert.assertFalse(result.getResult().getOutput().contains("Scala sub-project 'java_only' doesn't have Scoverage applied")); + } + + private void assertReportDirsEmpty() { + + Assert.assertFalse(reportDir().exists()); + Assert.assertFalse(reportDir(projectDir().toPath().resolve("scala_only").toFile()).exists()); + Assert.assertFalse(reportDir(projectDir().toPath().resolve("java_only").toFile()).exists()); + } +} diff --git a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java index 0c6156e..6f094bf 100644 --- a/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org.scoverage/ScalaJavaMultiModuleTest.java @@ -18,16 +18,18 @@ public void checkAndAggregateScoverage() throws Exception { AssertableBuildResult result = run("clean", ScoveragePlugin.getCHECK_NAME(), ScoveragePlugin.getAGGREGATE_NAME()); - result.assertTaskOutcome("java_only:" + ScoveragePlugin.getCOMPILE_NAME(), TaskOutcome.NO_SOURCE); + result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCOMPILE_NAME()); result.assertTaskSkipped(ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getREPORT_NAME()); result.assertTaskSkipped("java_only:" + ScoveragePlugin.getREPORT_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("scala_only:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSucceeded("mixed_scala_java:" + ScoveragePlugin.getCHECK_NAME()); result.assertTaskSkipped("java_only:" + ScoveragePlugin.getCHECK_NAME()); + result.assertTaskSucceeded(ScoveragePlugin.getAGGREGATE_NAME()); assertAllReportFilesExist(); diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle new file mode 100644 index 0000000..450d3e7 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'org.scoverage' apply false +} + +description = 'a multi-module Scala and Java project that defines scoverage only on root but not on subprojects' + +allprojects { + repositories { + jcenter() + } +} + +subprojects { p -> + if (p.name != 'dependencies') { + apply plugin: 'java' + dependencies { + implementation platform(project(':dependencies')) + testCompile group: 'org.junit.platform', name: 'junit-platform-runner' + } + + test { + useJUnitPlatform() + } + } +} + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle new file mode 100644 index 0000000..3ac33f7 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/dependencies/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java-platform' +} + +dependencies { + constraints { + api group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + api group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + api group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + api group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle new file mode 100644 index 0000000..bbcd2f4 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/build.gradle @@ -0,0 +1,3 @@ +dependencies { + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' +} diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java new file mode 100644 index 0000000..95c85de --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/main/java/org/hello/WorldJavaOnly.java @@ -0,0 +1,9 @@ +package org.hello; + +public class WorldJavaOnly { + + public String foo() { + String s = "java_only" + "a"; + return s; + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java new file mode 100644 index 0000000..68fd33d --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/java_only/src/test/java/org/hello/WorldJavaOnlyTest.java @@ -0,0 +1,11 @@ +package org.hello; + +import org.junit.Test; + +public class WorldJavaOnlyTest { + + @Test + public void foo() { + new WorldJavaOnly().foo(); + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle new file mode 100644 index 0000000..28ca396 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/build.gradle @@ -0,0 +1,9 @@ +apply plugin: 'scala' +// apply plugin: 'org.scoverage' // Oops forgot to configure scoverage + +dependencies { + compile group: 'org.scala-lang', name: 'scala-library' + + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" +} diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala new file mode 100644 index 0000000..268c5a5 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/main/scala/org/hello/WorldScalaOnly.scala @@ -0,0 +1,9 @@ +package org.hello + +class WorldScalaOnly { + + def foo(): String = { + val s = "scala_only" + "a" + s + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala new file mode 100644 index 0000000..7601021 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/scala_only/src/test/scala/org/hello/WorldScalaOnlySuite.scala @@ -0,0 +1,13 @@ +package org.hello + +import org.junit.runner.RunWith +import org.scalatest.FunSuite +import org.scalatest.junit.JUnitRunner + +@RunWith(classOf[JUnitRunner]) +class WorldScalaOnlySuite extends FunSuite { + + test("foo") { + new WorldScalaOnly().foo() + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle new file mode 100644 index 0000000..0f44066 --- /dev/null +++ b/src/functionalTest/resources/projects/multi-module-plugin-not-configured-for-scala/settings.gradle @@ -0,0 +1 @@ +include 'dependencies', 'java_only', 'scala_only' \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle index b486ee1..27246b6 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/build.gradle @@ -2,17 +2,16 @@ plugins { id 'org.scoverage' apply false } +description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' + allprojects { repositories { jcenter() } } -description = 'a multi-module Scala and Java project that builds successfully with 100% coverage' - -apply plugin: 'org.scoverage' - -allprojects { +subprojects { + apply plugin: 'java' dependencies { testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion @@ -21,12 +20,9 @@ allprojects { test { useJUnitPlatform() } - - scoverage { - minimumRate = 0.5 - } } +apply plugin: 'org.scoverage' scoverage { minimumRate = 0.5 } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle index 1cb42eb..c2060d5 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/java_only/build.gradle @@ -1,6 +1,3 @@ -apply plugin: 'java' - dependencies { - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion } diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle index 9d6a7ab..c107f19 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/mixed_scala_java/build.gradle @@ -1,6 +1,4 @@ -apply plugin: 'java' apply plugin: 'scala' -apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" @@ -16,4 +14,9 @@ ext.configureSources = { set, name -> set.java.srcDirs = [] } configureSources(sourceSets.main, 'main') -configureSources(sourceSets.test, 'test') \ No newline at end of file +configureSources(sourceSets.test, 'test') + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle index 97f6ee6..abca859 100644 --- a/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-multi-module/scala_only/build.gradle @@ -1,5 +1,4 @@ apply plugin: 'scala' -apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" @@ -8,3 +7,8 @@ dependencies { testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion } + +apply plugin: 'org.scoverage' +scoverage { + minimumRate = 0.5 +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle index 4a024a0..d70523d 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-cross-version/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } allprojects { @@ -14,6 +14,7 @@ allprojects { apply plugin: 'java' apply plugin: 'scala' + apply plugin: 'org.scoverage' dependencies { testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion diff --git a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle index af0a9b3..310e1da 100644 --- a/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module-multiple-test-tasks/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } allprojects { @@ -14,6 +14,7 @@ allprojects { apply plugin: 'java' apply plugin: 'scala' + apply plugin: 'org.scoverage' dependencies { compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" diff --git a/src/functionalTest/resources/projects/scala-multi-module/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/build.gradle index dcfad1a..3f10c36 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/build.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/build.gradle @@ -1,34 +1,36 @@ plugins { - id 'org.scoverage' + id 'org.scoverage' apply false } -allprojects { +description = 'a multi-module Scala project that builds successfully with 100% coverage' + +allprojects { p -> repositories { jcenter() } -} -description = 'a multi-module Scala project that builds successfully with 100% coverage' + if (p.name != 'dependencies') { + apply plugin: 'java' + apply plugin: 'scala' + apply plugin: 'org.scoverage' -allprojects { + dependencies { + implementation platform(project(':dependencies')) - apply plugin: 'java' - apply plugin: 'scala' + compile group: 'org.scala-lang', name: 'scala-library' - dependencies { - compile group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine' + testCompile group: 'org.junit.platform', name: 'junit-platform-runner' - testRuntime group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion - testCompile group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}" + } - testCompile group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion - } - - test { - useJUnitPlatform() - } + test { + useJUnitPlatform() + } - scoverage { - minimumRate = 0.5 + scoverage { + minimumRate = 0.5 + } } } \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle b/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle new file mode 100644 index 0000000..3ac33f7 --- /dev/null +++ b/src/functionalTest/resources/projects/scala-multi-module/dependencies/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java-platform' +} + +dependencies { + constraints { + api group: 'org.scala-lang', name: 'scala-library', version: "${scalaVersionMajor}.${scalaVersionMinor}.${scalaVersionBuild}" + + api group: 'org.junit.vintage', name: 'junit-vintage-engine', version: junitVersion + api group: 'org.junit.platform', name: 'junit-platform-runner', version: junitPlatformVersion + + api group: 'org.scalatest', name: "scalatest_${scalaVersionMajor}.${scalaVersionMinor}", version: scalatestVersion + } +} \ No newline at end of file diff --git a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle index 6eabe3b..084ba0c 100644 --- a/src/functionalTest/resources/projects/scala-multi-module/settings.gradle +++ b/src/functionalTest/resources/projects/scala-multi-module/settings.gradle @@ -1 +1 @@ -include 'a', 'b', 'common' \ No newline at end of file +include 'dependencies', 'a', 'b', 'common' \ No newline at end of file diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index 4666a6c..3dcf232 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -6,6 +6,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.invocation.Gradle import org.gradle.api.plugins.PluginAware +import org.gradle.api.plugins.scala.ScalaPlugin import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.scala.ScalaCompile import org.gradle.api.tasks.testing.Test @@ -32,11 +33,6 @@ class ScoveragePlugin implements Plugin { void apply(PluginAware pluginAware) { if (pluginAware instanceof Project) { applyProject(pluginAware) - if (pluginAware == pluginAware.rootProject) { - pluginAware.subprojects { p -> - p.plugins.apply(ScoveragePlugin) - } - } } else if (pluginAware instanceof Gradle) { pluginAware.allprojects { p -> p.plugins.apply(ScoveragePlugin) @@ -104,7 +100,6 @@ class ScoveragePlugin implements Plugin { def globalReportTask = project.tasks.register(REPORT_NAME, ScoverageAggregate) def globalCheckTask = project.tasks.register(CHECK_NAME, OverallCheckTask) - project.afterEvaluate { def detectedSourceEncoding = compileTask.scalaCompileOptions.encoding if (detectedSourceEncoding == null) { @@ -166,29 +161,6 @@ class ScoveragePlugin implements Plugin { reportDir = extension.reportDir } - // define aggregation task - if (project.childProjects.size() > 0) { - def allReportTasks = project.getAllprojects().findResults { - it.tasks.find { task -> - task.name == REPORT_NAME && task instanceof ScoverageAggregate - } - } - - def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { - dependsOn(allReportTasks) - group = 'verification' - runner = scoverageRunner - reportDir = extension.reportDir - sourceEncoding.set(detectedSourceEncoding) - deleteReportsOnAggregation = extension.deleteReportsOnAggregation - coverageOutputCobertura = extension.coverageOutputCobertura - coverageOutputXML = extension.coverageOutputXML - coverageOutputHTML = extension.coverageOutputHTML - coverageDebug = extension.coverageDebug - } - project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) - } - // make this project's scoverage compilation depend on scoverage compilation of any other project // which this project depends on its normal compilation // (essential when running without normal compilation on multi-module projects with inner dependencies) @@ -308,6 +280,39 @@ class ScoveragePlugin implements Plugin { } } } + + // define aggregation task + if (!project.subprojects.empty) { + project.gradle.projectsEvaluated { + project.subprojects.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 { + it.tasks.find { task -> + task.name == REPORT_NAME && task instanceof ScoverageAggregate + } + } + def allReportTasks = childReportTasks + globalReportTask + def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { + onlyIf { + !childReportTasks.empty + } + dependsOn(allReportTasks) + group = 'verification' + runner = scoverageRunner + reportDir = extension.reportDir + sourceEncoding.set(detectedSourceEncoding) + deleteReportsOnAggregation = extension.deleteReportsOnAggregation + coverageOutputCobertura = extension.coverageOutputCobertura + coverageOutputXML = extension.coverageOutputXML + coverageOutputHTML = extension.coverageOutputHTML + coverageDebug = extension.coverageDebug + } + project.tasks[CHECK_NAME].mustRunAfter(aggregationTask) + } + } } }