diff options
author | Marc R. Hoffmann <hoffmann@mountainminds.com> | 2016-04-19 13:22:01 +0200 |
---|---|---|
committer | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2016-04-19 13:22:01 +0200 |
commit | c181f60ce08ec9b0a6f59a2391c33c41bca8f1c0 (patch) | |
tree | 714c1ffa8b66fde4037131aade0269f63c8a40b6 | |
parent | bac679b3ae6363f1d610e705139f0e1964b319ea (diff) | |
download | jacoco-c181f60ce08ec9b0a6f59a2391c33c41bca8f1c0.tar.gz |
GitHub #388: New Maven goal "report-aggregate" to create reports for multi-module projects
34 files changed, 1138 insertions, 393 deletions
diff --git a/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh b/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh index 7efaea9d..55935690 100644 --- a/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-multi-module/verify.bsh @@ -13,7 +13,7 @@ import java.io.*; import org.codehaus.plexus.util.*; String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) ); -if ( buildLog.indexOf( "Skipping JaCoCo execution due to missing classes directory:" ) < 0 ) { +if ( buildLog.indexOf( "Skipping JaCoCo execution due to missing classes directory." ) < 0 ) { throw new RuntimeException( "Execution should be skipped when target/classes does not exist." ); } diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml new file mode 100644 index 00000000..d65b7a63 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/pom.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Marc R. Hoffmann, Jan Wloka - initial API and implementation +--> +<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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>jacoco</groupId> + <artifactId>it-report-aggregate</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>child1-test</artifactId> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>jacoco</groupId> + <artifactId>child1</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + +</project> diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java new file mode 100644 index 00000000..2b621c63 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1-test/src/test/java/package1/Example1bTest.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package1; + +import org.junit.Test; + +public class Example1bTest { + + @Test + public void test() { + new Example1b().b(); + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml new file mode 100644 index 00000000..530e0a1a --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Marc R. Hoffmann, Jan Wloka - initial API and implementation +--> +<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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>jacoco</groupId> + <artifactId>it-report-aggregate</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>child1</artifactId> + <packaging>jar</packaging> + +</project> diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java new file mode 100644 index 00000000..99e65345 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1a.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package1; + +public class Example1a { + + public void a() { + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java new file mode 100644 index 00000000..a5741466 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/main/java/package1/Example1b.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package1; + +public class Example1b { + + public void b() { + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java new file mode 100644 index 00000000..04ffa75c --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child1/src/test/java/package1/Example1aTest.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package1; + +import org.junit.Test; + +public class Example1aTest { + + @Test + public void test() { + new Example1a().a(); + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml new file mode 100644 index 00000000..e340ca2d --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/pom.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Marc R. Hoffmann, Jan Wloka - initial API and implementation +--> +<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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>jacoco</groupId> + <artifactId>it-report-aggregate</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>child2</artifactId> + <packaging>jar</packaging> + +</project> diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java new file mode 100644 index 00000000..5895fbb9 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/main/java/package2/Example2.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package2; + +public class Example2 { + + public void a() { + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java new file mode 100644 index 00000000..f382fc2b --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/child2/src/test/java/package2/Example2Test.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package package2; + +import org.junit.Test; + +public class Example2Test { + + @Test + public void test() { + new Example2().a(); + } + +} diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml new file mode 100644 index 00000000..71b7a196 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Marc R. Hoffmann, Jan Wloka - initial API and implementation +--> +<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>jacoco</groupId> + <artifactId>setup-parent</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>it-report-aggregate</artifactId> + <packaging>pom</packaging> + + <modules> + <module>child1</module> + <module>child1-test</module> + <module>child2</module> + <module>report</module> + </modules> + + <build> + <plugins> + <plugin> + <groupId>@project.groupId@</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <executions> + <execution> + <id>prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml new file mode 100644 index 00000000..d6e6fc74 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/report/pom.xml @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Marc R. Hoffmann, Jan Wloka - initial API and implementation +--> +<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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>jacoco</groupId> + <artifactId>it-report-aggregate</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <artifactId>report</artifactId> + <name>Aggregate Report</name> + + <dependencies> + <dependency> + <groupId>jacoco</groupId> + <artifactId>child1</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>jacoco</groupId> + <artifactId>child1-test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>jacoco</groupId> + <artifactId>child2</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>@project.groupId@</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh new file mode 100644 index 00000000..32a52dc1 --- /dev/null +++ b/jacoco-maven-plugin.test/it/it-report-aggregate/verify.bsh @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +import org.codehaus.plexus.util.*; + +String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) ); + +if ( buildLog.indexOf( "/child1/target/jacoco.exec" ) < 0 ) { + throw new RuntimeException( "Execution data from child1 was not loaded." ); +} + +if ( buildLog.indexOf( "/child1-test/target/jacoco.exec" ) < 0 ) { + throw new RuntimeException( "Execution data from child1-test was not loaded." ); +} + +if ( buildLog.indexOf( "/child2/target/jacoco.exec" ) < 0 ) { + throw new RuntimeException( "Execution data from child2 was not loaded." ); +} + +File reportChild1 = new File( basedir, "report/target/site/jacoco-aggregate/child1/index.html" ); +if ( !reportChild1.isFile() ) { + throw new RuntimeException( "Report for child1 was not created." ); +} + +File reportChild1test = new File( basedir, "report/target/site/jacoco-aggregate/child1-test/index.html" ); +if ( reportChild1test.isFile() ) { + throw new RuntimeException( "Report for child1-test should not be created." ); +} + +File reportChild2 = new File( basedir, "report/target/site/jacoco-aggregate/child2/index.html" ); +if ( !reportChild2.isFile() ) { + throw new RuntimeException( "Report for child2 was not created." ); +} diff --git a/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh b/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh index 90a58a95..a53ee995 100644 --- a/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-report-unreadable-dump/verify.bsh @@ -13,6 +13,6 @@ import java.io.*; import org.codehaus.plexus.util.*; String buildLog = FileUtils.fileRead( new File( basedir, "build.log" ) ); -if ( buildLog.indexOf( "Unable to read execution data file" ) < 0 ) { +if ( buildLog.indexOf( "Invalid execution data file." ) < 0 ) { throw new RuntimeException( "Error was not printed" ); } diff --git a/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh b/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh index 00a7667c..458148bd 100644 --- a/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-site-failsafe/verify.bsh @@ -13,7 +13,7 @@ import java.io.*; import org.codehaus.plexus.util.*; String projectReportsPage = FileUtils.fileRead( new File( basedir, "target/site/project-reports.html" ) ); -if ( projectReportsPage.indexOf( "JaCoCo Test Coverage Report." ) < 0 ) { +if ( projectReportsPage.indexOf( "JaCoCo Coverage Report." ) < 0 ) { throw new RuntimeException( "project-reports.html does not contain link to JaCoCo report" ); } diff --git a/jacoco-maven-plugin.test/it/it-site/verify.bsh b/jacoco-maven-plugin.test/it/it-site/verify.bsh index f2ea8293..d1c7cd32 100644 --- a/jacoco-maven-plugin.test/it/it-site/verify.bsh +++ b/jacoco-maven-plugin.test/it/it-site/verify.bsh @@ -13,7 +13,7 @@ import java.io.*; import org.codehaus.plexus.util.*; String projectReportsPage = FileUtils.fileRead( new File( basedir, "target/site/project-reports.html" ) ); -if ( projectReportsPage.indexOf( "JaCoCo Test Coverage Report." ) < 0 ) { +if ( projectReportsPage.indexOf( "JaCoCo Coverage Report." ) < 0 ) { throw new RuntimeException( "project-reports.html does not contain link to JaCoCo report" ); } diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java index 5d9d7c1c..0db69d6e 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/AbstractReportMojo.java @@ -11,13 +11,7 @@ *******************************************************************************/ package org.jacoco.maven; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -26,19 +20,8 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.reporting.AbstractMavenReport; import org.apache.maven.reporting.MavenReportException; -import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.analysis.ICoverageNode; -import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.data.SessionInfoStore; -import org.jacoco.core.tools.ExecFileLoader; -import org.jacoco.report.FileMultiReportOutput; import org.jacoco.report.IReportGroupVisitor; import org.jacoco.report.IReportVisitor; -import org.jacoco.report.ISourceFileLocator; -import org.jacoco.report.MultiReportVisitor; -import org.jacoco.report.csv.CSVFormatter; -import org.jacoco.report.html.HTMLFormatter; -import org.jacoco.report.xml.XMLFormatter; /** * Base class for creating a code coverage report for tests of a single project @@ -53,13 +36,30 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { * default-value="UTF-8" */ String outputEncoding; + + /** + * Name of the root node HTML report pages. + * + * @parameter default-value="${project.name}" + * @since 0.7.7 + */ + String title; + + /** + * Footer text used in HTML report pages. + * + * @parameter + * @since 0.7.7 + */ + String footer; + /** * Encoding of the source files. * - * @parameter property="project.build.sourceEncoding" - * default-value="UTF-8" + * @parameter property="project.build.sourceEncoding" default-value="UTF-8" */ String sourceEncoding; + /** * A list of class files to include in the report. May use wildcard * characters (* and ?). When not specified everything will be included. @@ -67,6 +67,7 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { * @parameter */ List<String> includes; + /** * A list of class files to exclude from the report. May use wildcard * characters (* and ?). When not specified nothing will be excluded. @@ -74,12 +75,14 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { * @parameter */ List<String> excludes; + /** * Flag used to suppress execution. * * @parameter property="jacoco.skip" default-value="false" */ boolean skip; + /** * Maven project. * @@ -87,18 +90,13 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { * @readonly */ MavenProject project; + /** * Doxia Site Renderer. * * @component */ Renderer siteRenderer; - SessionInfoStore sessionInfoStore; - ExecutionDataStore executionDataStore; - - public abstract String getOutputName(); - - public abstract String getName(final Locale locale); public String getDescription(final Locale locale) { return getName(locale) + " Coverage Report."; @@ -138,33 +136,29 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { } @Override - public abstract void setReportOutputDirectory( - final File reportOutputDirectory); - - @Override public boolean canGenerateReport() { if (skip) { getLog().info( "Skipping JaCoCo execution because property jacoco.skip is set."); return false; } - if (!getDataFile().exists()) { + if (!canGenerateReportRegardingDataFiles()) { getLog().info( - "Skipping JaCoCo execution due to missing execution data file:" - + getDataFile()); + "Skipping JaCoCo execution due to missing execution data file."); return false; } - final File classesDirectory = new File(getProject().getBuild() - .getOutputDirectory()); - if (!classesDirectory.exists()) { + if (!canGenerateReportRegardingClassesDirectory()) { getLog().info( - "Skipping JaCoCo execution due to missing classes directory:" - + classesDirectory); + "Skipping JaCoCo execution due to missing classes directory."); return false; } return true; } + abstract boolean canGenerateReportRegardingDataFiles(); + + abstract boolean canGenerateReportRegardingClassesDirectory(); + /** * This method is called when the report generation is invoked directly as a * standalone Mojo. @@ -185,12 +179,12 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { @Override protected void executeReport(final Locale locale) throws MavenReportException { - loadExecutionData(); try { - final IReportVisitor visitor = createVisitor(locale); - visitor.visitInfo(sessionInfoStore.getInfos(), - executionDataStore.getContents()); - createReport(visitor); + final ReportSupport support = new ReportSupport(getLog()); + loadExecutionData(support); + addFormatters(support, locale); + final IReportVisitor visitor = support.initRootVisitor(); + createReport(visitor, support); visitor.visitEnd(); } catch (final IOException e) { throw new MavenReportException("Error while creating report: " @@ -198,110 +192,13 @@ public abstract class AbstractReportMojo extends AbstractMavenReport { } } - void loadExecutionData() throws MavenReportException { - final ExecFileLoader loader = new ExecFileLoader(); - try { - loader.load(getDataFile()); - } catch (final IOException e) { - throw new MavenReportException( - "Unable to read execution data file " + getDataFile() - + ": " + e.getMessage(), e); - } - sessionInfoStore = loader.getSessionInfoStore(); - executionDataStore = loader.getExecutionDataStore(); - } - - void createReport(final IReportGroupVisitor visitor) throws IOException { - final FileFilter fileFilter = new FileFilter(this.getIncludes(), - this.getExcludes()); - final BundleCreator creator = new BundleCreator(this.getProject(), - fileFilter, getLog()); - final IBundleCoverage bundle = creator.createBundle(executionDataStore); - final SourceFileCollection locator = new SourceFileCollection( - getCompileSourceRoots(), sourceEncoding); - checkForMissingDebugInformation(bundle); - visitor.visitBundle(bundle, locator); - } - - void checkForMissingDebugInformation(final ICoverageNode node) { - if (node.getClassCounter().getTotalCount() > 0 - && node.getLineCounter().getTotalCount() == 0) { - getLog().warn( - "To enable source code annotation class files have to be compiled with debug information."); - } - } - - IReportVisitor createVisitor(final Locale locale) throws IOException { - final List<IReportVisitor> visitors = new ArrayList<IReportVisitor>(); - getOutputDirectoryFile().mkdirs(); - final XMLFormatter xmlFormatter = new XMLFormatter(); - xmlFormatter.setOutputEncoding(outputEncoding); - visitors.add(xmlFormatter.createVisitor(new FileOutputStream(new File( - getOutputDirectoryFile(), "jacoco.xml")))); - final CSVFormatter csvFormatter = new CSVFormatter(); - csvFormatter.setOutputEncoding(outputEncoding); - visitors.add(csvFormatter.createVisitor(new FileOutputStream(new File( - getOutputDirectoryFile(), "jacoco.csv")))); - final HTMLFormatter htmlFormatter = new HTMLFormatter(); - htmlFormatter.setOutputEncoding(outputEncoding); - htmlFormatter.setLocale(locale); - visitors.add(htmlFormatter.createVisitor(new FileMultiReportOutput( - getOutputDirectoryFile()))); - return new MultiReportVisitor(visitors); - } - - File resolvePath(final String path) { - File file = new File(path); - if (!file.isAbsolute()) { - file = new File(getProject().getBasedir(), path); - } - return file; - } - - List<File> getCompileSourceRoots() { - final List<File> result = new ArrayList<File>(); - for (final Object path : getProject().getCompileSourceRoots()) { - result.add(resolvePath((String) path)); - } - return result; - } - - private static class SourceFileCollection implements ISourceFileLocator { - - private final List<File> sourceRoots; - private final String encoding; - - public SourceFileCollection(final List<File> sourceRoots, - final String encoding) { - this.sourceRoots = sourceRoots; - this.encoding = encoding; - } - - public Reader getSourceFile(final String packageName, - final String fileName) throws IOException { - final String r; - if (packageName.length() > 0) { - r = packageName + '/' + fileName; - } else { - r = fileName; - } - for (final File sourceRoot : sourceRoots) { - final File file = new File(sourceRoot, r); - if (file.exists() && file.isFile()) { - return new InputStreamReader(new FileInputStream(file), - encoding); - } - } - return null; - } - - public int getTabWidth() { - return 4; - } - } + abstract void loadExecutionData(final ReportSupport support) + throws IOException; - abstract File getDataFile(); + abstract void addFormatters(final ReportSupport support, final Locale locale) + throws IOException; - abstract File getOutputDirectoryFile(); + abstract void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException; } diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java b/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java deleted file mode 100644 index b4c8179f..00000000 --- a/jacoco-maven-plugin/src/org/jacoco/maven/BundleCreator.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Evgeny Mandrikov - initial API and implementation - * Kyle Lieber - implementation of CheckMojo - * - *******************************************************************************/ -package org.jacoco.maven; - -import static java.lang.String.format; - -import java.io.File; -import java.io.IOException; -import java.util.Collection; -import java.util.List; - -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.project.MavenProject; -import org.codehaus.plexus.util.FileUtils; -import org.jacoco.core.analysis.Analyzer; -import org.jacoco.core.analysis.CoverageBuilder; -import org.jacoco.core.analysis.IBundleCoverage; -import org.jacoco.core.analysis.IClassCoverage; -import org.jacoco.core.data.ExecutionDataStore; - -/** - * Creates an IBundleCoverage. - */ -public final class BundleCreator { - - private final MavenProject project; - private final FileFilter fileFilter; - private final Log log; - - /** - * Construct a new BundleCreator given the MavenProject and FileFilter. - * - * @param project - * the MavenProject - * @param fileFilter - * the FileFilter - * @param log - * for log output - */ - public BundleCreator(final MavenProject project, - final FileFilter fileFilter, final Log log) { - this.project = project; - this.fileFilter = fileFilter; - this.log = log; - } - - /** - * Create an IBundleCoverage for the given ExecutionDataStore. - * - * @param executionDataStore - * the execution data. - * @return the coverage data. - * @throws IOException - * if class files can't be read - */ - public IBundleCoverage createBundle( - final ExecutionDataStore executionDataStore) throws IOException { - final CoverageBuilder builder = new CoverageBuilder(); - final Analyzer analyzer = new Analyzer(executionDataStore, builder); - final File classesDir = new File(this.project.getBuild() - .getOutputDirectory()); - - @SuppressWarnings("unchecked") - final List<File> filesToAnalyze = FileUtils.getFiles(classesDir, - fileFilter.getIncludes(), fileFilter.getExcludes()); - - for (final File file : filesToAnalyze) { - analyzer.analyzeAll(file); - } - - final IBundleCoverage bundle = builder - .getBundle(this.project.getName()); - logBundleInfo(bundle, builder.getNoMatchClasses()); - - return bundle; - } - - private void logBundleInfo(final IBundleCoverage bundle, - final Collection<IClassCoverage> nomatch) { - log.info(format("Analyzed bundle '%s' with %s classes", - bundle.getName(), - Integer.valueOf(bundle.getClassCounter().getTotalCount()))); - if (!nomatch.isEmpty()) { - log.warn(format( - "Classes in bundle '%s' do no match with execution data. " - + "For report generation the same class files must be used as at runtime.", - bundle.getName())); - for (final IClassCoverage c : nomatch) { - log.warn(format("Execution data for class %s does not match.", - c.getName())); - } - } - } - -} diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java index 10ec9eb2..b61acee1 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/CheckMojo.java @@ -19,15 +19,11 @@ import java.util.ArrayList; import java.util.List; import org.apache.maven.plugin.MojoExecutionException; -import org.jacoco.core.analysis.IBundleCoverage; import org.jacoco.core.analysis.ICoverageNode; -import org.jacoco.core.data.ExecutionDataStore; -import org.jacoco.core.tools.ExecFileLoader; import org.jacoco.report.IReportVisitor; import org.jacoco.report.check.IViolationsOutput; import org.jacoco.report.check.Limit; import org.jacoco.report.check.Rule; -import org.jacoco.report.check.RulesChecker; /** * Checks that the code coverage metrics are being met. @@ -170,19 +166,22 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { } private void executeCheck() throws MojoExecutionException { - final IBundleCoverage bundle = loadBundle(); violations = false; - final RulesChecker checker = new RulesChecker(); + final ReportSupport support = new ReportSupport(getLog()); + final List<Rule> checkerrules = new ArrayList<Rule>(); for (final RuleConfiguration r : rules) { checkerrules.add(r.rule); } - checker.setRules(checkerrules); + support.addRulesChecker(checkerrules, this); - final IReportVisitor visitor = checker.createVisitor(this); try { - visitor.visitBundle(bundle, null); + final IReportVisitor visitor = support.initRootVisitor(); + support.loadExecutionData(dataFile); + support.processProject(visitor, getProject(), this.getIncludes(), + this.getExcludes()); + visitor.visitEnd(); } catch (final IOException e) { throw new MojoExecutionException( "Error while checking code coverage: " + e.getMessage(), e); @@ -198,26 +197,6 @@ public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { } } - private IBundleCoverage loadBundle() throws MojoExecutionException { - final FileFilter fileFilter = new FileFilter(this.getIncludes(), - this.getExcludes()); - final BundleCreator creator = new BundleCreator(getProject(), - fileFilter, getLog()); - try { - final ExecutionDataStore executionData = loadExecutionData(); - return creator.createBundle(executionData); - } catch (final IOException e) { - throw new MojoExecutionException( - "Error while reading code coverage: " + e.getMessage(), e); - } - } - - private ExecutionDataStore loadExecutionData() throws IOException { - final ExecFileLoader loader = new ExecFileLoader(); - loader.load(dataFile); - return loader.getExecutionDataStore(); - } - public void onViolation(final ICoverageNode node, final Rule rule, final Limit limit, final String message) { this.getLog().warn(message); diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java index d4be7426..3da49410 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/FileFilter.java @@ -45,7 +45,7 @@ public class FileFilter { } /** - * Returns a list of files. + * Returns a list of file names. * * @param directory * the directory to scan @@ -60,6 +60,20 @@ public class FileFilter { } /** + * Returns a list of files. + * + * @param directory + * the directory to scan + * @return a list of files + * @throws IOException + * if file system access fails + */ + @SuppressWarnings("unchecked") + public List<File> getFiles(final File directory) throws IOException { + return FileUtils.getFiles(directory, getIncludes(), getExcludes()); + } + + /** * Get the includes pattern * * @return the pattern diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java new file mode 100644 index 00000000..e8087694 --- /dev/null +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportAggregateMojo.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * John Oliver, Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.model.Dependency; +import org.apache.maven.project.MavenProject; +import org.jacoco.report.IReportGroupVisitor; + +/** + * <p> + * Creates a structured code coverage report (HTML, XML, and CSV) from multiple + * projects within reactor. The report is created from all modules this project + * depends on. From those projects class and source files as well as JaCoCo + * execution data files will be collected. This also allows to create coverage + * reports when tests are in separate projects than the code under test, for + * example in case of integration tests. + * </p> + * + * <p> + * Using the dependency scope allows to distinguish projects which contribute + * execution data but should not be part of the report itself: + * </p> + * + * <ul> + * <li><code>compile</code>: Project source and execution data is included in + * the report.</li> + * <li><code>test</code>: Only execution data is considered for the report.</li> + * </ul> + * + * @goal report-aggregate + * @requiresProject true + * @threadSafe + * @since 0.7.7 + */ +public class ReportAggregateMojo extends AbstractReportMojo { + + /** + * A list of execution data files to include in the report from each + * project. May use wildcard characters (* and ?). When not specified all + * *.exec files from the target folder will be included. + * + * @parameter default-value="target/*.exec" + */ + List<String> dataFileIncludes; + + /** + * A list of execution data files to exclude from the report. May use + * wildcard characters (* and ?). When not specified nothing will be + * excluded. + * + * @parameter + */ + List<String> dataFileExcludes; + + /** + * Output directory for the reports. Note that this parameter is only + * relevant if the goal is run from the command line or from the default + * build lifecycle. If the goal is run indirectly as part of a site + * generation, the output directory configured in the Maven Site Plugin is + * used instead. + * + * @parameter + * default-value="${project.reporting.outputDirectory}/jacoco-aggregate" + */ + private File outputDirectory; + + /** + * The projects in the reactor. + * + * @parameter property="reactorProjects" + * @readonly + */ + private List<MavenProject> reactorProjects; + + @Override + boolean canGenerateReportRegardingDataFiles() { + return true; + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return true; + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + final FileFilter filter = new FileFilter(dataFileIncludes, + dataFileExcludes); + for (final MavenProject dependency : findDependencies( + Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST)) { + for (final File execFile : filter.getFiles(dependency.getBasedir())) { + support.loadExecutionData(execFile); + } + } + } + + @Override + void addFormatters(final ReportSupport support, final Locale locale) + throws IOException { + support.addAllFormatters(outputDirectory, outputEncoding, footer, + locale); + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + final IReportGroupVisitor group = visitor.visitGroup(title); + for (final MavenProject dependency : findDependencies(Artifact.SCOPE_COMPILE)) { + support.processProject(group, dependency.getArtifactId(), + dependency, getIncludes(), getExcludes(), sourceEncoding); + } + } + + @Override + protected String getOutputDirectory() { + return outputDirectory.getAbsolutePath(); + } + + @Override + public void setReportOutputDirectory(final File reportOutputDirectory) { + if (reportOutputDirectory != null + && !reportOutputDirectory.getAbsolutePath().endsWith( + "jacoco-aggregate")) { + outputDirectory = new File(reportOutputDirectory, + "jacoco-aggregate"); + } else { + outputDirectory = reportOutputDirectory; + } + } + + public String getOutputName() { + return "jacoco-aggregate/index"; + } + + public String getName(final Locale locale) { + return "JaCoCo Aggregate"; + } + + private List<MavenProject> findDependencies(final String... scopes) { + final List<MavenProject> result = new ArrayList<MavenProject>(); + final List<String> scopeList = Arrays.asList(scopes); + for (final Object dependencyObject : getProject().getDependencies()) { + final Dependency dependency = (Dependency) dependencyObject; + if (scopeList.contains(dependency.getScope())) { + final MavenProject project = findProjectFromReactor(dependency); + if (project != null) { + result.add(project); + } + } + } + return result; + } + + private MavenProject findProjectFromReactor(final Dependency d) { + for (final MavenProject p : reactorProjects) { + if (p.getGroupId().equals(d.getGroupId()) + && p.getArtifactId().equals(d.getArtifactId()) + && p.getVersion().equals(d.getVersion())) { + return p; + } + } + return null; + } + +} diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java index 9d8ef271..e0b0217c 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportITMojo.java @@ -13,8 +13,11 @@ package org.jacoco.maven; import java.io.File; +import java.io.IOException; import java.util.Locale; +import org.jacoco.report.IReportGroupVisitor; + /** * Same as <code>report</code>, but provides default values suitable for * integration-tests: @@ -50,6 +53,35 @@ public class ReportITMojo extends AbstractReportMojo { private File dataFile; @Override + boolean canGenerateReportRegardingDataFiles() { + return dataFile.exists(); + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return new File(getProject().getBuild().getOutputDirectory()).exists(); + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + support.loadExecutionData(dataFile); + } + + @Override + void addFormatters(final ReportSupport support, final Locale locale) + throws IOException { + support.addAllFormatters(outputDirectory, outputEncoding, footer, + locale); + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + support.processProject(visitor, title, getProject(), getIncludes(), + getExcludes(), sourceEncoding); + } + + @Override protected String getOutputDirectory() { return outputDirectory.getAbsolutePath(); } @@ -65,22 +97,10 @@ public class ReportITMojo extends AbstractReportMojo { } } - @Override - File getDataFile() { - return dataFile; - } - - @Override - File getOutputDirectoryFile() { - return outputDirectory; - } - - @Override public String getOutputName() { return "jacoco-it/index"; } - @Override public String getName(final Locale locale) { return "JaCoCo IT"; } diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java index f6abdaf2..23c80e4a 100644 --- a/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportMojo.java @@ -12,8 +12,11 @@ package org.jacoco.maven; import java.io.File; +import java.io.IOException; import java.util.Locale; +import org.jacoco.report.IReportGroupVisitor; + /** * Creates a code coverage report for tests of a single project in multiple * formats (HTML, XML, and CSV). @@ -45,6 +48,35 @@ public class ReportMojo extends AbstractReportMojo { private File dataFile; @Override + boolean canGenerateReportRegardingDataFiles() { + return dataFile.exists(); + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return new File(getProject().getBuild().getOutputDirectory()).exists(); + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + support.loadExecutionData(dataFile); + } + + @Override + void addFormatters(final ReportSupport support, final Locale locale) + throws IOException { + support.addAllFormatters(outputDirectory, outputEncoding, footer, + locale); + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + support.processProject(visitor, title, getProject(), getIncludes(), + getExcludes(), sourceEncoding); + } + + @Override protected String getOutputDirectory() { return outputDirectory.getAbsolutePath(); } @@ -59,23 +91,11 @@ public class ReportMojo extends AbstractReportMojo { } } - @Override - File getDataFile() { - return dataFile; - } - - @Override - File getOutputDirectoryFile() { - return outputDirectory; - } - - @Override public String getOutputName() { return "jacoco/index"; } - @Override public String getName(final Locale locale) { - return "JaCoCo Test"; + return "JaCoCo"; } } diff --git a/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java new file mode 100644 index 00000000..62819778 --- /dev/null +++ b/jacoco-maven-plugin/src/org/jacoco/maven/ReportSupport.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import static java.lang.String.format; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.tools.ExecFileLoader; +import org.jacoco.report.FileMultiReportOutput; +import org.jacoco.report.IReportGroupVisitor; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.ISourceFileLocator; +import org.jacoco.report.MultiReportVisitor; +import org.jacoco.report.check.IViolationsOutput; +import org.jacoco.report.check.Rule; +import org.jacoco.report.check.RulesChecker; +import org.jacoco.report.csv.CSVFormatter; +import org.jacoco.report.html.HTMLFormatter; +import org.jacoco.report.xml.XMLFormatter; + +/** + * Encapsulates the tasks to create reports for Maven projects. Instances are + * supposed to be used in the following sequence: + * + * <ol> + * <li>Create an instance</li> + * <li>Load one or multiple exec files with <code>loadExecutionData()</code></li> + * <li>Add one ore multiple formatters with <code>addXXX()</code> methods</li> + * <li>Create the root visitor with <code>initRootVisitor()</code></li> + * <li>Process one or multiple projects with <code>processProject()</code></li> + * </ol> + */ +final class ReportSupport { + + private final Log log; + private final ExecFileLoader loader; + private final List<IReportVisitor> formatters; + + /** + * Construct a new instance with the given log output. + * + * @param log + * for log output + */ + public ReportSupport(final Log log) { + this.log = log; + this.loader = new ExecFileLoader(); + this.formatters = new ArrayList<IReportVisitor>(); + } + + /** + * Loads the given execution data file. + * + * @param execFile + * execution data file to load + * @throws IOException + * if the file can't be loaded + */ + public void loadExecutionData(final File execFile) throws IOException { + log.info("Loading execution data file " + execFile); + loader.load(execFile); + } + + public void addXmlFormatter(final File targetfile, final String encoding) + throws IOException { + final XMLFormatter xml = new XMLFormatter(); + xml.setOutputEncoding(encoding); + formatters.add(xml.createVisitor(new FileOutputStream(targetfile))); + } + + public void addCsvFormatter(final File targetfile, final String encoding) + throws IOException { + final CSVFormatter csv = new CSVFormatter(); + csv.setOutputEncoding(encoding); + formatters.add(csv.createVisitor(new FileOutputStream(targetfile))); + } + + public void addHtmlFormatter(final File targetdir, final String encoding, + final String footer, final Locale locale) throws IOException { + final HTMLFormatter htmlFormatter = new HTMLFormatter(); + htmlFormatter.setOutputEncoding(encoding); + htmlFormatter.setLocale(locale); + if (footer != null) { + htmlFormatter.setFooterText(footer); + } + formatters.add(htmlFormatter.createVisitor(new FileMultiReportOutput( + targetdir))); + } + + public void addAllFormatters(final File targetdir, final String encoding, + final String footer, final Locale locale) throws IOException { + targetdir.mkdirs(); + addXmlFormatter(new File(targetdir, "jacoco.xml"), encoding); + addCsvFormatter(new File(targetdir, "jacoco.csv"), encoding); + addHtmlFormatter(targetdir, encoding, footer, locale); + } + + public void addRulesChecker(final List<Rule> rules, + final IViolationsOutput output) { + final RulesChecker checker = new RulesChecker(); + checker.setRules(rules); + formatters.add(checker.createVisitor(output)); + } + + public IReportVisitor initRootVisitor() throws IOException { + final IReportVisitor visitor = new MultiReportVisitor(formatters); + visitor.visitInfo(loader.getSessionInfoStore().getInfos(), loader + .getExecutionDataStore().getContents()); + return visitor; + } + + /** + * Calculates coverage for the given project and emits it to the report + * group without source references + * + * @param visitor + * group visitor to emit the project's coverage to + * @param project + * the MavenProject + * @param includes + * list of includes patterns + * @param excludes + * list of excludes patterns + * @throws IOException + * if class files can't be read + */ + public void processProject(final IReportGroupVisitor visitor, + final MavenProject project, final List<String> includes, + final List<String> excludes) throws IOException { + processProject(visitor, project.getArtifactId(), project, includes, + excludes, new NoSourceLocator()); + } + + /** + * Calculates coverage for the given project and emits it to the report + * group including source references + * + * @param visitor + * group visitor to emit the project's coverage to + * @param bundeName + * name for this project in the report + * @param project + * the MavenProject + * @param includes + * list of includes patterns + * @param excludes + * list of excludes patterns + * @param srcEncoding + * encoding of the source files within this project + * @throws IOException + * if class files can't be read + */ + public void processProject(final IReportGroupVisitor visitor, + final String bundeName, final MavenProject project, + final List<String> includes, final List<String> excludes, + final String srcEncoding) throws IOException { + processProject(visitor, bundeName, project, includes, excludes, + new SourceFileCollection(project, srcEncoding)); + } + + private void processProject(final IReportGroupVisitor visitor, + final String bundeName, final MavenProject project, + final List<String> includes, final List<String> excludes, + final ISourceFileLocator locator) throws IOException { + final CoverageBuilder builder = new CoverageBuilder(); + final File classesDir = new File(project.getBuild() + .getOutputDirectory()); + + if (classesDir.isDirectory()) { + final Analyzer analyzer = new Analyzer( + loader.getExecutionDataStore(), builder); + final FileFilter filter = new FileFilter(includes, excludes); + for (final File file : filter.getFiles(classesDir)) { + analyzer.analyzeAll(file); + } + } + + final IBundleCoverage bundle = builder.getBundle(bundeName); + logBundleInfo(bundle, builder.getNoMatchClasses()); + + visitor.visitBundle(bundle, locator); + } + + private void logBundleInfo(final IBundleCoverage bundle, + final Collection<IClassCoverage> nomatch) { + log.info(format("Analyzed bundle '%s' with %s classes", + bundle.getName(), + Integer.valueOf(bundle.getClassCounter().getTotalCount()))); + if (!nomatch.isEmpty()) { + log.warn(format( + "Classes in bundle '%s' do no match with execution data. " + + "For report generation the same class files must be used as at runtime.", + bundle.getName())); + for (final IClassCoverage c : nomatch) { + log.warn(format("Execution data for class %s does not match.", + c.getName())); + } + } + if (bundle.getClassCounter().getTotalCount() > 0 + && bundle.getLineCounter().getTotalCount() == 0) { + log.warn("To enable source code annotation class files have to be compiled with debug information."); + } + } + + private class NoSourceLocator implements ISourceFileLocator { + + public Reader getSourceFile(final String packageName, + final String fileName) { + return null; + } + + public int getTabWidth() { + return 0; + } + } + + private class SourceFileCollection implements ISourceFileLocator { + + private final List<File> sourceRoots; + private final String encoding; + + public SourceFileCollection(final MavenProject project, + final String encoding) { + this.sourceRoots = getCompileSourceRoots(project); + this.encoding = encoding; + } + + public Reader getSourceFile(final String packageName, + final String fileName) throws IOException { + final String r; + if (packageName.length() > 0) { + r = packageName + '/' + fileName; + } else { + r = fileName; + } + for (final File sourceRoot : sourceRoots) { + final File file = new File(sourceRoot, r); + if (file.exists() && file.isFile()) { + return new InputStreamReader(new FileInputStream(file), + encoding); + } + } + return null; + } + + public int getTabWidth() { + return 4; + } + } + + private static List<File> getCompileSourceRoots(final MavenProject project) { + final List<File> result = new ArrayList<File>(); + for (final Object path : project.getCompileSourceRoots()) { + result.add(resolvePath(project, (String) path)); + } + return result; + } + + private static File resolvePath(final MavenProject project, + final String path) { + File file = new File(path); + if (!file.isAbsolute()) { + file = new File(project.getBasedir(), path); + } + return file; + } + +} diff --git a/jacoco/assembly.xml b/jacoco/assembly.xml index 4d662c9f..4cebdd61 100644 --- a/jacoco/assembly.xml +++ b/jacoco/assembly.xml @@ -40,7 +40,7 @@ </excludes> </fileSet> <fileSet> - <directory>${basedir}/../org.jacoco.doc/target/coverage</directory> + <directory>${basedir}/../org.jacoco.tests.coverage/target/site/jacoco-aggregate</directory> <outputDirectory>/coverage</outputDirectory> </fileSet> <fileSet> diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 1aaa4316..031750d3 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -20,6 +20,15 @@ <h2>Snapshot Build @qualified.bundle.version@ (@build.date@)</h2> +<h3>New Features</h3> +<ul> + <li>New Maven goal <code>report-aggregate</code> to create reports for + multi-module projects + (GitHub <a href="https://github.com/jacoco/jacoco/issues/388">#388</a>).</li> + <li>New parameters <code>title</code> and <code>footer</code> for Maven + reporting goals allow customization of generated reports.</li> +</ul> + <h3>Fixed Bugs</h3> <ul> <li>Don't suppress EOF errors in case of truncated execution data files diff --git a/org.jacoco.doc/docroot/doc/maven.html b/org.jacoco.doc/docroot/doc/maven.html index 8e786c5d..52fee004 100644 --- a/org.jacoco.doc/docroot/doc/maven.html +++ b/org.jacoco.doc/docroot/doc/maven.html @@ -116,6 +116,7 @@ mvn help:describe -Dplugin=org.jacoco:jacoco-maven-plugin -Ddetail <li><a href="merge-mojo.html">merge</a></li> <li><a href="report-mojo.html">report</a></li> <li><a href="report-integration-mojo.html">report-integration</a></li> + <li><a href="report-aggregate-mojo.html">report-aggregate</a></li> <li><a href="check-mojo.html">check</a></li> <li><a href="dump-mojo.html">dump</a></li> <li><a href="instrument-mojo.html">instrument</a></li> diff --git a/org.jacoco.doc/pom.xml b/org.jacoco.doc/pom.xml index aaf75227..1405a4de 100644 --- a/org.jacoco.doc/pom.xml +++ b/org.jacoco.doc/pom.xml @@ -85,84 +85,6 @@ </goals> <configuration> <target> - <typedef resource="org/jacoco/ant/antlib.xml"/> - <echo message="Coverage report"/> - <report> - <executiondata> - <fileset dir="../org.jacoco.agent.test/target" includes="jacoco.exec"/> - <fileset dir="../org.jacoco.agent.rt.test/target" includes="jacoco.exec"/> - <fileset dir="../org.jacoco.ant.test/target" includes="jacoco.exec"/> - <fileset dir="../org.jacoco.core.test/target" includes="jacoco.exec"/> - <fileset dir="../org.jacoco.examples.test/target" includes="jacoco.exec"/> - <fileset dir="../org.jacoco.report.test/target" includes="jacoco.exec"/> - <fileset dir="../jacoco-maven-plugin.test/target" includes="jacoco.exec"/> - </executiondata> - <structure name="JaCoCo"> - <group name="org.jacoco.agent"> - <classfiles> - <!-- Process class files only, ignore jacocoagent.jar --> - <fileset dir="../org.jacoco.agent/target/classes" includes="**/*.class"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.agent/src"/> - </sourcefiles> - </group> - <group name="org.jacoco.agent.rt"> - <classfiles> - <fileset dir="../org.jacoco.agent.rt/target/classes"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.agent.rt/src"/> - </sourcefiles> - </group> - <group name="org.jacoco.ant"> - <classfiles> - <fileset dir="../org.jacoco.ant/target/classes"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.ant/src"/> - </sourcefiles> - </group> - <group name="org.jacoco.core"> - <classfiles> - <fileset dir="../org.jacoco.core/target/classes"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.core/src"/> - </sourcefiles> - </group> - <group name="org.jacoco.examples"> - <classfiles> - <fileset dir="../org.jacoco.examples/target/classes"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.examples/src"/> - </sourcefiles> - </group> - <group name="org.jacoco.report"> - <classfiles> - <fileset dir="../org.jacoco.report/target/classes"/> - </classfiles> - <sourcefiles> - <fileset dir="../org.jacoco.report/src"/> - </sourcefiles> - </group> - <group name="jacoco-maven-plugin"> - <classfiles> - <fileset dir="../jacoco-maven-plugin/target/classes" excludes="**/HelpMojo.class"/> - </classfiles> - <sourcefiles> - <fileset dir="../jacoco-maven-plugin/src"/> - </sourcefiles> - </group> - </structure> - <html destdir="${project.build.directory}/coverage" - footer="Code Coverage Report for JaCoCo ${project.version}" - locale="en"/> - <csv destfile="${project.build.directory}/coverage/coverage.csv"/> - <xml destfile="${project.build.directory}/coverage/coverage.xml"/> - </report> - <echo message="JUnit report"/> <mkdir dir="${project.build.directory}/junit"/> <junitreport todir="${project.build.directory}/junit"> @@ -185,11 +107,6 @@ </executions> <dependencies> <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>org.jacoco.ant</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant-junit</artifactId> <version>1.8.2</version> diff --git a/org.jacoco.tests.coverage/.gitignore b/org.jacoco.tests.coverage/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/org.jacoco.tests.coverage/.gitignore @@ -0,0 +1 @@ +/target diff --git a/org.jacoco.tests.coverage/.project b/org.jacoco.tests.coverage/.project new file mode 100644 index 00000000..a1bcc18f --- /dev/null +++ b/org.jacoco.tests.coverage/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.jacoco.tests.coverage</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + </natures> +</projectDescription> diff --git a/org.jacoco.tests.coverage/META-INF/MANIFEST.MF b/org.jacoco.tests.coverage/META-INF/MANIFEST.MF new file mode 100644 index 00000000..075c5d12 --- /dev/null +++ b/org.jacoco.tests.coverage/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: JaCoCo Coverage Report
+Bundle-SymbolicName: org.jacoco.tests.coverage
+Bundle-Version: 0.7.7.qualifier
+Bundle-Vendor: Mountainminds GmbH & Co. KG
diff --git a/org.jacoco.tests.coverage/build.properties b/org.jacoco.tests.coverage/build.properties new file mode 100644 index 00000000..5f22cdd4 --- /dev/null +++ b/org.jacoco.tests.coverage/build.properties @@ -0,0 +1 @@ +bin.includes = META-INF/ diff --git a/org.jacoco.tests.coverage/pom.xml b/org.jacoco.tests.coverage/pom.xml new file mode 100644 index 00000000..94c9a24f --- /dev/null +++ b/org.jacoco.tests.coverage/pom.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2009, 2016 Mountainminds GmbH & Co. KG and Contributors + All rights reserved. This program and the accompanying materials + are made available under the terms of the Eclipse Public License v1.0 + which accompanies this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Contributors: + Evgeny Mandrikov - initial API and implementation +--> +<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>org.jacoco</groupId> + <artifactId>org.jacoco.tests</artifactId> + <version>0.7.7-SNAPSHOT</version> + <relativePath>../org.jacoco.tests</relativePath> + </parent> + + <artifactId>org.jacoco.tests.coverage</artifactId> + <packaging>pom</packaging> + + <name>JaCoCo :: Coverage Report</name> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.core</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.core.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.report</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.report.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.agent</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.agent.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.agent.rt</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.agent.rt.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.ant</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.ant.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>jacoco-maven-plugin.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.examples</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>org.jacoco.examples.test</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <properties> + <maven.deploy.skip>true</maven.deploy.skip> + <!-- Analyze class files only to exclude shaded agent JAR from report --> + <jacoco.includes>**/*.class</jacoco.includes> + <jacoco.excludes>**/HelpMojo.class</jacoco.excludes> + </properties> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${project.version}</version> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + <configuration> + <title>JaCoCo</title> + <footer>Code Coverage Report for JaCoCo ${project.version}</footer> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/org.jacoco.tests/pom.xml b/org.jacoco.tests/pom.xml index eb8bf878..aecd0aa6 100644 --- a/org.jacoco.tests/pom.xml +++ b/org.jacoco.tests/pom.xml @@ -33,6 +33,7 @@ <module>../org.jacoco.ant.test</module> <module>../jacoco-maven-plugin.test</module> <module>../org.jacoco.examples.test</module> + <module>../org.jacoco.tests.coverage</module> </modules> <properties> |