diff --git a/pom.xml b/pom.xml index a5441c4c..9be11928 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.480.3 + 2.11 cobertura @@ -14,7 +14,10 @@ http://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin + 2.13 + 2.13 UTF-8 + 1.11 @@ -38,18 +41,6 @@ - - org.jenkins-ci.main - maven-plugin - compile - - - - org.sonatype.sisu.inject - cglib - - - org.easymock easymockclassextension @@ -59,7 +50,7 @@ org.jenkins-ci.plugins dashboard-view - 2.4 + 2.9.9 true @@ -80,6 +71,24 @@ 4.0 test + + org.jenkins-ci.plugins.workflow + workflow-job + ${workflow-jenkins-plugin.version} + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + ${workflow-jenkins-plugin.version} + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + ${workflow-jenkins-plugin.version} + test + diff --git a/src/main/java/hudson/plugins/cobertura/BuildUtils.java b/src/main/java/hudson/plugins/cobertura/BuildUtils.java index 797f62c4..70fe43d4 100644 --- a/src/main/java/hudson/plugins/cobertura/BuildUtils.java +++ b/src/main/java/hudson/plugins/cobertura/BuildUtils.java @@ -1,9 +1,9 @@ package hudson.plugins.cobertura; -import hudson.model.AbstractBuild; +import hudson.model.Run; public class BuildUtils { - public static AbstractBuild getPreviousNotFailedCompletedBuild(AbstractBuild b) { + public static Run getPreviousNotFailedCompletedBuild(Run b) { while (true) { b = b.getPreviousNotFailedBuild(); if (b == null) { diff --git a/src/main/java/hudson/plugins/cobertura/Chartable.java b/src/main/java/hudson/plugins/cobertura/Chartable.java index 7385e697..bfe8dd0a 100644 --- a/src/main/java/hudson/plugins/cobertura/Chartable.java +++ b/src/main/java/hudson/plugins/cobertura/Chartable.java @@ -1,6 +1,6 @@ package hudson.plugins.cobertura; -import hudson.model.AbstractBuild; +import hudson.model.Run; import hudson.plugins.cobertura.targets.CoverageMetric; import java.util.Map; @@ -12,6 +12,6 @@ public interface Chartable Map getResults(); - AbstractBuild< ? , ? > getOwner(); + Run getOwner(); } diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java index 0eeeb1f3..71245d44 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java @@ -1,19 +1,25 @@ package hudson.plugins.cobertura; +import hudson.model.Action; +import hudson.model.AbstractBuild; import hudson.model.HealthReport; import hudson.model.HealthReportingAction; import hudson.model.Result; -import hudson.model.AbstractBuild; +import hudson.model.Run; import hudson.plugins.cobertura.targets.CoverageMetric; import hudson.plugins.cobertura.targets.CoverageTarget; import hudson.plugins.cobertura.targets.CoverageResult; import hudson.util.ChartUtil; import hudson.util.DescribableList; +import jenkins.model.RunAction2; +import jenkins.tasks.SimpleBuildStep; import java.io.File; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; import java.util.EnumMap; import java.util.Map; import java.util.logging.Level; @@ -31,15 +37,17 @@ * @author connollys * @since 03-Jul-2007 08:43:08 */ -public class CoberturaBuildAction implements HealthReportingAction, StaplerProxy, Chartable { +public class CoberturaBuildAction implements HealthReportingAction, StaplerProxy, Chartable, SimpleBuildStep.LastBuildAction, RunAction2 { - private final AbstractBuild owner; + private transient Run owner; private CoverageTarget healthyTarget; private CoverageTarget unhealthyTarget; private boolean failUnhealthy; private boolean failUnstable; private boolean autoUpdateHealth; private boolean autoUpdateStability; + private boolean zoomCoverageChart; + private int maxNumberOfBuilds; /** * Overall coverage result. */ @@ -56,17 +64,18 @@ public HealthReport getBuildHealth() { if (health != null) { return health; } - //try to get targets from root project (for maven modules targets are null) - DescribableList rootpublishers = owner.getProject().getRootProject().getPublishersList(); - - if (rootpublishers != null) { - CoberturaPublisher publisher = (CoberturaPublisher) rootpublishers.get(CoberturaPublisher.class); - if (publisher != null) { - healthyTarget = publisher.getHealthyTarget(); - unhealthyTarget = publisher.getUnhealthyTarget(); + if (owner instanceof AbstractBuild) { + //try to get targets from root project (for maven modules targets are null) + DescribableList rootpublishers = ((AbstractBuild)owner).getProject().getRootProject().getPublishersList(); + + if (rootpublishers != null) { + CoberturaPublisher publisher = (CoberturaPublisher) rootpublishers.get(CoberturaPublisher.class); + if (publisher != null) { + healthyTarget = publisher.getHealthyTarget(); + unhealthyTarget = publisher.getUnhealthyTarget(); + } } } - if (healthyTarget == null || unhealthyTarget == null) { return null; } @@ -135,10 +144,20 @@ public Object getTarget() { return getResult(); //To change body of implemented methods use File | Settings | File Templates. } - public AbstractBuild getOwner() { + public Run getOwner() { return owner; } + private synchronized void setOwner(Run owner) { + this.owner = owner; + if (report != null) { + CoverageResult r = report.get(); + if (r != null) { + r.setOwner(owner); + } + } + } + public Map getResults() { return result; } @@ -156,8 +175,8 @@ public CoberturaBuildAction getPreviousResult() { * Gets the previous {@link CoberturaBuildAction} of the given build. */ /*package*/ - static CoberturaBuildAction getPreviousResult(AbstractBuild start) { - AbstractBuild b = start; + static CoberturaBuildAction getPreviousResult(Run start) { + Run b = start; while (true) { b = BuildUtils.getPreviousNotFailedCompletedBuild(b); if (b == null) { @@ -178,9 +197,10 @@ private boolean includeOnlyStable() { return onlyStable; } - CoberturaBuildAction(AbstractBuild owner, CoverageResult r, CoverageTarget healthyTarget, - CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, boolean autoUpdateHealth, boolean autoUpdateStability) { - this.owner = owner; + CoberturaBuildAction(CoverageResult r, CoverageTarget healthyTarget, + CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, + boolean failUnstable, boolean autoUpdateHealth, boolean autoUpdateStability, + boolean zoomCoverageChart, int maxNumberOfBuilds) { this.report = new WeakReference(r); this.healthyTarget = healthyTarget; this.unhealthyTarget = unhealthyTarget; @@ -189,7 +209,8 @@ private boolean includeOnlyStable() { this.failUnstable = failUnstable; this.autoUpdateHealth = autoUpdateHealth; this.autoUpdateStability = autoUpdateStability; - r.setOwner(owner); + this.zoomCoverageChart = zoomCoverageChart; + this.maxNumberOfBuilds = maxNumberOfBuilds; if (result == null) { result = new EnumMap(CoverageMetric.class); result.putAll(r.getResults()); @@ -200,6 +221,8 @@ private boolean includeOnlyStable() { /** * Obtains the detailed * {@link hudson.plugins.cobertura.targets.CoverageResult} instance. + * + * @return the {@link hudson.plugins.cobertura.targets.CoverageResult} instance. */ public synchronized CoverageResult getResult() { if (report != null) { @@ -227,13 +250,19 @@ public synchronized CoverageResult getResult() { } private static final Logger logger = Logger.getLogger(CoberturaBuildAction.class.getName()); - public static CoberturaBuildAction load(AbstractBuild build, CoverageResult result, CoverageTarget healthyTarget, - CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, boolean autoUpdateHealth, boolean autoUpdateStability) { - return new CoberturaBuildAction(build, result, healthyTarget, unhealthyTarget, onlyStable, failUnhealthy, failUnstable, autoUpdateHealth, autoUpdateStability); + public static CoberturaBuildAction load(CoverageResult result, CoverageTarget healthyTarget, + CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, + boolean autoUpdateHealth, boolean autoUpdateStability, boolean zoomCoverageChart, int maxNumberOfBuilds) { + return new CoberturaBuildAction(result, healthyTarget, unhealthyTarget, onlyStable, + failUnhealthy, failUnstable, autoUpdateHealth, autoUpdateStability, zoomCoverageChart, maxNumberOfBuilds); } /** * Generates the graph that shows the coverage trend up to this report. + * + * @param req the request + * @param rsp the response + * @throws IOException forwarded from StaplerResponse.sendRedirect2 */ public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException { if (ChartUtil.awtProblemCause != null) { @@ -250,4 +279,27 @@ public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException JFreeChart chart = new CoverageChart(this).createChart(); ChartUtil.generateGraph(req, rsp, chart, 500, 200); } + + public boolean getZoomCoverageChart() { + return zoomCoverageChart; + } + + public int getMaxNumberOfBuilds() { + return maxNumberOfBuilds; + } + + @Override + public Collection getProjectActions() { + return Collections.singleton(new CoberturaProjectAction(owner, onlyStable)); + } + + @Override + public void onAttached(Run r) { + setOwner(r); + } + + @Override + public void onLoad(Run r) { + setOwner(r); + } } diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java index 6fac5594..458fd1c2 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java @@ -1,6 +1,10 @@ package hudson.plugins.cobertura; -import hudson.model.*; +import hudson.model.Actionable; +import hudson.model.Job; +import hudson.model.ProminentProjectAction; +import hudson.model.Result; +import hudson.model.Run; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -13,25 +17,16 @@ */ public class CoberturaProjectAction extends Actionable implements ProminentProjectAction { - private final AbstractProject project; + private transient Run run; private boolean onlyStable; - public CoberturaProjectAction(AbstractProject project, boolean onlyStable) { - this.project = project; + public CoberturaProjectAction(Run run, boolean onlyStable) { + this.run = run; this.onlyStable = onlyStable; } - public CoberturaProjectAction(AbstractProject project) { - this.project = project; - - CoberturaPublisher cp = (CoberturaPublisher) project.getPublishersList().get(CoberturaPublisher.DESCRIPTOR); - if (cp != null) { - onlyStable = cp.getOnlyStable(); - } - } - - public AbstractProject getProject() { - return project; + public CoberturaProjectAction(Run run) { + this(run, false); } /** @@ -61,7 +56,7 @@ public String getUrlName() { * @return Value for property 'lastResult'. */ public CoberturaBuildAction getLastResult() { - for (AbstractBuild b = getLastBuildToBeConsidered(); b != null; b = BuildUtils.getPreviousNotFailedCompletedBuild(b)) { + for (Run b = getLastBuildToBeConsidered(); b != null; b = BuildUtils.getPreviousNotFailedCompletedBuild(b)) { if (b.getResult() == Result.FAILURE || (b.getResult() != Result.SUCCESS && onlyStable)) continue; CoberturaBuildAction r = b.getAction(CoberturaBuildAction.class); @@ -70,8 +65,8 @@ public CoberturaBuildAction getLastResult() { } return null; } - private AbstractBuild getLastBuildToBeConsidered(){ - return onlyStable ? project.getLastStableBuild() : project.getLastSuccessfulBuild(); + private Run getLastBuildToBeConsidered(){ + return onlyStable ? run.getParent().getLastStableBuild() : run.getParent().getLastSuccessfulBuild(); } /** * Getter for property 'lastResult'. @@ -79,7 +74,7 @@ public CoberturaBuildAction getLastResult() { * @return Value for property 'lastResult'. */ public Integer getLastResultBuild() { - for (AbstractBuild b = getLastBuildToBeConsidered(); b != null; b = BuildUtils.getPreviousNotFailedCompletedBuild(b)) { + for (Run b = getLastBuildToBeConsidered(); b != null; b = BuildUtils.getPreviousNotFailedCompletedBuild(b)) { if (b.getResult() == Result.FAILURE || (b.getResult() != Result.SUCCESS && onlyStable)) continue; CoberturaBuildAction r = b.getAction(CoberturaBuildAction.class); diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 45500b1c..355a7416 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -1,15 +1,16 @@ package hudson.plugins.cobertura; +import hudson.AbortException; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.model.Action; -import hudson.model.BuildListener; -import hudson.model.Result; -import hudson.model.AbstractBuild; import hudson.model.AbstractItem; import hudson.model.AbstractProject; +import hudson.model.Result; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.plugins.cobertura.renderers.SourceCodePainter; import hudson.plugins.cobertura.renderers.SourceEncoding; import hudson.plugins.cobertura.targets.CoverageMetric; @@ -20,6 +21,8 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; +import jenkins.MasterToSlaveFileCallable; +import jenkins.tasks.SimpleBuildStep; import java.io.File; import java.io.FilenameFilter; @@ -43,6 +46,7 @@ import org.apache.commons.beanutils.ConvertUtils; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; /** @@ -50,57 +54,58 @@ * * @author Stephen Connolly */ -public class CoberturaPublisher extends Recorder { +public class CoberturaPublisher extends Recorder implements SimpleBuildStep { - private final String coberturaReportFile; + private String coberturaReportFile; - private final boolean onlyStable; + private boolean onlyStable; - private final boolean failUnhealthy; + private boolean failUnhealthy; - private final boolean failUnstable; + private boolean failUnstable; - private final boolean autoUpdateHealth; + private boolean autoUpdateHealth; - private final boolean autoUpdateStability; + private boolean autoUpdateStability; + + private boolean zoomCoverageChart; + + private int maxNumberOfBuilds = 0; - private final boolean zoomCoverageChart; - - private final int maxNumberOfBuilds; - private boolean failNoReports = true; - private CoverageTarget healthyTarget; + private CoverageTarget healthyTarget = new CoverageTarget(); - private CoverageTarget unhealthyTarget; + private CoverageTarget unhealthyTarget = new CoverageTarget(); - private CoverageTarget failingTarget; + private CoverageTarget failingTarget = new CoverageTarget(); public static final CoberturaReportFilenameFilter COBERTURA_FILENAME_FILTER = new CoberturaReportFilenameFilter(); - private final SourceEncoding sourceEncoding; + private SourceEncoding sourceEncoding = SourceEncoding.UTF_8; + + @Deprecated + public CoberturaPublisher(String coberturaReportFile, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, + boolean autoUpdateHealth, boolean autoUpdateStability, boolean zoomCoverageChart, boolean failNoReports, SourceEncoding sourceEncoding, + int maxNumberOfBuilds) { + this.coberturaReportFile = coberturaReportFile; + this.onlyStable = onlyStable; + this.failUnhealthy = failUnhealthy; + this.failUnstable = failUnstable; + this.autoUpdateHealth = autoUpdateHealth; + this.autoUpdateStability = autoUpdateStability; + this.zoomCoverageChart = zoomCoverageChart; + this.failNoReports = failNoReports; + this.sourceEncoding = sourceEncoding; + this.maxNumberOfBuilds = maxNumberOfBuilds; + this.healthyTarget = new CoverageTarget(); + this.unhealthyTarget = new CoverageTarget(); + this.failingTarget = new CoverageTarget(); + } - /** - * @param coberturaReportFile the report directory - * @stapler-constructor - */ @DataBoundConstructor - public CoberturaPublisher(String coberturaReportFile, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, - boolean autoUpdateHealth, boolean autoUpdateStability, boolean zoomCoverageChart, boolean failNoReports, SourceEncoding sourceEncoding, - int maxNumberOfBuilds) { - this.coberturaReportFile = coberturaReportFile; - this.onlyStable = onlyStable; - this.failUnhealthy = failUnhealthy; - this.failUnstable = failUnstable; - this.autoUpdateHealth = autoUpdateHealth; - this.autoUpdateStability = autoUpdateStability; - this.zoomCoverageChart = zoomCoverageChart; - this.failNoReports = failNoReports; - this.sourceEncoding = sourceEncoding; - this.maxNumberOfBuilds = maxNumberOfBuilds; - this.healthyTarget = new CoverageTarget(); - this.unhealthyTarget = new CoverageTarget(); - this.failingTarget = new CoverageTarget(); + public CoberturaPublisher() { + this("", true, true, true, true, true, true, true, SourceEncoding.UTF_8, 42); } /** @@ -183,6 +188,15 @@ private void setTargets(List targets) { } } + /** + * @param coberturaReportFile the report directory + */ + @DataBoundSetter + public void setCoberturaReportFile(String coberturaReportFile) { + + this.coberturaReportFile = coberturaReportFile; + } + /** * Getter for property 'coberturaReportFile'. * @@ -192,6 +206,11 @@ public String getCoberturaReportFile() { return coberturaReportFile; } + @DataBoundSetter + public void setOnlyStable(boolean onlyStable) { + this.onlyStable = onlyStable; + } + /** * Which type of build should be considered. * @return the onlyStable @@ -199,11 +218,21 @@ public String getCoberturaReportFile() { public boolean getOnlyStable() { return onlyStable; } - + + @DataBoundSetter + public void setMaxNumberOfBuilds(int maxNumberOfBuilds) { + this.maxNumberOfBuilds = maxNumberOfBuilds; + } + public int getMaxNumberOfBuilds() { return maxNumberOfBuilds; } + @DataBoundSetter + public void setFailUnhealthy(boolean failUnhealthy) { + this.failUnhealthy = failUnhealthy; + } + /** * Getter for property 'failUnhealthy'. * @@ -213,6 +242,12 @@ public boolean getFailUnhealthy() { return failUnhealthy; } + + @DataBoundSetter + public void setFailUnstable(boolean failUnstable) { + this.failUnstable = failUnstable; + } + /** * Getter for property 'failUnstable'. * @@ -222,6 +257,11 @@ public boolean getFailUnstable() { return failUnstable; } + @DataBoundSetter + public void setAutoUpdateHealth(boolean autoUpdateHealth) { + this.autoUpdateHealth = autoUpdateHealth; + } + /** * Getter for property 'autoUpdateHealth'. * @@ -231,6 +271,11 @@ public boolean getAutoUpdateHealth() { return autoUpdateHealth; } + @DataBoundSetter + public void setAutoUpdateStability(boolean autoUpdateStability) { + this.autoUpdateStability = autoUpdateStability; + } + /** * Getter for property 'autoUpdateStability'. * @@ -240,14 +285,24 @@ public boolean getAutoUpdateStability() { return autoUpdateStability; } + @DataBoundSetter + public void setZoomCoverageChart(boolean zoomCoverageChart) { + this.zoomCoverageChart = zoomCoverageChart; + } + public boolean getZoomCoverageChart() { return zoomCoverageChart; } + @DataBoundSetter + public void setFailNoReports(boolean failNoReports) { + this.failNoReports = failNoReports; + } + public boolean isFailNoReports() { return failNoReports; } - + /** * Getter for property 'healthyTarget'. * @@ -306,7 +361,7 @@ public void setFailingTarget(CoverageTarget failingTarget) { * Gets the directory where the Cobertura Report is stored for the given project. */ /*package*/ - static File[] getCoberturaReports(AbstractBuild build) { + static File[] getCoberturaReports(Run build) { return build.getRootDir().listFiles(COBERTURA_FILENAME_FILTER); } @@ -314,51 +369,41 @@ static File[] getCoberturaReports(AbstractBuild build) { * {@inheritDoc} */ @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) + public void perform(Run build, FilePath workspace, Launcher launcher, final TaskListener listener) throws InterruptedException, IOException { Result threshold = onlyStable ? Result.SUCCESS : Result.UNSTABLE; - if (build.getResult().isWorseThan(threshold)) { + Result buildResult = build.getResult(); + if (buildResult != null && buildResult.isWorseThan(threshold)) { listener.getLogger().println("Skipping Cobertura coverage report as build was not " + threshold.toString() + " or better ..."); - return true; + return; } listener.getLogger().println("[Cobertura] Publishing Cobertura coverage report..."); - final FilePath[] moduleRoots = build.getModuleRoots(); - final boolean multipleModuleRoots = - moduleRoots != null && moduleRoots.length > 1; - final FilePath moduleRoot = multipleModuleRoots ? build.getWorkspace() : build.getModuleRoot(); final File buildCoberturaDir = build.getRootDir(); FilePath buildTarget = new FilePath(buildCoberturaDir); - FilePath[] reports = new FilePath[0]; + FilePath[] reports = null; try { - reports = moduleRoot.act(new ParseReportCallable(coberturaReportFile)); - - // if the build has failed, then there's not - // much point in reporting an error - if (build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { - return true; - } - + reports = workspace.act(new ParseReportCallable(coberturaReportFile)); } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("Unable to find coverage results")); - build.setResult(Result.FAILURE); + throw new AbortException("Unable to find coverage results"); } if (reports.length == 0) { String msg = "[Cobertura] No coverage results were found using the pattern '" + coberturaReportFile + "' relative to '" - + moduleRoot.getRemote() + "'." + + workspace.getRemote() + "'." + " Did you enter a pattern relative to the correct directory?" + " Did you generate the XML report(s) for Cobertura?"; listener.getLogger().println(msg); if (failNoReports) { - build.setResult(Result.FAILURE); + throw new AbortException(msg); } else { listener.getLogger().println("[Cobertura] Skipped cobertura reports."); } - return true; + return; } for (int i = 0; i < reports.length; i++) { @@ -367,8 +412,9 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen reports[i].copyTo(targetPath); } catch (IOException e) { Util.displayIOException(e, listener); - e.printStackTrace(listener.fatalError("Unable to copy coverage from " + reports[i] + " to " + buildTarget)); - build.setResult(Result.FAILURE); + String msg = "Unable to copy coverage from " + reports[i] + " to " + buildTarget; + e.printStackTrace(listener.fatalError(msg)); + throw new AbortException(msg); } } @@ -381,13 +427,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("Unable to parse " + coberturaXmlReport)); - build.setResult(Result.FAILURE); + throw new AbortException("Unable to parse " + coberturaXmlReport); } } if (result != null) { listener.getLogger().println("Cobertura coverage report found."); result.setOwner(build); - final FilePath paintedSourcesPath = new FilePath(new File(build.getProject().getRootDir(), "cobertura")); + final FilePath paintedSourcesPath = new FilePath(new File(build.getParent().getRootDir(), "cobertura")); paintedSourcesPath.mkdirs(); if (sourcePaths.contains(".")) { @@ -403,12 +449,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen SourceCodePainter painter = new SourceCodePainter(paintedSourcesPath, sourcePaths, result.getPaintedSources(), listener, getSourceEncoding()); - moduleRoot.act(painter); + workspace.act(painter); - final CoberturaBuildAction action = CoberturaBuildAction.load(build, result, healthyTarget, - unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAutoUpdateHealth(), getAutoUpdateStability()); + final CoberturaBuildAction action = CoberturaBuildAction.load(result, healthyTarget, + unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAutoUpdateHealth(), getAutoUpdateStability(), + getZoomCoverageChart(), getMaxNumberOfBuilds()); - build.getActions().add(action); + build.addAction(action); Set failingMetrics = failingTarget.getFailingMetrics(result); if (!failingMetrics.isEmpty()) { listener.getLogger().println("Code coverage enforcement failed for the following metrics:"); @@ -423,8 +470,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen listener.getLogger().println("Setting Build to unstable."); build.setResult(Result.UNSTABLE); } else { - listener.getLogger().println("Failing build due to unstability."); - build.setResult(Result.FAILURE); + throw new AbortException("Failing build due to unstability."); } } if (getFailUnhealthy()) { @@ -438,11 +484,10 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen setHealthyPercent = unhealthyTarget.getSetPercent(result, metric); listener.getLogger().println(" " + metric.getName() + "'s health is " + roundDecimalFloat(oldHealthyPercent * 100f) + " and set minimum health is " + roundDecimalFloat(setHealthyPercent * 100f) + "."); } - listener.getLogger().println("Failing build because it is unhealthy."); - build.setResult(Result.FAILURE); + throw new AbortException("Failing build because it is unhealthy."); } } - if (build.getResult() == Result.SUCCESS) { + if (build.getResult() == null || build.getResult() == Result.SUCCESS) { if (getAutoUpdateHealth()) { setNewPercentages(result, true, listener); } @@ -452,18 +497,15 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } } } else { - listener.getLogger().println("No coverage results were successfully parsed. Did you generate " + throw new AbortException("No coverage results were successfully parsed. Did you generate " + "the XML report(s) for Cobertura?"); - build.setResult(Result.FAILURE); } - - return true; } /** * Changes unhealthy or unstable percentage fields for ratcheting. */ - private void setNewPercentages(CoverageResult result, boolean select, BuildListener listener) { + private void setNewPercentages(CoverageResult result, boolean select, TaskListener listener) { Set healthyMetrics = healthyTarget.getAllMetrics(result); float newPercent; float oldPercent; @@ -491,14 +533,6 @@ private void setNewPercentages(CoverageResult result, boolean select, BuildListe } } - /** - * {@inheritDoc} - */ - @Override - public Action getProjectAction(AbstractProject project) { - return new CoberturaProjectAction(project, getOnlyStable()); - } - /** * {@inheritDoc} */ @@ -515,6 +549,11 @@ public BuildStepDescriptor getDescriptor() { return DESCRIPTOR; } + @DataBoundSetter + public void setSourceEncoding(SourceEncoding sourceEncoding) { + this.sourceEncoding = sourceEncoding; + } + public SourceEncoding getSourceEncoding() { return sourceEncoding; } @@ -525,7 +564,7 @@ public SourceEncoding getSourceEncoding() { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); - public static class ParseReportCallable implements FilePath.FileCallable { + public static class ParseReportCallable extends MasterToSlaveFileCallable { private static final long serialVersionUID = 1L; @@ -568,7 +607,7 @@ public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, Int reader.close(); } catch (XMLStreamException ex) { // - } + } } } finally { IOUtils.closeQuietly(is); @@ -583,8 +622,7 @@ public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, Int /** * Descriptor for {@link CoberturaPublisher}. Used as a singleton. The class is marked as public so that it can be * accessed from views. - *

- *

+ * * See views/hudson/plugins/cobertura/CoberturaPublisher/*.jelly for the actual HTML fragment for the * configuration screen. */ @@ -656,6 +694,9 @@ public boolean configure(StaplerRequest req, JSONObject formData) throws FormExc */ @Override public CoberturaPublisher newInstance(StaplerRequest req, JSONObject formData) throws FormException { + if (req == null) { + return null; + } CoberturaPublisher instance = req.bindJSON(CoberturaPublisher.class, formData); ConvertUtils.register(CoberturaPublisherTarget.CONVERTER, CoverageMetric.class); List targets = req diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java index 9184f375..6056ace5 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java @@ -24,11 +24,12 @@ public CoberturaPublisherTarget() { } /** - * @param metric - * @param healthy - * @param unhealthy - * @param unstable - * @stapler-constructor + * Constructor + * + * @param metric Coverage metric + * @param healthy Healthy target + * @param unhealthy Unhealthy target + * @param unstable Unstable target */ public CoberturaPublisherTarget(CoverageMetric metric, Float healthy, Float unhealthy, Float unstable) { this.metric = metric; diff --git a/src/main/java/hudson/plugins/cobertura/CoverageChart.java b/src/main/java/hudson/plugins/cobertura/CoverageChart.java index 03959066..267839f1 100644 --- a/src/main/java/hudson/plugins/cobertura/CoverageChart.java +++ b/src/main/java/hudson/plugins/cobertura/CoverageChart.java @@ -31,7 +31,9 @@ public class CoverageChart private int upperBound; /** - * @pre chartable!=null && chartable.getPreviousResult()!=null + * Constructor + * + * @param chartable Chartable object to chart */ public CoverageChart( Chartable chartable ) { @@ -39,7 +41,11 @@ public CoverageChart( Chartable chartable ) } /** - * @pre chartable!=null && chartable.getPreviousResult()!=null + * Constructor + * + * @param chartable Chartable object to chart + * @param zoomCoverageChart true to zoom coverage chart + * @param maximumBuilds maximum builds to include */ protected CoverageChart( Chartable chartable, boolean zoomCoverageChart, int maximumBuilds ) { @@ -78,33 +84,32 @@ protected CoverageChart( Chartable chartable, boolean zoomCoverageChart, int max protected static boolean isZoomCoverageChart( Chartable chartable ) { if( chartable == null ) return false; - CoberturaPublisher cp = (CoberturaPublisher) chartable.getOwner().getProject().getPublishersList().get( CoberturaPublisher.DESCRIPTOR ); + CoberturaBuildAction action = chartable.getOwner().getAction(CoberturaBuildAction.class); boolean zoomCoverageChart = false; - if( cp != null ) + if( action != null ) { - zoomCoverageChart = cp.getZoomCoverageChart(); + return action.getZoomCoverageChart(); } else { Log.warn( "Couldn't find CoberturaPublisher to decide if the graph should be zoomed" ); + return false; } - return zoomCoverageChart; } protected static int getMaximumBuilds( Chartable chartable ) { if( chartable == null ) return 0; - CoberturaPublisher cp = (CoberturaPublisher) chartable.getOwner().getProject().getPublishersList().get( CoberturaPublisher.DESCRIPTOR ); - int maximumBuilds = 0; - if( cp != null ) + CoberturaBuildAction action = chartable.getOwner().getAction(CoberturaBuildAction.class); + if( action != null ) { - maximumBuilds = cp.getMaxNumberOfBuilds(); + return action.getMaxNumberOfBuilds(); } else { Log.warn( "Couldn't find CoberturaPublisher to decide the maximum number of builds to be graphed" ); + return 0; } - return maximumBuilds; } public JFreeChart createChart() diff --git a/src/main/java/hudson/plugins/cobertura/CoverageColumn.java b/src/main/java/hudson/plugins/cobertura/CoverageColumn.java index 447b06bf..eb8e49f1 100644 --- a/src/main/java/hudson/plugins/cobertura/CoverageColumn.java +++ b/src/main/java/hudson/plugins/cobertura/CoverageColumn.java @@ -18,6 +18,8 @@ public class CoverageColumn extends ListViewColumn { /** * Creates a new instance of {@link CoverageColumn}. + * + * @param type the column type */ @DataBoundConstructor public CoverageColumn(final String type) { diff --git a/src/main/java/hudson/plugins/cobertura/IOUtils.java b/src/main/java/hudson/plugins/cobertura/IOUtils.java index 6067365f..73450a7d 100644 --- a/src/main/java/hudson/plugins/cobertura/IOUtils.java +++ b/src/main/java/hudson/plugins/cobertura/IOUtils.java @@ -9,8 +9,10 @@ public class IOUtils { /** * Closes a Closeable unconditionally. * Equivalent to Closeable.close(), except any exceptions will be ignored. This is typically used in finally blocks. - */ - public static void closeQuietly(Closeable closeable) { + * + * @param closeable the Closeable to close + */ + public static void closeQuietly(Closeable closeable) { if (closeable != null) { try { closeable.close(); diff --git a/src/main/java/hudson/plugins/cobertura/MavenCoberturaBuildAction.java b/src/main/java/hudson/plugins/cobertura/MavenCoberturaBuildAction.java index a90fd3ca..5c18b640 100644 --- a/src/main/java/hudson/plugins/cobertura/MavenCoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/MavenCoberturaBuildAction.java @@ -22,8 +22,8 @@ public class MavenCoberturaBuildAction extends CoberturaBuildAction implements A @SuppressWarnings("unused") private static final Logger LOGGER = Logger.getLogger(MavenCoberturaBuildAction.class.getName()); - MavenCoberturaBuildAction(MavenBuild build, CoverageResult r, CoverageTarget healthyTarget, CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, boolean autoUpdateHealth, boolean autoUpdateStability) { - super(build, r, healthyTarget, unhealthyTarget, onlyStable, failUnhealthy, failUnstable, autoUpdateHealth, autoUpdateStability); + MavenCoberturaBuildAction(CoverageResult r, CoverageTarget healthyTarget, CoverageTarget unhealthyTarget, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, boolean autoUpdateHealth, boolean autoUpdateStability, boolean zoomCoverageChart, int maxNumberOfBuilds) { + super(r, healthyTarget, unhealthyTarget, onlyStable, failUnhealthy, failUnstable, autoUpdateHealth, autoUpdateStability, zoomCoverageChart, maxNumberOfBuilds); } public MavenAggregatedReport createAggregatedAction(MavenModuleSetBuild build, Map> moduleBuilds) { diff --git a/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java index 09eec173..e6d2a6f8 100644 --- a/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java @@ -106,17 +106,19 @@ public boolean postExecute(final MavenBuildProxy build, final MavenProject pom, File outputDir; try { outputDir = mojo.getConfigurationValue("outputDirectory", File.class); - if (!outputDir.exists()) { + if (outputDir == null || !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 (formats != null) { + for (String o : formats) { + if ("xml".equalsIgnoreCase(o.trim())) { + haveXMLReport = true; + break; + } } } if (!haveXMLReport) { @@ -221,7 +223,7 @@ private boolean isCoberturaReport(MojoInfo mojo) { */ @Override public Collection getProjectActions(MavenModule project) { - return Collections.singleton(new CoberturaProjectAction(project)); + return Collections.singleton(new CoberturaProjectAction(project.getLastBuild())); } /** @@ -281,8 +283,8 @@ public Boolean call(MavenBuild build) throws IOException { CoverageResult result = CoberturaCoverageParser.parse(cvgxml, null, new HashSet()); result.setOwner(build); - CoberturaBuildAction o = CoberturaBuildAction.load(build, result, null, null, false, false, false, false, false); - build.getActions().add(o); + CoberturaBuildAction o = CoberturaBuildAction.load(result, null, null, false, false, false, false, false, false, 0); + build.addAction(o); } else { return false; } diff --git a/src/main/java/hudson/plugins/cobertura/Ratio.java b/src/main/java/hudson/plugins/cobertura/Ratio.java index 3030bace..562e5d56 100644 --- a/src/main/java/hudson/plugins/cobertura/Ratio.java +++ b/src/main/java/hudson/plugins/cobertura/Ratio.java @@ -35,6 +35,8 @@ private String print(float f) { /** * Gets the percentage in integer. + * + * @return percentage */ public int getPercentage() { return Math.round(getPercentageFloat()); @@ -44,6 +46,8 @@ public int getPercentage() { * Gets the percentage in float. * For exceptional cases of 0/0, return 100% as it corresponds to expected ammout. * For error cases of x/0, return 0% as x is unexpected ammout. + * + * @return percentage */ public float getPercentageFloat() { return denominator == 0 ? (numerator == 0 ? 100.0f : 0.0f) : (100 * numerator / denominator); @@ -52,7 +56,9 @@ public float getPercentageFloat() { static NumberFormat dataFormat = new DecimalFormat("000.00"); /** - * Gets the percentage as a formated string used for sorting the html table + * Gets the percentage as a formatted string used for sorting the html table + * + * @return percentage */ public String getPercentageString() { return dataFormat.format(getPercentageFloat()); @@ -84,8 +90,8 @@ public int hashCode() { private static final long serialVersionUID = 1L; -// -// fly-weight patterns for common Ratio instances (x/y) where x, Serializable { +public class SourceCodePainter extends MasterToSlaveFileCallable implements Serializable { private final Set sourcePaths; @@ -35,11 +36,11 @@ public class SourceCodePainter implements FilePath.FileCallable, Serial private final FilePath destination; - private final BuildListener listener; + private final TaskListener listener; private final SourceEncoding sourceEncoding; - public SourceCodePainter(FilePath destination, Set sourcePaths, Map paint, BuildListener listener, + public SourceCodePainter(FilePath destination, Set sourcePaths, Map paint, TaskListener listener, SourceEncoding sourceEncoding) { this.destination = destination; this.sourcePaths = sourcePaths; diff --git a/src/main/java/hudson/plugins/cobertura/renderers/SourceEncoding.java b/src/main/java/hudson/plugins/cobertura/renderers/SourceEncoding.java index 21084b00..bd6b608b 100644 --- a/src/main/java/hudson/plugins/cobertura/renderers/SourceEncoding.java +++ b/src/main/java/hudson/plugins/cobertura/renderers/SourceEncoding.java @@ -182,6 +182,6 @@ public static SourceEncoding getEncoding(String encodingName) { return encoding; } } - return SourceEncoding.ASCII; + return SourceEncoding.UTF_8; } } diff --git a/src/main/java/hudson/plugins/cobertura/targets/CoverageAggregationMode.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageAggregationMode.java index ccbf9431..c212ada7 100644 --- a/src/main/java/hudson/plugins/cobertura/targets/CoverageAggregationMode.java +++ b/src/main/java/hudson/plugins/cobertura/targets/CoverageAggregationMode.java @@ -63,6 +63,10 @@ public Ratio aggregate(Ratio a, Ratio b) { /** * Combinator function. Note that this function is defined to be left-associative and f(x,y) isn't necessarily * the same as f(y,x) + * + * @param a the first ratio + * @param b the second ratio + * @return Combined ratio */ public abstract Ratio aggregate(Ratio a, Ratio b); } diff --git a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java index bdf2ef2a..8bf6aad1 100755 --- a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java +++ b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java @@ -1,6 +1,5 @@ package hudson.plugins.cobertura.targets; -import hudson.model.AbstractBuild; import hudson.model.Api; import hudson.model.Item; import hudson.model.Run; @@ -36,7 +35,7 @@ import org.kohsuke.stapler.export.ExportedBean; /** - * Coverage result for a specific programming element. + * Coverage result for a specific programming element. * *

* Instances of {@link CoverageResult} form a tree structure to progressively represent smaller elements. @@ -78,7 +77,7 @@ public class CoverageResult implements Serializable, Chartable { private String relativeSourcePath; - public AbstractBuild owner = null; + public transient Run owner = null; public CoverageResult(CoverageElement elementType, CoverageResult parent, String name) { this.element = elementType; @@ -173,7 +172,7 @@ public void paint(int line, int hits, int branchHits, int branchTotal) { */ private File getSourceFile() { if (hasPermission()) { - return new File(owner.getProject().getRootDir(), "cobertura/" + relativeSourcePath); + return new File(owner.getParent().getRootDir(), "cobertura/" + relativeSourcePath); } return null; } @@ -185,7 +184,7 @@ private File getSourceFile() { */ public boolean isSourceFileAvailable() { if (hasPermission()) { - return owner == owner.getProject().getLastSuccessfulBuild() && getSourceFile().exists(); + return owner == owner.getParent().getLastSuccessfulBuild() && getSourceFile().exists(); } return false; } @@ -367,7 +366,7 @@ private List findEmptyMetrics(Map currMet List missingMetrics = new LinkedList(); for (CoverageMetric currMetric : allMetrics) { - if (!currMetricSet.containsKey(currMetric.getName())) + if (!currMetricSet.containsKey(currMetric)) { missingMetrics.add(currMetric); } @@ -396,7 +395,7 @@ public void updateMetric(CoverageMetric metric, Ratio additionalResult) { * * @return Value for property 'owner'. */ - public AbstractBuild getOwner() { + public Run getOwner() { return owner; } @@ -405,7 +404,7 @@ public void updateMetric(CoverageMetric metric, Ratio additionalResult) { * * @param owner Value to set for property 'owner'. */ - public void setOwner(AbstractBuild owner) { + public void setOwner(Run owner) { this.owner = owner; aggregateResults.clear(); for (CoverageResult child : children.values()) { @@ -436,18 +435,12 @@ public CoverageResult getPreviousResult() { if (owner == null) { return null; } - AbstractBuild prevBuild = BuildUtils.getPreviousNotFailedCompletedBuild(owner); - if (prevBuild == null) { - return null; - } + Run prevBuild = BuildUtils.getPreviousNotFailedCompletedBuild(owner); CoberturaBuildAction action = null; while ((prevBuild != null) && (null == (action = prevBuild.getAction(CoberturaBuildAction.class)))) { prevBuild = BuildUtils.getPreviousNotFailedCompletedBuild(prevBuild); } - if (action == null) { - return null; - } - return action.getResult(); + return action == null ? null : action.getResult(); } else { CoverageResult prevParent = parent.getPreviousResult(); return prevParent == null ? null : prevParent.getChild(name); @@ -470,6 +463,10 @@ public void doCoverageHighlightedSource(StaplerRequest req, StaplerResponse rsp) /** * Generates the graph that shows the coverage trend up to this report. + * + * @param req the stapler request + * @param rsp the stapler response + * @throws IOException from StaplerResponse.sendRedirect2 */ public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException { if (ChartUtil.awtProblemCause != null) { @@ -478,7 +475,7 @@ public void doGraph(StaplerRequest req, StaplerResponse rsp) throws IOException return; } - AbstractBuild build = getOwner(); + Run build = getOwner(); Calendar t = build.getTimestamp(); if (req.checkIfModified(t, rsp)) { diff --git a/src/main/java/hudson/plugins/cobertura/targets/CoverageTarget.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageTarget.java index 9cfc59fc..c4934f46 100644 --- a/src/main/java/hudson/plugins/cobertura/targets/CoverageTarget.java +++ b/src/main/java/hudson/plugins/cobertura/targets/CoverageTarget.java @@ -112,7 +112,7 @@ public Map getRangeScores(CoverageTarget min, Map diff --git a/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/nodata.jelly b/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/nodata.jelly index 454d150e..3d4bfe70 100644 --- a/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/nodata.jelly +++ b/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/nodata.jelly @@ -1,3 +1,4 @@ + diff --git a/src/main/resources/hudson/plugins/cobertura/CoberturaPublisher/config.jelly b/src/main/resources/hudson/plugins/cobertura/CoberturaPublisher/config.jelly index 43c09ced..a81e1912 100644 --- a/src/main/resources/hudson/plugins/cobertura/CoberturaPublisher/config.jelly +++ b/src/main/resources/hudson/plugins/cobertura/CoberturaPublisher/config.jelly @@ -1,3 +1,4 @@ + + diff --git a/src/main/resources/hudson/plugins/cobertura/dashboard/CoverageTablePortlet/portlet.jelly b/src/main/resources/hudson/plugins/cobertura/dashboard/CoverageTablePortlet/portlet.jelly index d38fef2f..ee10b91e 100644 --- a/src/main/resources/hudson/plugins/cobertura/dashboard/CoverageTablePortlet/portlet.jelly +++ b/src/main/resources/hudson/plugins/cobertura/dashboard/CoverageTablePortlet/portlet.jelly @@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> + diff --git a/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly b/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly index 0e5e3dcb..4c5ee321 100755 --- a/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly +++ b/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly @@ -1,3 +1,4 @@ + @@ -115,7 +116,7 @@ ${it.relativeSourcePath} -

${it.sourceFileContent}
+
diff --git a/src/main/resources/index.jelly b/src/main/resources/index.jelly index b774453e..d853359b 100644 --- a/src/main/resources/index.jelly +++ b/src/main/resources/index.jelly @@ -1,3 +1,4 @@ +
This plugin integrates Cobertura coverage reports to Jenkins.
diff --git a/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java index d1bff82d..ffb6a535 100644 --- a/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java +++ b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java @@ -50,8 +50,8 @@ public void testBuildUrlShouldBeCorrectInFolder() throws Exception { FreeStyleProject p = folder.createProject(FreeStyleProject.class, "project"); FreeStyleBuild build = p.scheduleBuild2(0).get(); // fake cobertura run - build.getActions().add(CoberturaBuildAction.load( - build, new CoverageResult(null, null, "cresult"), null, null, false, false, false, false, false + build.addAction(CoberturaBuildAction.load( + new CoverageResult(null, null, "cresult"), null, null, false, false, false, false, false, false, 0 )); Dashboard view = new Dashboard("view"); diff --git a/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java b/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java index c936fd60..3de3acdb 100644 --- a/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java +++ b/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java @@ -23,10 +23,11 @@ */ package hudson.plugins.cobertura; +import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; import hudson.model.FreeStyleProject; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.plugins.cobertura.renderers.SourceEncoding; import hudson.util.OneShotEvent; import org.junit.Rule; @@ -56,7 +57,8 @@ public void doNotWaitForPreviousBuild() throws Exception { firstRunning.block(); p.getPublishersList().clear(); - p.getPublishersList().add(new CoberturaPublisher("", true, true, true, true, true, true, true, SourceEncoding.UTF_8, 42)); + CoberturaPublisher publisher = new CoberturaPublisher(); + p.getPublishersList().add(publisher); p.scheduleBuild2(0).get(); @@ -69,16 +71,16 @@ private static class BlockingCoberturaPublisher extends CoberturaPublisher { private final OneShotEvent firstBlocked; public BlockingCoberturaPublisher(OneShotEvent firstRunning, OneShotEvent blockFirst) { - super("", true, true, true, true, true, true, true, SourceEncoding.UTF_8, 42); + super(); this.firstRunning = firstRunning; this.firstBlocked = blockFirst; } @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + public void perform(Run build, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException { firstRunning.signal(); firstBlocked.block(); - return true; + return; } } } diff --git a/src/test/java/hudson/plugins/cobertura/CoberturaPublisherPipelineTest.java b/src/test/java/hudson/plugins/cobertura/CoberturaPublisherPipelineTest.java new file mode 100644 index 00000000..fd976066 --- /dev/null +++ b/src/test/java/hudson/plugins/cobertura/CoberturaPublisherPipelineTest.java @@ -0,0 +1,209 @@ +package hudson.plugins.cobertura; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import hudson.FilePath; +import jenkins.model.Jenkins; + +public class CoberturaPublisherPipelineTest { + + /** + * Helper class to build a script with a CoverturaPublisher step + */ + protected class ScriptBuilder { + + private String result = "SUCCESS"; + private Boolean onlyStable = true; + + /** + * Sets the build result for the script + * @param result The value for result + * @return ScriptBuilder instance + */ + ScriptBuilder setBuildResult(String result) { + this.result = result; + return this; + } + + /** + * Sets the build result for the script + * @param onlyStable The value for onlyStable + * @return ScriptBuilder instance + */ + ScriptBuilder setOnlyStable(Boolean onlyStable) { + this.onlyStable = onlyStable; + return this; + } + + /** + * Gets the script as a string + * @return The script + */ + String getScript() { + StringBuilder script = new StringBuilder(); + script.append("node {\n"); + script.append(String.format("currentBuild.result = '%s'\n", this.result)); + script.append("step ([$class: 'CoberturaPublisher', "); + script.append("coberturaReportFile: '**/coverage.xml', "); + script.append(String.format("onlyStable: %s, ", this.onlyStable.toString())); + script.append("sourceEncoding: 'ASCII'])\n"); + script.append("}"); + return script.toString(); + } + } + + @Rule + public JenkinsRule jenkinsRule = new JenkinsRule(); + + /** + * Tests that a run with a report file publishes + */ + @Test + public void testReportFile() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().getScript())); + + copyCoverageFile("coverage-with-data.xml", "coverage.xml", project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogContains("Cobertura coverage report found.", run); + } + + /** + * Tests no report is published if coverage file isn't found + */ + @Test + public void testNoReportFile() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().getScript())); + + ensureWorkspaceExists(project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogNotContains("Cobertura coverage report found.", run); + } + + /** + * Tests report is published for unstable build if onlyStable = false + */ + @Test + public void testUnstableOnlyStableFalse() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().setBuildResult("UNSTABLE").setOnlyStable(false).getScript())); + + copyCoverageFile("coverage-with-data.xml", "coverage.xml", project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogContains("Cobertura coverage report found.", run); + } + + /** + * Tests report is not published for unstable build if onlyStable = true + */ + @Test + public void testUnstableOnlyStableTrue() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().setBuildResult("UNSTABLE").setOnlyStable(true).getScript())); + + copyCoverageFile("coverage-with-data.xml", "coverage.xml", project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogNotContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogContains("Skipping Cobertura coverage report as build was not SUCCESS or better", run); + } + + /** + * Tests no report is published for failed build if onlyStable = true + */ + @Test + public void testFailedOnlyStableTrue() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().setBuildResult("FAILED").setOnlyStable(true).getScript())); + + copyCoverageFile("coverage-with-data.xml", "coverage.xml", project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogNotContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogContains("Skipping Cobertura coverage report as build was not SUCCESS or better", run); + } + + /** + * Tests report is not published for failed build if onlyStable = true + */ + @Test + public void testFailedOnlyStableFalse() throws Exception { + Jenkins jenkins = jenkinsRule.jenkins; + WorkflowJob project = jenkins.createProject(WorkflowJob.class, "cob-test"); + + project.setDefinition(new CpsFlowDefinition(new ScriptBuilder().setBuildResult("FAILED").setOnlyStable(false).getScript())); + + copyCoverageFile("coverage-with-data.xml", "coverage.xml", project); + + WorkflowRun run = project.scheduleBuild2(0).get(); + jenkinsRule.waitForCompletion(run); + + jenkinsRule.assertLogNotContains("Publishing Cobertura coverage report...", run); + jenkinsRule.assertLogContains("Skipping Cobertura coverage report as build was not UNSTABLE or better", run); + } + + /** + * Creates workspace directory if needed, and returns it + * @param job The job for the workspace + * @return File representing workspace directory + */ + private File ensureWorkspaceExists(WorkflowJob job) { + FilePath path = jenkinsRule.jenkins.getWorkspaceFor(job); + File directory = new File(path.getRemote()); + directory.mkdirs(); + + return directory; + } + + /** + * Copies a coverage file from resources to a job's workspace directory + * @param sourceResourceName The name of the resource to copy + * @param targetFileName The name of the file in the target workspace + * @param job The job to copy the file to + * @throws IOException + */ + private void copyCoverageFile(String sourceResourceName, String targetFileName, WorkflowJob job) throws IOException { + File directory = ensureWorkspaceExists(job); + + File dest = new File(directory, targetFileName); + File src = new File(getClass().getResource(sourceResourceName).getPath()); + + FileUtils.copyFile(src, dest); + }; +} diff --git a/src/test/java/hudson/plugins/cobertura/CoverageResultBuilder.java b/src/test/java/hudson/plugins/cobertura/CoverageResultBuilder.java index 1a11d73a..89118ea5 100644 --- a/src/test/java/hudson/plugins/cobertura/CoverageResultBuilder.java +++ b/src/test/java/hudson/plugins/cobertura/CoverageResultBuilder.java @@ -50,7 +50,7 @@ public CoverageResult create() throws IOException { build = ctl.createMock( FreeStyleBuild.class ); build.number = c; - CoberturaBuildAction action = new CoberturaBuildAction( build, result, new CoverageTarget(), new CoverageTarget(), true, false, false, false, false ) + CoberturaBuildAction action = new CoberturaBuildAction( result, new CoverageTarget(), new CoverageTarget(), true, false, false, false, false, false, 0 ) { @Override public HealthReport getBuildHealth() diff --git a/src/test/java/hudson/plugins/cobertura/CoverageResultTest.java b/src/test/java/hudson/plugins/cobertura/CoverageResultTest.java index c5cdfcd2..a9521819 100644 --- a/src/test/java/hudson/plugins/cobertura/CoverageResultTest.java +++ b/src/test/java/hudson/plugins/cobertura/CoverageResultTest.java @@ -12,7 +12,7 @@ import org.easymock.classextension.EasyMock; import org.easymock.classextension.IMocksControl; -import hudson.model.AbstractBuild; +import hudson.model.Run; import hudson.plugins.cobertura.targets.CoverageElement; import hudson.plugins.cobertura.targets.CoverageMetric; import hudson.plugins.cobertura.targets.CoverageResult; @@ -27,7 +27,7 @@ public class CoverageResultTest extends TestCase { private static final String FILE_COVERAGE_DATA = "coverage-with-data.xml"; private IMocksControl ctl; - private AbstractBuild build; + private Run build; /** * Set up the mock objects used by the tests. @@ -35,7 +35,7 @@ public class CoverageResultTest extends TestCase { protected void setUp() throws Exception { super.setUp(); ctl = EasyMock.createControl(); - build = ctl.createMock("build", AbstractBuild.class); + build = ctl.createMock("build", Run.class); } /** @@ -51,7 +51,7 @@ private CoverageResult loadResults(String fileName) throws Exception { } /** - * Tests the behavior of {@link CoverageResult#setOwner(AbstractBuild)}. + * Tests the behavior of {@link CoverageResult#setOwner(Run)}. */ public void testSetOwner() throws Exception { ctl.replay();