
org.codehaus.mojo.cobertura.CoberturaReportMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cobertura-maven-plugin Show documentation
Show all versions of cobertura-maven-plugin Show documentation
This is the Mojo's Maven plugin for Cobertura. Cobertura is a free Java tool that calculates the percentage of code accessed by
tests. It can be used to identify which parts of your Java program are lacking test coverage.
package org.codehaus.mojo.cobertura;
/*
* Copyright 2011
*
* Licensed 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.
*/
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
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.artifact.Artifact;
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.mojo.cobertura.configuration.MaxHeapSizeUtil;
import org.codehaus.mojo.cobertura.tasks.CommandLineArguments;
import org.codehaus.mojo.cobertura.tasks.ReportTask;
/**
* Instruments, Tests, and Generates a Cobertura Report.
*
* @author Will Gwaltney
* @author Joakim Erdfelt
* @goal cobertura
* @execute phase="test" lifecycle="cobertura"
*/
public class CoberturaReportMojo
extends AbstractMavenReport
{
/**
* The format of the report. (supports 'html' or 'xml'. defaults to 'html')
*
* @parameter expression="${cobertura.report.format}"
* @deprecated
*/
private String format;
/**
* The format of the report. (can be 'html' and/or 'xml'. defaults to 'html')
*
* @parameter
*/
private String[] formats = new String[] { "html" };
/**
* The encoding for the java source code files.
*
* @parameter expression="${project.build.sourceEncoding}" default-value="UTF-8".
* @since 2.4
*/
private String encoding;
/**
* Maximum memory to pass to JVM of Cobertura processes.
*
* @parameter expression="${cobertura.maxmem}"
*/
private String maxmem = "64m";
/**
*
* The Datafile Location.
*
*
* @parameter expression="${cobertura.datafile}" default-value="${project.build.directory}/cobertura/cobertura.ser"
* @required
* @readonly
*/
private File dataFile;
/**
* Maven Internal: List of artifacts for the plugin.
*
* @parameter default-value="${plugin.artifacts}"
* @required
* @readonly
*/
private List pluginClasspathList;
/**
* The output directory for the report.
*
* @parameter default-value="${project.reporting.outputDirectory}/cobertura"
* @required
*/
private File outputDirectory;
/**
* Only output cobertura errors, avoid info messages.
*
* @parameter expression="${quiet}" default-value="false"
* @since 2.1
*/
private boolean quiet;
/**
* Generate aggregate reports in multi-module projects.
*
* @parameter expression="${cobertura.aggregate}" default-value="false"
* @since 2.5
*/
private boolean aggregate;
/**
* Whether to remove GPL licensed files from the generated report.
* This is required to distribute the report as part of a distribution,
* which is licensed under the ASL, or a similar license, which is
* incompatible with the GPL.
*
* @parameter default-value="false" expression="${cobertura.omitGplFiles}"
* @since 2.5
*/
private boolean omitGplFiles;
/**
* Maven Internal: The Doxia Site Renderer.
*
* @component
*/
private Renderer siteRenderer;
/**
* List of maven project of the current build
*
* @parameter expression="${reactorProjects}"
* @required
* @readonly
*/
private List reactorProjects;
/**
* Maven Internal: Project to interact with.
*
* @parameter default-value="${project}"
* @required
* @readonly
*/
private MavenProject project;
private Map < MavenProject, List < MavenProject > > projectChildren;
private String relDataFileName;
private String relAggregateOutputDir;
/**
* Constructs a CoberturaReportMojo
.
* Sets the max memory to the maven max memory if set, otherwise
* the default CoberturaReportMojo
value is used.
*/
public CoberturaReportMojo()
{
if ( MaxHeapSizeUtil.getInstance().envHasMavenMaxMemSetting() )
{
maxmem = MaxHeapSizeUtil.getInstance().getMavenMaxMemSetting();
}
}
/**
* @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
* @param locale for the message bundle
* @return localized cobertura name
*/
public String getName( Locale locale )
{
return getBundle( locale ).getString( "report.cobertura.name" );
}
/**
* @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
* @param locale for the message bundle
* @return localized description
*/
public String getDescription( Locale locale )
{
return getBundle( locale ).getString( "report.cobertura.description" );
}
@Override
protected String getOutputDirectory()
{
return outputDirectory.getAbsolutePath();
}
@Override
protected MavenProject getProject()
{
return project;
}
@Override
protected Renderer getSiteRenderer()
{
return siteRenderer;
}
/**
* perform the actual reporting
* @param task
* @param outputFormat
* @throws MavenReportException
*/
private void executeReportTask( ReportTask task, String outputFormat )
throws MavenReportException
{
task.setOutputFormat( outputFormat );
// execute task
try
{
task.execute();
}
catch ( MojoExecutionException e )
{
// throw new MavenReportException( "Error in Cobertura Report generation: " + e.getMessage(), e );
// better don't break the build if report is not generated, also due to the sporadic MCOBERTURA-56
getLog().error( "Error in Cobertura Report generation: " + e.getMessage(), e );
}
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale)
* @param locale not used
* @throws MavenReportException when an exception occurs
*/
protected void executeReport( Locale locale )
throws MavenReportException
{
if ( canGenerateSimpleReport() )
{
executeReport( getDataFile(), outputDirectory, getCompileSourceRoots() );
}
if ( canGenerateAggregateReports() )
{
executeAggregateReport( locale );
}
}
/**
* Generates aggregate cobertura reports for all multi-module projects.
*/
private void executeAggregateReport( Locale locale )
throws MavenReportException
{
for ( MavenProject proj : reactorProjects )
{
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 = getAllChildren( curProject );
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 ( File serFile : serFiles )
{
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 ( MavenProject child : children )
{
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
task.setLog( getLog() );
task.setPluginClasspathList( pluginClasspathList );
task.setQuiet( quiet );
// task specifics
task.setMaxmem( maxmem );
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 };
}
for ( int i = 0; i < formats.length; i++ )
{
executeReportTask( task, formats[i] );
}
removeGplFiles();
}
/**
* Removes files from the generated report, which are distributed under
* the GPL.
*/
private void removeGplFiles()
throws MavenReportException
{
if ( omitGplFiles )
{
final String[] files = new String[]
{
"js/customsorttypes.js", "js/sortabletable.js", "js/stringbuilder.js"
};
for ( int i = 0; i < files.length; i++ )
{
final File f = new File( outputDirectory, files[ i ] );
if ( f.exists() )
{
if ( f.delete() )
{
getLog().debug( "Removed GPL licensed file " + f.getPath() );
}
else
{
throw new MavenReportException( "Unable to remove GPL licensed file " + f.getPath() );
}
}
else
{
getLog().info( "GPL licensed file " + f.getPath() + " not found." );
}
}
}
}
/** {@inheritDoc} */
public String getOutputName()
{
return "cobertura/index";
}
@Override
public boolean isExternalReport()
{
return true;
}
@Override
public boolean canGenerateReport()
{
if ( canGenerateSimpleReport() )
{
return true;
}
else
{
getLog().info( "Not executing cobertura:report as the cobertura data file (" + getDataFile()
+ ") could not be found" );
}
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.
*
* @return true
if a simple report can be generated, otherwise false
*/
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.
*/
return getDataFile().exists() && getDataFile().isFile();
}
/**
* 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.
*/
@SuppressWarnings( "unchecked" )
private List getCompileSourceRoots()
{
return project.getExecutionProject().getCompileSourceRoots();
}
@Override
public void setReportOutputDirectory( File reportOutputDirectory )
{
if ( ( reportOutputDirectory != null ) && ( !reportOutputDirectory.getAbsolutePath().endsWith( "cobertura" ) ) )
{
this.outputDirectory = new File( reportOutputDirectory, "cobertura" );
}
else
{
this.outputDirectory = reportOutputDirectory;
}
}
/**
* Gets the resource bundle for the report text.
*
* @param locale The locale for the report, must not be null
.
* @return The resource bundle for the requested locale.
*/
private ResourceBundle getBundle( Locale locale )
{
return ResourceBundle.getBundle( "cobertura-report", locale );
}
/**
* 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 "pom".equals( mavenProject.getPackaging() );
}
/**
* 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 ( MavenProject proj : reactorProjects )
{
List depList = 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(), getDataFile() );
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 a list containing all the recursive, non-pom children of the given project, never null
.
*/
private List getAllChildren( MavenProject parentProject )
{
List children = projectChildren.get( parentProject );
if ( children == null )
{
return Collections.emptyList();
}
List result = new ArrayList();
for ( MavenProject child : children )
{
if ( isMultiModule( child ) )
{
result.addAll( getAllChildren( child ) );
}
else
{
result.add( child );
}
}
return result;
}
/**
* Returns any existing cobertura data files from the given list of projects.
*/
private List getOutputFiles( List projects )
{
List files = new ArrayList();
for ( MavenProject proj : projects )
{
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;
}
/**
* Get the data file which is or will be generated by Cobertura, never null
.
*
* @return the data file
*/
private File getDataFile()
{
return dataFile;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy