Adds new Code Climate-compliant JSON renderer

This commit is contained in:
Bob W. Hogg 2016-01-02 12:30:49 -08:00 committed by Andreas Dangel
parent d783bdcfb0
commit b2d5342493
5 changed files with 165 additions and 0 deletions

View File

@ -93,6 +93,12 @@
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>

View File

@ -0,0 +1,55 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.renderers;
import net.sourceforge.pmd.*;
/**
* Structure for the Code Climate Issue spec (https://github.com/codeclimate/spec/blob/master/SPEC.md#issues)
*/
public class CodeClimateIssue {
public final String type = "issue";
public String check_name;
public String description;
public Content content;
public final String[] categories = { "Style" };
public Location location;
public String severity;
/**
* Location structure
*/
public static class Location {
public String path;
public Lines lines;
private class Lines {
public int begin;
public int end;
}
public Location(String path, int beginLine, int endLine) {
this.path = path;
this.lines = new Lines();
lines.begin = beginLine;
lines.end = endLine;
}
}
/**
* Content structure
*/
public static class Content {
public String body;
/**
* Strip out all newlines from the body
* @param {String} body The text to compose the content from
*/
public Content(String body) {
this.body = body.replace(PMD.EOL, " ");
}
}
}

View File

@ -0,0 +1,72 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.renderers;
import com.google.gson.Gson;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleViolation;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
/**
* Renderer for Code Climate JSON format
*/
public class CodeClimateRenderer extends AbstractIncrementingRenderer {
public static final String NAME = "codeclimate";
protected static final String EOL = System.getProperty("line.separator", "\n");
public CodeClimateRenderer() {
super(NAME, "Code Climate integration.");
}
/**
* {@inheritDoc}
*/
@Override
public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException {
Writer writer = getWriter();
Gson gson = new Gson();
while (violations.hasNext()) {
RuleViolation rv = violations.next();
writer.write(gson.toJson(makeIssue(rv)) + EOL);
}
}
/**
* Generate a CodeClimateIssue suitable for processing into JSON from the given RuleViolation.
* @param rv RuleViolation to convert.
* @return The generated issue.
*/
private CodeClimateIssue makeIssue(RuleViolation rv) {
CodeClimateIssue issue = new CodeClimateIssue();
Rule rule = rv.getRule();
issue.check_name = rule.getName();
issue.description = rv.getDescription();
issue.content = new CodeClimateIssue.Content(rule.getDescription());
issue.location = new CodeClimateIssue.Location(rv.getFilename(), rv.getBeginLine(), rv.getEndLine());
switch(rule.getPriority()) {
case HIGH:
issue.severity = "critical";
break;
case MEDIUM_HIGH:
case MEDIUM:
case MEDIUM_LOW:
issue.severity = "normal";
break;
case LOW:
issue.severity = "info";
break;
}
return issue;
}
@Override
public String defaultFileExtension() {
return "json";
}
}

View File

@ -26,6 +26,7 @@ public class RendererFactory {
public static final Map<String, Class<? extends Renderer>> REPORT_FORMAT_TO_RENDERER;
static {
Map<String, Class<? extends Renderer>> map = new TreeMap<String, Class<? extends Renderer>>();
map.put(CodeClimateRenderer.NAME, CodeClimateRenderer.class);
map.put(XMLRenderer.NAME, XMLRenderer.class);
map.put(IDEAJRenderer.NAME, IDEAJRenderer.class);
map.put(TextColorRenderer.NAME, TextColorRenderer.class);

View File

@ -0,0 +1,31 @@
package net.sourceforge.pmd.renderers;
import net.sourceforge.pmd.*;
public class CodeClimateRendererTest extends AbstractRendererTst {
@Override
public Renderer getRenderer() {
return new CodeClimateRenderer();
}
@Override
public String getExpected() {
return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\"}" + PMD.EOL;
}
@Override
public String getExpectedEmpty() {
return "";
}
@Override
public String getExpectedMultiple() {
return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\"}" + PMD.EOL +
"{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\"}" + PMD.EOL;
}
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(CodeClimateRendererTest.class);
}
}