Skip to content

Commit

Permalink
Implemented custom rendering for chart lines and legend, configurable…
Browse files Browse the repository at this point in the history
… in a generic way. Fixed imports in various places.
  • Loading branch information
Anthony DeMartini committed Nov 26, 2014
1 parent 0884e11 commit 176abfa
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 132 deletions.
8 changes: 0 additions & 8 deletions src/main/java/com/secdec/codedx/api/client/CodeDxClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.PartSource;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/secdec/codedx/api/client/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class Filter {
public static final String SEVERITY_LOW = "Low";
public static final String SEVERITY_MEDIUM = "Medium";
public static final String SEVERITY_HIGH = "High";
public static final String SEVERITY_UNSPECIFIED = "Unspecified";

public String[] getCwe() {
return cwe;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/secdec/codedx/api/client/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package com.secdec.codedx.api.client;

import java.util.List;

/**
* Represents the JSON data for a CodeDx project.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.http.client.ClientProtocolException;

Expand Down Expand Up @@ -99,7 +97,7 @@ private Filter createFilter(String minSeverity, boolean onlyNew){

private String[] getSeverities(String minSeverity){

String[] possibleSeverities = {Filter.SEVERITY_INFO, Filter.SEVERITY_LOW, Filter.SEVERITY_MEDIUM, Filter.SEVERITY_HIGH};
String[] possibleSeverities = {Filter.SEVERITY_INFO, Filter.SEVERITY_LOW, Filter.SEVERITY_MEDIUM, Filter.SEVERITY_HIGH, Filter.SEVERITY_UNSPECIFIED};

for(int i = 0; i < possibleSeverities.length; i++){

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.jenkinsci.plugins.codedx;

import java.awt.Color;
import java.awt.Paint;
import java.util.List;

import hudson.util.StackedAreaRenderer2;
import hudson.util.ChartUtil.NumberOnlyBuildLabel;

Expand All @@ -13,9 +17,16 @@
* @author ademartini This file is heavily derived from the sloccount-plugin
*/
public class CodeDxAreaRenderer extends StackedAreaRenderer2 {
/** Unique identifier of this class. */

/** Unique identifier of this class. */
private static final long serialVersionUID = 1440842055316682192L;
private List<Color> rowColors;

public CodeDxAreaRenderer(List<Color> rowColors){

this.rowColors = rowColors;
}

/** {@inheritDoc} */
@Override
public final String generateURL(final CategoryDataset dataset, final int row, final int column) {
Expand All @@ -34,4 +45,26 @@ public final String generateURL(final CategoryDataset dataset, final int row, fi
private NumberOnlyBuildLabel getLabel(final CategoryDataset dataset, final int column) {
return (NumberOnlyBuildLabel)dataset.getColumnKey(column);
}

@Override
public Paint getItemPaint(int row, int column) {

if(rowColors == null){

return super.getItemPaint(row, column);
}

return rowColors.get(row);
}

@Override
public Paint getSeriesPaint(int series) {

if(rowColors == null){

return super.getSeriesPaint(series);
}

return rowColors.get(series);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import hudson.model.AbstractBuild;
import hudson.model.Action;
import hudson.model.HealthReport;
import hudson.model.HealthReportingAction;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
Expand Down Expand Up @@ -76,13 +73,15 @@ public CodeDxDiffSummary getSeverityDiffSummary() {
order.add("Medium");
order.add("Low");
order.add("Info");
order.add("Unspecified");

Map<String,String> iconMap = new HashMap<String,String>();

iconMap.put("High", "/plugin/codedx/icons/high.png");
iconMap.put("Medium", "/plugin/codedx/icons/medium.png");
iconMap.put("Low", "/plugin/codedx/icons/low.png");
iconMap.put("Info", "/plugin/codedx/icons/info.png");
iconMap.put("Unspecified", "/plugin/codedx/icons/unspecified.png");

return CodeDxDiffSummary.getDiffSummary(getPreviousSeverityStats(),
result.getStatistics("severity"), "Severity",new DiffGroupComparator(order),iconMap);
Expand Down
148 changes: 41 additions & 107 deletions src/main/java/org/jenkinsci/plugins/codedx/CodeDxChartBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

import java.awt.Color;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jenkinsci.plugins.codedx.model.CodeDxReportStatistics;
import org.jenkinsci.plugins.codedx.model.CodeDxGroupStatistics;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
Expand All @@ -18,6 +20,7 @@
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;

import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleInsets;

Expand All @@ -33,10 +36,12 @@ private CodeDxChartBuilder(){
}

public static JFreeChart buildChart(CodeDxBuildAction action,
int numBuildsInGraph, String statisticsName){
int numBuildsInGraph, String statisticsName, Map<String,Color> colors){

CategoryDataset dataset = buildDataset(action, numBuildsInGraph, statisticsName);

JFreeChart chart = ChartFactory.createStackedAreaChart(null, null,
"Findings", buildDataset(action, numBuildsInGraph, statisticsName),
"Findings", dataset,
PlotOrientation.VERTICAL, true, false, true);

chart.setBackgroundPaint(Color.white);
Expand All @@ -47,7 +52,7 @@ public static JFreeChart buildChart(CodeDxBuildAction action,
plot.setForegroundAlpha(0.8f);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.black);

CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
plot.setDomainAxis(domainAxis);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
Expand All @@ -61,16 +66,38 @@ public static JFreeChart buildChart(CodeDxBuildAction action,
// crop extra space around the graph
plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));

CodeDxAreaRenderer renderer = new CodeDxAreaRenderer();
plot.setRenderer(renderer);

List rows = dataset.getRowKeys();

List<Color> colorList = new ArrayList<Color>();

if(colors != null){

for(Object row : rows){

if(colors.containsKey(row)){

colorList.add(colors.get(row));
}
}
}

if(colorList.size() == rows.size()){

plot.setRenderer(new CodeDxAreaRenderer(colorList));
}
else{

plot.setRenderer(new CodeDxAreaRenderer(null));
}

return chart;
}

private static CategoryDataset buildDataset(CodeDxBuildAction lastAction,
int numBuildsInGraph, String statisticsName){
DataSetBuilder<String, NumberOnlyBuildLabel> builder = new DataSetBuilder<String, NumberOnlyBuildLabel>();
Set<String> allSeverities = new HashSet<String>();
Set<String> allGroups = new HashSet<String>();

CodeDxBuildAction action = lastAction;
int numBuilds = 0;
Expand All @@ -81,17 +108,17 @@ private static CategoryDataset buildDataset(CodeDxBuildAction lastAction,
if(result != null){
NumberOnlyBuildLabel buildLabel = new NumberOnlyBuildLabel(action.getBuild());

allSeverities.addAll(result.getStatistics(statisticsName).getAllGroups());
Set<String> remainingSeverities = new HashSet<String>(allSeverities);
allGroups.addAll(result.getStatistics(statisticsName).getAllGroups());
Set<String> remainingGroups = new HashSet<String>(allGroups);

for(CodeDxGroupStatistics severityStats : result.getStatistics(statisticsName).getStatistics()){
builder.add(severityStats.getFindings(), severityStats.getGroup(), buildLabel);
remainingSeverities.remove(severityStats.getGroup());
for(CodeDxGroupStatistics groupStats : result.getStatistics(statisticsName).getStatistics()){
builder.add(groupStats.getFindings(), groupStats.getGroup(), buildLabel);
remainingGroups.remove(groupStats.getGroup());
}

for(String language : remainingSeverities) {
for(String group : remainingGroups) {
// Language disappeared
builder.add(0, language, buildLabel);
builder.add(0, group, buildLabel);
}

++numBuilds;
Expand All @@ -102,97 +129,4 @@ private static CategoryDataset buildDataset(CodeDxBuildAction lastAction,

return builder.build();
}

public static JFreeChart buildChartDelta(CodeDxBuildAction action,
int numBuildsInGraph, String statisticsName){

JFreeChart chart = ChartFactory.createStackedAreaChart(null, null,
"Findings Delta", buildDatasetDelta(action, numBuildsInGraph, statisticsName),
PlotOrientation.VERTICAL, true, false, true);

chart.setBackgroundPaint(Color.white);

CategoryPlot plot = chart.getCategoryPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setOutlinePaint(null);
plot.setForegroundAlpha(0.8f);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.black);

CategoryAxis domainAxis = new ShiftedCategoryAxis(null);
plot.setDomainAxis(domainAxis);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);
domainAxis.setLowerMargin(0.0);
domainAxis.setUpperMargin(0.0);
domainAxis.setCategoryMargin(0.0);

NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

// crop extra space around the graph
plot.setInsets(new RectangleInsets(0, 0, 0, 5.0));

CodeDxAreaRenderer renderer = new CodeDxAreaRenderer();
plot.setRenderer(renderer);

return chart;
}

private static CategoryDataset buildDatasetDelta(CodeDxBuildAction lastAction,
int numBuildsInGraph, String statisticsName){
DataSetBuilder<String, NumberOnlyBuildLabel> builder = new DataSetBuilder<String, NumberOnlyBuildLabel>();
Set<String> allSeverities = new HashSet<String>();
CodeDxBuildAction action = lastAction;

// Initial languages from the first action
if(action != null && action.getResult() != null) {
allSeverities.addAll(action.getResult().getStatistics(statisticsName).getAllGroups());
}

int numBuilds = 0;

// numBuildsInGraph <= 1 means unlimited
while(action != null && (numBuildsInGraph <= 1 || numBuilds < numBuildsInGraph)){
CodeDxBuildAction previousAction = action.getPreviousAction();
CodeDxResult result = action.getResult();
CodeDxReportStatistics previousStatistics = null;

if(result != null){
NumberOnlyBuildLabel buildLabel = new NumberOnlyBuildLabel(action.getBuild());

if(previousAction != null && previousAction.getResult() != null){
previousStatistics = previousAction.getResult().getStatistics(statisticsName);
} else {
// This will produce zero delta for the first build
previousStatistics = result.getStatistics(statisticsName);
}

allSeverities.addAll(previousStatistics.getAllGroups());
Set<String> remainingSeverities = new HashSet<String>(allSeverities);

for(CodeDxGroupStatistics current : result.getStatistics(statisticsName).getStatistics()){
CodeDxGroupStatistics previous = previousStatistics.getGroup(current.getGroup());

builder.add(current.getFindings() - previous.getFindings(),
current.getGroup(), buildLabel);

remainingSeverities.remove(current.getGroup());
}

for(String severity : remainingSeverities) {
CodeDxGroupStatistics previous
= previousStatistics.getGroup(severity);

// Language disappeared (current - previous = 0 - previous)
builder.add(-previous.getFindings(), severity, buildLabel);
}

++numBuilds;
}

action = previousAction;
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.util.ChartUtil;

import java.awt.Color;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

import com.secdec.codedx.api.client.Filter;

/**
*
* @author ademartini This file is heavily derived from the sloccount-plugin (author: lordofthepigs)
Expand Down Expand Up @@ -146,10 +153,18 @@ public void doSeverityTrend(final StaplerRequest request, final StaplerResponse
AbstractBuild<?,?> lastBuild = this.getLastFinishedBuild();
CodeDxBuildAction lastAction = lastBuild.getAction(CodeDxBuildAction.class);

Map<String,Color> colorMap = new HashMap<String,Color>();

colorMap.put(Filter.SEVERITY_HIGH, new Color(0xbd0026));
colorMap.put(Filter.SEVERITY_MEDIUM, new Color(0xfd8d3c));
colorMap.put(Filter.SEVERITY_LOW, new Color(0xfed976));
colorMap.put(Filter.SEVERITY_INFO, new Color(0x888888));
colorMap.put(Filter.SEVERITY_UNSPECIFIED, new Color(0xadadad));

ChartUtil.generateGraph(
request,
response,
CodeDxChartBuilder.buildChart(lastAction, analysisResultConfiguration.getNumBuildsInGraph(),"severity"),
CodeDxChartBuilder.buildChart(lastAction, analysisResultConfiguration.getNumBuildsInGraph(),"severity",colorMap),
CHART_WIDTH,
CHART_HEIGHT);
}
Expand All @@ -172,7 +187,7 @@ public void doStatusTrend(final StaplerRequest request, final StaplerResponse re
ChartUtil.generateGraph(
request,
response,
CodeDxChartBuilder.buildChart(lastAction, analysisResultConfiguration.getNumBuildsInGraph(),"status"),
CodeDxChartBuilder.buildChart(lastAction, analysisResultConfiguration.getNumBuildsInGraph(),"status",null),
CHART_WIDTH,
CHART_HEIGHT);
}
Expand Down

0 comments on commit 176abfa

Please sign in to comment.