Index: src/main/java/org/codehaus/mojo/cobertura/CoberturaReportMojo.java =================================================================== --- src/main/java/org/codehaus/mojo/cobertura/CoberturaReportMojo.java (revision 13790) +++ src/main/java/org/codehaus/mojo/cobertura/CoberturaReportMojo.java (working copy) @@ -20,16 +20,25 @@ */ import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.ResourceBundle; +import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler; +import net.sourceforge.cobertura.coveragedata.ProjectData; +import org.apache.maven.doxia.siterenderer.Renderer; 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.codehaus.doxia.sink.Sink; -import org.codehaus.doxia.site.renderer.SiteRenderer; +import org.codehaus.mojo.cobertura.tasks.CommandLineArguments; import org.codehaus.mojo.cobertura.tasks.ReportTask; /** @@ -110,13 +119,29 @@ private boolean quiet; /** + * Generate aggregate reports in multi-module projects. + * + * @parameter expression="${cobertura.aggregate}" default-value="false" + */ + private boolean aggregate; + + /** * Maven Internal: The Doxia Site Renderer. * * @component */ - private SiteRenderer siteRenderer; + private Renderer siteRenderer; /** + * List of maven project of the current build + * + * @parameter expression="${reactorProjects}" + * @required + * @readonly + */ + protected List reactorProjects; + + /** * Maven Internal: Project to interact with. * * @parameter default-value="${project}" @@ -125,6 +150,10 @@ */ private MavenProject project; + private Map projectChildren; + private String relDataFileName; + private String relAggregateOutputDir; + /** * @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale) * @param locale for the message bundle @@ -167,7 +196,7 @@ * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer() * @return SiteRenderer */ - protected SiteRenderer getSiteRenderer() + protected Renderer getSiteRenderer() { return siteRenderer; } @@ -213,12 +242,83 @@ protected void executeReport( Locale locale ) throws MavenReportException { + if ( canGenerateSimpleReport() ) + { + executeReport(dataFile, outputDirectory, getCompileSourceRoots()); + } - if ( !canGenerateReport() ) + if(canGenerateAggregateReports()) { + executeAggregateReport(locale); + } + } + + /** + * Generates aggregate cobertura reports for all multi-module projects. + */ + private void executeAggregateReport( Locale locale ) + throws MavenReportException { + for(Iterator iter = reactorProjects.iterator(); iter.hasNext(); ) { + MavenProject proj = (MavenProject)iter.next(); + if(!isMultiModule(proj)) { + continue; + } + executeAggregateReport(locale, proj); + } + } + + /** + * Generates an aggregate cobertura report for the given project. + */ + private void executeAggregateReport( Locale locale, MavenProject curProject ) + throws MavenReportException + { + List children = new ArrayList(); + getAllChildren(curProject, children); + + if(children.isEmpty()) { return; } + List serFiles = getOutputFiles(children); + if(serFiles.isEmpty()) { + getLog().info("Not executing aggregate cobertura:report for " + curProject.getName() + + " as no child cobertura data files could not be found" ); + return; + } + + getLog().info("Executing aggregate cobertura:report for " + curProject.getName()); + + ProjectData aggProjectData = new ProjectData(); + for (Iterator iter = serFiles.iterator(); iter.hasNext(); ) { + File serFile = (File)iter.next(); + ProjectData data = CoverageDataFileHandler.loadCoverageData(serFile); + aggProjectData.merge(data); + } + + File aggSerFile = new File(curProject.getBasedir(), relDataFileName); + aggSerFile.getAbsoluteFile().getParentFile().mkdirs(); + getLog().info("Saving aggregate cobertura information in " + aggSerFile.getAbsolutePath()); + CoverageDataFileHandler.saveCoverageData(aggProjectData, aggSerFile); + + // get all compile source roots + List aggCompileSourceRoots = new ArrayList(); + for(Iterator iter = children.iterator(); iter.hasNext(); ) { + MavenProject child = (MavenProject)iter.next(); + aggCompileSourceRoots.addAll(child.getCompileSourceRoots()); + } + + File reportDir = new File(curProject.getBasedir(), relAggregateOutputDir); + reportDir.mkdirs(); + executeReport(aggSerFile, reportDir, aggCompileSourceRoots); + } + + /** + * Executes the cobertura report task for the given dataFile, outputDirectory, and compileSourceRoots. + */ + private void executeReport(File curDataFile, File curOutputDirectory, List curCompileSourceRoots) + throws MavenReportException + { ReportTask task = new ReportTask(); // task defaults @@ -228,12 +328,16 @@ // task specifics task.setMaxmem( maxmem ); - task.setDataFile( dataFile ); - task.setOutputDirectory( outputDirectory ); - task.setCompileSourceRoots( getCompileSourceRoots() ); + task.setDataFile( curDataFile ); + task.setOutputDirectory( curOutputDirectory ); + task.setCompileSourceRoots( curCompileSourceRoots ); task.setSourceEncoding( encoding ); - + CommandLineArguments cmdLineArgs; + cmdLineArgs = new CommandLineArguments(); + cmdLineArgs.setUseCommandsFile(true); + task.setCmdLineArgs(cmdLineArgs); + if ( format != null ) { formats = new String[] { format }; @@ -266,14 +370,34 @@ */ public boolean canGenerateReport() { + if(canGenerateSimpleReport()) { + return true; + } + if(canGenerateAggregateReports()) { + return true; + } + + if(aggregate && isMultiModule(project)) { + // unfortunately, we don't know before hand whether we can generate an aggregate report for a + // multi-module. if we return false here, then we won't get a link in the main reports list. so we'll + // just be optimistic + return true; + } + return false; + } + + /** + * Returns whether or not we can generate a simple (non-aggregate) report for this project. + */ + private boolean canGenerateSimpleReport() + { /* * Don't have to check for source directories or java code or the like for report generation. Checks for source * directories or java project classpath existence should only occur in the Instrument Mojo. */ if ( dataFile == null || !dataFile.exists() ) { - getLog().info( - "Not executing cobertura:report as the cobertura data file (" + dataFile + getLog().info("Not executing cobertura:report as the cobertura data file (" + dataFile + ") could not be found" ); return false; } @@ -283,6 +407,25 @@ } } + /** + * Returns whether or not we can generate any aggregate reports at this time. + */ + private boolean canGenerateAggregateReports() + { + // we only generate aggregate reports after the last project runs + if(aggregate && isLastProject(project, reactorProjects)) { + buildAggregateInfo(); + + if(!getOutputFiles(reactorProjects).isEmpty()) { + return true; + } + } + return false; + } + + /** + * Returns the compileSourceRoots for the currently executing project. + */ private List getCompileSourceRoots() { return project.getExecutionProject().getCompileSourceRoots(); @@ -314,4 +457,126 @@ return ResourceBundle.getBundle( "cobertura-report", locale, getClass().getClassLoader() ); } + /** + * Check whether the element is the last element of the list + * + * @param project element to check + * @param mavenProjectList list of maven project + * @return true if project is the last element of mavenProjectList list + */ + private boolean isLastProject(MavenProject project, List mavenProjectList) + { + return project.equals(mavenProjectList.get(mavenProjectList.size() - 1)); } + + /** + * Test if the project has pom packaging + * + * @param mavenProject Project to test + * @return True if it has a pom packaging + */ + private boolean isMultiModule(MavenProject mavenProject) + { + return mavenProject.getPackaging().equals("pom"); + } + + /** + * Generates various information needed for building aggregate reports. + */ + private void buildAggregateInfo() + { + if(projectChildren != null) { + // already did this work + return; + } + + // build parent-child map + projectChildren = new HashMap(); + for(Iterator iter = reactorProjects.iterator(); iter.hasNext(); ) { + MavenProject proj = (MavenProject)iter.next(); + List depList = (List)projectChildren.get(proj.getParent()); + if(depList == null) { + depList = new ArrayList(); + projectChildren.put(proj.getParent(), depList); + } + depList.add(proj); + } + + // attempt to determine where data files and output dir are + relDataFileName = relativize(project.getBasedir(), dataFile); + if(relDataFileName == null) { + getLog().warn("Could not determine relative data file name, defaulting to 'cobertura/cobertura.ser'"); + relDataFileName = "cobertura/cobertura.ser"; + } + relAggregateOutputDir = relativize(project.getBasedir(), outputDirectory); + if(relAggregateOutputDir == null) { + getLog().warn("Could not determine relative output dir name, defaulting to 'cobertura'"); + relAggregateOutputDir = "cobertura"; + } + } + + /** + * Returns all the recursive, non-pom children of the given project. + */ + private void getAllChildren(MavenProject parentProject, List allChildren) + { + List children = (List)projectChildren.get(parentProject); + if(children == null) { + return; + } + + for(Iterator iter = children.iterator(); iter.hasNext(); ) { + MavenProject child = (MavenProject)iter.next(); + if(isMultiModule(child)) { + getAllChildren(child, allChildren); + } else { + allChildren.add(child); + } + } + } + + /** + * Returns any existing cobertura data files from the given list of projects. + */ + private List getOutputFiles(List projects) + { + List files = new ArrayList(); + for(Iterator iter = projects.iterator(); iter.hasNext(); ) { + MavenProject proj = (MavenProject)iter.next(); + if(isMultiModule(proj)) { + continue; + } + File outputFile = new File(proj.getBasedir(), relDataFileName); + if(outputFile.exists()) { + files.add(outputFile); + } + } + return files; + } + + /** + * Attempts to make the given childFile relative to the given parentFile. + */ + private String relativize(File parentFile, File childFile) + { + try { + URI parentURI = parentFile.getCanonicalFile().toURI().normalize(); + URI childURI = childFile.getCanonicalFile().toURI().normalize(); + + URI relativeURI = parentURI.relativize(childURI); + if(relativeURI.isAbsolute()) { + // child is not relative to parent + return null; + } + String relativePath = relativeURI.getPath(); + if(File.separatorChar != '/') { + relativePath = relativePath.replace('/', File.separatorChar); + } + return relativePath; + } catch(Exception e) { + getLog().warn("Failed relativizing " + childFile + " to " + parentFile, e); + } + return null; + } + +} Index: src/it/mcobertura-65/pom.xml =================================================================== --- src/it/mcobertura-65/pom.xml (revision 0) +++ src/it/mcobertura-65/pom.xml (revision 0) @@ -0,0 +1,61 @@ + + + 4.0.0 + org.codehaus.mojo.cobertura.its + agg-report-it + pom + 2.5-SNAPSHOT + agg-report-it + + @sitePluginVersion@ + @pom.version@ + + + + + + + junit + junit + 4.8.2 + test + + + + + proj1 + proj2 + + + + + org.apache.maven.plugins + maven-site-plugin + ${site-plugin-version} + + + + + true + + + org.codehaus.mojo + cobertura-maven-plugin + ${main-plugin-version} + + true + + + + + + + test-dev + + 2.2 + 2.5-SNAPSHOT + + + + + Property changes on: src/it/mcobertura-65/pom.xml ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: src/it/mcobertura-65/proj1/src/main/java/org/codehaus/mojo/cobertura/it/Proj1Code.java =================================================================== --- src/it/mcobertura-65/proj1/src/main/java/org/codehaus/mojo/cobertura/it/Proj1Code.java (revision 0) +++ src/it/mcobertura-65/proj1/src/main/java/org/codehaus/mojo/cobertura/it/Proj1Code.java (revision 0) @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.mojo.cobertura.it; + +public class Proj1Code { + + private String str; + + public Proj1Code() { + // + } + + public void setStr(String str) { + this.str = str; + } + + public String getStr() { + return str; + } + + public String toString() { + return super.toString() + " {} " + str; + } +} Property changes on: src/it/mcobertura-65/proj1/src/main/java/org/codehaus/mojo/cobertura/it/Proj1Code.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: src/it/mcobertura-65/proj1/pom.xml =================================================================== --- src/it/mcobertura-65/proj1/pom.xml (revision 0) +++ src/it/mcobertura-65/proj1/pom.xml (revision 0) @@ -0,0 +1,22 @@ + + 4.0.0 + org.codehaus.mojo.cobertura.its + agg-report-it-proj1 + jar + 2.5-SNAPSHOT + agg-report-it-proj1 + + org.codehaus.mojo.cobertura.its + agg-report-it + 2.5-SNAPSHOT + + + + junit + junit + 4.8.2 + test + + + Property changes on: src/it/mcobertura-65/proj1/pom.xml ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: src/it/mcobertura-65/proj2/src/test/java/org/codehaus/mojo/cobertura/it/Proj2Test.java =================================================================== --- src/it/mcobertura-65/proj2/src/test/java/org/codehaus/mojo/cobertura/it/Proj2Test.java (revision 0) +++ src/it/mcobertura-65/proj2/src/test/java/org/codehaus/mojo/cobertura/it/Proj2Test.java (revision 0) @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.mojo.cobertura.it; + +import junit.framework.TestCase; + +public class Proj2Test extends TestCase { + + public void testSomethingElse() { + Proj2Code code = new Proj2Code(); + code.setStr("Hello Sailor"); + code.toString(); + } + +} Property changes on: src/it/mcobertura-65/proj2/src/test/java/org/codehaus/mojo/cobertura/it/Proj2Test.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: src/it/mcobertura-65/proj2/src/main/java/org/codehaus/mojo/cobertura/it/Proj2Code.java =================================================================== --- src/it/mcobertura-65/proj2/src/main/java/org/codehaus/mojo/cobertura/it/Proj2Code.java (revision 0) +++ src/it/mcobertura-65/proj2/src/main/java/org/codehaus/mojo/cobertura/it/Proj2Code.java (revision 0) @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.mojo.cobertura.it; + +public class Proj2Code { + + private String str; + + public Proj2Code() { + // + } + + public void setStr(String str) { + this.str = str; + } + + public String getStr() { + return str; + } + + public String toString() { + return super.toString() + " {} " + str; + } +} Property changes on: src/it/mcobertura-65/proj2/src/main/java/org/codehaus/mojo/cobertura/it/Proj2Code.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: src/it/mcobertura-65/proj2/pom.xml =================================================================== --- src/it/mcobertura-65/proj2/pom.xml (revision 0) +++ src/it/mcobertura-65/proj2/pom.xml (revision 0) @@ -0,0 +1,23 @@ + + 4.0.0 + org.codehaus.mojo.cobertura.its + agg-report-it-proj2 + jar + 2.5-SNAPSHOT + agg-report-it-proj2 + + org.codehaus.mojo.cobertura.its + agg-report-it + 2.5-SNAPSHOT + + + + + junit + junit + 4.8.2 + test + + + Property changes on: src/it/mcobertura-65/proj2/pom.xml ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Index: pom.xml =================================================================== --- pom.xml (revision 13790) +++ pom.xml (working copy) @@ -37,7 +37,7 @@ - 2.0.1 + 2.1 @@ -124,34 +124,30 @@ org.apache.maven maven-artifact - 2.0 + 2.2.1 org.apache.maven maven-plugin-api - 2.0 + 2.2.1 org.apache.maven.reporting maven-reporting-api - 2.0 + 2.2.1 org.apache.maven maven-project - 2.0 + 2.2.1 org.apache.maven.reporting maven-reporting-impl - 2.0 + 2.0.4.2 + - org.codehaus.plexus - plexus-container-default - 1.0-alpha-9 - - commons-lang commons-lang 2.4 @@ -161,6 +157,12 @@ plexus-utils 2.0.2 + + org.apache.maven.shared + maven-invoker + 2.0.11 + + httpunit @@ -171,6 +173,8 @@ junit junit + 4.8.1 + test org.apache.maven.shared