From 85fd6380809a45dff5319d8eb385920d2163fe10 Mon Sep 17 00:00:00 2001 From: Michael Barrientos Date: Wed, 8 Jun 2016 19:03:32 -0700 Subject: [PATCH 01/12] JENKINS-30700 / #50 Jenkins pipeline support --- pom.xml | 33 +++++--- .../hudson/plugins/cobertura/BuildUtils.java | 4 +- .../hudson/plugins/cobertura/Chartable.java | 4 +- .../cobertura/CoberturaBuildAction.java | 81 +++++++++++++------ .../cobertura/CoberturaProjectAction.java | 33 ++++---- .../plugins/cobertura/CoberturaPublisher.java | 61 +++++--------- .../plugins/cobertura/CoverageChart.java | 17 ++-- .../cobertura/MavenCoberturaBuildAction.java | 4 +- .../cobertura/MavenCoberturaPublisher.java | 4 +- .../renderers/SourceCodePainter.java | 9 ++- .../cobertura/targets/CoverageResult.java | 23 ++---- .../CoverageTablePortletTest.java | 2 +- .../cobertura/CoberturaFunctionalTest.java | 9 ++- .../cobertura/CoverageResultBuilder.java | 2 +- .../plugins/cobertura/CoverageResultTest.java | 8 +- 15 files changed, 152 insertions(+), 142 deletions(-) diff --git a/pom.xml b/pom.xml index 85eaa2c6..ddc545f6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.480.3 + 1.609.2 cobertura @@ -15,6 +15,7 @@ UTF-8 + 1.11 @@ -43,18 +44,6 @@ - - org.jenkins-ci.main - maven-plugin - compile - - - - org.sonatype.sisu.inject - cglib - - - org.easymock easymockclassextension @@ -85,6 +74,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..d678496f 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java @@ -1,19 +1,24 @@ package hudson.plugins.cobertura; +import hudson.model.Action; 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 +36,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 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 +63,6 @@ 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 (healthyTarget == null || unhealthyTarget == null) { return null; } @@ -135,10 +131,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 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 +162,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 +184,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 +196,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()); @@ -227,9 +235,11 @@ 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); } /** @@ -250,4 +260,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..93ae4b7c 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 final 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 8e6406aa..30e9b549 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -5,11 +5,11 @@ 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 +20,8 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; +import jenkins.SlaveToMasterFileCallable; +import jenkins.tasks.SimpleBuildStep; import java.io.File; import java.io.FilenameFilter; @@ -50,7 +52,7 @@ * * @author Stephen Connolly */ -public class CoberturaPublisher extends Recorder { +public class CoberturaPublisher extends Recorder implements SimpleBuildStep { private final String coberturaReportFile; @@ -85,7 +87,7 @@ public class CoberturaPublisher extends Recorder { * @stapler-constructor */ @DataBoundConstructor - public CoberturaPublisher(String coberturaReportFile, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, + 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; @@ -306,15 +308,7 @@ public void setFailingTarget(CoverageTarget failingTarget) { * Gets the directory where the Cobertura Report is stored for the given project. */ /*package*/ - static File getCoberturaReportDir(AbstractItem project) { - return new File(project.getRootDir(), "cobertura"); - } - - /** - * 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); } @@ -322,30 +316,26 @@ 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)) { 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]; try { - reports = moduleRoot.act(new ParseReportCallable(coberturaReportFile)); + reports = workspace.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; + return; } } catch (IOException e) { @@ -357,7 +347,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen 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); @@ -366,7 +356,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen } else { listener.getLogger().println("[Cobertura] Skipped cobertura reports."); } - return true; + return; } for (int i = 0; i < reports.length; i++) { @@ -395,7 +385,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen 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.getRootDir(), "cobertura")); paintedSourcesPath.mkdirs(); if (sourcePaths.contains(".")) { @@ -411,10 +401,11 @@ 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); Set failingMetrics = failingTarget.getFailingMetrics(result); @@ -464,14 +455,12 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen + "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; @@ -499,14 +488,6 @@ private void setNewPercentages(CoverageResult result, boolean select, BuildListe } } - /** - * {@inheritDoc} - */ - @Override - public Action getProjectAction(AbstractProject project) { - return new CoberturaProjectAction(project, getOnlyStable()); - } - /** * {@inheritDoc} */ @@ -533,7 +514,7 @@ public SourceEncoding getSourceEncoding() { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); - public static class ParseReportCallable implements FilePath.FileCallable { + public static class ParseReportCallable extends SlaveToMasterFileCallable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/plugins/cobertura/CoverageChart.java b/src/main/java/hudson/plugins/cobertura/CoverageChart.java index 03959066..868e165c 100644 --- a/src/main/java/hudson/plugins/cobertura/CoverageChart.java +++ b/src/main/java/hudson/plugins/cobertura/CoverageChart.java @@ -78,33 +78,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/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..296a4d9b 100644 --- a/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java @@ -221,7 +221,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,7 +281,7 @@ 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); + CoberturaBuildAction o = CoberturaBuildAction.load(result, null, null, false, false, false, false, false, false, 0); build.getActions().add(o); } else { return false; diff --git a/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java b/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java index a6c968ed..3c970f14 100644 --- a/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java +++ b/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java @@ -3,9 +3,10 @@ import static hudson.plugins.cobertura.IOUtils.closeQuietly; import hudson.FilePath; -import hudson.model.BuildListener; +import hudson.model.TaskListener; import hudson.plugins.cobertura.targets.CoveragePaint; import hudson.remoting.VirtualChannel; +import jenkins.SlaveToMasterFileCallable; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -27,7 +28,7 @@ * @author Stephen Connolly * @since 31-Aug-2007 16:52:25 */ -public class SourceCodePainter implements FilePath.FileCallable, Serializable { +public class SourceCodePainter extends SlaveToMasterFileCallable 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/targets/CoverageResult.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java index bdf2ef2a..52e43ccc 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; @@ -78,7 +77,7 @@ public class CoverageResult implements Serializable, Chartable { private String relativeSourcePath; - public AbstractBuild owner = null; + public 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; } @@ -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); @@ -478,7 +471,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/test/java/CoverageTablePortlet/CoverageTablePortletTest.java b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java index d1bff82d..0cc8b944 100644 --- a/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java +++ b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java @@ -51,7 +51,7 @@ public void testBuildUrlShouldBeCorrectInFolder() throws Exception { 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 + 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..9fe43080 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; @@ -75,10 +76,10 @@ public BlockingCoberturaPublisher(OneShotEvent firstRunning, OneShotEvent blockF } @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/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(); From efe1402d45bf81e985e8166ec1ed5b6c34b9c5f4 Mon Sep 17 00:00:00 2001 From: Michael Barrientos Date: Thu, 29 Sep 2016 06:57:46 -0700 Subject: [PATCH 02/12] Null pointer fixes --- .../plugins/cobertura/CoberturaPublisher.java | 19 ++++++++++++------- .../cobertura/MavenCoberturaPublisher.java | 2 +- .../CoverageTablePortletTest.java | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 30e9b549..ddc8d7a4 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -67,9 +67,9 @@ public class CoberturaPublisher extends Recorder implements SimpleBuildStep { private final boolean autoUpdateStability; private final boolean zoomCoverageChart; - + private final int maxNumberOfBuilds; - + private boolean failNoReports = true; private CoverageTarget healthyTarget; @@ -201,7 +201,7 @@ public String getCoberturaReportFile() { public boolean getOnlyStable() { return onlyStable; } - + public int getMaxNumberOfBuilds() { return maxNumberOfBuilds; } @@ -249,7 +249,7 @@ public boolean getZoomCoverageChart() { public boolean isFailNoReports() { return failNoReports; } - + /** * Getter for property 'healthyTarget'. * @@ -309,7 +309,8 @@ public void setFailingTarget(CoverageTarget failingTarget) { */ /*package*/ static File[] getCoberturaReports(Run build) { - return build.getRootDir().listFiles(COBERTURA_FILENAME_FILTER); + File rootDir = build.getRootDir(); + return rootDir.listFiles(COBERTURA_FILENAME_FILTER); } /** @@ -319,6 +320,10 @@ static File[] getCoberturaReports(Run build) { 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() == null) { + listener.getLogger().println("Build had no result; build result must be set before running Cobertura publisher."); + return; + } if (build.getResult().isWorseThan(threshold)) { listener.getLogger().println("Skipping Cobertura coverage report as build was not " + threshold.toString() + " or better ..."); return; @@ -407,7 +412,7 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina 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:"); @@ -557,7 +562,7 @@ public FilePath[] invoke(File f, VirtualChannel channel) throws IOException, Int reader.close(); } catch (XMLStreamException ex) { // - } + } } } finally { IOUtils.closeQuietly(is); diff --git a/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java index 296a4d9b..adfc966b 100644 --- a/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java @@ -282,7 +282,7 @@ public Boolean call(MavenBuild build) throws IOException { result.setOwner(build); CoberturaBuildAction o = CoberturaBuildAction.load(result, null, null, false, false, false, false, false, false, 0); - build.getActions().add(o); + build.addAction(o); } else { return false; } diff --git a/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java index 0cc8b944..ffb6a535 100644 --- a/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java +++ b/src/test/java/CoverageTablePortlet/CoverageTablePortletTest.java @@ -50,7 +50,7 @@ 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.addAction(CoberturaBuildAction.load( new CoverageResult(null, null, "cresult"), null, null, false, false, false, false, false, false, 0 )); From 9b13a1b368df11a69685502e4cb46940f70a4c88 Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Fri, 20 Jan 2017 10:43:58 -0800 Subject: [PATCH 03/12] Pom file update --- pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ddc545f6..4f7662bc 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 1.609.2 + 2.11 cobertura @@ -14,6 +14,8 @@ http://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin + 1.625.3 + 2.13 UTF-8 1.11 @@ -53,7 +55,7 @@ org.jenkins-ci.plugins dashboard-view - 2.4 + 2.9.9 true From a0bb2c8d3ae885e361e37708e55087dc65d658e8 Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Fri, 20 Jan 2017 10:44:18 -0800 Subject: [PATCH 04/12] Add missing escape by default to jelly files --- .../plugins/cobertura/CoberturaProjectAction/floatingBox.jelly | 1 + .../hudson/plugins/cobertura/CoberturaProjectAction/nodata.jelly | 1 + .../hudson/plugins/cobertura/CoberturaPublisher/config.jelly | 1 + .../plugins/cobertura/dashboard/CoverageTablePortlet/main.jelly | 1 + .../cobertura/dashboard/CoverageTablePortlet/portlet.jelly | 1 + .../hudson/plugins/cobertura/targets/CoverageResult/index.jelly | 1 + src/main/resources/index.jelly | 1 + 7 files changed, 7 insertions(+) diff --git a/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/floatingBox.jelly b/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/floatingBox.jelly index afeca44d..1e9e9b66 100644 --- a/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/floatingBox.jelly +++ b/src/main/resources/hudson/plugins/cobertura/CoberturaProjectAction/floatingBox.jelly @@ -1,3 +1,4 @@ + 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..c26788a2 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 @@ + 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.
From e81a2dcdc7474effa49f5e71c5f201144b8c8ae8 Mon Sep 17 00:00:00 2001 From: Michael Barrientos Date: Sun, 22 Jan 2017 09:28:56 -0800 Subject: [PATCH 05/12] Fixes for pipeline compatibility from code review * Treat getResult() == null as success * Add transient keyword to Run<> instance variables. * Change to use DataBoundSetter instead of massive constructor * Kill now irrelevant constructor unit test * Use AbortException instead of explicitly setting result failure * MasterToSlaveFileCallable --- .../cobertura/CoberturaBuildAction.java | 15 +- .../cobertura/CoberturaProjectAction.java | 2 +- .../plugins/cobertura/CoberturaPublisher.java | 138 +++++++++++------- .../renderers/SourceCodePainter.java | 6 +- .../cobertura/targets/CoverageResult.java | 4 +- .../cobertura/CoberturaFunctionalTest.java | 5 +- .../cobertura/CoberturaPublisherTest.java | 49 ------- 7 files changed, 108 insertions(+), 111 deletions(-) delete mode 100644 src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java index d678496f..e8f6ae49 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java @@ -1,6 +1,7 @@ package hudson.plugins.cobertura; import hudson.model.Action; +import hudson.model.AbstractBuild; import hudson.model.HealthReport; import hudson.model.HealthReportingAction; import hudson.model.Result; @@ -38,7 +39,7 @@ */ public class CoberturaBuildAction implements HealthReportingAction, StaplerProxy, Chartable, SimpleBuildStep.LastBuildAction, RunAction2 { - private Run owner; + private transient Run owner; private CoverageTarget healthyTarget; private CoverageTarget unhealthyTarget; private boolean failUnhealthy; @@ -63,6 +64,18 @@ public HealthReport getBuildHealth() { if (health != null) { return health; } + 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; } diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java index 93ae4b7c..458fd1c2 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaProjectAction.java @@ -17,7 +17,7 @@ */ public class CoberturaProjectAction extends Actionable implements ProminentProjectAction { - private final Run run; + private transient Run run; private boolean onlyStable; public CoberturaProjectAction(Run run, boolean onlyStable) { diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index ddc8d7a4..bbf93c66 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -1,5 +1,6 @@ package hudson.plugins.cobertura; +import hudson.AbortException; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; @@ -20,7 +21,7 @@ import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; -import jenkins.SlaveToMasterFileCallable; +import jenkins.MasterToSlaveFileCallable; import jenkins.tasks.SimpleBuildStep; import java.io.File; @@ -45,6 +46,7 @@ import org.apache.commons.beanutils.ConvertUtils; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.StaplerRequest; /** @@ -54,55 +56,36 @@ */ 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 final boolean zoomCoverageChart; + private boolean zoomCoverageChart; - private final int maxNumberOfBuilds; + private int maxNumberOfBuilds = 0; 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; - /** - * @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() { } /** @@ -185,6 +168,15 @@ private void setTargets(List targets) { } } + /** + * @param coberturaReportFile the report directory + */ + @DataBoundSetter + public void setCoberturaReportFile(String coberturaReportFile) { + + this.coberturaReportFile = coberturaReportFile; + } + /** * Getter for property 'coberturaReportFile'. * @@ -194,6 +186,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 @@ -202,10 +199,20 @@ 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'. * @@ -215,6 +222,12 @@ public boolean getFailUnhealthy() { return failUnhealthy; } + + @DataBoundSetter + public void setFailUnstable(boolean failUnstable) { + this.failUnstable = failUnstable; + } + /** * Getter for property 'failUnstable'. * @@ -224,6 +237,11 @@ public boolean getFailUnstable() { return failUnstable; } + @DataBoundSetter + public void setAutoUpdateHealth(boolean autoUpdateHealth) { + this.autoUpdateHealth = autoUpdateHealth; + } + /** * Getter for property 'autoUpdateHealth'. * @@ -233,6 +251,11 @@ public boolean getAutoUpdateHealth() { return autoUpdateHealth; } + @DataBoundSetter + public void setAutoUpdateStability(boolean autoUpdateStability) { + this.autoUpdateStability = autoUpdateStability; + } + /** * Getter for property 'autoUpdateStability'. * @@ -242,10 +265,20 @@ 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; } @@ -320,11 +353,7 @@ static File[] getCoberturaReports(Run build) { 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() == null) { - listener.getLogger().println("Build had no result; build result must be set before running Cobertura publisher."); - return; - } - if (build.getResult().isWorseThan(threshold)) { + if (build.getResult() != null && build.getResult().isWorseThan(threshold)) { listener.getLogger().println("Skipping Cobertura coverage report as build was not " + threshold.toString() + " or better ..."); return; } @@ -339,14 +368,14 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina // if the build has failed, then there's not // much point in reporting an error - if (build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { + if (build.getResult() != null && build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { return; } } 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) { @@ -357,7 +386,7 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina + " 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."); } @@ -370,8 +399,9 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina 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); } } @@ -384,13 +414,13 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina } 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.getRootDir(), "cobertura")); + final FilePath paintedSourcesPath = new FilePath(new File(build.getParent().getRootDir(), "cobertura")); paintedSourcesPath.mkdirs(); if (sourcePaths.contains(".")) { @@ -427,8 +457,7 @@ unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAuto 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()) { @@ -442,11 +471,10 @@ unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAuto 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); } @@ -456,9 +484,8 @@ unhealthyTarget, getOnlyStable(), getFailUnhealthy(), getFailUnstable(), getAuto } } } 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); } } @@ -509,6 +536,11 @@ public BuildStepDescriptor getDescriptor() { return DESCRIPTOR; } + @DataBoundSetter + public void setSourceEncoding(SourceEncoding sourceEncoding) { + this.sourceEncoding = sourceEncoding; + } + public SourceEncoding getSourceEncoding() { return sourceEncoding; } @@ -519,7 +551,7 @@ public SourceEncoding getSourceEncoding() { @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); - public static class ParseReportCallable extends SlaveToMasterFileCallable { + public static class ParseReportCallable extends MasterToSlaveFileCallable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java b/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java index 3c970f14..b015e3d6 100644 --- a/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java +++ b/src/main/java/hudson/plugins/cobertura/renderers/SourceCodePainter.java @@ -6,7 +6,7 @@ import hudson.model.TaskListener; import hudson.plugins.cobertura.targets.CoveragePaint; import hudson.remoting.VirtualChannel; -import jenkins.SlaveToMasterFileCallable; +import jenkins.MasterToSlaveFileCallable; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -24,11 +24,11 @@ /** * TODO javadoc. - * + * * @author Stephen Connolly * @since 31-Aug-2007 16:52:25 */ -public class SourceCodePainter extends SlaveToMasterFileCallable implements Serializable { +public class SourceCodePainter extends MasterToSlaveFileCallable implements Serializable { private final Set sourcePaths; diff --git a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java index 52e43ccc..14cbe730 100755 --- a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java +++ b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java @@ -35,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. @@ -77,7 +77,7 @@ public class CoverageResult implements Serializable, Chartable { private String relativeSourcePath; - public Run owner = null; + public transient Run owner = null; public CoverageResult(CoverageElement elementType, CoverageResult parent, String name) { this.element = elementType; diff --git a/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java b/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java index 9fe43080..3de3acdb 100644 --- a/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java +++ b/src/test/java/hudson/plugins/cobertura/CoberturaFunctionalTest.java @@ -57,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(); @@ -70,7 +71,7 @@ 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; } diff --git a/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java b/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java deleted file mode 100644 index 123b5b7d..00000000 --- a/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package hudson.plugins.cobertura; - -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -public class CoberturaPublisherTest { - - @Test - public void testGetOnlyStable() { - CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, true, false, false, false, false, false, false, null, 0); - CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); - assertTrue(testObjectTrue.getOnlyStable()); - assertTrue(!testObjectFalse.getOnlyStable()); - } - - @Test - public void testGetFailUnhealthy() { - CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, true, false, false, false, false, false, null, 0); - CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); - assertTrue(testObjectTrue.getFailUnhealthy()); - assertTrue(!testObjectFalse.getFailUnhealthy()); - } - - @Test - public void testGetFailUnstable() { - CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, true, false, false, false, false, null, 0); - CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); - assertTrue(testObjectTrue.getFailUnstable()); - assertTrue(!testObjectFalse.getFailUnstable()); - } - - @Test - public void testGetAutoUpdateHealth() { - CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, false, true, false, false, false, null, 0); - CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); - assertTrue(testObjectTrue.getAutoUpdateHealth()); - assertTrue(!testObjectFalse.getAutoUpdateHealth()); - } - - @Test - public void testGetAutoUpdateStability() { - CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, false, false, true, false, false, null, 0); - CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); - assertTrue(testObjectTrue.getAutoUpdateStability()); - assertTrue(!testObjectFalse.getAutoUpdateStability()); - } - -} From 0bec1fa4e21842f46efca7ff9d95237e99236493 Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Mon, 23 Jan 2017 09:16:18 -0800 Subject: [PATCH 06/12] Fix lint errors --- .../plugins/cobertura/CoberturaBuildAction.java | 2 +- .../hudson/plugins/cobertura/CoberturaPublisher.java | 12 ++++++------ .../plugins/cobertura/MavenCoberturaPublisher.java | 12 +++++++----- .../plugins/cobertura/targets/CoverageResult.java | 4 ++-- .../plugins/cobertura/targets/CoverageTarget.java | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java index d678496f..aa79c82d 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java @@ -135,7 +135,7 @@ public Object getTarget() { return owner; } - private void setOwner(Run owner) { + private synchronized void setOwner(Run owner) { this.owner = owner; if (report != null) { CoverageResult r = report.get(); diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index ddc8d7a4..27814dd6 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -320,11 +320,8 @@ static File[] getCoberturaReports(Run build) { 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() == null) { - listener.getLogger().println("Build had no result; build result must be set before running Cobertura publisher."); - return; - } - 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; } @@ -339,7 +336,7 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina // if the build has failed, then there's not // much point in reporting an error - if (build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { + if (buildResult != null && buildResult.isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { return; } @@ -650,6 +647,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/MavenCoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/MavenCoberturaPublisher.java index adfc966b..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) { diff --git a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java index 52e43ccc..3f42f789 100755 --- a/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java +++ b/src/main/java/hudson/plugins/cobertura/targets/CoverageResult.java @@ -77,7 +77,7 @@ public class CoverageResult implements Serializable, Chartable { private String relativeSourcePath; - public Run owner = null; + public transient Run owner = null; public CoverageResult(CoverageElement elementType, CoverageResult parent, String name) { this.element = elementType; @@ -366,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); } 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 Date: Mon, 23 Jan 2017 09:49:38 -0800 Subject: [PATCH 07/12] Update pom file --- pom.xml | 2 +- .../plugins/cobertura/CoberturaBuildAction.java | 6 ++++++ .../plugins/cobertura/CoberturaPublisher.java | 15 ++++++++++++--- .../cobertura/CoberturaPublisherTarget.java | 11 ++++++----- .../hudson/plugins/cobertura/CoverageChart.java | 10 ++++++++-- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 4f7662bc..496530a5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ http://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin - 1.625.3 + 2.13 2.13 UTF-8 1.11 diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java index aa79c82d..9ba2e7c6 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaBuildAction.java @@ -208,6 +208,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) { @@ -244,6 +246,10 @@ public static CoberturaBuildAction load(CoverageResult result, CoverageTarget he /** * 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) { diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 27814dd6..d0f92bf3 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -83,8 +83,18 @@ public class CoberturaPublisher extends Recorder implements SimpleBuildStep { private final SourceEncoding sourceEncoding; /** + * CoberturaPublisher constructor + * * @param coberturaReportFile the report directory - * @stapler-constructor + * @param onlyStable true to consider only stable builds + * @param failUnhealthy true to fail unhealthy builds + * @param failUnstable true to fail unstable builds + * @param autoUpdateHealth true to auto-update health + * @param autoUpdateStability true to auto-update stability + * @param zoomCoverageChart true to zoom coverage chart + * @param failNoReports true to fail if no reports + * @param sourceEncoding source encoding + * @param maxNumberOfBuilds max number of builds */ @DataBoundConstructor public CoberturaPublisher(String coberturaReportFile, boolean onlyStable, boolean failUnhealthy, boolean failUnstable, @@ -574,8 +584,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. */ diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java index 9184f375..3b94d910 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 amount + * @param unhealthy Unhealthy amount + * @param unstable Unstable amount */ 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 868e165c..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 ) { From 2ad9deda31d344cf697cf3c1ce13e19c215c80ed Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Mon, 23 Jan 2017 10:52:42 -0800 Subject: [PATCH 08/12] Fix java lint errors --- .../plugins/cobertura/CoberturaPublisher.java | 2 +- .../cobertura/CoberturaPublisherTarget.java | 6 +++--- .../plugins/cobertura/CoverageColumn.java | 2 ++ .../hudson/plugins/cobertura/IOUtils.java | 6 ++++-- .../java/hudson/plugins/cobertura/Ratio.java | 19 ++++++++++++++++--- .../targets/CoverageAggregationMode.java | 4 ++++ .../cobertura/targets/CoverageResult.java | 4 ++++ 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 79812158..6375122c 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -363,7 +363,7 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina final File buildCoberturaDir = build.getRootDir(); FilePath buildTarget = new FilePath(buildCoberturaDir); - FilePath[] reports = new FilePath[0]; + FilePath[] reports = null; try { reports = workspace.act(new ParseReportCallable(coberturaReportFile)); diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java index 3b94d910..6056ace5 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisherTarget.java @@ -27,9 +27,9 @@ public CoberturaPublisherTarget() { * Constructor * * @param metric Coverage metric - * @param healthy Healthy amount - * @param unhealthy Unhealthy amount - * @param unstable Unstable amount + * @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/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/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 Date: Fri, 24 Feb 2017 16:30:18 -0800 Subject: [PATCH 09/12] Fix jelly escape issue --- .../java/hudson/plugins/cobertura/renderers/SourceEncoding.java | 2 +- .../hudson/plugins/cobertura/targets/CoverageResult/index.jelly | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly b/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly index c26788a2..4c5ee321 100755 --- a/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly +++ b/src/main/resources/hudson/plugins/cobertura/targets/CoverageResult/index.jelly @@ -116,7 +116,7 @@ ${it.relativeSourcePath} -

${it.sourceFileContent}
+
From ef26ee4a46405f22c3d61eb8bb2f44268cdd774e Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Mon, 27 Mar 2017 19:58:09 -0700 Subject: [PATCH 10/12] Restore default constructor and tests --- .../plugins/cobertura/CoberturaPublisher.java | 26 +++++++--- .../cobertura/CoberturaPublisherTest.java | 49 +++++++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 6375122c..1e689cd6 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -83,9 +83,28 @@ public class CoberturaPublisher extends Recorder implements SimpleBuildStep { public static final CoberturaReportFilenameFilter COBERTURA_FILENAME_FILTER = new CoberturaReportFilenameFilter(); private SourceEncoding sourceEncoding = SourceEncoding.UTF_8; + + 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(); + } @DataBoundConstructor public CoberturaPublisher() { + this("", true, true, true, true, true, true, true, SourceEncoding.UTF_8, 42); } /** @@ -366,13 +385,6 @@ public void perform(Run build, FilePath workspace, Launcher launcher, fina FilePath[] reports = null; try { reports = workspace.act(new ParseReportCallable(coberturaReportFile)); - - // if the build has failed, then there's not - // much point in reporting an error - if (buildResult != null && buildResult.isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) { - return; - } - } catch (IOException e) { Util.displayIOException(e, listener); e.printStackTrace(listener.fatalError("Unable to find coverage results")); diff --git a/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java b/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java new file mode 100644 index 00000000..123b5b7d --- /dev/null +++ b/src/test/java/hudson/plugins/cobertura/CoberturaPublisherTest.java @@ -0,0 +1,49 @@ +package hudson.plugins.cobertura; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class CoberturaPublisherTest { + + @Test + public void testGetOnlyStable() { + CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, true, false, false, false, false, false, false, null, 0); + CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); + assertTrue(testObjectTrue.getOnlyStable()); + assertTrue(!testObjectFalse.getOnlyStable()); + } + + @Test + public void testGetFailUnhealthy() { + CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, true, false, false, false, false, false, null, 0); + CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); + assertTrue(testObjectTrue.getFailUnhealthy()); + assertTrue(!testObjectFalse.getFailUnhealthy()); + } + + @Test + public void testGetFailUnstable() { + CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, true, false, false, false, false, null, 0); + CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); + assertTrue(testObjectTrue.getFailUnstable()); + assertTrue(!testObjectFalse.getFailUnstable()); + } + + @Test + public void testGetAutoUpdateHealth() { + CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, false, true, false, false, false, null, 0); + CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); + assertTrue(testObjectTrue.getAutoUpdateHealth()); + assertTrue(!testObjectFalse.getAutoUpdateHealth()); + } + + @Test + public void testGetAutoUpdateStability() { + CoberturaPublisher testObjectTrue = new CoberturaPublisher(null, false, false, false, false, true, false, false, null, 0); + CoberturaPublisher testObjectFalse = new CoberturaPublisher(null, false, false, false, false, false, false, false, null, 0); + assertTrue(testObjectTrue.getAutoUpdateStability()); + assertTrue(!testObjectFalse.getAutoUpdateStability()); + } + +} From 33b4ef3001eb242bd1323e813b265a1693ff4bcf Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Mon, 27 Mar 2017 19:58:55 -0700 Subject: [PATCH 11/12] Add some pipeline tests --- .../CoberturaPublisherPipelineTest.java | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 src/test/java/hudson/plugins/cobertura/CoberturaPublisherPipelineTest.java 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); + }; +} From 749806c6317e83213509e5151f978aa84a74c1ec Mon Sep 17 00:00:00 2001 From: Jeff Pearce Date: Tue, 28 Mar 2017 14:01:16 -0700 Subject: [PATCH 12/12] Mark old constructor as deprecated --- src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java index 1e689cd6..94d95845 100644 --- a/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java +++ b/src/main/java/hudson/plugins/cobertura/CoberturaPublisher.java @@ -84,6 +84,7 @@ public class CoberturaPublisher extends Recorder implements SimpleBuildStep { 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) {