From 11df8fbf40d6a9a9a1a97747a0c0e7ac898f1617 Mon Sep 17 00:00:00 2001 From: David Renz Date: Tue, 17 May 2016 10:44:54 +0200 Subject: [PATCH 01/10] Fixed #38 --- .../StdCyclomaticComplexityRule.java | 18 ++++++++++++++++++ .../complexity/xml/StdCyclomaticComplexity.xml | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java index a1cbcc4611..c7a6d0383d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/StdCyclomaticComplexityRule.java @@ -16,6 +16,7 @@ import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.ast.Node; @@ -96,6 +97,23 @@ public class StdCyclomaticComplexityRule extends AbstractApexRule { } return data; } + + @Override + public Object visit(ASTUserTrigger node, Object data) { + reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); + showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); + showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); + entryStack.push(new Entry(node)); + super.visit(node, data); + if (showClassesComplexity) { + Entry classEntry = entryStack.pop(); + if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { + addViolation(data, node, new String[] { "class", node.getImage(), + classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')' }); + } + } + return data; + } @Override public Object visit(ASTUserInterface node, Object data) { diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/complexity/xml/StdCyclomaticComplexity.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/complexity/xml/StdCyclomaticComplexity.xml index 525c7ddd6b..c0c974f257 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/complexity/xml/StdCyclomaticComplexity.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/complexity/xml/StdCyclomaticComplexity.xml @@ -59,6 +59,17 @@ public class Foo { ]]> + + Simple trigger + 1 + 2 + + + Simple enum 1 From b4a0e0780618be728f1c8f55c04f0f5bcb2feddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20So=CC=88semann?= Date: Tue, 17 May 2016 16:55:16 +0200 Subject: [PATCH 02/10] Remove line breaks and multi-spaces before passing rule violation description to JSON --- .../sourceforge/pmd/renderers/CodeClimateRenderer.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index 5e65c1fba8..1c9410ae5e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -58,7 +58,7 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { CodeClimateIssue issue = new CodeClimateIssue(); issue.check_name = rule.getName(); - issue.description = rv.getDescription(); + issue.description = getCleanedDescription(rv); issue.content = new CodeClimateIssue.Content(rule.getDescription()); issue.location = getLocation(rv); @@ -107,4 +107,11 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { rv.getEndLine()); return result; } + + private String getCleanedDescription(RuleViolation rv) { + String result = rv.getDescription().trim(); + result = result.replaceAll("\\s+", " "); + result = result.replaceAll("\\s*[\\r\\n]+\\s*", ""); + return result; + } } From 2daa7e7773671bebc90ea1abdbfbfc67a2e59cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20So=CC=88semann?= Date: Tue, 17 May 2016 17:26:47 +0200 Subject: [PATCH 03/10] Added rule information as JSON Body readup --- .../pmd/renderers/CodeClimateRenderer.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index 1c9410ae5e..9b0c00c82f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -10,6 +10,7 @@ import static net.sourceforge.pmd.renderers.CodeClimateRule.CODECLIMATE_REMEDIAT import java.io.IOException; import java.io.Writer; import java.util.Iterator; +import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -58,8 +59,8 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { CodeClimateIssue issue = new CodeClimateIssue(); issue.check_name = rule.getName(); - issue.description = getCleanedDescription(rv); - issue.content = new CodeClimateIssue.Content(rule.getDescription()); + issue.description = cleaned(rv.getDescription()); + issue.content = getContent(rv); issue.location = getLocation(rv); switch(rule.getPriority()) { @@ -108,10 +109,28 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { return result; } - private String getCleanedDescription(RuleViolation rv) { - String result = rv.getDescription().trim(); + private String cleaned(String original) { + String result = original.trim(); result = result.replaceAll("\\s+", " "); result = result.replaceAll("\\s*[\\r\\n]+\\s*", ""); + result = result.replaceAll("'", "`"); return result; } + + private CodeClimateIssue.Content getContent(RuleViolation rv) { + String body = "### Description /n/n" + cleaned( rv.getRule().getDescription() ); + + List examples = rv.getRule().getExamples(); + + if(!examples.isEmpty()) { + body += "\n" + + "### Example\n"; + + for(String snippet : examples) { + body += "\n" +"```" + snippet + "```"; + } + } + + return new CodeClimateIssue.Content(body); + } } From cf61dcc6441e66cb6a4853735e24ee2f22275cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20S=C3=B6semann?= Date: Tue, 17 May 2016 22:17:28 +0200 Subject: [PATCH 04/10] Renderer test --- .../sourceforge/pmd/renderers/CodeClimateRendererTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index 48bea7a7df..bd3eaea679 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -14,7 +14,7 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @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\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } @Override @@ -24,8 +24,8 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @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\",\"remediation_points\":50000}" + "\u0000" + 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\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } public static junit.framework.Test suite() { From 2c023408ed46f1bccac18f4957e72e8148822f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20S=C3=B6semann?= Date: Wed, 18 May 2016 21:17:31 +0200 Subject: [PATCH 05/10] Solved Markdown with line breaks inside of JSON problem --- .../pmd/renderers/CodeClimateRenderer.java | 30 +++++++++++-------- .../renderers/CodeClimateRendererTest.java | 6 ++-- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index 9b0c00c82f..d9f900a3a6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -10,12 +10,12 @@ import static net.sourceforge.pmd.renderers.CodeClimateRule.CODECLIMATE_REMEDIAT import java.io.IOException; import java.io.Writer; import java.util.Iterator; -import java.util.List; import org.apache.commons.lang3.StringUtils; import com.google.gson.Gson; +import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleViolation; @@ -24,10 +24,10 @@ import net.sourceforge.pmd.RuleViolation; */ public class CodeClimateRenderer extends AbstractIncrementingRenderer { public static final String NAME = "codeclimate"; + public static final String BODY_PLACEHOLDER = "REPLACE_THIS_WITH_MARKDOWN"; public static final int REMEDIATION_POINTS_DEFAULT = 50000; public static final String[] CODECLIMATE_DEFAULT_CATEGORIES = new String[]{ "Style" }; - protected static final String EOL = System.getProperty("line.separator", "\n"); // Note: required by https://github.com/codeclimate/spec/blob/master/SPEC.md protected static final String NULL_CHARACTER = "\u0000"; @@ -45,7 +45,9 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { while (violations.hasNext()) { RuleViolation rv = violations.next(); - writer.write(gson.toJson(asIssue(rv)) + NULL_CHARACTER + EOL); + String json = gson.toJson(asIssue(rv)); + json = json.replaceAll(BODY_PLACEHOLDER, getBody(rv)); + writer.write(json + NULL_CHARACTER + PMD.EOL); } } @@ -60,7 +62,7 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { CodeClimateIssue issue = new CodeClimateIssue(); issue.check_name = rule.getName(); issue.description = cleaned(rv.getDescription()); - issue.content = getContent(rv); + issue.content = new CodeClimateIssue.Content(BODY_PLACEHOLDER); issue.location = getLocation(rv); switch(rule.getPriority()) { @@ -117,20 +119,22 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { return result; } - private CodeClimateIssue.Content getContent(RuleViolation rv) { - String body = "### Description /n/n" + cleaned( rv.getRule().getDescription() ); + private String getBody(RuleViolation rv) { + Rule rule = rv.getRule(); - List examples = rv.getRule().getExamples(); + String result = "### Description" + PMD.EOL + + cleaned( rule.getDescription() ); - if(!examples.isEmpty()) { - body += "\n" + - "### Example\n"; + if(!rule.getExamples().isEmpty()) { + result += PMD.EOL + "### Example" + PMD.EOL; - for(String snippet : examples) { - body += "\n" +"```" + snippet + "```"; + for(String snippet : rule.getExamples()) { + result += "```java " + PMD.EOL + + snippet + PMD.EOL + + "``` "; } } - return new CodeClimateIssue.Content(body); + return result; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index bd3eaea679..b3b8c36fe7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -14,7 +14,7 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpected() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } @Override @@ -24,8 +24,8 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpectedMultiple() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + - "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description /n/ndesc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } public static junit.framework.Test suite() { From 4c0ce89afd918f3c09a78b8d6e54a3c8af183103 Mon Sep 17 00:00:00 2001 From: David Renz Date: Thu, 19 May 2016 14:12:22 +0200 Subject: [PATCH 06/10] Improved Markdown output #40 --- .../pmd/renderers/CodeClimateRenderer.java | 70 +++++++++++++------ .../renderers/CodeClimateRendererTest.java | 6 +- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index d9f900a3a6..482f321ee9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -9,6 +9,7 @@ import static net.sourceforge.pmd.renderers.CodeClimateRule.CODECLIMATE_REMEDIAT import java.io.IOException; import java.io.Writer; +import java.util.Arrays; import java.util.Iterator; import org.apache.commons.lang3.StringUtils; @@ -16,6 +17,7 @@ import org.apache.commons.lang3.StringUtils; import com.google.gson.Gson; import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PropertyDescriptor; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleViolation; @@ -79,22 +81,9 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { break; } - issue.remediation_points = REMEDIATION_POINTS_DEFAULT; - if(rule.hasDescriptor(CODECLIMATE_REMEDIATION_MULTIPLIER)) { - issue.remediation_points *= rule.getProperty(CODECLIMATE_REMEDIATION_MULTIPLIER); - } + issue.remediation_points = getRemediationPoints(rule); + issue.categories = getCategories(rule); - if(rule.hasDescriptor(CODECLIMATE_CATEGORIES)) { - Object[] categories = rule.getProperty(CODECLIMATE_CATEGORIES); - issue.categories = new String[categories.length]; - for (int i = 0; i < categories.length; i++) { - issue.categories[i] = String.valueOf(categories[i]); - } - } - else { - issue.categories = CODECLIMATE_DEFAULT_CATEGORIES; - } - return issue; } @@ -122,19 +111,58 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { private String getBody(RuleViolation rv) { Rule rule = rv.getRule(); - String result = "### Description" + PMD.EOL + - cleaned( rule.getDescription() ); + String result = "## " + rule.getName() + PMD.EOL + PMD.EOL + + "Since: PMD " + rule.getSince() + PMD.EOL + PMD.EOL + + "Priority: " + rule.getPriority() + PMD.EOL + PMD.EOL + + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): " + Arrays.toString(getCategories(rule)).replaceAll("[\\[\\]]","") + PMD.EOL + PMD.EOL + + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): " + getRemediationPoints(rule) + PMD.EOL + PMD.EOL + + cleaned(rule.getDescription()); if(!rule.getExamples().isEmpty()) { - result += PMD.EOL + "### Example" + PMD.EOL; + result += PMD.EOL + PMD.EOL + "Example(s):" + PMD.EOL + PMD.EOL; for(String snippet : rule.getExamples()) { - result += "```java " + PMD.EOL + - snippet + PMD.EOL + - "``` "; + result += "```java " + PMD.EOL + snippet + PMD.EOL + "``` "; + } + } + + if(!rule.getPropertyDescriptors().isEmpty()) { + result += PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL; + result += "Name | Default Value | Description" + PMD.EOL; + result += "--- | --- | ---" + PMD.EOL; + + for(PropertyDescriptor property : rule.getPropertyDescriptors()) { + result += property.name() + " | " + property.defaultValue() + " | " + property.description() + PMD.EOL; } } return result; } + + private int getRemediationPoints(Rule rule) { + int remediation_points = REMEDIATION_POINTS_DEFAULT; + + if(rule.hasDescriptor(CODECLIMATE_REMEDIATION_MULTIPLIER)) { + remediation_points *= rule.getProperty(CODECLIMATE_REMEDIATION_MULTIPLIER); + } + + return remediation_points; + } + + private String[] getCategories(Rule rule) { + String[] result; + + if(rule.hasDescriptor(CODECLIMATE_CATEGORIES)) { + Object[] categories = rule.getProperty(CODECLIMATE_CATEGORIES); + result = new String[categories.length]; + for (int i = 0; i < categories.length; i++) { + result[i] = String.valueOf(categories[i]); + } + } + else { + result = CODECLIMATE_DEFAULT_CATEGORIES; + } + + return result; + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index b3b8c36fe7..26c1e065ab 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -14,7 +14,7 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpected() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } @Override @@ -24,8 +24,8 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpectedMultiple() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + - "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"### Description" + PMD.EOL + "desc\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } public static junit.framework.Test suite() { From 0cb79873889c405848943a508b457eeebebef793 Mon Sep 17 00:00:00 2001 From: David Renz Date: Fri, 20 May 2016 12:46:06 +0200 Subject: [PATCH 07/10] Fixed #40 --- .../pmd/renderers/CodeClimateRenderer.java | 36 ++++++++++++------- .../renderers/CodeClimateRendererTest.java | 6 ++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java index 482f321ee9..1feac29a4c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/CodeClimateRenderer.java @@ -15,6 +15,7 @@ import java.util.Iterator; import org.apache.commons.lang3.StringUtils; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PropertyDescriptor; @@ -43,12 +44,12 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { @Override public void renderFileViolations(Iterator violations) throws IOException { Writer writer = getWriter(); - Gson gson = new Gson(); + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); while (violations.hasNext()) { RuleViolation rv = violations.next(); String json = gson.toJson(asIssue(rv)); - json = json.replaceAll(BODY_PLACEHOLDER, getBody(rv)); + json = json.replace(BODY_PLACEHOLDER, getBody(rv)); writer.write(json + NULL_CHARACTER + PMD.EOL); } } @@ -111,28 +112,37 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer { private String getBody(RuleViolation rv) { Rule rule = rv.getRule(); - String result = "## " + rule.getName() + PMD.EOL + PMD.EOL + - "Since: PMD " + rule.getSince() + PMD.EOL + PMD.EOL + - "Priority: " + rule.getPriority() + PMD.EOL + PMD.EOL + - "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): " + Arrays.toString(getCategories(rule)).replaceAll("[\\[\\]]","") + PMD.EOL + PMD.EOL + - "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): " + getRemediationPoints(rule) + PMD.EOL + PMD.EOL + + String result = "## " + rule.getName() + "\\n\\n" + + "Since: PMD " + rule.getSince() + "\\n\\n" + + "Priority: " + rule.getPriority() + "\\n\\n" + + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): " + Arrays.toString(getCategories(rule)).replaceAll("[\\[\\]]","") + "\\n\\n" + + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): " + getRemediationPoints(rule) + "\\n\\n" + cleaned(rule.getDescription()); if(!rule.getExamples().isEmpty()) { - result += PMD.EOL + PMD.EOL + "Example(s):" + PMD.EOL + PMD.EOL; + result += "\\n\\n### Example:\\n\\n"; for(String snippet : rule.getExamples()) { - result += "```java " + PMD.EOL + snippet + PMD.EOL + "``` "; + snippet = snippet.replaceAll("\\n", "\\\\n"); + snippet = snippet.replaceAll("\\t", "\\\\t"); + result += "```java\\n" + snippet + "\\n``` "; } } if(!rule.getPropertyDescriptors().isEmpty()) { - result += PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL; - result += "Name | Default Value | Description" + PMD.EOL; - result += "--- | --- | ---" + PMD.EOL; + result += "\\n\\n### [PMD properties](http://pmd.github.io/pmd-5.1.3/pmd-developer.html)\\n\\n"; + result += "Name | Default Value | Description\\n"; + result += "--- | --- | ---\\n"; for(PropertyDescriptor property : rule.getPropertyDescriptors()) { - result += property.name() + " | " + property.defaultValue() + " | " + property.description() + PMD.EOL; + String defaultValue; + try { + defaultValue = Arrays.toString((String[])property.defaultValue()).replaceAll("[\\[\\]]",""); + } + catch(Exception ignore) { + defaultValue = property.defaultValue().toString(); + } + result += property.name() + " | " + defaultValue + " | " + property.description() + "\\n"; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index 26c1e065ab..e30a541496 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -14,7 +14,7 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpected() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style\\n\\n[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000\\n\\ndesc\\n\\n### [PMD properties](http://pmd.github.io/pmd-5.1.3/pmd-developer.html)\\n\\nName | Default Value | Description\\n--- | --- | ---\\nviolationSuppressRegex | null | Suppress violations with messages matching a regular expression\\nviolationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression.\\n\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } @Override @@ -24,8 +24,8 @@ public class CodeClimateRendererTest extends AbstractRendererTst { @Override public String getExpectedMultiple() { - return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + - "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo" + PMD.EOL + PMD.EOL + "Since: PMD null" + PMD.EOL + PMD.EOL + "Priority: Low" + PMD.EOL + PMD.EOL + "[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style" + PMD.EOL + PMD.EOL + "[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000" + PMD.EOL + PMD.EOL + "desc" + PMD.EOL + PMD.EOL + "This rule has the following properties:" + PMD.EOL + PMD.EOL + "Name | Default Value | Description" + PMD.EOL + "--- | --- | ---" + PMD.EOL + "violationSuppressRegex | null | Suppress violations with messages matching a regular expression" + PMD.EOL + "violationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression." + PMD.EOL + "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; + return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style\\n\\n[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000\\n\\ndesc\\n\\n### [PMD properties](http://pmd.github.io/pmd-5.1.3/pmd-developer.html)\\n\\nName | Default Value | Description\\n--- | --- | ---\\nviolationSuppressRegex | null | Suppress violations with messages matching a regular expression\\nviolationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression.\\n\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL + + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\",\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n[Categories](https://github.com/codeclimate/spec/blob/master/SPEC.md#categories): Style\\n\\n[Remediation Points](https://github.com/codeclimate/spec/blob/master/SPEC.md#remediation-points): 50000\\n\\ndesc\\n\\n### [PMD properties](http://pmd.github.io/pmd-5.1.3/pmd-developer.html)\\n\\nName | Default Value | Description\\n--- | --- | ---\\nviolationSuppressRegex | null | Suppress violations with messages matching a regular expression\\nviolationSuppressXPath | null | Suppress violations on nodes which match a given relative XPath expression.\\n\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"n/a\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}" + "\u0000" + PMD.EOL; } public static junit.framework.Test suite() { From d8fd2450835e10709a5df0ec62d3f890ae10e10f Mon Sep 17 00:00:00 2001 From: David Renz Date: Fri, 20 May 2016 15:30:33 +0200 Subject: [PATCH 08/10] Update README.md --- README.md | 59 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index d441cc9f4a..c6166fc52b 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,3 @@ -# PMD +# PMD - Salesfoce.com Apex -[![Build Status](https://travis-ci.org/pmd/pmd.svg?branch=master)](https://travis-ci.org/pmd/pmd) - -## About - -PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, -unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex, XML, XSL. -Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code in -Java, C, C++, C#, PHP, Ruby, Fortran, JavaScript, Salesforce.com Apex, Perl, Swift. - -## Source - -Our latest source of PMD can be found on [GitHub]. Fork us! - -### How to build PMD? - -You'll need to have a `~/.m2/toolchains.xml` file setup with jdk 1.6 (for pmd 5.3.x), jdk 1.7 (for pmd 5.4.x and pmd 5.5.x) -and jdk 1.8 (for some features in pmd 5.5.x). See [maven toolchains](https://maven.apache.org/guides/mini/guide-using-toolchains.html). -A example file can be found here: [example-toolchains.xml](https://github.com/pmd/pmd/blob/master/example-toolchains.xml). - -Use maven in the top-level directory: - - mvn clean package - -This will create the zip files in the directory `pmd-dist/target`: - - cd pmd-dist/target - ls *.zip - -That's all ! - -### How to build the documentation (maven site)? - -Building the maven site is done with the following commands: - - mvn clean install -DskipTests=true - mvn install site site:stage -Psite - -You'll find the built site in the directory `target/staging/`. - -### Bug Reports - -We are using Sourceforge for bug tracking. Please file your bugs at . - -### Pull Requests - -Pull requests are always welcome: - - -## News and Website - -More information can be found on our [Website] and on [SourceForge]. - - -[GitHub]: https://github.com/pmd/pmd -[Website]: https://pmd.github.io -[SourceForge]: https://sourceforge.net/projects/pmd/ +[PMD] (https://github.com/pmd/pmd) fork to develop and maintain a language module for [Salesforce.com Apex] (https://developer.salesforce.com/page/Apex) From 52fd661785d9e06d774badb7307bcd5d47862ed3 Mon Sep 17 00:00:00 2001 From: David Renz Date: Fri, 20 May 2016 15:30:54 +0200 Subject: [PATCH 09/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6166fc52b..4d877d32dd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# PMD - Salesfoce.com Apex +# PMD - Salesforce.com Apex [PMD] (https://github.com/pmd/pmd) fork to develop and maintain a language module for [Salesforce.com Apex] (https://developer.salesforce.com/page/Apex) From 169c7ada1ae35cf7097b6f7a977bd4bed47b4579 Mon Sep 17 00:00:00 2001 From: David Renz Date: Fri, 20 May 2016 15:34:06 +0200 Subject: [PATCH 10/10] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4d877d32dd..cc66c72c6b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # PMD - Salesforce.com Apex [PMD] (https://github.com/pmd/pmd) fork to develop and maintain a language module for [Salesforce.com Apex] (https://developer.salesforce.com/page/Apex) + +### Code Climate Engine +There is also a Code Climate Engine based on this PMD module for Salesforce.com Apex. You can find more information about the engine on our [Code Climate Apex Engine GitHub repository] (https://github.com/Up2Go/codeclimate-apex).