package hudson.plugins.concordionpresenter;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.servlet.ServletException;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import hudson.tasks.Recorder;
import hudson.util.FormValidation;
/**
* Simple Recorder plugin for archiving Concordion test report pages.
*
* @author Rob Johnston <rob@rjohnst.com>
*/
public class ConcordionPresenter extends Recorder implements Serializable {
private static final long serialVersionUID = -6785762127770397981L;
private final String location;
private static volatile List<ConcordionProjectAction> actions = new ArrayList<ConcordionProjectAction>();
@DataBoundConstructor
public ConcordionPresenter(final String location) {
this.location = location;
}
protected static FilePath getConcordionReportDirectory(final AbstractBuild<?, ?> build) {
return new FilePath(new File(build.getRootDir(), "concordion"));
}
public String getLocation() {
return location;
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.BUILD;
}
@Override
public boolean perform(final AbstractBuild<?, ?> build,
final Launcher launcher, final BuildListener listener) throws InterruptedException, IOException {
listener.getLogger().println("Archiving Concordion test report...");
ConcordionBuildAction action;
final long buildTime = build.getTimeInMillis();
try {
final FilePath testReport = build.getWorkspace().child(getLocation());
if (build.getResult().isWorseOrEqualTo(Result.FAILURE) &&
buildTime + 1000 /*error margin*/ > testReport.lastModified()) {
listener.getLogger().println("Concordion report looks stale, not archiving. Did tests run?");
return true;
}
final FilePath target = getConcordionReportDirectory(build);
listener.getLogger().println(String.format("Archiving report from %s to %s", testReport, target));
testReport.copyRecursiveTo(target);
action = new ConcordionBuildAction(build);
} catch (IOException e) {
e.printStackTrace(listener.error("Failed to archive concordion report"));
build.setResult(Result.FAILURE);
return true;
}
build.getActions().add(action);
return true;
}
@Override
public BuildStepDescriptor getDescriptor() {
return (DescriptorImpl) super.getDescriptor();
}
@Override
public Collection<? extends Action> getProjectActions(
AbstractProject<?, ?> project) {
// the ProjectAction is stateless, so let's not keep creating them
if (actions.size() == 0) {
synchronized (this) {
if (actions.size() == 0) {
// double checked locking works in java5
actions.add(new ConcordionProjectAction());
}
}
}
return actions;
}
@Extension
public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
public FormValidation doCheckLocation(@AncestorInPath final AbstractProject<?, ?> project, @QueryParameter final String value) throws IOException, ServletException {
return FilePath.validateFileMask(project.getSomeWorkspace(), value);
}
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
@Override
public String getDisplayName() {
return "Publish Concordion test report";
}
}
}