Skip to content

Commit

Permalink
DocFX parser JENKINS-48670
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Dec 21, 2017
1 parent 4d7069f commit 1ca81e0
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 6 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ Changelog of Violations lib.
**Ignoring case when checking for equality**


[d0dd37fb3e50ddc](https://github.com/tomasbjerre/violations-lib/commit/d0dd37fb3e50ddc) Tomas Bjerre *2017-12-21 10:10:07*
[4d7069f628813b6](https://github.com/tomasbjerre/violations-lib/commit/4d7069f628813b6) Tomas Bjerre *2017-12-21 10:12:56*


### Jira JENKINS-48670

**DocFX parser**


[091877506b6e903](https://github.com/tomasbjerre/violations-lib/commit/091877506b6e903) Tomas Bjerre *2017-12-21 12:30:04*


### No issue
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ It supports:
* [_CPPLint_](https://github.com/theandrewdavis/cpplint)
* [_CPPCheck_](http://cppcheck.sourceforge.net/)
* [_CSSLint_](https://github.com/CSSLint/csslint)
* [_DocFX_](http://dotnet.github.io/docfx/)
* [_Findbugs_](http://findbugs.sourceforge.net/)
* [_Flake8_](http://flake8.readthedocs.org/en/latest/)
* [_AnsibleLint_](https://github.com/willthames/ansible-lint) with `-p`
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/se/bjurr/violations/lib/parsers/DocFXParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package se.bjurr.violations.lib.parsers;

import static se.bjurr.violations.lib.model.Violation.violationBuilder;
import static se.bjurr.violations.lib.reports.Parser.DOCFX;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import se.bjurr.violations.lib.model.SEVERITY;
import se.bjurr.violations.lib.model.Violation;
import se.bjurr.violations.lib.util.HTMLUtils;
import se.bjurr.violations.lib.util.JSON2Java;

public class DocFXParser implements ViolationsParser {
private static Logger LOG = Logger.getLogger(DocFXParser.class.getName());

@Override
public List<Violation> parseReportOutput(String reportContent) throws Exception {
final List<Violation> violations = new ArrayList<>();

final String[] lines = reportContent.split("\\r?\\n");
for (final String rawLineToParse : lines) {
@SuppressWarnings("unchecked")
final Map<String, Object> parsedMap =
(Map<String, Object>) JSON2Java.parseJSON(rawLineToParse);
final String message = (String) parsedMap.get("message");
final String messageSeverity = (String) parsedMap.get("message_severity");
final String fileEncoded = (String) parsedMap.get("file");
if (fileEncoded == null) {
LOG.log(Level.FINE, "Ignoring " + rawLineToParse + " because there is not file attribute");
continue;
}
final String file = HTMLUtils.htmlDecode(fileEncoded);
final String code = (String) parsedMap.get("code");
final String lineString = (String) parsedMap.get("line");
Integer lineInt;
if (lineString == null) {
lineInt = 0;
} else {
lineInt = Integer.parseInt(lineString);
}
final String source = (String) parsedMap.get("source");
final SEVERITY severity = getSeverity(messageSeverity);
violations.add(
violationBuilder() //
.setFile(file) //
.setMessage(message) //
.setParser(DOCFX) //
.setRule(code) //
.setSeverity(severity) //
.setStartLine(lineInt) //
.setSpecific("source", source)
.build());
}

return violations;
}

private SEVERITY getSeverity(String messageSeverity) {
if (messageSeverity.equalsIgnoreCase("Error")) {
return SEVERITY.ERROR;
}
if (messageSeverity.equalsIgnoreCase("Warning")) {
return SEVERITY.WARN;
}
return SEVERITY.INFO;
}
}
12 changes: 7 additions & 5 deletions src/main/java/se/bjurr/violations/lib/reports/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import se.bjurr.violations.lib.parsers.CheckStyleParser;
import se.bjurr.violations.lib.parsers.CodeNarcParser;
import se.bjurr.violations.lib.parsers.CppLintParser;
import se.bjurr.violations.lib.parsers.DocFXParser;
import se.bjurr.violations.lib.parsers.FindbugsParser;
import se.bjurr.violations.lib.parsers.Flake8Parser;
import se.bjurr.violations.lib.parsers.FxCopParser;
Expand Down Expand Up @@ -69,7 +70,8 @@ public enum Parser {
SIMIAN(new SimianParser()), //
STYLECOP(new StyleCopParser()), //
XMLLINT(new XMLLintParser()), //
ZPTLINT(new ZPTLintParser());
ZPTLINT(new ZPTLintParser()), //
DOCFX(new DocFXParser());

private static Logger LOG = Logger.getLogger(Parser.class.getSimpleName());
private ViolationsParser violationsParser;
Expand All @@ -79,12 +81,12 @@ private Parser(ViolationsParser violationsParser) {
}

public List<Violation> findViolations(List<File> includedFiles) {
List<Violation> violations = new ArrayList<>();
for (File file : includedFiles) {
final List<Violation> violations = new ArrayList<>();
for (final File file : includedFiles) {
try {
String string = Utils.toString(new FileInputStream(file));
final String string = Utils.toString(new FileInputStream(file));
violations.addAll(violationsParser.parseReportOutput(string));
} catch (Exception e) {
} catch (final Exception e) {
LOG.log(SEVERE, "Error when parsing " + file.getAbsolutePath() + " as " + this.name(), e);
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/se/bjurr/violations/lib/util/HTMLUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package se.bjurr.violations.lib.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class HTMLUtils {
private HTMLUtils() {}

public static String htmlDecode(String input) {
final Pattern p = Pattern.compile("&#(\\d+);");
final Matcher m = p.matcher(input);
final StringBuffer sb = new StringBuffer();
while (m.find()) {
final Integer found = Integer.valueOf(m.group(1));
final String character = String.valueOf((char) found.intValue());
m.appendReplacement(sb, character);
}
m.appendTail(sb);
return sb.toString();
}
}
38 changes: 38 additions & 0 deletions src/main/java/se/bjurr/violations/lib/util/JSON2Java.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package se.bjurr.violations.lib.util;

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicReference;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class JSON2Java {

private static final ScriptEngine jsonParser;

static {
try {
final Path path = Paths.get(JSON2Java.class.getResource("/json2java.js").toURI());
final byte[] initBytes = Files.readAllBytes(path);
final String init = new String(initBytes, Charset.forName("UTF-8"));
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
engine.eval(init);
jsonParser = engine;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}

public static Object parseJSON(String json) {
try {
final String eval = "new java.util.concurrent.atomic.AtomicReference(toJava((" + json + ")))";
final AtomicReference<?> ret = (AtomicReference<?>) jsonParser.eval(eval);
return ret.get();
} catch (final ScriptException e) {
throw new RuntimeException("Invalid json", e);
}
}
}
26 changes: 26 additions & 0 deletions src/main/resources/json2java.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
toJava = function(o) {
return o == null ? null : o.toJava();
};
Object.prototype.toJava = function() {
var m = new java.util.HashMap();
for (var key in this)
if (this.hasOwnProperty(key))
m.put(key, toJava(this[key]));
return m;
};
Array.prototype.toJava = function() {
var l = this.length;
var a = new java.lang.reflect.Array.newInstance(java.lang.Object, l);
for (var i = 0;i < l;i++)
a[i] = toJava(this[i]);
return a;
};
String.prototype.toJava = function() {
return new java.lang.String(this);
};
Boolean.prototype.toJava = function() {
return java.lang.Boolean.valueOf(this);
};
Number.prototype.toJava = function() {
return java.lang.Integer(this);
};
65 changes: 65 additions & 0 deletions src/test/java/se/bjurr/violations/lib/DocFXTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package se.bjurr.violations.lib;

import static org.assertj.core.api.Assertions.assertThat;
import static se.bjurr.violations.lib.TestUtils.getRootFolder;
import static se.bjurr.violations.lib.ViolationsReporterApi.violationsReporterApi;
import static se.bjurr.violations.lib.model.SEVERITY.WARN;
import static se.bjurr.violations.lib.reports.Parser.DOCFX;

import java.util.List;
import org.junit.Test;
import se.bjurr.violations.lib.model.Violation;

public class DocFXTest {

@Test
public void testThatViolationsCanBeParsed() {
final String rootFolder = getRootFolder();

final List<Violation> actual =
violationsReporterApi() //
.withPattern(".*/docfx/.*\\.json$") //
.inFolder(rootFolder) //
.findAll(DOCFX) //
.violations();

assertThat(actual) //
.hasSize(3);

final Violation violation0 = actual.get(0);
assertThat(violation0.getMessage()) //
.isEqualTo("Invalid file link:(~/missing.md#mobiilisovellus).");
assertThat(violation0.getFile()) //
.isEqualTo("sanasto.md");
assertThat(violation0.getSeverity()) //
.isEqualTo(WARN);
assertThat(violation0.getRule().get()) //
.isEqualTo("InvalidFileLink");
assertThat(violation0.getStartLine()) //
.isEqualTo(63);

final Violation violation1 = actual.get(1);
assertThat(violation1.getMessage()) //
.isEqualTo("Invalid file link:(~/mobiilirajapinta/puuttuu.md).");
assertThat(violation1.getFile()) //
.isEqualTo("mobiilirajapinta/json-dateandtime.md");
assertThat(violation1.getSeverity()) //
.isEqualTo(WARN);
assertThat(violation1.getRule().get()) //
.isEqualTo("InvalidFileLink");
assertThat(violation1.getStartLine()) //
.isEqualTo(18);

final Violation violation2 = actual.get(2);
assertThat(violation2.getMessage()) //
.isEqualTo("Invalid file link:(~/mobiilirajapinta/joopajoo.md).");
assertThat(violation2.getFile()) //
.isEqualTo("mobiilirajapinta/json-nimeämiskäytäntö.md");
assertThat(violation2.getSeverity()) //
.isEqualTo(WARN);
assertThat(violation2.getRule().get()) //
.isEqualTo("InvalidFileLink");
assertThat(violation2.getStartLine()) //
.isEqualTo(7);
}
}
16 changes: 16 additions & 0 deletions src/test/resources/docfx/docfx.log.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{"message":"5 plug-in(s) loaded.","date_time":"2017-12-20T12:30:12.3697241Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.68"}
{"message":"Post processor ExtractSearchIndex loaded.","date_time":"2017-12-20T12:30:12.5057377Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.74"}
{"message":"Markdown engine is dfm","date_time":"2017-12-20T12:30:12.7607632Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.75"}
{"message":"Max parallelism is 8.","source":"BuildCore.Build Document","date_time":"2017-12-20T12:30:12.8427714Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.1"}
{"message":"Building 3 file(s) in TocDocumentProcessor(BuildTocDocument)...","source":"BuildCore.Build Document.CompilePhaseHandlerWithIncremental.TocDocumentProcessor","date_time":"2017-12-20T12:30:14.8749746Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.26.7.1"}
{"message":"Building 39 file(s) in ConceptualDocumentProcessor(BuildConceptualDocument=>CountWord=>ValidateConceptualDocumentMetadata)...","source":"BuildCore.Build Document.CompilePhaseHandlerWithIncremental.ConceptualDocumentProcessor","date_time":"2017-12-20T12:30:14.8759747Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.26.8.1"}
{"message":"Building 3 file(s) in ResourceDocumentProcessor(ValidateResourceMetadata)...","source":"BuildCore.Build Document.CompilePhaseHandlerWithIncremental.ResourceDocumentProcessor","date_time":"2017-12-20T12:30:14.8769748Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.26.9.1"}
{"message":"Invalid file link:(~/missing.md#mobiilisovellus).","source":"BuildCore.Build Document.LinkPhaseHandlerWithIncremental.ConceptualDocumentProcessor.Save","file":"sanasto.md","line":"63","date_time":"2017-12-20T12:30:17.0181889Z","message_severity":"warning","code":"InvalidFileLink","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.27.9.1.2"}
{"message":"Invalid file link:(~/mobiilirajapinta/puuttuu.md).","source":"BuildCore.Build Document.LinkPhaseHandlerWithIncremental.ConceptualDocumentProcessor.Save","file":"mobiilirajapinta/json-dateandtime.md","line":"18","date_time":"2017-12-20T12:30:17.0181889Z","message_severity":"warning","code":"InvalidFileLink","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.27.9.1.4"}
{"message":"Invalid file link:(~/mobiilirajapinta/joopajoo.md).","source":"BuildCore.Build Document.LinkPhaseHandlerWithIncremental.ConceptualDocumentProcessor.Save","file":"mobiilirajapinta/json-nime&#228;misk&#228;yt&#228;nt&#246;.md","line":"7","date_time":"2017-12-20T12:30:17.019189Z","message_severity":"warning","code":"InvalidFileLink","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.27.9.1.19"}
{"message":"Applying templates to 45 model(s)...","source":"BuildCore.Build Document.LinkPhaseHandlerWithIncremental.Apply Templates","date_time":"2017-12-20T12:30:17.2742145Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.27.17.1"}
{"message":"XRef map exported.","source":"BuildCore.Build Document","date_time":"2017-12-20T12:30:17.8822753Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.80.1.29"}
{"message":"Extracting index data from 39 html files","source":"Postprocess.HandlePostProcessorsWithIncremental.HandlePostProcessors.Processing ExtractSearchIndex","date_time":"2017-12-20T12:30:18.5913462Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.81.1.3.2.1"}
{"message":"Manifest file saved to manifest.json.","source":"Postprocess","date_time":"2017-12-20T12:30:18.7063577Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.81.4"}
{"message":"Completed building documents in 6373,7365 milliseconds.","date_time":"2017-12-20T12:30:18.7783649Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.82"}
{"message":"Completed in 11285,689 milliseconds","date_time":"2017-12-20T12:30:18.7823653Z","message_severity":"info","correlation_id":"5CEF92F0-944B-469D-A9A6-57BEB66C1DAC.86"}

0 comments on commit 1ca81e0

Please sign in to comment.