Skip to content

Commit

Permalink
Fix JaCoCo aggregation (#62)
Browse files Browse the repository at this point in the history
* Exclude external libraries from jacocoAggregation plugin source sets

* Upgrade build to Gradle 7

* Support Gradle 8 jacocoAggregation plugin

* Fix jacocoAggregation example
  • Loading branch information
daniel-shuy authored Jun 23, 2023
1 parent fe4166d commit 580c3e9
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 32 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,13 @@ and specify the output file in the `coverallsJacoco` config.

```kotlin
coverallsJacoco {
reportPath = "code-coverage-report/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml"
reportPath = "build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml"
}
```

The `jacoco-report-aggregation` plugin must be configured in the same project as this plugin, regardless whether it is
configured in the root project or a standalone utility subproject.

## (Not Recommended) Multi-Project Support - Pure Kotlin/Java
To consolidate multiple JaCoCo coverage reports, the following code can be used to add a new task `codeCoverageReport`
```kotlin
Expand Down
5 changes: 4 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ buildscript {
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
languageVersion = "1.4"
}
}

Expand Down Expand Up @@ -105,6 +104,10 @@ tasks {
}
}

tasks.coverallsJacoco {
mustRunAfter("jacocoTestReport")
}

plugins {
idea
jacoco
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
object Versions {
const val kotlin = "1.4.21"
const val kotlin = "1.8.22"
const val kotlinxCoroutines = "1.4.2"

const val dom4j = "2.1.1"
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 2 additions & 3 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#Thu Jul 09 14:22:53 CEST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 2 additions & 0 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ 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
Expand Down Expand Up @@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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
Expand Down
25 changes: 7 additions & 18 deletions gradlew.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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.
Expand All @@ -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%
Expand All @@ -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
Expand Down
36 changes: 31 additions & 5 deletions src/main/kotlin/SourceReportParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import org.apache.log4j.LogManager
import org.apache.log4j.Logger
import org.dom4j.io.SAXReader
import org.gradle.api.Project
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.VerificationType
import org.gradle.api.tasks.SourceSetContainer
import java.io.File
import java.math.BigInteger
Expand Down Expand Up @@ -68,15 +72,37 @@ object SourceReportParser {
fun parse(project: Project): List<SourceReport> {
val pluginExtension = project.extensions.getByType(CoverallsJacocoPluginExtension::class.java)

// if sources are not specified, then lookup android source sets, or if jacocoAggregate plugin is present,
// if sources are not specified, then lookup android source sets, or if jacocoAggregation plugin is present,
// else fallback to main source set
val sourceDirs = if (pluginExtension.reportSourceSets.count() == 0) {
if (hasAndroidExtension) {
if (hasAndroidExtension) { // android source set
project.extensions.findByType(BaseAppModuleExtension::class.java)!!.sourceSets
.getByName("main").java.srcDirs.filterNotNull()
} else project.configurations.findByName("allCodeCoverageReportSourceDirectories")?.files
?: project.extensions.getByType(SourceSetContainer::class.java)
.getByName("main").allJava.srcDirs.filterNotNull()
} else // jacocoAggregation plugin
// Gradle 7
project.configurations.findByName("allCodeCoverageReportSourceDirectories")
?.incoming?.artifactView { view -> view
.componentFilter { it is ProjectComponentIdentifier }
.lenient(true)
}?.files?.files
// Gradle 8+
?: project.configurations.findByName("aggregateCodeCoverageReportResults")
?.incoming?.artifactView { view ->
val objects = project.objects
view.withVariantReselection()
view.componentFilter { it is ProjectComponentIdentifier}
view.attributes { attributes -> attributes
.attribute(Bundling.BUNDLING_ATTRIBUTE,
objects.named(Bundling::class.java, Bundling.EXTERNAL))
.attribute(Category.CATEGORY_ATTRIBUTE,
objects.named(Category::class.java, Category.VERIFICATION))
.attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE,
objects.named(VerificationType::class.java, VerificationType.MAIN_SOURCES))
}
}?.files?.files
// main source set
?: project.extensions.getByType(SourceSetContainer::class.java)
.getByName("main").allJava.srcDirs.filterNotNull()
} else {
pluginExtension.reportSourceSets.toList()
}
Expand Down
106 changes: 103 additions & 3 deletions src/test/kotlin/SourceReportParserTest.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package org.gradle.plugin.coveralls.jacoco

import io.mockk.every
import io.mockk.invoke
import io.mockk.mockk
import io.mockk.slot
import io.mockk.verify
import org.gradle.api.Action
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.artifacts.ArtifactView
import org.gradle.api.artifacts.ArtifactView.ViewConfiguration
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.VerificationType
import org.gradle.api.tasks.SourceSetContainer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -184,12 +195,101 @@ internal class SourceReportParserTest {
}

@Test
fun `SourceReportParser uses jacocoAggregation provided source sets and parses jacoco report`() {
fun `SourceReportParser uses Gradle 7 jacocoAggregation provided source sets and parses jacoco report`() {
val project = mockk<Project> {
every { rootDir } returns File("src/test/resources/testrepo")
every { configurations.findByName("allCodeCoverageReportSourceDirectories") } returns mockk {
every { files } returns setOf( testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional)
every { files } returns emptySet()
every { incoming } returns mockk {
val artifactViewConfigAction = slot<Action<ViewConfiguration>>()
every {
artifactView(capture(artifactViewConfigAction))
} answers {
artifactViewConfigAction.captured.execute(mockk {
every { componentFilter(any()) } returns this
every { lenient(true) } returns this
})
mockk {
every { files } returns mockk {
every { files } returns setOf( testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional)
}
}
}
}
}
every { extensions.getByType(CoverallsJacocoPluginExtension::class.java) } returns mockk {
every { reportPath } returns testReport.path
every { reportSourceSets } returns emptySet()
}
}

val actual = SourceReportParser.parse(project)
val expected = listOf(
SourceReport(
"src/main/kotlin/Main.kt",
"36083cd4c2ac736f9210fd3ed23504b5",
listOf(null, null, null, null, 1, 1, 1, 1, null, 1, 1, 0, 0, 1, 1, null, 1, 1, 1)
),
SourceReport(
"src/main/kotlin/internal/Util.kt",
"805ee340f4d661be591b4eb42f6164d2",
listOf(null, null, null, null, 1, 1, 1, null, null)
),
SourceReport(
"src/anotherMain/kotlin/Lib.kt",
"8b5c1c773cf81996efc19a08f0ac3648",
listOf(null, null, null, null, 1, 1, 1, null, null, null, null, null, null)
)
)
assertEquals(expected, actual)
}

@Test
fun `SourceReportParser uses Gradle 8+ jacocoAggregation provided source sets and parses jacoco report`() {
val project = mockk<Project> {
every { rootDir } returns File("src/test/resources/testrepo")
val bundling = mockk<Bundling>()
val category = mockk<Category>()
val verificationType = mockk<VerificationType>()
every { objects } returns mockk {
every { named(Bundling::class.java, Bundling.EXTERNAL) } returns bundling
every { named(Category::class.java, Category.VERIFICATION) } returns category
every { named(VerificationType::class.java, VerificationType.MAIN_SOURCES) } returns verificationType
}
every { configurations.findByName("allCodeCoverageReportSourceDirectories") } returns null
every { configurations.findByName("aggregateCodeCoverageReportResults") } returns mockk {
every { files } returns emptySet()
every { incoming } returns mockk {
val artifactViewConfigAction = slot<Action<ViewConfiguration>>()
every {
artifactView(capture(artifactViewConfigAction))
} answers {
artifactViewConfigAction.captured.execute(mockk ArtifactViewConfig@ {
every { withVariantReselection() } returns this
every { componentFilter(any()) } returns this
val attributeContainerAction = slot<Action<AttributeContainer>>()
every {
attributes(capture(attributeContainerAction))
} answers {
attributeContainerAction.captured.execute(mockk {
every { attribute(Bundling.BUNDLING_ATTRIBUTE, bundling) } returns this
every { attribute(Category.CATEGORY_ATTRIBUTE, category) } returns this
every {
attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, verificationType)
} returns this
})
this@ArtifactViewConfig
}
})
mockk {
every { files } returns mockk {
every { files } returns setOf( testKotlinStyleSourceDir,
testKotlinStyleSourceDirAdditional)
}
}
}
}
}
every { extensions.getByType(CoverallsJacocoPluginExtension::class.java) } returns mockk {
every { reportPath } returns testReport.path
Expand Down

0 comments on commit 580c3e9

Please sign in to comment.