Skip to content

Commit

Permalink
Merge pull request #23 from centic9/JENKINS-16790
Browse files Browse the repository at this point in the history
JENKINS-16790: Link from Dashboard to coverage report
  • Loading branch information
ognjenb committed Jul 24, 2013
2 parents 3df827f + ba9453f commit e73f8b1
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 34 deletions.
Expand Up @@ -15,7 +15,7 @@ public enum CoverageRange {
POOR(50.0, new Color(0xFF, 0x7F, 0x00), new Color(0x00, 0x00, 0x00)), //
TRAGIC(25.0, new Color(0xFF, 0x00, 0x00), new Color(0xEE, 0xEE, 0xEE)), //
ABYSSMAL(0.0, new Color(0x00, 0x00, 0x00), new Color(0xEE, 0xEE, 0xEE)),
NA(0.0, new Color(0xFF, 0xFF, 0xFF), new Color(0xEE, 0xEE, 0xEE));
NA(0.0, new Color(0xFF, 0xFF, 0xFF), new Color(0x00, 0x00, 0x00));

/**
* Minimum coverage amount for this range
Expand Down
35 changes: 17 additions & 18 deletions src/main/java/hudson/plugins/jacococoveragecolumn/JaCoCoColumn.java
Expand Up @@ -26,15 +26,24 @@ public class JaCoCoColumn extends ListViewColumn {
public JaCoCoColumn() {
}

public String getPercent(final Job<?, ?> job) {
public boolean hasCoverage(final Job<?, ?> job) {
final Run<?, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
final StringBuilder stringBuilder = new StringBuilder();

if (lastSuccessfulBuild == null) {
stringBuilder.append("N/A");
return false;
} else if (lastSuccessfulBuild.getAction(JacocoBuildAction.class) == null){
return false;
}

return true;
}

public String getPercent(final Job<?, ?> job) {
final StringBuilder stringBuilder = new StringBuilder();

if (!hasCoverage(job)) {
stringBuilder.append("N/A");
} else {
final Run<?, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
final Double percent = getLinePercent(lastSuccessfulBuild);
stringBuilder.append(percent);
}
Expand All @@ -47,13 +56,8 @@ public String getLineColor(final Job<?, ?> job, final BigDecimal amount) {
return null;
}

if(job != null) {
final Run<?, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
if (lastSuccessfulBuild == null) {
return CoverageRange.NA.getLineHexString();
} else if (lastSuccessfulBuild.getAction(JacocoBuildAction.class) == null){
return CoverageRange.NA.getLineHexString();
}
if(job != null && !hasCoverage(job)) {
return CoverageRange.NA.getLineHexString();
}

return CoverageRange.valueOf(amount.doubleValue()).getLineHexString();
Expand All @@ -64,13 +68,8 @@ public String getFillColor(final Job<?, ?> job, final BigDecimal amount) {
return null;
}

if(job != null) {
final Run<?, ?> lastSuccessfulBuild = job.getLastSuccessfulBuild();
if (lastSuccessfulBuild == null) {
return CoverageRange.NA.getFillHexString();
} else if (lastSuccessfulBuild.getAction(JacocoBuildAction.class) == null){
return CoverageRange.NA.getFillHexString();
}
if(job != null && !hasCoverage(job)) {
return CoverageRange.NA.getFillHexString();
}

final Color c = CoverageRange.fillColorOf(amount.doubleValue());
Expand Down
Expand Up @@ -13,7 +13,18 @@

<j:choose>
<j:when test="${coverageAmount != null}">
<td style="color:#${color}; background-color:#${backgroundColor};" data="${coverageAmount}" align="center">${coveragePercent}%</td>
<td style="color:#${color}; background-color:#${backgroundColor};" data="${coverageAmount}" align="center">
<j:choose>
<j:when test="${it.hasCoverage(job)}">
<a style="color:#${color}" href="${job.url}lastSuccessfulBuild/jacoco/">
${coveragePercent}%
</a>
</j:when>
<j:otherwise>
N/A
</j:otherwise>
</j:choose>
</td>
</j:when>
<j:otherwise>
<td data="-" align="center"></td>
Expand Down
Expand Up @@ -10,13 +10,16 @@
import hudson.model.ExternalRun;
import hudson.model.Job;
import hudson.plugins.jacoco.JacocoBuildAction;
import hudson.plugins.jacoco.model.Coverage;
import hudson.plugins.jacoco.model.CoverageElement.Type;
import hudson.search.QuickSilver;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

Expand All @@ -25,6 +28,8 @@
import org.junit.Test;
import org.kohsuke.stapler.export.Exported;

import edu.emory.mathcs.backport.java.util.Collections;

public class JaCoCoColumnTest {

protected Float percentFloat;
Expand All @@ -46,9 +51,10 @@ public void testGetPercentWithNoLastSuccessfulBuild() {
protected void reload() {
}
};
assertFalse(jacocoColumn.hasCoverage(mockJob));
assertEquals("N/A", jacocoColumn.getPercent(mockJob));
assertEquals(new BigDecimal("0.0"), jacocoColumn.getLineCoverage(mockJob));

EasyMock.verify(context);
}

Expand All @@ -59,6 +65,7 @@ public void testGetPercentWithLastSuccessfulBuild() {
EasyMock.replay(context);

final Job<?, ?> mockJob = new ExternalJobExtension("externaljob");
assertFalse(jacocoColumn.hasCoverage(mockJob));
assertEquals("N/A", jacocoColumn.getPercent(mockJob));
assertEquals(new BigDecimal("0.0"), jacocoColumn.getLineCoverage(mockJob));

Expand Down Expand Up @@ -129,6 +136,7 @@ public void finished(Result result) {
protected synchronized void saveNextBuildNumber() throws IOException {
}
};
assertTrue(jacocoColumn.hasCoverage(mockJob));
assertEquals("0.0", jacocoColumn.getPercent(mockJob));
assertEquals(new BigDecimal("0.0"), jacocoColumn.getLineCoverage(mockJob));

Expand All @@ -142,18 +150,25 @@ public void testGetLineColorWithNull() throws Exception {

@Test
public void testGetLineColor() throws Exception {
assertEquals(CoverageRange.NA.getLineHexString(), jacocoColumn.getLineColor(null, BigDecimal.valueOf(100)));
final BuildListener listener = EasyMock.createNiceMock(BuildListener.class);
EasyMock.replay(listener);

// without job we cannot check for NA
assertEquals(CoverageRange.PERFECT.getLineHexString(), jacocoColumn.getLineColor(null, BigDecimal.valueOf(100)));

// with job, we detect that it has a build, but no JaCoCoBuildAction => NA
Job<?, ?> mockJob = new ExternalJobExtension("externaljob");
assertEquals(CoverageRange.NA.getLineHexString(), jacocoColumn.getLineColor(mockJob, BigDecimal.valueOf(100)));

// with job and build and JaCoCoBuildAction we detect correct coverage again
mockJob = new ExternalJobExtensionWithBuildAction("externaljob", listener);
assertEquals(CoverageRange.PERFECT.getLineHexString(), jacocoColumn.getLineColor(mockJob, BigDecimal.valueOf(100)));

mockJob = new ExternalJobExtension("externaljob") {
@Override
public ExternalRun getLastSuccessfulBuild() {
return null;
}
};
// finally with job, but no build => NA again
mockJob = new ExternalJobExtensionWithNoLastBuild("externaljob");
assertEquals(CoverageRange.NA.getLineHexString(), jacocoColumn.getLineColor(mockJob, BigDecimal.valueOf(100)));

EasyMock.verify(listener);
}

@Test
Expand All @@ -163,18 +178,25 @@ public void testGetFillColorWithNull() throws Exception {

@Test
public void testGetFillColor100() throws Exception {
final BuildListener listener = EasyMock.createNiceMock(BuildListener.class);
EasyMock.replay(listener);

// without job we cannot check for NA
assertEquals(CoverageRange.PERFECT.getFillHexString(), jacocoColumn.getFillColor(null, BigDecimal.valueOf(100)));

// with job, we detect that it has a build, but no JaCoCoBuildAction => NA
Job<?, ?> mockJob = new ExternalJobExtension("externaljob");
assertEquals(CoverageRange.NA.getFillHexString(), jacocoColumn.getFillColor(mockJob, BigDecimal.valueOf(100)));

mockJob = new ExternalJobExtension("externaljob") {
@Override
public ExternalRun getLastSuccessfulBuild() {
return null;
}
};
// with job and build and JaCoCoBuildAction we detect correct coverage again
mockJob = new ExternalJobExtensionWithBuildAction("externaljob", listener);
assertEquals(CoverageRange.PERFECT.getFillHexString(), jacocoColumn.getFillColor(mockJob, BigDecimal.valueOf(100)));

// finally with job, but no build => NA again
mockJob = new ExternalJobExtensionWithNoLastBuild("externaljob");
assertEquals(CoverageRange.NA.getFillHexString(), jacocoColumn.getFillColor(mockJob, BigDecimal.valueOf(100)));

EasyMock.verify(listener);
}

@Test
Expand All @@ -184,6 +206,42 @@ public void testDescriptor() throws FormException {
assertNotNull(jacocoColumn.getDescriptor().getDisplayName());
}

private final class ExternalJobExtensionWithNoLastBuild extends ExternalJobExtension {

private ExternalJobExtensionWithNoLastBuild(String name) {
super(name);
}

@Override
public ExternalRun getLastSuccessfulBuild() {
return null;
}
}

private final class ExternalJobExtensionWithBuildAction extends ExternalJobExtension {

private final BuildListener listener;

private ExternalJobExtensionWithBuildAction(String name, BuildListener listener) {
super(name);
this.listener = listener;
}

@Override
@Exported
@QuickSilver
public ExternalRun getLastSuccessfulBuild() {
try {
ExternalRun run = newBuild();
Map<Type, Coverage> map = Collections.emptyMap();
run.addAction(new JacocoBuildAction(null, null, map, null, listener, null, null));
return run;
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}

private class ExternalJobExtension extends ExternalJob {

private ExternalJobExtension(String name) {
Expand Down

0 comments on commit e73f8b1

Please sign in to comment.