Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {
compile("org.sonarsource.java:sonar-java-plugin:4.3.0.7717")

testCompile("org.assertj:assertj-core:2.8.0")
testCompile("org.skyscreamer:jsonassert:1.5.0")
testCompile("junit:junit:4.12")
}

Expand Down
3 changes: 0 additions & 3 deletions src/main/java/cc/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

Expand Down
70 changes: 16 additions & 54 deletions src/main/java/cc/JsonReport.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package cc;

import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import java.io.PrintStream;
import cc.models.CodeClimateIssue;
import cc.serialization.GsonFactory;
import com.google.gson.Gson;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Arrays;
import java.util.function.Function;
import org.sonarlint.cli.util.Logger;

import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.AnalysisResults;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
Expand All @@ -21,63 +22,24 @@ public class JsonReport implements org.sonarlint.cli.report.Reporter {
"VULNERABILITY"
);

final Gson gson;
final String baseDir;

public JsonReport(String baseDir) {
this.baseDir = baseDir;
this.gson = new GsonFactory().create();
}

@Override
public void execute(String projectName, Date date, Collection<Trackable> trackables, AnalysisResults result, Function<String, RuleDetails> ruleDescriptionProducer) {
for (Trackable trackable : trackables) {
Issue issue = trackable.getIssue();
RuleDetails ruleDetails = ruleDescriptionProducer.apply(issue.getRuleKey());

if (VALID_RULE_DETAIL_TYPES.contains(ruleDetails.getType())) {
JsonObject json = new JsonObject();
json.addProperty("type", "issue");
json.addProperty("check_name", issue.getRuleKey());
json.addProperty("severity", ruleDetails.getSeverity().toLowerCase());
json.addProperty("description", issue.getMessage());

JsonObject content = new JsonObject();
json.add("content", content);
content.addProperty("body", ruleDetails.getHtmlDescription());
// // ruleDetails.getExtendedDescription();

JsonObject location = new JsonObject();
json.add("location", location);

// Code Climate CLI expects relative path to file
location.addProperty("path", issue.getInputFile().getPath().replaceFirst("^/tmp/code/", ""));

JsonObject lines = new JsonObject();
location.add("lines", lines);

if (issue.getStartLine() != null) {
lines.addProperty("begin", issue.getStartLine());

if (issue.getEndLine() != null) {
lines.addProperty("end", issue.getEndLine());
} else {
lines.addProperty("end", 1);
}
} else {
lines.addProperty("begin", 1);
lines.addProperty("end", 1);
}

String category;
switch (ruleDetails.getType()) {
case "VULNERABILITY": {
category = "Security";
break;
}
default: {
category = "Bug Risk";
break;
}
}
JsonArray categories = new JsonArray();
categories.add(category);
json.add("categories", categories);

System.out.println(json.toString() + "\0");
String type = ruleDetails.getType();
if (VALID_RULE_DETAIL_TYPES.contains(type)) {
CodeClimateIssue codeClimateIssue = CodeClimateIssue.from(issue, ruleDetails, baseDir);
System.out.println(gson.toJson(codeClimateIssue) + "\0");
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/cc/models/Categories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cc.models;

import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;

import java.util.ArrayList;

class Categories extends ArrayList<String> {
public Categories(String ruleType) {
String category;
switch (ruleType) {
case "VULNERABILITY": {
category = "Security";
break;
}
default: {
category = "Bug Risk";
break;
}
}
add(category);
}

public static Categories from(RuleDetails ruleDetails) {
return new Categories(ruleDetails.getType());
}
}
34 changes: 34 additions & 0 deletions src/main/java/cc/models/CodeClimateIssue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cc.models;

import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;

public class CodeClimateIssue {
public final String type = "issue";
public final String checkName;
public final String severity;
public final String description;
public final Content content;
public final Location location;
public final Categories categories;

public CodeClimateIssue(String checkName, String severity, String description, Content content, Location location, Categories categories) {
this.checkName = checkName;
this.severity = severity;
this.description = description;
this.content = content;
this.location = location;
this.categories = categories;
}

public static CodeClimateIssue from(Issue issue, RuleDetails ruleDetails, String baseDir) {
String checkName = issue.getRuleKey();
String description = issue.getMessage();
String severity = Severity.from(ruleDetails);
Content content = Content.from(ruleDetails);
Location location = Location.from(baseDir, issue);
Categories categories = Categories.from(ruleDetails);
return new CodeClimateIssue(checkName, severity, description, content, location, categories);
}

}
15 changes: 15 additions & 0 deletions src/main/java/cc/models/Content.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cc.models;

import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;

class Content {
String body;

public Content(String body) {
this.body = body;
}

public static Content from(RuleDetails ruleDetails) {
return new Content(ruleDetails.getHtmlDescription());
}
}
20 changes: 20 additions & 0 deletions src/main/java/cc/models/Lines.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cc.models;

import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;

class Lines {
final Integer begin;
final Integer end;

public Lines(Integer begin, Integer end) {
this.begin = begin;
this.end = end;
}

public static Lines from(Issue issue) {
if(issue.getStartLine() == null || issue.getEndLine() == null) {
return null;
}
return new Lines(issue.getStartLine(), issue.getEndLine());
}
}
25 changes: 25 additions & 0 deletions src/main/java/cc/models/Location.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cc.models;

import org.sonarsource.sonarlint.core.client.api.common.analysis.ClientInputFile;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;

class Location {
final String path;
final Lines lines;

public Location(String baseDir, String path, Lines lines) {
String regex = ("^" + baseDir + "/").replace("//", "/");
this.path = path.replaceFirst(regex, "");
this.lines = lines;
}

public static Location from(String baseDir, Issue issue) {
ClientInputFile inputFile = issue.getInputFile();

if (inputFile == null || inputFile.getPath() == null) {
return null;
}

return new Location(baseDir, inputFile.getPath(), Lines.from(issue));
}
}
15 changes: 15 additions & 0 deletions src/main/java/cc/models/Severity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cc.models;

import com.google.gson.annotations.SerializedName;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;

public class Severity {

public static String from(RuleDetails ruleDetails) {
String severity = ruleDetails.getSeverity();
if(severity == null) {
return null;
}
return severity.toLowerCase();
}
}
13 changes: 13 additions & 0 deletions src/main/java/cc/serialization/GsonFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cc.serialization;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class GsonFactory {
public Gson create() {
return new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/sonarlint/cli/CustomMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public CustomReportFactory(Charset charset) {

@Override
public List<Reporter> createReporters(Path basePath) {
return Arrays.asList(new JsonReport());
return Arrays.asList(new JsonReport(basePath.toString()));
}
}
}
62 changes: 62 additions & 0 deletions src/test/java/cc/JsonReportTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cc;

import org.junit.Before;
import org.junit.Test;
import org.sonarsource.sonarlint.core.client.api.common.RuleDetails;
import org.sonarsource.sonarlint.core.tracking.Trackable;
import support.fakes.FakeRuleDetails;
import support.OutputHelper;
import support.fakes.FakeIssue;
import support.fakes.FakeTrackable;

import java.util.Date;
import java.util.List;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

public class JsonReportTest {

OutputHelper output;

@Before
public void setUp() throws Exception {
output = OutputHelper.setup();
}

@Test
public void serialize_issue() throws Exception {
executeReport("major", new FakeIssue("file.java", 0, 1));
assertThat(output.stdout.toString()).contains("\"type\":\"issue\"");
}

@Test
public void serialize_issue_relative_path() throws Exception {
executeReport("major", new FakeIssue("/tmp/dir/file.java", 0, 1));
assertThat(output.stdout.toString()).contains("\"path\":\"dir/file.java\"");
}

@Test
public void does_not_include_unknown_severity() throws Exception {
executeReport(null, new FakeIssue("file.java", 0, 1));
assertThat(output.stdout.toString()).doesNotContain("severity");
}

@Test
public void does_not_include_unknown_path() throws Exception {
executeReport("major", new FakeIssue(null, 1, 0));
assertThat(output.stdout.toString()).doesNotContain("path");
}

@Test
public void does_not_include_unknown_location() throws Exception {
executeReport("major", new FakeIssue("file.java", null, null));
assertThat(output.stdout.toString()).doesNotContain("lines");
}

void executeReport(String severity, FakeIssue issue) {
RuleDetails ruleDetails = new FakeRuleDetails(severity);
List<Trackable> trackables = asList(new FakeTrackable(issue));
new JsonReport("/tmp").execute("prj", new Date(0), trackables, null, _ruleKey -> ruleDetails);
}
}
36 changes: 36 additions & 0 deletions src/test/java/cc/models/CodeClimateIssueTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cc.models;

import cc.serialization.GsonFactory;
import com.google.gson.Gson;
import org.junit.Test;
import support.fakes.FakeRuleDetails;

import static org.assertj.core.api.Assertions.assertThat;

public class CodeClimateIssueTest {

@Test
public void down_case_severities() throws Exception {
assertThat(createIssueForSeverity("MAJOR").severity).isEqualTo("major");
assertThat(createIssueForSeverity("MINOR").severity).isEqualTo("minor");
assertThat(createIssueForSeverity("CRITICAL").severity).isEqualTo("critical");
assertThat(createIssueForSeverity(null).severity).isNull();
}

@Test
public void properly_serialize_severity() throws Exception {
Gson gson = new GsonFactory().create();
assertThat(gson.toJson(createIssueForSeverity("INFO"))).contains("\"severity\":\"info\"");
}

private CodeClimateIssue createIssueForSeverity(String severity) {
return new CodeClimateIssue(
"check",
Severity.from(new FakeRuleDetails(severity)),
"desc",
new Content(""),
new Location("/tmp", "path", new Lines(0, 1)),
new Categories("VULNERABILITY")
);
}
}
Loading