From d23d44c3080b3ef78a1c83b19111e9ab5a80e3d1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 5 Apr 2020 20:13:53 +0200 Subject: [PATCH 1/6] [core] Add JsonRenderer Fixes #1286 --- docs/pages/pmd/userdocs/cli_reference.md | 2 + .../pmd/renderers/JsonRenderer.java | 151 ++++++++++++++++++ .../pmd/renderers/RendererFactory.java | 1 + .../pmd/renderers/JsonRendererTest.java | 93 +++++++++++ .../sourceforge/pmd/renderers/json/empty.json | 8 + .../json/expected-configurationerror.json | 14 ++ .../pmd/renderers/json/expected-multiple.json | 34 ++++ .../expected-processingerror-no-message.json | 14 ++ .../json/expected-processingerror.json | 14 ++ .../renderers/json/expected-suppressed.json | 26 +++ .../pmd/renderers/json/expected.json | 24 +++ 11 files changed, 381 insertions(+) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json create mode 100644 pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index ca45b101de..42e0964a63 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -234,6 +234,8 @@ which can be specified with the `-property` option on the command-line. * sourcePath: * fileName: +* **json**: JSON format. + * **summaryhtml**: Summary HTML format. Properties: diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java new file mode 100644 index 0000000000..3a92c2a4fd --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java @@ -0,0 +1,151 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.renderers; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; + +import org.apache.commons.lang3.StringUtils; + +import net.sourceforge.pmd.PMDVersion; +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.RuleViolation; + +import com.google.gson.stream.JsonWriter; + +public class JsonRenderer extends AbstractIncrementingRenderer { + public static final String NAME = "json"; + + private JsonWriter jsonWriter; + + public JsonRenderer() { + super(NAME, "JSON format."); + } + + @Override + public String defaultFileExtension() { + return "json"; + } + + @Override + public void start() throws IOException { + jsonWriter = new JsonWriter(writer); + jsonWriter.setHtmlSafe(true); + jsonWriter.setIndent(" "); + + jsonWriter.beginObject(); + jsonWriter.name("version").value(PMDVersion.VERSION); + jsonWriter.name("timestamp").value(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").format(new Date())); + jsonWriter.name("files").beginArray(); + } + + @Override + public void renderFileViolations(Iterator violations) throws IOException { + String filename = null; + + while (violations.hasNext()) { + RuleViolation rv = violations.next(); + String nextFilename = determineFileName(rv.getFilename()); + if (!nextFilename.equals(filename)) { + // New File + if (filename != null) { + // Not first file ? + jsonWriter.endArray(); // violations + jsonWriter.endObject(); // file object + } + filename = nextFilename; + jsonWriter.beginObject(); + jsonWriter.name("filename").value(filename); + jsonWriter.name("violations").beginArray(); + } + renderSingleViolation(rv); + } + + jsonWriter.endArray(); // violations + jsonWriter.endObject(); // file object + } + + private void renderSingleViolation(RuleViolation rv) throws IOException { + renderSingleViolation(rv, null, null); + } + + private void renderSingleViolation(RuleViolation rv, String suppressionType, String userMsg) throws IOException { + jsonWriter.beginObject(); + jsonWriter.name("beginline").value(rv.getBeginLine()); + jsonWriter.name("begincolumn").value(rv.getBeginColumn()); + jsonWriter.name("endline").value(rv.getEndLine()); + jsonWriter.name("endcolumn").value(rv.getEndColumn()); + jsonWriter.name("description").value(rv.getDescription()); + jsonWriter.name("rule").value(rv.getRule().getName()); + jsonWriter.name("ruleset").value(rv.getRule().getRuleSetName()); + jsonWriter.name("priority").value(rv.getRule().getPriority().getPriority()); + if (StringUtils.isNotBlank(rv.getRule().getExternalInfoUrl())) { + jsonWriter.name("externalInfoUrl").value(rv.getRule().getExternalInfoUrl()); + } + if (StringUtils.isNotBlank(suppressionType)) { + jsonWriter.name("suppressiontype").value(suppressionType); + } + if (StringUtils.isNotBlank(userMsg)) { + jsonWriter.name("usermsg").value(userMsg); + } + jsonWriter.endObject(); + } + + @Override + public void end() throws IOException { + jsonWriter.endArray(); // files + + jsonWriter.name("suppressedViolations").beginArray(); + String filename = null; + if (!this.suppressed.isEmpty()) { + for (Report.SuppressedViolation s : this.suppressed) { + RuleViolation rv = s.getRuleViolation(); + String nextFilename = determineFileName(rv.getFilename()); + if (!nextFilename.equals(filename)) { + // New File + if (filename != null) { + // Not first file ? + jsonWriter.endArray(); // violations + jsonWriter.endObject(); // file object + } + filename = nextFilename; + jsonWriter.beginObject(); + jsonWriter.name("filename").value(filename); + jsonWriter.name("violations").beginArray(); + } + renderSingleViolation(rv, s.suppressedByNOPMD() ? "nopmd" : "annotation", s.getUserMessage()); + } + jsonWriter.endArray(); // violations + jsonWriter.endObject(); // file object + } + jsonWriter.endArray(); + + jsonWriter.name("processingErrors").beginArray(); + for (Report.ProcessingError error : this.errors) { + jsonWriter.beginObject(); + jsonWriter.name("filename").value(error.getFile()); + jsonWriter.name("message").value(error.getMsg()); + jsonWriter.name("detail").value(error.getDetail()); + jsonWriter.endObject(); + } + jsonWriter.endArray(); + + jsonWriter.name("configurationErrors").beginArray(); + for (Report.ConfigurationError error : this.configErrors) { + jsonWriter.beginObject(); + jsonWriter.name("rule").value(error.rule().getName()); + jsonWriter.name("ruleset").value(error.rule().getRuleSetName()); + jsonWriter.name("message").value(error.issue()); + jsonWriter.endObject(); + } + jsonWriter.endArray(); + + jsonWriter.endObject(); + jsonWriter.flush(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java index 8c918c2093..18abb8a29d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java @@ -43,6 +43,7 @@ public final class RendererFactory { map.put(SummaryHTMLRenderer.NAME, SummaryHTMLRenderer.class); map.put(VBHTMLRenderer.NAME, VBHTMLRenderer.class); map.put(EmptyRenderer.NAME, EmptyRenderer.class); + map.put(JsonRenderer.NAME, JsonRenderer.class); REPORT_FORMAT_TO_RENDERER = Collections.unmodifiableMap(map); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java new file mode 100644 index 0000000000..a712995c1c --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java @@ -0,0 +1,93 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.renderers; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.Report.ConfigurationError; +import net.sourceforge.pmd.Report.ProcessingError; +import net.sourceforge.pmd.ReportTest; + +public class JsonRendererTest extends AbstractRendererTest { + + @Override + public Renderer getRenderer() { + return new JsonRenderer(); + } + + @Override + public String getExpected() { + return readFile("expected.json"); + } + + @Override + public String getExpectedEmpty() { + return readFile("empty.json"); + } + + @Override + public String getExpectedMultiple() { + return readFile("expected-multiple.json"); + } + + @Override + public String getExpectedError(ProcessingError error) { + String expected = readFile("expected-processingerror.json"); + expected = expected.replace("###REPLACE_ME###", error.getDetail() + .replaceAll("\n", "\\\\n") + .replaceAll("\t", "\\\\t")); + return expected; + } + + @Override + public String getExpectedError(ConfigurationError error) { + return readFile("expected-configurationerror.json"); + } + + @Override + public String getExpectedErrorWithoutMessage(ProcessingError error) { + String expected = readFile("expected-processingerror-no-message.json"); + expected = expected.replace("###REPLACE_ME###", error.getDetail() + .replaceAll("\n", "\\\\n") + .replaceAll("\t", "\\\\t")); + return expected; + } + + private String readFile(String name) { + try (InputStream in = JsonRendererTest.class.getResourceAsStream("json/" + name)) { + return IOUtils.toString(in, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public String filter(String expected) { + String result = expected.replaceAll("\"timestamp\":\\s*\"[^\"]+\"", "\"timestamp\": \"--replaced--\""); + return result; + } + + @Test + public void suppressedViolations() throws IOException { + Report rep = new Report(); + Map suppressedLines = new HashMap<>(); + suppressedLines.put(1, "test"); + rep.suppress(suppressedLines); + rep.addRuleViolation(newRuleViolation(1)); + String actual = ReportTest.render(getRenderer(), rep); + String expected = readFile("expected-suppressed.json"); + Assert.assertEquals(filter(expected), filter(actual)); + } +} diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json new file mode 100644 index 0000000000..eb16a2fe2b --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json @@ -0,0 +1,8 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [], + "suppressedViolations": [], + "processingErrors": [], + "configurationErrors": [] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json new file mode 100644 index 0000000000..9e0d5cb850 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json @@ -0,0 +1,14 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [], + "suppressedViolations": [], + "processingErrors": [], + "configurationErrors": [ + { + "rule": "Foo", + "ruleset": "RuleSet", + "message": "a configuration error" + } + ] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json new file mode 100644 index 0000000000..d0a362f137 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json @@ -0,0 +1,34 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [ + { + "filename": "notAvailable.ext", + "violations": [ + { + "beginline": 1, + "begincolumn": 1, + "endline": 1, + "endcolumn": 1, + "description": "blah", + "rule": "Foo", + "ruleset": "RuleSet", + "priority": 5 + }, + { + "beginline": 1, + "begincolumn": 1, + "endline": 1, + "endcolumn": 2, + "description": "blah", + "rule": "Foo", + "ruleset": "RuleSet", + "priority": 5 + } + ] + } + ], + "suppressedViolations": [], + "processingErrors": [], + "configurationErrors": [] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json new file mode 100644 index 0000000000..8a8573717e --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json @@ -0,0 +1,14 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [], + "suppressedViolations": [], + "processingErrors": [ + { + "filename": "file", + "message": "NullPointerException: null", + "detail": "###REPLACE_ME###" + } + ], + "configurationErrors": [] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json new file mode 100644 index 0000000000..ff8534f54e --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json @@ -0,0 +1,14 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [], + "suppressedViolations": [], + "processingErrors": [ + { + "filename": "file", + "message": "RuntimeException: Error", + "detail": "###REPLACE_ME###" + } + ], + "configurationErrors": [] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json new file mode 100644 index 0000000000..799a648406 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json @@ -0,0 +1,26 @@ +{ + "version": "unknown", + "timestamp": "2020-04-05T19:42:21.800+02:00", + "files": [], + "suppressedViolations": [ + { + "filename": "notAvailable.ext", + "violations": [ + { + "beginline": 1, + "begincolumn": 1, + "endline": 1, + "endcolumn": 1, + "description": "blah", + "rule": "Foo", + "ruleset": "RuleSet", + "priority": 5, + "suppressiontype": "nopmd", + "usermsg": "test" + } + ] + } + ], + "processingErrors": [], + "configurationErrors": [] +} \ No newline at end of file diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json new file mode 100644 index 0000000000..d4a4d778b6 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json @@ -0,0 +1,24 @@ +{ + "version": "unknown", + "timestamp": "--replaced--", + "files": [ + { + "filename": "notAvailable.ext", + "violations": [ + { + "beginline": 1, + "begincolumn": 1, + "endline": 1, + "endcolumn": 1, + "description": "blah", + "rule": "Foo", + "ruleset": "RuleSet", + "priority": 5 + } + ] + } + ], + "suppressedViolations": [], + "processingErrors": [], + "configurationErrors": [] +} \ No newline at end of file From fc88b79b92aaf829fcc8b687dfa304955e8ef619 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 6 Apr 2020 19:59:54 +0200 Subject: [PATCH 2/6] Fix build under windows --- .../net/sourceforge/pmd/renderers/JsonRendererTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java index a712995c1c..2a1f08fd3c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java @@ -46,6 +46,7 @@ public class JsonRendererTest extends AbstractRendererTest { public String getExpectedError(ProcessingError error) { String expected = readFile("expected-processingerror.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() + .replaceAll("\r", "\\\\r") .replaceAll("\n", "\\\\n") .replaceAll("\t", "\\\\t")); return expected; @@ -60,6 +61,7 @@ public class JsonRendererTest extends AbstractRendererTest { public String getExpectedErrorWithoutMessage(ProcessingError error) { String expected = readFile("expected-processingerror-no-message.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() + .replaceAll("\r", "\\\\r") .replaceAll("\n", "\\\\n") .replaceAll("\t", "\\\\t")); return expected; @@ -75,7 +77,9 @@ public class JsonRendererTest extends AbstractRendererTest { @Override public String filter(String expected) { - String result = expected.replaceAll("\"timestamp\":\\s*\"[^\"]+\"", "\"timestamp\": \"--replaced--\""); + String result = expected + .replaceAll("\"timestamp\":\\s*\"[^\"]+\"", "\"timestamp\": \"--replaced--\"") + .replaceAll("\r\n", "\n"); // make the test run on Windows, too return result; } From 5abaa7489a2812f2433a7c65ec7fc37e98b0faee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Apr 2020 09:14:04 +0200 Subject: [PATCH 3/6] Update release notes (add todo) Closes #1286, refs #2404, #2413 --- docs/pages/release_notes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 1c86a1b374..a094b704af 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -30,6 +30,12 @@ not change the result of your rules*, if it does, please report a bug at https:/ Note that XPath 1.0 support, the default XPath version, is deprecated since PMD 6.22.0. **We highly recommend that you upgrade your rules to XPath 2.0**. Please refer to the [migration guide](https://pmd.github.io/latest/pmd_userdocs_extending_writing_xpath_rules.html#migrating-from-10-to-20). +#### New JSON renderer + +PMD now supports a JSON renderer (use it with `-f json` on the CLI). + +TODO link to doc when the doc PR for renderers is updated & merged + #### New Rules * The new Apex rule {% rule "apex/codestyle/FieldDeclarationsShouldBeAtStart" %} (`apex-codestyle`) @@ -46,6 +52,7 @@ Note that XPath 1.0 support, the default XPath version, is deprecated since PMD * [#2210](https://github.com/pmd/pmd/issues/2210): \[apex] ApexCRUDViolation: Support WITH SECURITY_ENFORCED * [#2399](https://github.com/pmd/pmd/issues/2399): \[apex] ApexCRUDViolation: false positive with security enforced with line break * core + * [#1286](https://github.com/pmd/pmd/issues/1286): \[core] Export Supporting JSON Format * [#2019](https://github.com/pmd/pmd/issues/2019): \[core] Insufficient deprecation warnings for XPath attributes * [#2355](https://github.com/pmd/pmd/issues/2355): \[doc] Improve documentation about incremental analysis * [#2356](https://github.com/pmd/pmd/issues/2356): \[doc] Add missing doc about pmd.github.io From 57ae752756f61b7c607e0d3a3c60e77676e91cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Apr 2020 09:26:55 +0200 Subject: [PATCH 4/6] Add separate format version --- .../java/net/sourceforge/pmd/renderers/JsonRenderer.java | 9 ++++++++- .../net/sourceforge/pmd/renderers/json/empty.json | 3 ++- .../pmd/renderers/json/expected-configurationerror.json | 3 ++- .../pmd/renderers/json/expected-multiple.json | 3 ++- .../json/expected-processingerror-no-message.json | 3 ++- .../pmd/renderers/json/expected-processingerror.json | 3 ++- .../pmd/renderers/json/expected-suppressed.json | 3 ++- .../net/sourceforge/pmd/renderers/json/expected.json | 3 ++- 8 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java index 3a92c2a4fd..a6a6f4afcd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/JsonRenderer.java @@ -21,6 +21,12 @@ import com.google.gson.stream.JsonWriter; public class JsonRenderer extends AbstractIncrementingRenderer { public static final String NAME = "json"; + // TODO do we make this public? It would make it possible to write eg + // if (jsonObject.getInt("formatVersion") > JsonRenderer.FORMAT_VERSION) + // /* handle unsupported version */ + // because the JsonRenderer.FORMAT_VERSION would be hardcoded by the compiler + private static final int FORMAT_VERSION = 0; + private JsonWriter jsonWriter; public JsonRenderer() { @@ -39,7 +45,8 @@ public class JsonRenderer extends AbstractIncrementingRenderer { jsonWriter.setIndent(" "); jsonWriter.beginObject(); - jsonWriter.name("version").value(PMDVersion.VERSION); + jsonWriter.name("formatVersion").value(FORMAT_VERSION); + jsonWriter.name("pmdVersion").value(PMDVersion.VERSION); jsonWriter.name("timestamp").value(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").format(new Date())); jsonWriter.name("files").beginArray(); } diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json index eb16a2fe2b..28db728358 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/empty.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [], "suppressedViolations": [], diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json index 9e0d5cb850..a127b5bd62 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-configurationerror.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [], "suppressedViolations": [], diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json index d0a362f137..15717aed32 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-multiple.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [ { diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json index 8a8573717e..0435f39fff 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror-no-message.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [], "suppressedViolations": [], diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json index ff8534f54e..48dbbc6d17 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-processingerror.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [], "suppressedViolations": [], diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json index 799a648406..e2686a2af2 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected-suppressed.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "2020-04-05T19:42:21.800+02:00", "files": [], "suppressedViolations": [ diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json index d4a4d778b6..aaa7ad707e 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/renderers/json/expected.json @@ -1,5 +1,6 @@ { - "version": "unknown", + "formatVersion": 0, + "pmdVersion": "unknown", "timestamp": "--replaced--", "files": [ { From 33fd5d0ba29ee8d801952d9dc00ce2bd6ae6cd6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Apr 2020 10:48:43 +0200 Subject: [PATCH 5/6] Add documentation --- docs/pages/pmd/userdocs/pmd_report_formats.md | 14 +++++++ docs/report-examples/pmd-report-json.json | 39 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/report-examples/pmd-report-json.json diff --git a/docs/pages/pmd/userdocs/pmd_report_formats.md b/docs/pages/pmd/userdocs/pmd_report_formats.md index ff7fd639e7..b28b1fe6cc 100644 --- a/docs/pages/pmd/userdocs/pmd_report_formats.md +++ b/docs/pages/pmd/userdocs/pmd_report_formats.md @@ -128,6 +128,20 @@ This for loop can be replaced by a foreach loop * sourcePath: * fileName: +## json + +JSON format. + +This prints a single JSON object containing some header information, +and then the violations grouped by file. The root object fields are +* `formatVersion`: an integer which will be incremented if we change the serialization format +* `pmdVersion`: the version of PMD that produced the report +* `timestamp`: explicit +* `files`: an array of objects (see the example) + +[Example](report-examples/pmd-report-json.json) + + ## summaryhtml Summary HTML format. diff --git a/docs/report-examples/pmd-report-json.json b/docs/report-examples/pmd-report-json.json new file mode 100644 index 0000000000..fe1f3ce473 --- /dev/null +++ b/docs/report-examples/pmd-report-json.json @@ -0,0 +1,39 @@ +{ + "formatVersion": 0, + "pmdVersion": "6.23.0-SNAPSHOT", + "timestamp": "2020-04-05T20:13:49.698+02:00", + "files": [ + { + "filename": "/home/me/pmd/src/main/java/net/sourceforge/pmd/PMDVersion.java", + "violations": [ + { + "beginline": 16, + "begincolumn": 14, + "endline": 79, + "endcolumn": 1, + "description": "The utility class name \u0027PMDVersion\u0027 doesn\u0027t match \u0027[A-Z][a-zA-Z0-9]+(Utils?|Helper)\u0027", + "rule": "ClassNamingConventions", + "ruleset": "Code Style", + "priority": 1, + "externalInfoUrl": "https://pmd.github.io/pmd/pmd_rules_java_codestyle.html#classnamingconventions" + } + ] + }, + { + "filename": "/home/me/pmd/src/main/java/net/sourceforge/pmd/RuleContext.java", + "violations": [ + { + "beginline": 124, + "begincolumn": 9, + "endline": 125, + "endcolumn": 111, + "description": "Logger calls should be surrounded by log level guards.", + "rule": "GuardLogStatement", + "ruleset": "Best Practices", + "priority": 2, + "externalInfoUrl": "https://pmd.github.io/pmd/pmd_rules_java_bestpractices.html#guardlogstatement" + } + ] + } + ] +} From daf84fb2bcc3f2da6938588c96b5e59ce3222f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Apr 2020 10:51:50 +0200 Subject: [PATCH 6/6] Fix todo in release notes --- docs/pages/release_notes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index d9c768fd63..f4e125cde4 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -33,8 +33,7 @@ Note that XPath 1.0 support, the default XPath version, is deprecated since PMD #### New JSON renderer PMD now supports a JSON renderer (use it with `-f json` on the CLI). - -TODO link to doc when the doc PR for renderers is updated & merged +See [the documentation and example](https://pmd.github.io/latest/pmd_userdocs_report_formats.hmtl#json) #### New Rules