
org.apache.maven.plugin.clover.CloverReportMojo Maven / Gradle / Ivy
/*
* Copyright 2001-2006 The Apache Software Foundation.
*
* 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.
*/
package org.apache.maven.plugin.clover;
import com.cenqua.clover.tasks.CloverReportTask;
import com.cenqua.clover.tasks.CloverFormatType;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.doxia.siterenderer.Renderer;
import org.apache.maven.plugin.clover.internal.AbstractCloverMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.tools.ant.Project;
import org.codehaus.plexus.resource.ResourceManager;
import java.io.File;
import java.util.*;
/**
* Generate a Clover report from existing Clover databases. The generated report
* is an external report generated by Clover itself. If the project generating the report is a top level project and
* if the aggregate
configuration element is set to true then an aggregated report will also be created.
*
* Note: This report mojo should be an @aggregator and the clover:aggregate
mojo shouldn't exist. This
* is a limitation of the site plugin which doesn't support @aggregator reports...
*
* @goal clover
*
* @author Vincent Massol
* @version $Id: CloverReportMojo.java 522080 2007-03-24 18:18:39Z vmassol $
*/
public class CloverReportMojo extends AbstractMavenReport
{
// TODO: Need some way to share config elements and code between report mojos and main build mojos.
// See http://jira.codehaus.org/browse/MNG-1886
/**
* The location of the Clover database.
*
* @parameter expression="${project.build.directory}/clover/clover.db"
* @required
*/
private String cloverDatabase;
/**
* The location of the merged clover database to create when running a report in a multimodule build.
*
* @parameter expression="${project.build.directory}/clover/cloverMerge.db"
* @required
*/
private String cloverMergeDatabase;
/**
* The directory where the Clover report will be generated.
*
* @parameter expression="${project.reporting.outputDirectory}/clover"
* @required
*/
private File outputDirectory;
/**
* The location where historical Clover data will be saved.
*
* Note: It's recommended to modify the location of this directory so that it points to a more permanent
* location as the ${project.build.directory}
directory is erased when the project is cleaned.
*
* @parameter default-value="${project.build.directory}/clover/history"
* @required
*/
private String historyDir;
/**
* When the Clover Flush Policy is set to "interval" or threaded this value is the minimum
* period between flush operations (in milliseconds).
*
* @parameter default-value="500"
*/
private int flushInterval;
/**
* If true we'll wait 2*flushInterval to ensure coverage data is flushed to the Clover database before running
* any query on it.
*
* Note: The only use case where you would want to turn this off is if you're running your tests in a separate
* JVM. In that case the coverage data will be flushed by default upon the JVM shutdown and there would be no need
* to wait for the data to be flushed. As we can't control whether users want to fork their tests or not, we're
* offering this parameter to them.
*
* @parameter default-value="true"
*/
private boolean waitForFlush;
/**
* Decide whether to generate an HTML report or not.
* @parameter default-value="true"
*/
private boolean generateHtml;
/**
* Decide whether to generate a PDF report or not.
* @parameter default-value="false"
*/
private boolean generatePdf;
/**
* Decide whether to generate a XML report or not.
* @parameter default-value="false"
*/
private boolean generateXml;
/**
* Decide whether to generate a Clover historical report or not.
* @parameter default-value="false"
*/
private boolean generateHistorical;
/**
* Comma or space separated list of Clover contexts (block, statement or method filers) to exclude when
* generating coverage reports.
* @parameter
*/
private String contextFilters;
/**
* Note: This is passed by Maven and must not be configured by the user.
*
* @component
*/
private Renderer siteRenderer;
/**
* The Maven project instance for the executing project.
*
* Note: This is passed by Maven and must not be configured by the user.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* The projects in the reactor for aggregation report.
*
* Note: This is passed by Maven and must not be configured by the user.
*
* @parameter expression="${reactorProjects}"
* @readonly
*/
private List reactorProjects;
/**
* A Clover license file to be used by the plugin. The plugin tries to resolve this parameter first as a resource,
* then as a URL, and then as a file location on the filesystem.
*
* @parameter
*/
private String licenseLocation;
/**
* Resource manager used to locate any Clover license file provided by the user.
* @component
*/
private ResourceManager resourceManager;
/**
* @see org.apache.maven.reporting.AbstractMavenReport#executeReport(java.util.Locale)
*/
public void executeReport( Locale locale ) throws MavenReportException
{
// Register the Clover license
try
{
AbstractCloverMojo.registerLicenseFile(this.resourceManager, this.licenseLocation, getLog(),
this.getClass().getClassLoader());
}
catch (MojoExecutionException e)
{
throw new MavenReportException("Failed to locate Clover license", e);
}
// Ensure the output directory exists
this.outputDirectory.mkdirs();
File singleModuleCloverDatabase = new File( this.cloverDatabase );
if ( singleModuleCloverDatabase.exists() )
{
createAllReportTypes( this.cloverDatabase, "Maven Clover" );
}
File mergedCloverDatabase = new File ( this.cloverMergeDatabase );
if ( mergedCloverDatabase.exists() )
{
createAllReportTypes( this.cloverMergeDatabase, "Maven Aggregated Clover" );
}
}
/**
* Example of title prefixes: "Maven Clover", "Maven Aggregated Clover"
*/
private void createAllReportTypes( String database, String titlePrefix )
{
File historyDir = new File( this.outputDirectory, "history" );
if ( this.generateHtml )
{
createReport( database,
createCurrentReportForCloverReportTask( titlePrefix + " report", this.outputDirectory, false ),
createHistoricalReportForCloverReportTask( titlePrefix + " historical report", historyDir ),
createFormatTypeForCloverReportTask( "html" ) );
}
if ( this.generatePdf )
{
// Note: PDF reports only support summary reports
createReport( database, createCurrentReportForCloverReportTask( titlePrefix + "report",
new File( this.outputDirectory, "clover.pdf" ), true ),
createHistoricalReportForCloverReportTask( titlePrefix + "Historical report",
new File( historyDir, "clover-history.pdf" ) ),
createFormatTypeForCloverReportTask( "pdf" ) );
}
if ( this.generateXml )
{
// No historical reports for XML outputs
createReport( database,
createCurrentReportForCloverReportTask( titlePrefix + "report",
new File( this.outputDirectory, "clover.xml" ), false ),
null,
createFormatTypeForCloverReportTask( "xml" ) );
}
}
/**
* Note: We use Clover's clover-report
Ant task instead of the Clover CLI APIs because the CLI
* APIs are limited and do not support historical reports.
*/
private void createReport( String database, CloverReportTask.CurrentEx currentEx,
CloverReportTask.HistoricalEx historicalEx, CloverFormatType type )
{
Project antProject = AbstractCloverMojo.registerCloverAntTasks();
CloverReportTask cloverReportTask = (CloverReportTask) antProject.createTask( "clover-report" );
cloverReportTask.setInitString( database );
// Add current report definition
currentEx.addFormat( type );
cloverReportTask.addCurrent( currentEx );
// Add historical report definition
if ( historicalEx != null )
{
historicalEx.addFormat( type );
cloverReportTask.addHistorical( historicalEx );
}
cloverReportTask.execute();
}
private CloverReportTask.CurrentEx createCurrentReportForCloverReportTask( String title, File outFile,
boolean isSummaryReport )
{
CloverReportTask.CurrentEx currentEx = new CloverReportTask.CurrentEx();
currentEx.setTitle( title );
currentEx.setAlwaysReport( true );
currentEx.setOutFile( outFile );
currentEx.setSummary( isSummaryReport );
return currentEx;
}
private CloverReportTask.HistoricalEx createHistoricalReportForCloverReportTask( String title, File outFile)
{
CloverReportTask.HistoricalEx historicalEx = null;
// Only generate historical reports if the user has asked for it, if the history dir exists and if it contains
// historical data.
if ( this.generateHistorical && isHistoricalDirectoryValid( outFile ) )
{
historicalEx = new CloverReportTask.HistoricalEx();
historicalEx.setTitle( title );
historicalEx.setAlwaysReport( true );
historicalEx.setOutFile( outFile );
historicalEx.setHistoryDir( new File( this.historyDir ) );
}
return historicalEx;
}
private boolean isHistoricalDirectoryValid( File outFile )
{
boolean isValid = false;
File dir = new File ( this.historyDir );
if ( dir.exists() )
{
if ( dir.listFiles().length > 0 )
{
isValid = true;
}
else
{
getLog().warn( "No Clover historical data found in [" + this.historyDir + "], skipping Clover "
+ "historical report generation ([" + outFile + "])" );
}
}
else
{
getLog().warn( "Clover historical directory [" + this.historyDir + "] does not exist, skipping Clover "
+ "historical report generation ([" + outFile + "])" );
}
return isValid;
}
private CloverFormatType createFormatTypeForCloverReportTask( String format )
{
CloverFormatType type = new CloverFormatType();
type.setType( format );
if ( this.contextFilters != null )
{
type.setFilter( contextFilters );
}
return type;
}
/**
* @see org.apache.maven.reporting.MavenReport#getOutputName()
*/
public String getOutputName()
{
return "clover/index";
}
/**
* @see org.apache.maven.reporting.MavenReport#getDescription(java.util.Locale)
*/
public String getDescription( Locale locale )
{
return getBundle( locale ).getString( "report.clover.description" );
}
private static ResourceBundle getBundle( Locale locale )
{
return ResourceBundle.getBundle( "clover-report", locale, CloverReportMojo.class.getClassLoader() );
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
*/
protected String getOutputDirectory()
{
return this.outputDirectory.getAbsoluteFile().toString();
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
*/
protected Renderer getSiteRenderer()
{
return this.siteRenderer;
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#getProject()
*/
protected MavenProject getProject()
{
return this.project;
}
/**
* @see org.apache.maven.reporting.MavenReport#getName(java.util.Locale)
*/
public String getName( Locale locale )
{
return getBundle( locale ).getString( "report.clover.name" );
}
/**
* Always return true as we're using the report generated by Clover rather than creating our own report.
* @return true
*/
public boolean isExternalReport()
{
return true;
}
/**
* Generate reports if a Clover module database or a Clover merged database exist.
*
* @return true if a project should be generated
* @see org.apache.maven.reporting.AbstractMavenReport#canGenerateReport()
*/
public boolean canGenerateReport()
{
boolean canGenerate = false;
AbstractCloverMojo.waitForFlush( this.waitForFlush, this.flushInterval );
File singleModuleCloverDatabase = new File( this.cloverDatabase );
File mergedCloverDatabase = new File ( this.cloverMergeDatabase );
if (singleModuleCloverDatabase.exists() || mergedCloverDatabase.exists() )
{
if ( this.generateHtml || this.generatePdf || this.generateXml )
{
canGenerate = true;
}
}
else
{
getLog().warn("No Clover database found, skipping report generation");
}
return canGenerate;
}
/**
* @see org.apache.maven.reporting.AbstractMavenReport#setReportOutputDirectory(java.io.File)
*/
public void setReportOutputDirectory( File reportOutputDirectory )
{
if ( ( reportOutputDirectory != null ) && ( !reportOutputDirectory.getAbsolutePath().endsWith( "clover" ) ) )
{
this.outputDirectory = new File( reportOutputDirectory, "clover" );
}
else
{
this.outputDirectory = reportOutputDirectory;
}
}
}