Skip to content

Add Scala 3 support #149

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

Merged
merged 1 commit into from
Dec 17, 2023
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ This can be set as project property.

##### Scala version configuration

Plugin supports Scala 2.12.x and 2.13.x versions by automatically loading and configuring matching `scalac-scoverage-plugin` Scalac SCoverage Plugin artifact. For this to work Scala version has to be set. It can be done by defining `scalaVersion` plugin configuration parameter or `scala.version` project property. Without this setting, coverage will not be calculated.
Plugin supports Scala 2.12.8+, 2.13.0+ and 3.2.0+ versions by automatically loading and configuring matching `scalac-scoverage-plugin` Scalac SCoverage Plugin artifact. For this to work Scala version has to be set. It can be done by defining `scalaVersion` plugin configuration parameter or `scala.version` project property. Without this setting, coverage will not be calculated.

```xml
<project>
Expand Down
3 changes: 2 additions & 1 deletion src/it/integration_tests_parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@
<scala.compat.version>2.13</scala.compat.version>
<scala.minor.version>12</scala.minor.version>
<scala.version>${scala.compat.version}.${scala.minor.version}</scala.version>
<scala.library.artifact.id>scala-library</scala.library.artifact.id>
</properties>

<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<artifactId>${scala.library.artifact.id}</artifactId>
<version>${scala.version}</version>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals=clean verify site -e -ntp
46 changes: 46 additions & 0 deletions src/it/test_ScalaMavenPlugin_Scala32Plus_ScalaTest/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>it.scoverage-maven-plugin</groupId>
<artifactId>integration_tests_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../integration_tests_parent/pom.xml</relativePath>
</parent>

<artifactId>test_ScalaMavenPlugin_Scala32Plus_ScalaTest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Test Scoverage Report using scala-maven-plugin, Scala 3.2+ and ScalaTest</name>
<description>Test Scoverage Report using scala-maven-plugin, Scala 3.2+ and ScalaTest</description>

<properties>
<scala.compat.version>3</scala.compat.version>
<scala.version>3.3.1</scala.version>
<scala.library.artifact.id>scala3-library_3</scala.library.artifact.id>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package service

object HelloServiceScala {
def hello = { "Hello" }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package service

import org.scalatest.wordspec.AnyWordSpec

class HelloServiceScalaTest extends AnyWordSpec {

"HelloService" should {
"say hello" in {
assert(HelloServiceScala.hello == "Hello")
}
}
}
19 changes: 19 additions & 0 deletions src/it/test_ScalaMavenPlugin_Scala32Plus_ScalaTest/validate.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
try {

def logFile = new File(basedir, "build.log")
def lines = logFile.readLines()
assert lines.contains("[INFO] Statement coverage.: 100.00%")
assert lines.contains("[INFO] Branch coverage....: 100.00%")

def scoverageFile = new File(basedir, "target/scoverage.xml")
assert scoverageFile.exists()

def reportFile = new File(basedir, "target/site/scoverage/index.html")
assert reportFile.exists()

return true

} catch (Throwable e) {
e.printStackTrace()
return false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals=clean verify site -e -ntp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>it.scoverage-maven-plugin</groupId>
<artifactId>integration_tests_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../integration_tests_parent/pom.xml</relativePath>
</parent>

<artifactId>test_ScalaMavenPlugin_Scala32Plus_ScalaTest_ScalaVersion_Not_Set</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Test Scoverage Report using scala-maven-plugin, Scala 3.2+ and ScalaTest when scala.version is not set</name>
<description>Test Scoverage Report using scala-maven-plugin, Scala 3.2+ and ScalaTest when scala.version is not set</description>

<properties>
<scala.compat.version>3</scala.compat.version>
<scala.version/>
<scala.library.artifact.id>scala3-library_3</scala.library.artifact.id>
</properties>

<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>${scala.library.artifact.id}</artifactId>
<version>3.3.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.scalatest</groupId>
<artifactId>scalatest-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package service

object HelloServiceScala {
def hello = { "Hello" }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package service

import org.scalatest.wordspec.AnyWordSpec

class HelloServiceScalaTest extends AnyWordSpec {

"HelloService" should {
"say hello" in {
assert(HelloServiceScala.hello == "Hello")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
try {

def logFile = new File(basedir, "build.log")
def lines = logFile.readLines()
assert lines.contains("[INFO] Statement coverage.: 100.00%")
assert lines.contains("[INFO] Branch coverage....: 100.00%")

def scoverageFile = new File(basedir, "target/scoverage.xml")
assert scoverageFile.exists()

def reportFile = new File(basedir, "target/site/scoverage/index.html")
assert reportFile.exists()

return true

} catch (Throwable e) {
e.printStackTrace()
return false
}
65 changes: 41 additions & 24 deletions src/main/java/org/scoverage/plugin/SCoveragePreCompileMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
import java.io.OutputStreamWriter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import edu.emory.mathcs.backport.java.util.Arrays;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
Expand Down Expand Up @@ -228,6 +226,7 @@ public void execute() throws MojoExecutionException

String scalaBinaryVersion = null;
String resolvedScalaVersion = resolveScalaVersion();
boolean scala2 = true;
if ( resolvedScalaVersion != null )
{
if ( "2.12".equals( resolvedScalaVersion ) || resolvedScalaVersion.startsWith( "2.12." ) )
Expand All @@ -238,9 +237,14 @@ else if ( "2.13".equals( resolvedScalaVersion ) || resolvedScalaVersion.startsWi
{
scalaBinaryVersion = "2.13";
}
else if ( resolvedScalaVersion.compareTo("3.2.") > 0 ) // Scala 3 is supported from 3.2.0
{
scalaBinaryVersion = "3";
scala2 = false;
}
else
{
getLog().warn( String.format( "Skipping SCoverage execution - unsupported Scala version \"%s\"",
getLog().warn( String.format( "Skipping SCoverage execution - unsupported Scala version \"%s\". Supported Scala versions are 2.12.8+, 2.13.0+ and 3.2.0+ .",
resolvedScalaVersion ) );
return;
}
Expand Down Expand Up @@ -278,16 +282,18 @@ else if ( "2.13".equals( resolvedScalaVersion ) || resolvedScalaVersion.startsWi

try
{
List<Artifact> pluginArtifacts = getScalaScoveragePluginArtifacts( resolvedScalaVersion, scalaBinaryVersion );
Artifact runtimeArtifact = getScalaScoverageRuntimeArtifact( scalaBinaryVersion );

addScoverageDependenciesToClasspath( runtimeArtifact );
List<Artifact> pluginArtifacts = getScalaScoveragePluginArtifacts( resolvedScalaVersion, scalaBinaryVersion, scala2 );
if ( scala2 ) // Scala 3 doesn't need scalac-scoverage-runtime
{
Artifact runtimeArtifact = getScalaScoverageRuntimeArtifact( scalaBinaryVersion );
addScoverageDependenciesToClasspath( runtimeArtifact );
}

String arg = DATA_DIR_OPTION + dataDirectory.getAbsolutePath();
String arg = ( scala2 ? SCALA2_DATA_DIR_OPTION : SCALA3_COVERAGE_OUT_OPTION ) + dataDirectory.getAbsolutePath();
String _scalacOptions = quoteArgument( arg );
String addScalacArgs = arg;

arg = SOURCE_ROOT_OPTION + project.getBasedir().getAbsolutePath();
arg = scala2 ? ( SOURCE_ROOT_OPTION + project.getBasedir().getAbsolutePath() ) : "";
_scalacOptions = _scalacOptions + SPACE + quoteArgument( arg );
addScalacArgs = addScalacArgs + PIPE + arg;

Expand All @@ -305,17 +311,19 @@ else if ( "2.13".equals( resolvedScalaVersion ) || resolvedScalaVersion.startsWi
addScalacArgs = addScalacArgs + PIPE + arg;
}

if ( highlighting )
if ( highlighting && scala2 )
{
_scalacOptions = _scalacOptions + SPACE + "-Yrangepos";
addScalacArgs = addScalacArgs + PIPE + "-Yrangepos";
}

String _scalacPlugins = pluginArtifacts.stream()
.map(x -> String.format("%s:%s:%s", x.getGroupId(), x.getArtifactId(),x.getVersion())).collect(Collectors.joining(" "));
String _scalacPlugins = scala2 ? pluginArtifacts.stream()
.map(x -> String.format("%s:%s:%s", x.getGroupId(), x.getArtifactId(), x.getVersion())).collect(Collectors.joining(" ")) : "";

arg = PLUGIN_OPTION + pluginArtifacts.stream().map(x -> x.getFile().getAbsolutePath()).collect(Collectors.joining(String.valueOf(java.io.File.pathSeparatorChar)));
addScalacArgs = addScalacArgs + PIPE + arg;
if ( scala2 ) {
arg = PLUGIN_OPTION + pluginArtifacts.stream().map(x -> x.getFile().getAbsolutePath()).collect(Collectors.joining(String.valueOf(java.io.File.pathSeparatorChar)));
addScalacArgs = addScalacArgs + PIPE + arg;
}

Properties projectProperties = project.getProperties();

Expand Down Expand Up @@ -358,9 +366,11 @@ else if ( "2.13".equals( resolvedScalaVersion ) || resolvedScalaVersion.startsWi
// Private utility methods

private static final String SCALA_LIBRARY_GROUP_ID = "org.scala-lang";
private static final String SCALA_LIBRARY_ARTIFACT_ID = "scala-library";
private static final String SCALA2_LIBRARY_ARTIFACT_ID = "scala-library";
private static final String SCALA3_LIBRARY_ARTIFACT_ID = "scala3-library_3";

private static final String DATA_DIR_OPTION = "-P:scoverage:dataDir:";
private static final String SCALA2_DATA_DIR_OPTION = "-P:scoverage:dataDir:";
private static final String SCALA3_COVERAGE_OUT_OPTION = "-coverage-out:";
private static final String SOURCE_ROOT_OPTION = "-P:scoverage:sourceRoot:";
private static final String EXCLUDED_PACKAGES_OPTION = "-P:scoverage:excludedPackages:";
private static final String EXCLUDED_FILES_OPTION = "-P:scoverage:excludedFiles:";
Expand All @@ -378,15 +388,19 @@ private String quoteArgument( String arg )
private String resolveScalaVersion()
{
String result = scalaVersion;
if ( result == null )
if ( result == null || result.isEmpty() )
{
// check project direct dependencies (transitive dependencies cannot be checked in this Maven lifecycle phase)
@SuppressWarnings( "unchecked" )
List<Dependency> dependencies = project.getDependencies();
for ( Dependency dependency: dependencies )
{
if ( SCALA_LIBRARY_GROUP_ID.equals( dependency.getGroupId() )
&& SCALA_LIBRARY_ARTIFACT_ID.equals( dependency.getArtifactId() ) )
&& (
SCALA2_LIBRARY_ARTIFACT_ID.equals( dependency.getArtifactId() ) ||
SCALA3_LIBRARY_ARTIFACT_ID.equals( dependency.getArtifactId() )
)
)
{
result = dependency.getVersion();
break;
Expand Down Expand Up @@ -428,22 +442,25 @@ private ArtifactVersion getScalacPluginVersion() {
}
}

private List<Artifact> getScalaScoveragePluginArtifacts(String resolvedScalaVersion, String scalaMainVersion )
private List<Artifact> getScalaScoveragePluginArtifacts( String resolvedScalaVersion, String scalaBinaryVersion, boolean scala2 )
throws ArtifactNotFoundException, ArtifactResolutionException
{
String resolvedScalacPluginVersion = getScalacPluginVersion().toString();
List<Artifact> resolvedArtifacts = new ArrayList<>();
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-plugin_" + resolvedScalaVersion, resolvedScalacPluginVersion));
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-domain_" + scalaMainVersion, resolvedScalacPluginVersion));
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-serializer_" + scalaMainVersion, resolvedScalacPluginVersion));
if ( scala2 ) // Scala 3 doesn't need scalac-scoverage-plugin
{
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-plugin_" + resolvedScalaVersion, resolvedScalacPluginVersion));
}
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-domain_" + scalaBinaryVersion, resolvedScalacPluginVersion));
resolvedArtifacts.add(getResolvedArtifact("org.scoverage", "scalac-scoverage-serializer_" + scalaBinaryVersion, resolvedScalacPluginVersion));
return resolvedArtifacts;
}

private Artifact getScalaScoverageRuntimeArtifact( String scalaMainVersion )
private Artifact getScalaScoverageRuntimeArtifact( String scalaBinaryVersion )
throws ArtifactNotFoundException, ArtifactResolutionException
{
return getResolvedArtifact(
"org.scoverage", "scalac-scoverage-runtime_" + scalaMainVersion,
"org.scoverage", "scalac-scoverage-runtime_" + scalaBinaryVersion,
getScalacPluginVersion().toString() );
}

Expand Down