[英]Gradle Multi-Project Build with JaCoCo Code Coverage fails when using Spring Boot
Starting with the sample from https://docs.gradle.org/current/samples/sample_jvm_multi_project_with_code_coverage.html (ie, the code here https://github.com/gradle/gradle/tree/master/subprojects/docs/src/samples/java/jvm-multi-project-with-code-coverage ) and simply adding Spring Boot by changing application/build.gradle
to Starting with the sample from https://docs.gradle.org/current/samples/sample_jvm_multi_project_with_code_coverage.html (ie, the code here https://github.com/gradle/gradle/tree/master/subprojects/docs/src/ samples/java/jvm-multi-project-with-code-coverage )并通过将
application/build.gradle
更改为简单地添加 Spring Boot
plugins {
id 'myproject.java-conventions'
id 'application'
}
dependencies {
implementation project(':list')
implementation project(':utilities')
implementation 'org.springframework.boot:spring-boot-starter-web:2.3.8.RELEASE' // <-- this line is new
}
application {
mainClass = 'org.gradle.sample.Main'
}
and changing application/src/main/java/org/gradle/sample/app/Main.java
to并将
application/src/main/java/org/gradle/sample/app/Main.java
为
package org.gradle.sample.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.gradle.sample.list.LinkedList;
import static org.gradle.sample.utilities.StringUtils.join;
import static org.gradle.sample.utilities.StringUtils.split;
import static org.gradle.sample.app.MessageUtils.getMessage;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
LinkedList tokens;
tokens = split(getMessage());
System.out.println(join(tokens));
SpringApplication.run(Main.class, args);
}
}
will break the example (full working, or rather non-working example here: https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage/tree/57e57b8bf24ef4208d9a03a361714c916701e599 ).将打破这个例子(完整的工作,或者更确切地说是非工作的例子: https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage/tree/57e57b8bf24ef4208d9a03a361714c916701e599 )。
When calling打电话时
./gradlew clean build codeCoverage -stacktrace
it will fail with它会失败
> Task :code-coverage-report:codeCoverageReport FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':code-coverage-report:codeCoverageReport'.
> Error while creating report
* Try:
Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':code-coverage-report:codeCoverageReport'.
[...]
Caused by: java.io.IOException: Error while analyzing log4j-api-2.13.3.jar@org/apache/logging/log4j/util/ProcessIdUtil.class.
at org.jacoco.core.analysis.Analyzer.analyzerError(Analyzer.java:162)
at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:134)
at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:157)
at org.jacoco.core.analysis.Analyzer.analyzeAll(Analyzer.java:193)
at org.jacoco.core.analysis.Analyzer.analyzeZip(Analyzer.java:265)
at org.jacoco.core.analysis.Analyzer.analyzeAll(Analyzer.java:196)
at org.jacoco.ant.ReportTask.createBundle(ReportTask.java:573)
at org.jacoco.ant.ReportTask.createReport(ReportTask.java:545)
at org.jacoco.ant.ReportTask.execute(ReportTask.java:496)
... 251 more
Caused by: java.lang.IllegalStateException: Can't add different class with same name: org/apache/logging/log4j/util/ProcessIdUtil
at org.jacoco.core.analysis.CoverageBuilder.visitCoverage(CoverageBuilder.java:106)
at org.jacoco.core.analysis.Analyzer$1.visitEnd(Analyzer.java:99)
at org.objectweb.asm.ClassVisitor.visitEnd(ClassVisitor.java:378)
at org.jacoco.core.internal.flow.ClassProbesAdapter.visitEnd(ClassProbesAdapter.java:100)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:722)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:401)
at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:116)
at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:132)
... 258 more
* Get more help at https://help.gradle.org
BUILD FAILED in 8s
19 actionable tasks: 19 executed
I have a suspicion that this may be related to https://github.com/jacoco/jacoco/issues/407 .我怀疑这可能与https://github.com/jacoco/jacoco/issues/407有关。 However, my question is whether there is any way to fix this problem.
但是,我的问题是是否有任何方法可以解决此问题。 Unfortunately, the official documentation at https://docs.gradle.org/current/userguide/jacoco_plugin.html does not provide any guidance on this topic.
不幸的是, https://docs.gradle.org/current/userguide/jacoco_plugin.html的官方文档没有提供关于这个主题的任何指导。
As far as I can tell, the problematic line is https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage/blob/57e57b8bf24ef4208d9a03a361714c916701e599/buildSrc/src/main/groovy/myproject.jacoco-aggregation.gradle#L38据我所知,有问题的行是https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage/blob/57e57b8bf24ef4208d9a03a361714c916701e599/buildSrc/scorc/main/groovyproject。 -aggregation.gradle#L38
// Task to gather code coverage from multiple subprojects
def codeCoverageReport = tasks.register('codeCoverageReport', JacocoReport) {
additionalClassDirs(configurations.runtimeClasspath) // <-- this line here
additionalSourceDirs(sourcesPath.incoming.artifactView { lenient(true) }.files)
executionData(coverageDataPath.incoming.artifactView { lenient(true) }.files.filter { it.exists() })
reports {
// xml is usually used to integrate code coverage with
// other tools like SonarQube, Coveralls or Codecov
xml.enabled true
// HTML reports can be used to see code coverage
// without any external tools
html.enabled true
}
}
Removing it will make the build work again.删除它将使构建再次工作。 However, then the code coverage report is empty.
但是,代码覆盖率报告是空的。 Is there any way to adjust it, so it will only include code from the project itself, but not external jars, etc.?
有没有办法调整它,所以它只会包含来自项目本身的代码,而不包含外部 jars 等?
Just do that and you will be fine (all external classes will be excluded):只要这样做,你会没事的(所有外部类都将被排除在外):
additionalClassDirs(configurations.runtimeClasspath.get().filter{it.path.contains(rootProject.name) })
This works with a Kotlin DSL, with Groovy you might have to change the code a little bit maybe this way:这适用于 Kotlin DSL,对于 Groovy,您可能需要通过以下方式稍微更改代码:
additionalClassDirs(configurations.runtimeClasspath.filter{it.path.contains(rootProject.name) })
One possible approach is to define一种可能的方法是定义
def sourcesOutputPath = configurations.create("sourcesOutputPath") {
visible = false
canBeResolved = true
canBeConsumed = false
extendsFrom(configurations.implementation)
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, 'source-output-folders'))
}
}
and then use it in然后在
additionalClassDirs(sourcesOutputPath.incoming.artifactView { lenient(true) }.files)
instead of代替
additionalClassDirs(configurations.runtimeClasspath)
A full, working setup can be found in https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage在https://github.com/SamuelBucheliZ/gradle-jvm-multi-project-with-code-coverage中可以找到完整的工作设置
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.