Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gitlab codeclimate improvements #123

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ https://docs.gitlab.com/ce/ci/variables/#9-0-renaming
| sonar.gitlab.api_version | GitLab API version (default `v4` or `v3`) | Administration, Variable | >= 2.1.0 |
| sonar.gitlab.all_issues | All issues new and old (default false, only new) | Administration, Variable | >= 2.1.0 |
| sonar.gitlab.json_mode | Create a json report in root for GitLab EE (codeclimate.json or gl-sast-report.json) | Project, Variable | >= 3.0.0 |
| sonar.gitlab.json_all_issues | Always report all issues in JSON report regardless of analysis mode | Project, Variable | >= 3.1.0-SNAPSHOT |
| sonar.gitlab.query_max_retry | Max retry for wait finish analyse for publish mode | Administration, Variable | >= 3.0.0 |
| sonar.gitlab.query_wait | Max retry for wait finish analyse for publish mode | Administration, Variable | >= 3.0.0 |
| sonar.gitlab.quality_gate_fail_mode | Quality gate fail mode: error or warn (default error) | Administration, Variable | >= 3.0.0 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class GitLabPlugin implements Plugin {
public static final String GITLAB_API_VERSION = "sonar.gitlab.api_version";
public static final String GITLAB_ALL_ISSUES = "sonar.gitlab.all_issues";
public static final String GITLAB_JSON_MODE = "sonar.gitlab.json_mode";
public static final String GITLAB_JSON_ALL_ISSUES = "sonar.gitlab.json_all_issues";
public static final String GITLAB_QUERY_MAX_RETRY = "sonar.gitlab.query_max_retry";
public static final String GITLAB_QUERY_WAIT = "sonar.gitlab.query_wait";
public static final String GITLAB_QUALITY_GATE_FAIL_MODE = "sonar.gitlab.quality_gate_fail_mode";
Expand Down Expand Up @@ -88,7 +89,7 @@ public static List<PropertyDefinition> definitions() {
.description("The unique id, path with namespace, name with namespace, web url, ssh url or http url of the current project that GitLab.").category(CATEGORY)
.subCategory(SUBCATEGORY).index(5).onlyOnQualifiers(Qualifiers.PROJECT).build(),
PropertyDefinition.builder(GITLAB_COMMIT_SHA).name("GitLab Commit SHA").description("The commit revision for which project is built.").category(CATEGORY)
.subCategory(SUBCATEGORY).index(6).hidden().build(),
.subCategory(SUBCATEGORY).index(6).hidden().multiValues(true).build(),
PropertyDefinition.builder(GITLAB_REF_NAME).name("GitLab Ref Name").description("The commit revision for which project is built.").category(CATEGORY).subCategory(SUBCATEGORY)
.index(7).hidden().build(),
PropertyDefinition.builder(GITLAB_MAX_BLOCKER_ISSUES_GATE).name("Max Blocker Issues Gate").description("Max blocker issues to make the status fail.").category(CATEGORY)
Expand Down Expand Up @@ -135,23 +136,25 @@ public static List<PropertyDefinition> definitions() {
.type(PropertyType.BOOLEAN).defaultValue(String.valueOf(false)).index(26).build(),
PropertyDefinition.builder(GITLAB_JSON_MODE).name("Generate json report").description("Create a json report in root for GitLab EE").category(CATEGORY).subCategory(SUBCATEGORY)
.type(PropertyType.SINGLE_SELECT_LIST).options(JsonMode.NONE.name(), JsonMode.CODECLIMATE.name(), JsonMode.SAST.name()).defaultValue(JsonMode.NONE.name()).onlyOnQualifiers(Qualifiers.PROJECT).index(27).build(),
PropertyDefinition.builder(GITLAB_JSON_ALL_ISSUES).name("JSON report all issues").description("JSON report should always report all issues").category(CATEGORY).subCategory(SUBCATEGORY)
.type(PropertyType.BOOLEAN).defaultValue(Boolean.FALSE.toString()).onlyOnQualifiers(Qualifiers.PROJECT).index(28).build(),
PropertyDefinition.builder(GITLAB_QUERY_MAX_RETRY).name("Query max retry").description("Max retry for wait finish analyse for publish mode").category(CATEGORY).subCategory(SUBCATEGORY)
.type(PropertyType.INTEGER).defaultValue(String.valueOf(50)).index(28).build(),
.type(PropertyType.INTEGER).defaultValue(String.valueOf(50)).index(29).build(),
PropertyDefinition.builder(GITLAB_QUERY_WAIT).name("Query waiting between retry").description("Max retry for wait finish analyse for publish mode (millisecond)").category(CATEGORY).subCategory(SUBCATEGORY)
.type(PropertyType.INTEGER).defaultValue(String.valueOf(1000)).index(29).build(),
.type(PropertyType.INTEGER).defaultValue(String.valueOf(1000)).index(30).build(),
PropertyDefinition.builder(GITLAB_QUALITY_GATE_FAIL_MODE).name("Quality Gate fail mode").description("Quality gate fail mode: error or warn")
.category(CATEGORY).subCategory(SUBCATEGORY).type(PropertyType.SINGLE_SELECT_LIST)
.options(QualityGateFailMode.WARN.getMeaning(), QualityGateFailMode.ERROR.getMeaning()).defaultValue(QualityGateFailMode.ERROR.getMeaning())
.index(30).build(),
.index(31).build(),
PropertyDefinition.builder(GITLAB_ISSUE_FILTER).name("Issue filter").description("Filter on issue, if MAJOR then show only MAJOR, CRITICAL and BLOCKER")
.category(CATEGORY).subCategory(SUBCATEGORY).type(PropertyType.SINGLE_SELECT_LIST)
.options(Severity.INFO.name(), Severity.MINOR.name(), Severity.MAJOR.name(), Severity.CRITICAL.name(), Severity.BLOCKER.name())
.defaultValue(Severity.INFO.name())
.index(31).build(),
.index(32).build(),
PropertyDefinition.builder(GITLAB_LOAD_RULES).name("Load rules information").description("Load rule for all issues")
.category(CATEGORY).subCategory(SUBCATEGORY).type(PropertyType.BOOLEAN)
.defaultValue(String.valueOf(false))
.index(32).build()
.index(33).build()

);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ public JsonMode jsonMode() {
return s != null ? s : JsonMode.NONE;
}

public boolean jsonReportAllIssues() {
return Boolean.valueOf(configuration.get(GitLabPlugin.GITLAB_JSON_ALL_ISSUES).orElse("false"));
}

public int queryMaxRetry() {
return configuration.getInt(GitLabPlugin.GITLAB_QUERY_MAX_RETRY).orElse(50);
}
Expand Down
28 changes: 22 additions & 6 deletions src/main/java/com/talanlabs/sonar/plugins/gitlab/Reporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package com.talanlabs.sonar.plugins.gitlab;

import com.talanlabs.sonar.plugins.gitlab.models.*;
import org.apache.commons.lang3.StringEscapeUtils;
import org.sonar.api.batch.rule.Severity;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -54,14 +55,10 @@ public void setQualityGate(QualityGate qualityGate) {

public void process(Issue issue, @Nullable Rule rule, @Nullable String revision, @Nullable String gitLabUrl, @Nullable String src, String ruleLink, boolean reportedOnDiff) {
String r = revision != null ? revision : gitLabPluginConfiguration.commitSHA().get(0);
ReportIssue reportIssue = ReportIssue.newBuilder().issue(issue).rule(rule).revision(r).url(gitLabUrl).file(src).ruleLink(ruleLink).reportedOnDiff(reportedOnDiff).build();
ReportIssue reportIssue = getReportIssue(issue, rule, gitLabUrl, src, ruleLink, reportedOnDiff, r);
List<ReportIssue> reportIssues = reportIssuesMap.computeIfAbsent(issue.getSeverity(), k -> new ArrayList<>());
reportIssues.add(reportIssue);

if (!gitLabPluginConfiguration.jsonMode().equals(JsonMode.NONE)) {
jsonIssues.add(reportIssue);
}

increment(issue.getSeverity());
if (!reportedOnDiff) {
notReportedIssueCount++;
Expand All @@ -75,6 +72,25 @@ public void process(Issue issue, @Nullable Rule rule, @Nullable String revision,
}
}

public void processForJSON(Issue issue, @Nullable Rule rule, @Nullable String revision, @Nullable String gitLabUrl, @Nullable String src, String ruleLink, boolean reportedOnDiff) {
String r = revision != null ? revision : gitLabPluginConfiguration.commitSHA().get(0);
ReportIssue reportIssue = getReportIssue(issue, rule, gitLabUrl, src, ruleLink, reportedOnDiff, r);

jsonIssues.add(reportIssue);
}

private ReportIssue getReportIssue(Issue issue, @Nullable Rule rule, @Nullable String gitLabUrl, @Nullable String src, String ruleLink, boolean reportedOnDiff, String revision) {
return ReportIssue.newBuilder()
.issue(issue)
.rule(rule)
.revision(revision)
.url(gitLabUrl)
.file(src)
.ruleLink(ruleLink)
.reportedOnDiff(reportedOnDiff)
.build();
}

private void increment(Severity severity) {
this.newIssuesBySeverity[SEVERITIES.indexOf(severity)]++;
}
Expand Down Expand Up @@ -260,6 +276,6 @@ private String buildIssueSastJson(ReportIssue reportIssue) {
}

private String prepareMessageJson(String message) {
return message.replaceAll("\"", "\\\\\"");
return StringEscapeUtils.escapeJson(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public Reporter build(QualityGate qualityGate, List<Issue> issues) {
}

if (!gitLabPluginConfiguration.jsonMode().equals(JsonMode.NONE)) {
processIssuesForJSON(report, issues);

String json = report.buildJson();
commitFacade.writeJsonFile(json);
}
Expand All @@ -91,11 +93,15 @@ private boolean isGlobalComments(QualityGate qualityGate, Reporter report) {
}

private void processIssues(Reporter report, List<Issue> issues) {
getStreamIssue(issues).sorted(ISSUE_COMPARATOR).forEach(i -> processIssue(report, i));
getStreamIssue(issues, gitLabPluginConfiguration.allIssues()).sorted(ISSUE_COMPARATOR).forEach(i -> processIssue(report, i, false));
}

private void processIssuesForJSON(Reporter report, List<Issue> issues) {
getStreamIssue(issues, gitLabPluginConfiguration.jsonReportAllIssues()).sorted(ISSUE_COMPARATOR).forEach(i -> processIssue(report, i, true));
}

private Stream<Issue> getStreamIssue(List<Issue> issues) {
return issues.stream().filter(p -> gitLabPluginConfiguration.allIssues() || p.isNewIssue()).filter(i -> {
private Stream<Issue> getStreamIssue(List<Issue> issues, boolean allIssues) {
return issues.stream().filter(p -> allIssues || p.isNewIssue()).filter(i -> {
if (gitLabPluginConfiguration.onlyIssueFromCommitLine()) {
return onlyIssueFromCommitLine(i);
}
Expand All @@ -108,7 +114,7 @@ private boolean onlyIssueFromCommitLine(Issue issue) {
return hasFile && issue.getLine() != null && commitFacade.getRevisionForLine(issue.getFile(), issue.getLine()) != null;
}

private void processIssue(Reporter report, Issue issue) {
private void processIssue(Reporter report, Issue issue, boolean json) {
boolean reportedInline = false;

String revision = null;
Expand All @@ -129,7 +135,11 @@ private void processIssue(Reporter report, Issue issue) {
rule = sonarFacade.getRule(issue.getRuleKey());
}

report.process(issue, rule, revision, url, src, ruleLink, reportedInline);
if (json) {
report.processForJSON(issue, rule, revision, url, src, ruleLink, reportedInline);
} else {
report.process(issue, rule, revision, url, src, ruleLink, reportedInline);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void oneIssueNoSast() {
public void oneIssueSast() {
settings.setProperty(GitLabPlugin.GITLAB_JSON_MODE, JsonMode.SAST.name());

reporter.process(Utils.newIssue("123", "component", null, 10, Severity.INFO, true, "Issue \"NULL\"", "rule"), null, null, GITLAB_URL, "file", "http://myserver", true);
reporter.processForJSON(Utils.newIssue("123", "component", null, 10, Severity.INFO, true, "Issue \"NULL\"", "rule"), null, null, GITLAB_URL, "file", "http://myserver", true);

Assertions.assertThat(reporter.buildJson()).isEqualTo("[{\"tool\":\"sonarqube\",\"fingerprint\":\"123\",\"message\":\"Issue \\\"NULL\\\"\",\"file\":\"file\",\"line\":\"10\",\"priority\":\"INFO\",\"solution\":\"http://myserver\"}]");
}
Expand All @@ -129,7 +129,7 @@ public void oneIssueSast() {
public void oneIssueCodeClimate() {
settings.setProperty(GitLabPlugin.GITLAB_JSON_MODE, JsonMode.CODECLIMATE.name());

reporter.process(Utils.newIssue("456", "component", null, 20, Severity.INFO, true, "Issue \"NULL\"", "rule"), null, null, GITLAB_URL, "file", "http://myserver", true);
reporter.processForJSON(Utils.newIssue("456", "component", null, 20, Severity.INFO, true, "Issue \"NULL\"", "rule"), null, null, GITLAB_URL, "file", "http://myserver", true);

Assertions.assertThat(reporter.buildJson()).isEqualTo("[{\"fingerprint\":\"456\",\"check_name\":\"Issue \\\"NULL\\\"\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":20,\"end\":20}}}]");
}
Expand All @@ -139,7 +139,7 @@ public void issuesSast() {
settings.setProperty(GitLabPlugin.GITLAB_JSON_MODE, JsonMode.SAST.name());

for (int i = 0; i < 5; i++) {
reporter.process(Utils.newIssue("toto_" + i, "component", null, null, Severity.INFO, true, "Issue", "rule" + i), null, null, GITLAB_URL, "file", "http://myserver/rule" + i, true);
reporter.processForJSON(Utils.newIssue("toto_" + i, "component", null, null, Severity.INFO, true, "Issue", "rule" + i), null, null, GITLAB_URL, "file", "http://myserver/rule" + i, true);
}

Assertions.assertThat(reporter.buildJson()).isEqualTo("[{\"tool\":\"sonarqube\",\"fingerprint\":\"toto_0\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver/rule0\"},{\"tool\":\"sonarqube\",\"fingerprint\":\"toto_1\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver/rule1\"},{\"tool\":\"sonarqube\",\"fingerprint\":\"toto_2\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver/rule2\"},{\"tool\":\"sonarqube\",\"fingerprint\":\"toto_3\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver/rule3\"},{\"tool\":\"sonarqube\",\"fingerprint\":\"toto_4\",\"message\":\"Issue\",\"file\":\"file\",\"line\":\"0\",\"priority\":\"INFO\",\"solution\":\"http://myserver/rule4\"}]");
Expand All @@ -150,7 +150,7 @@ public void issuesCodeClimate() {
settings.setProperty(GitLabPlugin.GITLAB_JSON_MODE, JsonMode.CODECLIMATE.name());

for (int i = 0; i < 5; i++) {
reporter.process(Utils.newIssue("tata_" + i, "component", null, null, Severity.INFO, true, "Issue", "rule" + i), null, null, GITLAB_URL, "file", "http://myserver/rule" + i, true);
reporter.processForJSON(Utils.newIssue("tata_" + i, "component", null, null, Severity.INFO, true, "Issue", "rule" + i), null, null, GITLAB_URL, "file", "http://myserver/rule" + i, true);
}

Assertions.assertThat(reporter.buildJson()).isEqualTo("[{\"fingerprint\":\"tata_0\",\"check_name\":\"Issue\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":0,\"end\":0}}},{\"fingerprint\":\"tata_1\",\"check_name\":\"Issue\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":0,\"end\":0}}},{\"fingerprint\":\"tata_2\",\"check_name\":\"Issue\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":0,\"end\":0}}},{\"fingerprint\":\"tata_3\",\"check_name\":\"Issue\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":0,\"end\":0}}},{\"fingerprint\":\"tata_4\",\"check_name\":\"Issue\",\"location\":{\"path\":\"file\",\"lines\": { \"begin\":0,\"end\":0}}}]");
Expand Down