diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 37bbdbf..a8189eb 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -11,8 +11,19 @@ on: jobs: build: + strategy: + fail-fast: false + matrix: + include: + - name: 'ignore warnings' + additional-check-args: '' + continue-on-error: false + - name: 'fail on warning' + additional-check-args: '--warning-mode=fail -PfailOnWarning' + continue-on-error: true runs-on: ubuntu-latest + continue-on-error: ${{ matrix.continue-on-error }} steps: - uses: actions/checkout@v2 @@ -24,4 +35,4 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew --info --stacktrace check + run: ./gradlew --info --stacktrace check ${{ matrix.additional-check-args }} diff --git a/build.gradle b/build.gradle index abbc5eb..8e122bd 100644 --- a/build.gradle +++ b/build.gradle @@ -104,6 +104,8 @@ task functionalTest(type: Test) { showStandardStreams = System.env.CI == 'true' } + systemProperty 'failOnWarning', project.hasProperty('failOnWarning') + mustRunAfter crossScalaVersionTest } check.dependsOn functionalTest @@ -206,4 +208,4 @@ idea.project.settings { taskTriggers { beforeBuild fixIdeaPluginClasspath, pluginUnderTestMetadata } -} \ No newline at end of file +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 69a9715..ffed3a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index b0d6d0a..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,13 +1,13 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,84 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 15e1ee3..ac1b06f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -5,7 +5,7 @@ @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem -@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java index e6c3bf3..a7b7e5b 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaCrossVersionAggregationTest.java @@ -30,7 +30,7 @@ public void checkAndAggregateAll() throws Exception { private void assertAggregationFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_12/src/main/scala/org/hello/World2_12.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "2_13/src/main/scala/org/hello/World2_13.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World2_12.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World2_13.scala.html").exists()); } } diff --git a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java index 55a15c8..657ca8e 100644 --- a/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java +++ b/src/crossScalaVersionTest/java/org/scoverage/ScalaVersionTest.java @@ -27,6 +27,6 @@ public void report() throws Exception { File reportDir = reportDir(projectDir().toPath().resolve(scalaVersion).toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/World" + scalaVersion + ".scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/World" + scalaVersion + ".scala.html").exists()); } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java index ba82eae..c4c2e38 100644 --- a/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaJavaAnnotationProcessorTest.java @@ -44,13 +44,13 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScala.scala.html").exists()); } private void assertMixedScalaJavaReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScala.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java index 8a35add..2b09933 100644 --- a/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaJavaMultiModuleTest.java @@ -46,21 +46,21 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "scala_only/src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "mixed_scala_java/src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScalaOnly.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/WorldScala.scala.html").exists()); } private void assertScalaOnlyReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("scala_only").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScalaOnly.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScalaOnly.scala.html").exists()); } private void assertMixedScalaJavaReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("mixed_scala_java").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/WorldScala.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/WorldScala.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java index 87f5c02..5da6f60 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleTest.java @@ -297,35 +297,35 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/common/WorldCommon.scala.html").exists()); } private void assertRootReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } private void assertAReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/a/WorldA.scala.html").exists()); } private void assertBReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/b/WorldB.scala.html").exists()); } private void assertCommonReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/common/WorldCommon.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java index 49d0bc1..dc84e1f 100644 --- a/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaMultiModuleWithMultipleTestTasksTest.java @@ -294,35 +294,35 @@ private void assertAllReportFilesExist() { private void assertAggregationFilesExist() { - Assert.assertTrue(resolve(reportDir(), "a/src/main/scala/org/hello/a/WorldA.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "b/src/main/scala/org/hello/b/WorldB.scala.html").exists()); - Assert.assertTrue(resolve(reportDir(), "common/src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/common/WorldCommon.scala.html").exists()); } private void assertRootReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } private void assertAReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("a").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/a/WorldA.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/a/WorldA.scala.html").exists()); } private void assertBReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("b").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/b/WorldB.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/b/WorldB.scala.html").exists()); } private void assertCommonReportFilesExist() { File reportDir = reportDir(projectDir().toPath().resolve("common").toFile()); Assert.assertTrue(resolve(reportDir, "index.html").exists()); - Assert.assertTrue(resolve(reportDir, "src/main/scala/org/hello/common/WorldCommon.scala.html").exists()); + Assert.assertTrue(resolve(reportDir, "org/hello/common/WorldCommon.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java index de9da68..19e0e82 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleTest.java @@ -91,7 +91,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -125,7 +125,7 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -136,6 +136,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java index e7f701a..3ce3b63 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithDependencyManagerTest.java @@ -26,6 +26,6 @@ public void checkScoverage() throws Exception { private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } -} \ No newline at end of file +} diff --git a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java index 0511eb5..cba1c6a 100644 --- a/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java +++ b/src/functionalTest/java/org/scoverage/ScalaSingleModuleWithMultipleTestTasksTest.java @@ -109,7 +109,7 @@ public void reportScoverageWithExcludedClasses() throws Exception { result.assertTaskDoesntExist(ScoveragePlugin.getAGGREGATE_NAME()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -143,7 +143,7 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro "-PexcludedFile=.*", "-P" + ScoveragePlugin.getSCOVERAGE_COMPILE_ONLY_PROPERTY()); Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertFalse(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertFalse(resolve(reportDir(), "org/hello/World.scala.html").exists()); assertCoverage(100.0); // coverage is 100 since no classes are covered // compiled class should exist in the default classes directory, but not in scoverage @@ -155,6 +155,6 @@ public void reportScoverageWithoutNormalCompilationAndWithExcludedClasses() thro private void assertReportFilesExist() { Assert.assertTrue(resolve(reportDir(), "index.html").exists()); - Assert.assertTrue(resolve(reportDir(), "src/main/scala/org/hello/World.scala.html").exists()); + Assert.assertTrue(resolve(reportDir(), "org/hello/World.scala.html").exists()); } } diff --git a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java index e08d1e5..051b6bb 100644 --- a/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java +++ b/src/functionalTest/java/org/scoverage/ScoverageFunctionalTest.java @@ -127,7 +127,11 @@ private void configureArguments(String... arguments) { fullArguments.add("-PjunitVersion=5.3.2"); fullArguments.add("-PjunitPlatformVersion=1.3.2"); fullArguments.add("-PscalatestVersion=3.0.8"); - fullArguments.add("--warning-mode=all"); + if (Boolean.parseBoolean(System.getProperty("failOnWarning"))) { + fullArguments.add("--warning-mode=fail"); + } else { + fullArguments.add("--warning-mode=all"); + } fullArguments.addAll(Arrays.asList(arguments)); runner.withArguments(fullArguments); diff --git a/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle index 9e5797f..c67b12d 100644 --- a/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle +++ b/src/functionalTest/resources/projects/scala-java-annotation-processor/build.gradle @@ -6,7 +6,7 @@ description = 'a multi-module Scala and Java project using a Java annotation pro allprojects { repositories { - jcenter() + mavenCentral() } } diff --git a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy index b445e29..9815dd1 100644 --- a/src/main/groovy/org/scoverage/ScoverageAggregate.groovy +++ b/src/main/groovy/org/scoverage/ScoverageAggregate.groovy @@ -1,19 +1,28 @@ package org.scoverage import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles 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 static org.gradle.api.tasks.PathSensitivity.RELATIVE + class ScoverageAggregate extends DefaultTask { @Nested ScoverageRunner runner + @InputFiles + @PathSensitive(RELATIVE) + final Property sources = project.objects.property(FileCollection) + @OutputDirectory final Property reportDir = project.objects.property(File) @@ -52,7 +61,7 @@ class ScoverageAggregate extends DefaultTask { if (coverage.nonEmpty()) { new ScoverageWriter(project.logger).write( - project.projectDir, + sources.get().getFiles(), reportDir.get(), coverage.get(), sourceEncoding.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageExtension.groovy b/src/main/groovy/org/scoverage/ScoverageExtension.groovy index e106306..210a825 100644 --- a/src/main/groovy/org/scoverage/ScoverageExtension.groovy +++ b/src/main/groovy/org/scoverage/ScoverageExtension.groovy @@ -28,8 +28,6 @@ class ScoverageExtension { final Property dataDir /** a directory to write final output to */ final Property reportDir - /** sources to highlight */ - final Property sources /** range positioning for highlighting */ final Property highlighting /** regex for each excluded package */ @@ -61,9 +59,6 @@ class ScoverageExtension { scoverageScalaVersion = project.objects.property(String) - sources = project.objects.property(File) - sources.set(project.projectDir) - dataDir = project.objects.property(File) dataDir.set(new File(project.buildDir, 'scoverage')) diff --git a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy index ae5d68e..4f1ba18 100644 --- a/src/main/groovy/org/scoverage/ScoveragePlugin.groovy +++ b/src/main/groovy/org/scoverage/ScoveragePlugin.groovy @@ -29,7 +29,8 @@ class ScoveragePlugin implements Plugin { static final String DEFAULT_REPORT_DIR = 'reports' + File.separatorChar + 'scoverage' - private final ConcurrentHashMap> taskDependencies = new ConcurrentHashMap<>() + private final ConcurrentHashMap> crossProjectTaskDependencies = new ConcurrentHashMap<>() + private final ConcurrentHashMap> sameProjectTaskDependencies = new ConcurrentHashMap<>() @Override void apply(PluginAware pluginAware) { @@ -124,7 +125,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = taskReportDir - sources = extension.sources + sources = originalSourceSet.scala.getSourceDirectories() dataDir = extension.dataDir sourceEncoding.set(detectedSourceEncoding) coverageOutputCobertura = extension.coverageOutputCobertura @@ -143,6 +144,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sources = originalSourceSet.scala.getSourceDirectories() dirsToAggregateFrom = dataDirs sourceEncoding.set(detectedSourceEncoding) deleteReportsOnAggregation = false @@ -194,11 +196,16 @@ class ScoveragePlugin implements Plugin { originalCompileTask.enabled = false; compileTask.destinationDirectory = originalCompileTask.destinationDirectory - originalJarTask.mustRunAfter(compileTask) + + project.getTasks().each { + if (recursiveDependenciesOf(it, true).contains(originalCompileTask)) { + it.dependsOn(compileTask) + } + } // make this project's scoverage compilation depend on scoverage compilation of any other project // which this project depends on its normal compilation - def originalCompilationDependencies = recursiveDependenciesOf(compileTask).findAll { + def originalCompilationDependencies = recursiveDependenciesOf(compileTask, false).findAll { it instanceof ScalaCompile } originalCompilationDependencies.each { @@ -299,6 +306,10 @@ class ScoveragePlugin implements Plugin { } } def allReportTasks = childReportTasks + globalReportTask.get() + def allSources = project.objects.fileCollection() + allReportTasks.each { + allSources = allSources.plus(it.sources.get()) + } def aggregationTask = project.tasks.create(AGGREGATE_NAME, ScoverageAggregate) { def dataDirs = allReportTasks.findResults { it.dirsToAggregateFrom.get() }.flatten() onlyIf { @@ -308,6 +319,7 @@ class ScoveragePlugin implements Plugin { group = 'verification' runner = scoverageRunner reportDir = extension.reportDir + sources = allSources sourceEncoding.set(detectedSourceEncoding) dirsToAggregateFrom = dataDirs deleteReportsOnAggregation = extension.deleteReportsOnAggregation @@ -376,16 +388,22 @@ class ScoveragePlugin implements Plugin { } } - private Set recursiveDependenciesOf(Task task) { - if (!taskDependencies.containsKey(task)) { + private Set recursiveDependenciesOf(Task task, boolean sameProjectOnly) { + def cache = sameProjectOnly ? sameProjectTaskDependencies : crossProjectTaskDependencies + if (!cache.containsKey(task)) { def directDependencies = task.getTaskDependencies().getDependencies(task) - def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it) }.flatten() + if (sameProjectOnly) { + directDependencies = directDependencies.findAll { + it.project == task.project + } + } + def nestedDependencies = directDependencies.collect { recursiveDependenciesOf(it, sameProjectOnly) }.flatten() def dependencies = directDependencies + nestedDependencies - taskDependencies.put(task, dependencies) + cache.put(task, dependencies) return dependencies } else { - return taskDependencies.get(task) + return cache.get(task) } } } diff --git a/src/main/groovy/org/scoverage/ScoverageReport.groovy b/src/main/groovy/org/scoverage/ScoverageReport.groovy index e95f547..8a15aab 100644 --- a/src/main/groovy/org/scoverage/ScoverageReport.groovy +++ b/src/main/groovy/org/scoverage/ScoverageReport.groovy @@ -1,10 +1,12 @@ package org.scoverage import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.PathSensitive @@ -23,9 +25,9 @@ class ScoverageReport extends DefaultTask { @PathSensitive(RELATIVE) final Property dataDir = project.objects.property(File) - @InputDirectory + @InputFiles @PathSensitive(RELATIVE) - final Property sources = project.objects.property(File) + final Property sources = project.objects.property(FileCollection) @OutputDirectory final Property reportDir = project.objects.property(File) @@ -54,7 +56,7 @@ class ScoverageReport extends DefaultTask { project.logger.info("[scoverage] Could not find coverage file, skipping...") } else { new ScoverageWriter(project.logger).write( - sources.get(), + sources.get().getFiles(), reportDir.get(), coverage.get(), sourceEncoding.get(), diff --git a/src/main/groovy/org/scoverage/ScoverageWriter.java b/src/main/groovy/org/scoverage/ScoverageWriter.java index 2f95a51..1e09105 100644 --- a/src/main/groovy/org/scoverage/ScoverageWriter.java +++ b/src/main/groovy/org/scoverage/ScoverageWriter.java @@ -1,14 +1,23 @@ package org.scoverage; import org.gradle.api.logging.Logger; +import scala.Option; 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 scala.collection.JavaConverters; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Set; /** * Util for generating and saving coverage files. @@ -26,7 +35,7 @@ public ScoverageWriter(Logger logger) { /** * Generates all reports from given data. * - * @param sourceDir directory with project sources + * @param sourceDirs directories with project sources * @param reportDir directory for generate reports * @param coverage coverage data * @param sourceEncoding the encoding of the source files @@ -35,21 +44,33 @@ public ScoverageWriter(Logger logger) { * @param coverageOutputHTML switch for Scoverage HTML output * @param coverageDebug switch for Scoverage Debug output */ - public void write(File sourceDir, + public void write(Set sourceDirs, File reportDir, Coverage coverage, String sourceEncoding, Boolean coverageOutputCobertura, Boolean coverageOutputXML, Boolean coverageOutputHTML, - Boolean coverageDebug) { + Boolean coverageDebug) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { logger.info("[scoverage] Generating scoverage reports..."); reportDir.mkdirs(); + Object scalaBuffer = Class.forName("scala.collection.JavaConverters") + .getMethod("asScalaBuffer", java.util.List.class) + .invoke(null, new ArrayList<>(sourceDirs)); + Object sourceDirsSeq = scalaBuffer.getClass().getMethod("toIndexedSeq").invoke(scalaBuffer); + if (coverageOutputCobertura) { - new CoberturaXmlWriter(sourceDir, reportDir).write(coverage); + Constructor cst; + try { + cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = CoberturaXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class); + } + CoberturaXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir); + writer.write(coverage); logger.info("[scoverage] Written Cobertura XML report to " + reportDir.getAbsolutePath() + File.separator + @@ -57,13 +78,21 @@ public void write(File sourceDir, } if (coverageOutputXML) { - new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ false).write(coverage); + Constructor cst; + try { + cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, boolean.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = ScoverageXmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, boolean.class); + } + ScoverageXmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, false); + writer.write(coverage); logger.info("[scoverage] Written XML report to " + reportDir.getAbsolutePath() + File.separator + Constants.XMLReportFilename()); if (coverageDebug) { - new ScoverageXmlWriter(sourceDir, reportDir, /* debug = */ true).write(coverage); + ScoverageXmlWriter writerDebug = cst.newInstance(sourceDirsSeq, reportDir, true); + writerDebug.write(coverage); logger.info("[scoverage] Written XML report with debug information to " + reportDir.getAbsolutePath() + File.separator + @@ -72,7 +101,14 @@ public void write(File sourceDir, } if (coverageOutputHTML) { - new ScoverageHtmlWriter(new File[]{sourceDir}, reportDir, new Some<>(sourceEncoding)).write(coverage); + Constructor cst; + try { + cst = ScoverageHtmlWriter.class.getConstructor(Class.forName("scala.collection.immutable.Seq"), File.class, Option.class); + } catch (NoSuchMethodException | ClassNotFoundException e) { + cst = ScoverageHtmlWriter.class.getConstructor(Class.forName("scala.collection.Seq"), File.class, Option.class); + } + ScoverageHtmlWriter writer = cst.newInstance(sourceDirsSeq, reportDir, new Some<>(sourceEncoding)); + writer.write(coverage); logger.info("[scoverage] Written HTML report to " + reportDir.getAbsolutePath() + File.separator +