diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/AbstractReport.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/AbstractReport.java index cba11ff..2e5c65a 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/AbstractReport.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/AbstractReport.java @@ -1,6 +1,6 @@ package com.vectorcast.plugins.vectorcastcoverage; -import hudson.model.AbstractBuild; +import hudson.model.Run; import hudson.model.ModelObject; import java.io.IOException; @@ -70,7 +70,7 @@ public SELF getPreviousResult() { } @Override - public AbstractBuild getBuild() { + public Run getBuild() { return parent.getBuild(); } } diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/CoverageReport.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/CoverageReport.java index 0da1c9c..0e05077 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/CoverageReport.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/CoverageReport.java @@ -1,6 +1,6 @@ package com.vectorcast.plugins.vectorcastcoverage; -import hudson.model.AbstractBuild; +import hudson.model.Run; import hudson.util.IOException2; import org.apache.commons.digester.Digester; import org.xml.sax.SAXException; @@ -54,7 +54,7 @@ public CoverageReport getPreviousResult() { } @Override - public AbstractBuild getBuild() { + public Run getBuild() { return action.owner; } diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTBuildAction.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTBuildAction.java index a2f1438..6549b76 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTBuildAction.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTBuildAction.java @@ -22,6 +22,13 @@ import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; +import jenkins.model.RunAction2; +import jenkins.tasks.SimpleBuildStep.LastBuildAction; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import hudson.model.Action; +import hudson.model.Run; /** * Build view extension by VectorCAST plugin. @@ -30,12 +37,13 @@ * * @author Kohsuke Kawaguchi */ -public final class VectorCASTBuildAction extends CoverageObject implements HealthReportingAction, StaplerProxy { +public final class VectorCASTBuildAction extends CoverageObject implements HealthReportingAction, StaplerProxy, Serializable, RunAction2, LastBuildAction { - public final AbstractBuild owner; + public transient Run owner; private transient WeakReference report; - + private transient VectorCASTProjectAction vectorcastProjectAction; + /** * Non-null if the coverage has pass/fail rules. */ @@ -43,11 +51,10 @@ public final class VectorCASTBuildAction extends CoverageObject owner, Rule rule, Ratio StatementCoverage, Ratio BranchCoverage, Ratio BasisPathCoverage, Ratio MCDCCoverage, Ratio FunctionCoverage, Ratio FunctionCallCoverage, Ratio Complexity, VectorCASTHealthReportThresholds thresholds) { + public VectorCASTBuildAction(Run owner, Rule rule, Ratio StatementCoverage, Ratio BranchCoverage, Ratio BasisPathCoverage, Ratio MCDCCoverage, Ratio FunctionCoverage, Ratio FunctionCallCoverage, Ratio Complexity, VectorCASTHealthReportThresholds thresholds) { this.owner = owner; this.rule = rule; this.Statement = StatementCoverage; @@ -158,7 +165,7 @@ public Object getTarget() { } @Override - public AbstractBuild getBuild() { + public Run getBuild() { return owner; } @@ -223,8 +230,8 @@ public VectorCASTBuildAction getPreviousResult() { /** * Gets the previous {@link VectorCASTBuildAction} of the given build. */ - /*package*/ static VectorCASTBuildAction getPreviousResult(AbstractBuild start) { - AbstractBuild b = start; + /*package*/ static VectorCASTBuildAction getPreviousResult(Run start) { + Run b = start; while(true) { b = b.getPreviousBuild(); if(b==null) @@ -268,6 +275,24 @@ public static VectorCASTBuildAction load(AbstractBuild owner, Rule rule, Ve return new VectorCASTBuildAction(owner,rule,ratios[0],ratios[1],ratios[2],ratios[3],ratios[4],ratios[5],ratios[6],thresholds); } + + public static VectorCASTBuildAction load(Run owner, Rule rule, VectorCASTHealthReportThresholds thresholds, InputStream... streams) throws IOException { + Ratio ratios[] = null; + boolean[] flag = {false}; + for (InputStream in: streams) { + try { + ratios = loadRatios(in, ratios, flag); + } catch (XmlPullParserException e) { + throw new IOException2("Failed to parse " + in, e); + } finally { + if (in != null) { + in.close(); + } + } + } + + return new VectorCASTBuildAction(owner,rule,ratios[0],ratios[1],ratios[2],ratios[3],ratios[4],ratios[5],ratios[6],thresholds); + } public static VectorCASTBuildAction load(AbstractBuild owner, Rule rule, VectorCASTHealthReportThresholds thresholds, InputStream... streams) throws IOException, XmlPullParserException { Ratio ratios[] = null; @@ -361,5 +386,31 @@ else if ( t.equals("complexity, %") ) } + private void setOwner(Run owner) { + logger.log(Level.INFO,"setOwner (create new vectorcastProjectAction)"); + vectorcastProjectAction = new VectorCASTProjectAction (owner.getParent()); + + this.owner = owner; + } + + @Override + public void onLoad(Run run) { + setOwner(run); + } + + @Override + public void onAttached(Run run) { + setOwner(run); + } + + @Override + public Collection getProjectActions() { + if (vectorcastProjectAction == null) + { + vectorcastProjectAction = new VectorCASTProjectAction (owner.getParent()); + } + return Collections.singletonList(vectorcastProjectAction); + } + private static final Logger logger = Logger.getLogger(VectorCASTBuildAction.class.getName()); } diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTHealthReportThresholds.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTHealthReportThresholds.java index 1616439..df5a1e1 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTHealthReportThresholds.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTHealthReportThresholds.java @@ -1,6 +1,7 @@ package com.vectorcast.plugins.vectorcastcoverage; import java.io.Serializable; +import org.kohsuke.stapler.DataBoundConstructor; /** * Holds the configuration details for {@link hudson.model.HealthReport} generation @@ -26,6 +27,7 @@ public class VectorCASTHealthReportThresholds implements Serializable { public VectorCASTHealthReportThresholds() { } + @DataBoundConstructor public VectorCASTHealthReportThresholds(int minStatement, int maxStatement, int minBranch, int maxBranch, int minBasisPath, int maxBasisPath, int minMCDC, int maxMCDC, int minFunction, int maxFunction, int minFunctionCall, int maxFunctionCall) { this.minStatement = minStatement; this.maxStatement = maxStatement; diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTProjectAction.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTProjectAction.java index d111114..3ac3a5d 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTProjectAction.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTProjectAction.java @@ -1,23 +1,23 @@ package com.vectorcast.plugins.vectorcastcoverage; -import hudson.model.AbstractBuild; -import hudson.model.AbstractProject; +import hudson.model.Job; +import hudson.model.Run; import hudson.model.Action; import hudson.model.Result; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.io.IOException; - + /** * Project view extension by VectorCAST plugin. * * @author Kohsuke Kawaguchi */ public final class VectorCASTProjectAction implements Action { - public final AbstractProject project; + public final Job project; - public VectorCASTProjectAction(AbstractProject project) { + public VectorCASTProjectAction(Job project) { this.project = project; } @@ -38,7 +38,7 @@ public String getUrlName() { * @return last build result */ public VectorCASTBuildAction getLastResult() { - for( AbstractBuild b = project.getLastBuild(); b!=null; b=b.getPreviousBuild()) { + for( Run b = project.getLastBuild(); b!=null; b=b.getPreviousBuild()) { if(b.getResult()== Result.FAILURE) continue; VectorCASTBuildAction r = b.getAction(VectorCASTBuildAction.class); @@ -49,7 +49,7 @@ public VectorCASTBuildAction getLastResult() { } public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException { - if (getLastResult() != null) - getLastResult().doGraph(req,rsp); + if (getLastResult() != null) + getLastResult().doGraph(req,rsp); } } diff --git a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTPublisher.java b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTPublisher.java index d21f6d9..7d28526 100644 --- a/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTPublisher.java +++ b/src/main/java/com/vectorcast/plugins/vectorcastcoverage/VectorCASTPublisher.java @@ -10,44 +10,77 @@ import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; -import hudson.model.BuildListener; +import hudson.model.TaskListener; import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; +import hudson.model.Run; +import java.io.InputStream; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; +import javax.annotation.Nonnull; +import org.kohsuke.stapler.DataBoundConstructor; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import jenkins.tasks.SimpleBuildStep; +import hudson.model.Job; /** * {@link Publisher} that captures VectorCAST coverage reports. * * @author Kohsuke Kawaguchi */ -public class VectorCASTPublisher extends Recorder { +public class VectorCASTPublisher extends Recorder implements SimpleBuildStep { /** * Relative path to the VectorCAST XML file inside the workspace. */ public String includes; - public boolean useThreshold; + public VectorCASTHealthReportThresholds healthyTarget; + public VectorCASTHealthReportThresholds unhealthyTarget; + /** /** * Rule to be enforced. Can be null. * * TODO: define a configuration mechanism. */ public Rule rule; - + + public VectorCASTPublisher() { + this.includes = "xml_data/coverage_results*.xml"; + this.useThreshold = false; + this.healthyTarget = new VectorCASTHealthReportThresholds(); + this.unhealthyTarget = new VectorCASTHealthReportThresholds(); + } + + public VectorCASTPublisher(String includes, Boolean useThreshold) { + this.includes = includes; + this.useThreshold = useThreshold; + this.healthyTarget = new VectorCASTHealthReportThresholds(); + this.unhealthyTarget = new VectorCASTHealthReportThresholds(); + } + + @DataBoundConstructor + public VectorCASTPublisher(String includes, Boolean useThreshold, VectorCASTHealthReportThresholds healthyTarget, VectorCASTHealthReportThresholds unhealthyTarget) { + this.includes = includes; + this.useThreshold = useThreshold; + this.healthyTarget = healthyTarget; + this.unhealthyTarget = unhealthyTarget; + } /** * {@link hudson.model.HealthReport} thresholds to apply. */ @@ -107,48 +140,65 @@ protected static void saveCoverageReports(FilePath folder, FilePath[] files) thr } @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + public void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnull Launcher launcher, + @Nonnull TaskListener listener) throws InterruptedException, IOException { + performImpl(run, workspace, listener); + } + + + public boolean performImpl(Run run, FilePath workspace, TaskListener listener) throws InterruptedException, IOException { final PrintStream logger = listener.getLogger(); + // Make sure VectorCAST actually ran - if (build instanceof MavenBuild) { - MavenBuild mavenBuild = (MavenBuild) build; + if (run instanceof MavenBuild) { + MavenBuild mavenBuild = (MavenBuild) run; if (!didVecctorCASTRun(mavenBuild)) { listener.getLogger().println("Skipping VecctorCAST coverage report as mojo did not run."); return true; } - } else if (build instanceof MavenModuleSetBuild) { - MavenModuleSetBuild moduleSetBuild = (MavenModuleSetBuild) build; + } else if (run instanceof MavenModuleSetBuild) { + MavenModuleSetBuild moduleSetBuild = (MavenModuleSetBuild) run; if (!didVecctorCASTRun(moduleSetBuild.getModuleLastBuilds().values())) { listener.getLogger().println("Skipping VecctorCAST coverage report as mojo did not run."); return true; } } - EnvVars env = build.getEnvironment(listener); - env.overrideAll(build.getBuildVariables()); + Map envs; + if (run instanceof AbstractBuild) + { + envs = ((AbstractBuild) run).getBuildVariables(); + } + else + { + envs = Collections.emptyMap(); + } + + EnvVars env = run.getEnvironment(listener); + env.overrideAll(envs); includes = env.expand(includes); FilePath[] reports; if (includes == null || includes.trim().length() == 0) { - FilePath workspace = build.getWorkspace(); + //FilePath workspace = build.getWorkspace(); if (workspace!= null) { logger.println("[VectorCASTCoverage] [INFO]: looking for coverage reports in the entire workspace: " + workspace.getRemote()); } - reports = locateCoverageReports(build.getWorkspace(), "**/coverage.xml"); + reports = locateCoverageReports(workspace, "**/coverage.xml"); } else { logger.println("[VectorCASTCoverage] [INFO]: looking for coverage reports in the provided path: " + includes); - reports = locateCoverageReports(build.getWorkspace(), includes); + reports = locateCoverageReports(workspace, includes); } if (reports.length == 0) { - Result result = build.getResult(); + Result result = run.getResult(); if (result == null || result.isWorseThan(Result.UNSTABLE)) { return true; } logger.println("[VectorCASTCoverage] [INFO]: no coverage files found in workspace. Was any report generated?"); - build.setResult(Result.FAILURE); + run.setResult(Result.FAILURE); return true; } else { StringBuffer buf = new StringBuffer(); @@ -159,31 +209,37 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen logger.println("[VectorCASTCoverage] [INFO]: found " + reports.length + " report files: " + buf.toString()); } - FilePath vcFolder = new FilePath(getVectorCASTReport(build)); + FilePath vcFolder = new FilePath(getVectorCASTReport(run)); saveCoverageReports(vcFolder, reports); - logger.println("[VectorCASTCoverage] [INFO]: stored " + reports.length + " report file(s) in the build folder: " + vcFolder); + logger.println("[VectorCASTCoverage] [INFO]: stored " + reports.length + " report file(s) in the run folder: " + vcFolder); + + //convert FilePath to steams + InputStream[] streams = new InputStream[reports.length]; + for (int i=0; i build, + private void checkThreshold(Run run, final PrintStream logger, EnvVars env, final VectorCASTBuildAction action) { Ratio ratio = null; @@ -199,7 +255,7 @@ private void checkThreshold(AbstractBuild build, || isFunctionCoverageOk(action) || isFunctionCallCoverageOk(action)){ logger.println("[VectorCASTCoverage] [INFO]: Build failed due to coverage percentage threshold exceeds "); - build.setResult(Result.FAILURE); + run.setResult(Result.FAILURE); } if (isStatementCoverageOk(action)) { logger.println("[VectorCASTCoverage] [INFO]: Statement coverage "+action.getStatementCoverage().getPercentage()+"% < "+healthReports.getMinStatement()+"%."); @@ -261,8 +317,8 @@ private boolean isFunctionCallCoverageOk(final VectorCASTBuildAction action) thr return action.getFunctionCallCoverage().getPercentage() < healthReports.getMinFunctionCall(); } - @Override - public Action getProjectAction(AbstractProject project) { + + public Action getProjectAction(Job project) { return new VectorCASTProjectAction(project); } @@ -274,8 +330,8 @@ public BuildStepMonitor getRequiredMonitorService() { /** * Gets the directory to store report files */ - static File getVectorCASTReport(AbstractBuild build) { - return new File(build.getRootDir(), "vectorcastcoverage"); + static File getVectorCASTReport(Run run ) { + return new File(run.getRootDir(), "vectorcastcoverage"); } @Override @@ -284,8 +340,8 @@ public BuildStepDescriptor getDescriptor() { } private boolean didVecctorCASTRun(Iterable mavenBuilds) { - for (MavenBuild build : mavenBuilds) { - if (didVecctorCASTRun(build)) { + for (MavenBuild run : mavenBuilds) { + if (didVecctorCASTRun(run)) { return true; } } @@ -315,14 +371,21 @@ public String getDisplayName() { return Messages.VcastCoveragePublisher_DisplayName(); } - @Override public boolean isApplicable(Class aClass) { return true; } + @Override + public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { + req.bindParameters(this, "vectorcastcoverage."); + save(); + return super.configure(req, formData); + } + @Override public Publisher newInstance(StaplerRequest req, JSONObject json) throws FormException { VectorCASTPublisher pub = new VectorCASTPublisher(); + req.bindParameters(pub, "vectorcastcoverage."); req.bindParameters(pub.healthReports, "vectorCASTHealthReports."); // start ugly hack