/* * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the "License"). You may not use this file except * in compliance with the License. * * You can obtain a copy of the license at * https://jwsdp.dev.java.net/CDDLv1.0.html * See the License for the specific language governing * permissions and limitations under the License. * * When distributing Covered Code, include this CDDL * HEADER in each file and include the License file at * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable, * add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your * own identifying information: Portions Copyright [yyyy] * [name of copyright owner] */ package hudson.plugins.javatest_report; import hudson.Extension; import hudson.FilePath; import hudson.FilePath.FileCallable; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.remoting.VirtualChannel; import hudson.model.Build; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Project; import hudson.model.Result; import hudson.model.Action; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; import hudson.tasks.test.TestResultProjectAction; import hudson.util.IOException2; import org.apache.tools.ant.types.FileSet; import org.kohsuke.stapler.StaplerRequest; import java.io.File; import java.io.IOException; import java.io.Serializable; import net.sf.json.JSONObject; /** * @author Rama Pulavarthi */ public class JavaTestReportPublisher extends Recorder implements Serializable { private final String includes; private final String jtwork; public JavaTestReportPublisher(String includes,String jtwork) { this.includes = includes; this.jtwork = jtwork; } /** * Ant "<fileset @includes="..." /> pattern to specify SQE XML files */ public String getIncludes() { return includes; } /** * TCK work directory so that JTR files can be accessed. */ public String getJtwork() { return jtwork; } public Action getProjectAction(Project project) { return new TestResultProjectAction(project); } /** * Indicates an orderly abortion of the processing. */ private static final class AbortException extends RuntimeException { public AbortException(String s) { super(s); } } @Override public boolean perform(AbstractBuild<?,?> build, Launcher launcher, final BuildListener listener) throws IOException, InterruptedException { archiveJTWork(build,listener); listener.getLogger().println("Collecting JavaTest reports"); // target directory File dataDir = JavaTestAction.getDataDir(build); dataDir.mkdirs(); final FilePath target = new FilePath(dataDir); final long buildTime = build.getTimestamp().getTimeInMillis(); final long nowMaster = System.currentTimeMillis(); try { build.getWorkspace().act(new FileCallable<Void>() { public Void invoke(File ws, VirtualChannel channel) throws IOException { final long nowSlave = System.currentTimeMillis(); FileSet fs = new FileSet(); org.apache.tools.ant.Project p = new org.apache.tools.ant.Project(); fs.setProject(p); fs.setDir(ws); fs.setIncludes(includes); String[] includedFiles = fs.getDirectoryScanner(p).getIncludedFiles(); if(includedFiles.length==0) // no test result. Most likely a configuration error or fatal problem throw new AbortException("No Java test report files were found. Configuration error?"); int counter=0; // archive report files. // this is not the most efficient way to do this, // but there usually aren't too many report files, so this works OK in practice. for (String file : includedFiles) { File src = new File(ws, file); if(src.lastModified()<buildTime+(nowSlave-nowMaster)) { listener.getLogger().println("Skipping "+src+" because it's not up to date"); continue; // not up to date. } try { new FilePath(src).copyTo(target.child("report"+(counter++)+".xml")); } catch (InterruptedException e) { throw new IOException2("aborted while copying "+src,e); } } return null; } private static final long serialVersionUID = 1L; }); } catch (AbortException e) { listener.getLogger().println(e.getMessage()); build.setResult(Result.FAILURE); return true; /// but this is not a fatal error } JavaTestAction action = new JavaTestAction(build, listener); build.getActions().add(action); Report r = action.getResult(); if(r.getTotalCount()==0) { listener.getLogger().println("Test reports were found but none of them are new. Did tests run?"); // no test result. Most likely a configuration error or fatal problem build.setResult(Result.FAILURE); } if(r.getFailCount()>0) build.setResult(Result.UNSTABLE); return true; } private void archiveJTWork(AbstractBuild<?,?> owner, BuildListener listener) throws IOException, InterruptedException { if (jtwork == null || jtwork.equals("")) { listener.getLogger().println("Set JavaTest Work directory for better reporting"); } else { owner.getWorkspace().child(jtwork).copyRecursiveTo("**/*", new FilePath(owner.getArtifactsDir()).child("java-test-work")); } } public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.BUILD; } @Override public BuildStepDescriptor<Publisher> getDescriptor() { return DescriptorImpl.DESCRIPTOR; } public static class DescriptorImpl extends BuildStepDescriptor<Publisher> { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); public DescriptorImpl() { super(JavaTestReportPublisher.class); } public String getDisplayName() { return "Publish JavaTest result report"; } @Override public String getHelpFile() { return "/plugin/javatest-report/help.html"; } @Override public Publisher newInstance(StaplerRequest req, JSONObject formData) { return new JavaTestReportPublisher(req.getParameter("javatest_includes"), req.getParameter("javatest_jtwork")); } @Override public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; } } private static final long serialVersionUID = 1L; }