Skip to content

Scala 3 support; Upgrade to Scoverage version 2.0.7 #188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repositories {
group 'org.scoverage'
description = 'gradle-scoverage is a Gradle plugin for calculating code coverage using Scoverage'
if (project.version == 'unspecified') {
version = '7.0.0-SNAPSHOT'
version = '8.0.0-SNAPSHOT'
}
ext {
website = 'http://scoverage.org'
Expand Down Expand Up @@ -46,7 +46,8 @@ targetCompatibility = '1.8'


dependencies {
compileOnly "org.scoverage:scalac-scoverage-plugin_2.13:1.4.2"
compileOnly "org.scoverage:scalac-scoverage-plugin_2.13.8:2.0.7"
compileOnly "org.scoverage:scalac-scoverage-reporter_2.13:2.0.7"
implementation group: 'commons-io', name: 'commons-io', version: '2.6'

testImplementation 'junit:junit:4.12'
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
6 changes: 6 additions & 0 deletions src/crossScalaVersionTest/java/org/scoverage/Scala32Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.scoverage;

public class Scala32Test extends ScalaVersionTest {

public Scala32Test() { super("3_2"); }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dependencies {
implementation group: 'org.scala-lang', name: 'scala-library', version: "2.12.8"
implementation group: 'org.scala-lang', name: 'scala-library', version: "2.12.17"
testImplementation group: 'org.scalatest', name: "scalatest_2.12", version: scalatestVersion
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dependencies {
implementation group: 'org.scala-lang', name: 'scala-library', version: "2.13.1"
implementation group: 'org.scala-lang', name: 'scala-library', version: "2.13.10"
testImplementation group: 'org.scalatest', name: "scalatest_2.13", version: scalatestVersion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies {
implementation 'org.scala-lang:scala3-library_3:3.2.0'
testImplementation 'org.scalatest:scalatest_3:3.2.14'
testImplementation 'org.scalatestplus:junit-4-13_3:3.2.14.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.hello

class World3_2 {

// Scala 3 enum to force Scala 3 (Dotty) compiler
enum Num(val value: String):
case Three extends Num("3")
case Two extends Num("2")

def foo(): String = {
val s = Num.Three.value + Num.Two.value
s
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.hello

import org.junit.runner.RunWith
import org.scalatest.funsuite.AnyFunSuite
import org.scalatestplus.junit.JUnitRunner

@RunWith(classOf[JUnitRunner])
class World3_2Suite extends AnyFunSuite {

test("foo") {
new World3_2().foo()
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
include '2_12', '2_13'
include '2_12', '2_13', '3_2'
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private void configureArguments(String... arguments) {

fullArguments.add("-PscalaVersionMajor=2");
fullArguments.add("-PscalaVersionMinor=12");
fullArguments.add("-PscalaVersionBuild=8");
fullArguments.add("-PscalaVersionBuild=17");
fullArguments.add("-PjunitVersion=5.3.2");
fullArguments.add("-PjunitPlatformVersion=1.3.2");
fullArguments.add("-PscalatestVersion=3.0.8");
Expand Down
31 changes: 31 additions & 0 deletions src/main/groovy/org/scoverage/ScalaVersion.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.scoverage

class ScalaVersion {
final String primaryVersion
final Optional<String> secondaryVersion
final Integer majorVersion
final String scalacScoverageVersion
final String scalacScoveragePluginVersion
final String scalacScoverageRuntimeVersion

ScalaVersion(primaryVersion) {
this(primaryVersion, Optional.empty())
}

ScalaVersion(String primaryVersion, Optional<String> secondaryVersion) {
this.primaryVersion = primaryVersion
this.secondaryVersion = secondaryVersion

this.majorVersion = primaryVersion.substring(0, primaryVersion.indexOf('.')).toInteger()
this.scalacScoverageVersion = this.majorVersion < 3
? primaryVersion.substring(0, primaryVersion.lastIndexOf('.'))
: this.majorVersion.toString()
this.scalacScoveragePluginVersion = secondaryVersion.orElse(primaryVersion)
this.scalacScoverageRuntimeVersion = scalacScoveragePluginVersion.substring(0, scalacScoveragePluginVersion.lastIndexOf('.'))
}

@Override
String toString() {
return majorVersion < 3 ? primaryVersion : "$primaryVersion (${secondaryVersion.get()})"
}
}
5 changes: 3 additions & 2 deletions src/main/groovy/org/scoverage/ScoverageAggregate.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.TaskAction
import scoverage.report.CoverageAggregator
import scoverage.reporter.CoverageAggregator

import static org.gradle.api.tasks.PathSensitivity.RELATIVE

Expand Down Expand Up @@ -57,7 +57,8 @@ class ScoverageAggregate extends DefaultTask {

def dirs = []
dirs.addAll(dirsToAggregateFrom.get())
def coverage = CoverageAggregator.aggregate(dirs.unique() as File[])
def sourceRoot = getProject().getRootDir()
def coverage = CoverageAggregator.aggregate(dirs.unique() as File[], sourceRoot)

if (coverage.nonEmpty()) {
new ScoverageWriter(project.logger).write(
Expand Down
2 changes: 1 addition & 1 deletion src/main/groovy/org/scoverage/ScoverageExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ScoverageExtension {
project.plugins.apply(ScalaPlugin.class)

scoverageVersion = project.objects.property(String)
scoverageVersion.set('1.4.11')
scoverageVersion.set('2.0.7')

scoverageScalaVersion = project.objects.property(String)

Expand Down
111 changes: 72 additions & 39 deletions src/main/groovy/org/scoverage/ScoveragePlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,21 @@ class ScoveragePlugin implements Plugin<PluginAware> {
}

project.afterEvaluate {
def scalaFullVersion = resolveScalaVersion(project)
def scalaBinaryVersion = scalaFullVersion.substring(0, scalaFullVersion.lastIndexOf('.'))
def scalaVersion = resolveScalaVersions(project)

def scoverageVersion = project.extensions.scoverage.scoverageVersion.get()
project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaVersion")

project.logger.info("Using scoverage scalac plugin $scoverageVersion for scala $scalaFullVersion")
def scalacScoverageVersion = scalaVersion.scalacScoverageVersion
def scalacScoveragePluginVersion = scalaVersion.scalacScoveragePluginVersion
def scalacScoverageRuntimeVersion = scalaVersion.scalacScoverageRuntimeVersion

project.dependencies {
scoverage("org.scoverage:scalac-scoverage-plugin_$scalaFullVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-runtime_$scalaBinaryVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-domain_$scalacScoverageVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-reporter_$scalacScoverageVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-serializer_$scalacScoverageVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-runtime_$scalacScoverageRuntimeVersion:$scoverageVersion")
scoverage("org.scoverage:scalac-scoverage-plugin_$scalacScoveragePluginVersion:$scoverageVersion")
}
}
}
Expand Down Expand Up @@ -162,32 +168,45 @@ class ScoveragePlugin implements Plugin<PluginAware> {
if (existingParameters) {
parameters.addAll(existingParameters)
}
parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString())
if (extension.excludedPackages.get()) {
def packages = extension.excludedPackages.get().join(';')
parameters.add("-P:scoverage:excludedPackages:$packages".toString())
}
if (extension.excludedFiles.get()) {
def packages = extension.excludedFiles.get().join(';')
parameters.add("-P:scoverage:excludedFiles:$packages".toString())
}
if (extension.highlighting.get()) {
parameters.add('-Yrangepos')
}
scalaCompileOptions.additionalParameters = parameters
// the compile task creates a store of measured statements
outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage'))

dependsOn project.configurations[CONFIGURATION_NAME]
doFirst {
/*
It is crucial that this would run in `doFirst`, as this resolves the (dependencies of the)
configuration, which we do not want to do at configuration time (but only at execution time).
*/
def pluginFile = project.configurations[CONFIGURATION_NAME].find {
it.name.startsWith("scalac-scoverage-plugin")

def scalaVersion = resolveScalaVersions(project)
if (scalaVersion.majorVersion < 3) {
parameters.add("-P:scoverage:dataDir:${extension.dataDir.get().absolutePath}".toString())
parameters.add("-P:scoverage:sourceRoot:${extension.project.getRootDir().absolutePath}".toString())
if (extension.excludedPackages.get()) {
def packages = extension.excludedPackages.get().join(';')
parameters.add("-P:scoverage:excludedPackages:$packages".toString())
}
scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFile.absolutePath)
if (extension.excludedFiles.get()) {
def packages = extension.excludedFiles.get().join(';')
parameters.add("-P:scoverage:excludedFiles:$packages".toString())
}
if (extension.highlighting.get()) {
parameters.add('-Yrangepos')
}
scalaCompileOptions.additionalParameters = parameters
// the compile task creates a store of measured statements
outputs.file(new File(extension.dataDir.get(), 'scoverage.coverage'))

dependsOn project.configurations[CONFIGURATION_NAME]
doFirst {
/*
It is crucial that this would run in `doFirst`, as this resolves the (dependencies of the)
configuration, which we do not want to do at configuration time (but only at execution time).
*/
def pluginFiles = project.configurations[CONFIGURATION_NAME].findAll {
it.name.startsWith("scalac-scoverage-plugin") ||
it.name.startsWith("scalac-scoverage-domain") ||
it.name.startsWith("scalac-scoverage-serializer")
}.collect {
it.absolutePath
}
scalaCompileOptions.additionalParameters.add('-Xplugin:' + pluginFiles.join(":"))
}
} else {
parameters.add("-coverage-out:${extension.dataDir.get().absolutePath}".toString())
parameters.add("-sourceroot:${extension.project.getRootDir().absolutePath}".toString())
scalaCompileOptions.additionalParameters = parameters
}
}

Expand Down Expand Up @@ -364,27 +383,41 @@ class ScoveragePlugin implements Plugin<PluginAware> {
}
}

private String resolveScalaVersion(Project project) {

private ScalaVersion resolveScalaVersions(Project project) {
def scalaVersionProperty = project.extensions.scoverage.scoverageScalaVersion
if (scalaVersionProperty.isPresent()) {
def configuredScalaVersion = scalaVersionProperty.get()
project.logger.info("Using configured Scala version: $configuredScalaVersion")
return configuredScalaVersion
return new ScalaVersion(configuredScalaVersion)
} else {
project.logger.info("No Scala version configured. Detecting scala library...")
def components = project.configurations.compileClasspath.incoming.resolutionResult.getAllComponents()

def scala3Library = components.find {
it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala3-library_3"
}
def scalaLibrary = components.find {
it.moduleVersion.group == "org.scala-lang" && it.moduleVersion.name == "scala-library"
}

// Scala 3
if (scala3Library != null) {
def scala3Version = scala3Library.moduleVersion.version
def scala2Version = scalaLibrary.moduleVersion.version
project.logger.info("Detected scala 3 library in compilation classpath. Scala 3 version: $scala3Version; using Scala 2 library: $scala2Version")
return new ScalaVersion(scala3Version, Optional.of(scala2Version))
}

// Scala 2
if (scalaLibrary != null) {
def scalaVersion = scalaLibrary.moduleVersion.version
project.logger.info("Detected scala library in compilation classpath. Scala version: $scalaVersion")
return scalaVersion
} else {
project.logger.info("No scala library detected. Using default Scala version: $DEFAULT_SCALA_VERSION")
return DEFAULT_SCALA_VERSION
def scala2Version = scalaLibrary.moduleVersion.version
project.logger.info("Detected scala library in compilation classpath. Scala version: $scala2Version")
return new ScalaVersion(scala2Version)
}

// No Scala library was found, using default Scala version
project.logger.info("No scala library detected. Using default Scala version: $DEFAULT_SCALA_VERSION")
return new ScalaVersion(DEFAULT_SCALA_VERSION)
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/groovy/org/scoverage/ScoverageReport.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.TaskAction
import scoverage.report.CoverageAggregator
import scoverage.reporter.CoverageAggregator

import static org.gradle.api.tasks.PathSensitivity.RELATIVE

Expand Down Expand Up @@ -50,7 +50,8 @@ class ScoverageReport extends DefaultTask {
reportDir.get().delete()
reportDir.get().mkdirs()

def coverage = CoverageAggregator.aggregate([dataDir.get()] as File[])
def sourceRoot = getProject().getRootDir()
def coverage = CoverageAggregator.aggregate([dataDir.get()] as File[], sourceRoot)

if (coverage.isEmpty()) {
project.logger.info("[scoverage] Could not find coverage file, skipping...")
Expand Down
36 changes: 25 additions & 11 deletions src/main/groovy/org/scoverage/ScoverageWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import scala.Some;
import scala.collection.immutable.Seq;
import scala.collection.mutable.Buffer;
import scoverage.Constants;
import scoverage.Coverage;
import scoverage.report.CoberturaXmlWriter;
import scoverage.report.ScoverageHtmlWriter;
import scoverage.report.ScoverageXmlWriter;
import scoverage.domain.Constants;
import scoverage.domain.Coverage;
import scoverage.reporter.CoberturaXmlWriter;
import scoverage.reporter.ScoverageHtmlWriter;
import scoverage.reporter.ScoverageXmlWriter;
import scala.collection.JavaConverters;

import java.io.File;
Expand Down Expand Up @@ -65,11 +65,17 @@ public void write(Set<File> sourceDirs,
if (coverageOutputCobertura) {
Constructor<CoberturaXmlWriter> cst;
try {
cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class);
cst = CoberturaXmlWriter.class.getConstructor(
Class.forName("scala.collection.immutable.Seq"),
File.class,
Class.forName("scala.Option"));
} catch (NoSuchMethodException | ClassNotFoundException e) {
cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class);
cst = CoberturaXmlWriter.class.getConstructor(
Class.forName("scala.collection.Seq"),
File.class,
Class.forName("scala.Option"));
}
CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir);
CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, new Some<>(sourceEncoding));
writer.write(coverage);
logger.info("[scoverage] Written Cobertura XML report to " +
reportDir.getAbsolutePath() +
Expand All @@ -80,11 +86,19 @@ public void write(Set<File> sourceDirs,
if (coverageOutputXML) {
Constructor<ScoverageXmlWriter> cst;
try {
cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, boolean.class);
cst = ScoverageXmlWriter.class.getConstructor(
Class.forName("scala.collection.immutable.Seq"),
File.class,
boolean.class,
Class.forName("scala.Option"));
} catch (NoSuchMethodException | ClassNotFoundException e) {
cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, boolean.class);
cst = ScoverageXmlWriter.class.getConstructor(
Class.forName("scala.collection.Seq"),
File.class,
boolean.class,
Class.forName("scala.Option"));
}
ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false);
ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false, new Some<>(sourceEncoding));
writer.write(coverage);
logger.info("[scoverage] Written XML report to " +
reportDir.getAbsolutePath() +
Expand Down