package hudson.plugins.cobertura;
import hudson.Extension;
import hudson.FilePath;
import hudson.Util;
import hudson.maven.MavenBuild;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MavenModule;
import hudson.maven.MavenReporter;
import hudson.maven.MavenReporterDescriptor;
import hudson.maven.MojoInfo;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.plugins.cobertura.renderers.SourceCodePainter;
import hudson.plugins.cobertura.targets.CoverageResult;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* Created by IntelliJ IDEA.
* User: stephen
* Date: 17-Nov-2007
* Time: 19:08:46
*/
public class MavenCoberturaPublisher extends MavenReporter {
@Override
public boolean preExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
if (isCoberturaReport(mojo)) {
// tell cobertura:cobertura to generate the XML report
XmlPlexusConfiguration c = (XmlPlexusConfiguration) mojo.configuration.getChild("formats");
if (c == null) {
listener.getLogger().println("[HUDSON] Configuring cobertura-maven-plugin to enable xml reports");
XmlPlexusConfiguration fmts = new XmlPlexusConfiguration("formats");
XmlPlexusConfiguration fmt = new XmlPlexusConfiguration("format");
fmt.setValue("html"); // this is in by default
fmts.addChild(fmt);
fmt = new XmlPlexusConfiguration("format");
fmt.setValue("xml"); // need this
fmts.addChild(fmt);
mojo.configuration.addChild(fmts);
} else {
XmlPlexusConfiguration[] fmts = (XmlPlexusConfiguration[]) c.getChildren("format");
boolean xmlConfigured = false;
for (XmlPlexusConfiguration fmt : fmts) {
if ("xml".equalsIgnoreCase(fmt.getValue().trim())) {
xmlConfigured = true;
break;
}
}
if (xmlConfigured) {
listener.getLogger()
.println("[HUDSON] cobertura-maven-plugin already configured with xml reports enabled");
} else {
listener.getLogger().println("[HUDSON] Configuring cobertura-maven-plugin to enable xml reports");
XmlPlexusConfiguration fmt = new XmlPlexusConfiguration("format");
fmt.setValue("xml"); // need this
c.addChild(fmt);
}
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean postExecute(final MavenBuildProxy build, final MavenProject pom,
final MojoInfo mojo, final BuildListener listener,
final Throwable error) throws InterruptedException, IOException {
if (!isCoberturaReport(mojo)) return true;
boolean haveXMLReport = false;
File outputDir;
try {
outputDir = mojo.getConfigurationValue("outputDirectory", File.class);
if (!outputDir.exists()) {
// cobertura-maven-plugin will not generate a report for non-java projects
return true;
}
String[] formats = mojo.getConfigurationValue("formats", String[].class);
for (String o : formats) {
if ("xml".equalsIgnoreCase(o.trim())) {
haveXMLReport = true;
break;
}
}
if (!haveXMLReport) {
listener.getLogger()
.println("[HUDSON] I could not auto-configure the cobertura-maven-plugin to generate xml reports");
listener.getLogger()
.println("[HUDSON] If the cobertura plugin needs was configured to generate xml reports, e.g.");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] <plugin>");
listener.getLogger().println("[HUDSON] <groupId>org.codehaus.mojo</groupId>");
listener.getLogger().println("[HUDSON] <artifactId>codehaus-maven-plugin</artifactId>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] <configuration>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] <formats>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger()
.println("[HUDSON] <format>xml</format> <!-- ensure this format is present -->");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] </formats>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] </configuration>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] </plugin>");
listener.getLogger().println("[HUDSON] ...");
listener.getLogger().println("[HUDSON] Code coverage reports would be enabled");
build.setResult(Result.UNSTABLE);
return true;
}
} catch (ComponentConfigurationException e) {
e.printStackTrace(listener.fatalError("Unable to obtain configuration from cobertura mojo"));
build.setResult(Result.UNSTABLE);
return true;
}
File reportFile = new File(outputDir, "coverage.xml");
if (!reportFile.exists()) {
listener.getLogger()
.println("[HUDSON] Cobertura report not generated (probably this module is not a java module)");
return true;
}
FilePath reportFilePath = new FilePath(reportFile);
FilePath target = build.getRootDir();
try {
target.mkdirs();
listener.getLogger().println("[HUDSON] Recording coverage results");
reportFilePath.copyTo(target.child("coverage.xml"));
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError("Unable to copy " + reportFilePath + " to " + target));
build.setResult(Result.FAILURE);
}
CoverageResult result = null;
Set<String> sourcePaths = new HashSet<String>();
try {
result = CoberturaCoverageParser.parse(reportFile, null, sourcePaths);
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError("Unable to parse " + reportFilePath));
build.setResult(Result.FAILURE);
}
if (result != null) {
result.setOwner(null);
final FilePath paintedSourcesPath = build.getProjectRootDir().child("cobertura");
paintedSourcesPath.mkdirs();
SourceCodePainter painter = new SourceCodePainter(paintedSourcesPath, sourcePaths,
result.getPaintedSources(), listener);
new FilePath(pom.getBasedir()).act(painter);
if (!build.execute(new MavenCoberturaActionAdder(listener))) {
listener.getLogger().println("[HUDSON] Unable to add link to cobertura results");
build.setResult(Result.FAILURE);
return true;
}
} else {
listener.getLogger().println("[HUDSON] Unable to parse coverage results.");
build.setResult(Result.FAILURE);
return true;
}
build.registerAsProjectAction(this);
return true;
}
private boolean isCoberturaReport(MojoInfo mojo) {
if (!mojo.pluginName.matches("org.codehaus.mojo", "cobertura-maven-plugin"))
return false;
if (!mojo.getGoal().equals("cobertura"))
return false;
return true;
}
/**
* {@inheritDoc}
*/
@Override
public Action getProjectAction(MavenModule project) {
return new CoberturaProjectAction(project);
}
/**
* {@inheritDoc}
*/
@Override
public MavenReporterDescriptor getDescriptor() {
return DESCRIPTOR;
}
/**
* Descriptor should be singleton.
*/
@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends MavenReporterDescriptor {
/**
* Do not instantiate DescriptorImpl.
*/
private DescriptorImpl() {
super(MavenCoberturaPublisher.class);
}
/**
* {@inheritDoc}
*/
public String getDisplayName() {
return Messages.MavenCoberturaPublisher_displayName();
}
/**
* {@inheritDoc}
*/
@Override
public MavenReporter newAutoInstance(MavenModule mavenModule) {
return new MavenCoberturaPublisher();
}
}
private static final long serialVersionUID = 1L;
private static class MavenCoberturaActionAdder implements MavenBuildProxy.BuildCallable<Boolean, IOException> {
private static final long serialVersionUID = -5470450037371279762L;
@SuppressWarnings("unused")
private final BuildListener listener;
public MavenCoberturaActionAdder(BuildListener listener) {
this.listener = listener;
}
public Boolean call(MavenBuild build) throws IOException {
try {
CoberturaBuildAction cba = build.getAction(CoberturaBuildAction.class);
if (cba == null) {
File cvgxml = new File(build.getRootDir(), "coverage.xml");
CoverageResult result = CoberturaCoverageParser.parse(cvgxml, null, new HashSet<String>());
result.setOwner(build);
CoberturaBuildAction o = CoberturaBuildAction.load(build, result, null, null, false);
build.getActions().add(o);
} else {
return false;
}
} catch (NullPointerException e) {
return false;
}
return true;
}
}
}