diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/publishers/JacocoReportPublisher.java b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/publishers/JacocoReportPublisher.java index 3cb41e04..7557e9cf 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/publishers/JacocoReportPublisher.java +++ b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/publishers/JacocoReportPublisher.java @@ -40,9 +40,13 @@ import org.w3c.dom.Element; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -128,12 +132,8 @@ public void process(@Nonnull StepContext context, @Nonnull Element mavenSpyLogsE if (jacocoPrepareAgentEvents.isEmpty()) { LOGGER.log(Level.FINE, "No org.jacoco:jacoco-maven-plugin:prepare-agent execution found"); return; - } else if (jacocoPrepareAgentEvents.size() > 1) { // JENKINS-54139 - if (LOGGER.isLoggable(Level.FINE)) - listener.getLogger().print("[withMaven - Jacoco] More than 1 Maven module (" + jacocoPrepareAgentEvents.size() + ") generated a Jacoco code coverage report, " + - "skip automatic collect of Jacoco reports as the Jenkins Jacoco report is not designed to render multiple reports per build"); - return; } + try { Class.forName("hudson.plugins.jacoco.JacocoPublisher"); } catch (ClassNotFoundException e) { @@ -143,6 +143,7 @@ public void process(@Nonnull StepContext context, @Nonnull Element mavenSpyLogsE return; } + List jacocoReportDetails = new ArrayList<>(); for (Element jacocoPrepareAgentEvent : jacocoPrepareAgentEvents) { @@ -200,24 +201,54 @@ public void process(@Nonnull StepContext context, @Nonnull Element mavenSpyLogsE listener.getLogger().println("[withMaven] jacocoPublisher - Archive JaCoCo analysis results for Maven artifact " + mavenArtifact.toString() + " generated by " + pluginInvocation + ": execFile: " + destFile + ", sources: " + sourceDirectoryRelativePath + ", classes: " + classesDirectoryRelativePath); - JacocoPublisher jacocoPublisher = new JacocoPublisher(); - - jacocoPublisher.setExecPattern(destFile); - jacocoPublisher.setSourcePattern(sourceDirectoryRelativePath); - jacocoPublisher.setClassPattern(classesDirectoryRelativePath); - - try { - jacocoPublisher.perform(run, workspace, launcher, listener); - } catch (Exception e) { - listener.error("[withMaven] jacocoPublisher - Silently ignore exception archiving JaCoCo results for Maven artifact " + mavenArtifact.toString() + " generated by " + - pluginInvocation + ": " + e); - LOGGER.log(Level.WARNING, "Exception processing " + XmlUtils.toString(jacocoPrepareAgentEvent), e); + jacocoReportDetails.add(new JacocoReportDetails(destFile, sourceDirectoryRelativePath, classesDirectoryRelativePath, mavenArtifact.toString() + " " + pluginInvocation)); + } + + JacocoPublisher jacocoPublisher = new JacocoPublisher(); + + String aggregatedDestFile = jacocoReportDetails.stream().map(details -> details.execFile).collect(Collectors.joining(",")); + String aggregatedSourceDirectory = jacocoReportDetails.stream().map(details -> details.sourceDirectory).collect(Collectors.joining(",")); + String aggregatedClassesDirectory = jacocoReportDetails.stream().map(details -> details.classesDirectory).collect(Collectors.joining(",")); + + jacocoPublisher.setExecPattern(aggregatedDestFile); + jacocoPublisher.setSourcePattern(aggregatedSourceDirectory); + jacocoPublisher.setClassPattern(aggregatedClassesDirectory); + + try { + jacocoPublisher.perform(run, workspace, launcher, listener); + } catch (Exception e) { + listener.error("[withMaven] jacocoPublisher - Silently ignore exception archiving JaCoCo results for " + jacocoReportDetails); + listener.error("[withMaven] jacocoPublisher - Silently ignore exception archiving JaCoCo results: " + e); + + if (LOGGER.isLoggable(Level.FINE)) { + StringWriter buffer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(buffer); + e.printStackTrace(printWriter); + listener.error(buffer.toString()); } + } + } + + public static class JacocoReportDetails { + final String execFile, sourceDirectory, classesDirectory, description; + public JacocoReportDetails(String execFile, String sourceDirectory, String classesDirectory, String description) { + this.execFile = execFile; + this.sourceDirectory = sourceDirectory; + this.classesDirectory = classesDirectory; + this.description = description; } + @Override + public String toString() { + return "JacocoReportDetails{" + + "execFile='" + execFile + '\'' + + ", sourceDirectory='" + sourceDirectory + '\'' + + ", classesDirectory='" + classesDirectory + '\'' + + ", description='" + description + '\'' + + '}'; + } } - @Symbol("jacocoPublisher") @Extension public static class DescriptorImpl extends AbstractHealthAwarePublisher.DescriptorImpl { diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/WithMavenStepOnMasterTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/WithMavenStepOnMasterTest.java index f4457a42..a9ccc62b 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/WithMavenStepOnMasterTest.java +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/WithMavenStepOnMasterTest.java @@ -32,6 +32,7 @@ import java.io.File; import java.util.Collection; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.Map; @@ -183,7 +184,15 @@ public void maven_build_jar_project_on_master_succeeds() throws Exception { assertThat(tasksResultAction.getProjectActions().size(), is(1)); } - @Ignore("disable while we can't use ASM 6.x due to jenkins enforcer preventing jars supporting java 11 https://gist.github.com/cyrille-leclerc/ac2ad901c27b3b96fd3efa6ed8062f7c") + /** + * + *
+     * ERROR: [withMaven] jacocoPublisher - Silently ignore exception archiving JaCoCo results:
+     * java.io.IOException: While reading class directory: /var/folders/lq/50t8n2nx7l316pwm8gc_2rt40000gn/T/j h8464991534006021463/jobs/jar-with-jacoco/builds/1/jacoco/classes
+     * 
+ * @throws Exception + */ + @Ignore("IOException: While reading class directory: .../jacoco/classes") @Test public void maven_build_jar_with_jacoco_succeeds() throws Exception { loadMavenJarWithJacocoInGitRepo(this.gitRepoRule); @@ -205,12 +214,15 @@ public void maven_build_jar_with_jacoco_succeeds() throws Exception { verifyFileIsFingerPrinted(pipeline, build, "jenkins/mvn/test/jar-with-jacoco/0.1-SNAPSHOT/jar-with-jacoco-0.1-SNAPSHOT.jar"); verifyFileIsFingerPrinted(pipeline, build, "jenkins/mvn/test/jar-with-jacoco/0.1-SNAPSHOT/jar-with-jacoco-0.1-SNAPSHOT.pom"); - TestResultAction testResultAction = build.getAction(TestResultAction.class); - assertThat(testResultAction.getTotalCount(), is(2)); + List testResultActions = build.getActions(TestResultAction.class); + assertThat(testResultActions.size(), is(1)); + TestResultAction testResultAction = testResultActions.get(0); + assertThat(testResultAction.getTotalCount(), is(1)); assertThat(testResultAction.getFailCount(), is(0)); - // verify Task Scanner is called for jenkins.mvn.test:mono-module-maven-app - JacocoBuildAction jacocoBuildAction = build.getAction(JacocoBuildAction.class); + List jacocoBuildActions = build.getActions(JacocoBuildAction.class); + assertThat(jacocoBuildActions.size(), is(1)); + JacocoBuildAction jacocoBuildAction = jacocoBuildActions.get(0); assertThat(jacocoBuildAction.getProjectActions().size(), is(1)); }