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 @@
+
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();