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

[JENKINS-73363] Add support for protoLint JSON format #1075

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package edu.hm.hafner.analysis.parser;

import org.json.JSONArray;
import org.json.JSONObject;

import edu.hm.hafner.analysis.Issue;
import edu.hm.hafner.analysis.IssueBuilder;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;

/**
* Parser for ProtoLint JSON reports.
*
* <p>The recommended report format is JSON. The JSON report contains more information (affected rule, severity,
* basedir) as the plaintext format. For full feature set please use protoLint &gt;= 0.50.2.
*
* <p>We still support plaintext reports and JSON reports generated with protoLint &lt; 0.50.2 as well.
*
* @author [email protected]
* @see <a href="https://github.com/yoheimuta/protolint">https://github.com/yoheimuta/protolint</a>
*/
public class ProtoLintJsonParser extends JsonIssueParser {
private static final long serialVersionUID = 573706779074579673L;

@Override
protected void parseJsonObject(final Report report, final JSONObject jsonReport, final IssueBuilder issueBuilder) {
String basedir = jsonReport.optString("basedir");
JSONArray results = jsonReport.optJSONArray("lints", new JSONArray(0));

parseResults(report, basedir, results, issueBuilder);
}

private void parseResults(final Report report, final String basedir, final JSONArray jsonReport, final IssueBuilder issueBuilder) {
for (int i = 0; i < jsonReport.length(); i++) {
JSONObject finding = (JSONObject) jsonReport.get(i);
report.add(convertToIssue(basedir, finding, issueBuilder));
}
}

private Issue convertToIssue(final String basedir, final JSONObject finding, final IssueBuilder issueBuilder) {
// The filename is always relative to the working dir the protoLint process was started with.
// In order to get the absolute filename we need to prepend the basedir which is available with protoLint >= 0.50.2
String filename = finding.getString("filename");
if (!basedir.isEmpty()) {
filename = basedir + "/" + filename;
}
return issueBuilder.setFileName(filename)
.setLineStart(finding.getInt("line"))
.setColumnStart(finding.getInt("column"))
.setMessage(finding.getString("message"))
.setSeverity(mapSeverity(finding.optString("severity")))
.setType(finding.getString("rule"))
.buildAndClean();
}

private Severity mapSeverity(final String aProtoLintSeverity) {
// ProtoLint knows the following severities
// https://github.com/yoheimuta/protolint/blob/master/linter/rule/rule.go#L9
// which can be mapped with the provided mapping method
return Severity.guessFromString(aProtoLintSeverity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
import edu.hm.hafner.util.LookaheadStream;

/**
* Parser for ProtoLint.
* Parser for ProtoLint plaintext reports.
*
* <p>The recommended report format is now JSON! This parser is just used as fallback.
*
* @author David Hart
* @see <a href="https://github.com/yoheimuta/protolint">https://github.com/yoheimuta/protolint</a>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package edu.hm.hafner.analysis.registry;

import static j2html.TagCreator.a;
import static j2html.TagCreator.code;
import static j2html.TagCreator.join;
import static j2html.TagCreator.text;

import java.util.Collection;

import edu.hm.hafner.analysis.IssueParser;
import edu.hm.hafner.analysis.parser.ProtoLintJsonParser;
import edu.hm.hafner.analysis.parser.ProtoLintParser;

/**
* A descriptor for ProtoLint.
*
* <p>We use a composite parser for supporting JSON (preferred) and plaintext (fallback) format.
*
* @author Lorenz Munsch
* @author [email protected]
*/
class ProtoLintDescriptor extends ParserDescriptor {
class ProtoLintDescriptor extends CompositeParserDescriptor {
private static final String ID = "protolint";
private static final String NAME = "ProtoLint";

Expand All @@ -17,8 +28,17 @@
}

@Override
public IssueParser createParser(final Option... options) {
return new ProtoLintParser();
protected Collection<? extends IssueParser> createParsers() {
return asList(new ProtoLintJsonParser(), new ProtoLintParser());
}

@Override
public String getHelp() {
return join(text("Use protolint with options"),
code("-reporter=json -output_file=protolint-report.json"),
text(", see"),
a("protoLint CLI options").withHref("https://github.com/yoheimuta/protolint?tab=readme-ov-file#usage"),
text("for usage details.")).render();

Check warning on line 41 in src/main/java/edu/hm/hafner/analysis/registry/ProtoLintDescriptor.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 37-41 are not covered by tests

Check warning on line 41 in src/main/java/edu/hm/hafner/analysis/registry/ProtoLintDescriptor.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/edu/hm/hafner/analysis/registry/ProtoLintDescriptor.java#L37-L41

Added lines #L37 - L41 were not covered by tests
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package edu.hm.hafner.analysis.parser;

import edu.hm.hafner.analysis.IssueParser;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;
import edu.hm.hafner.analysis.assertions.SoftAssertions;
import edu.hm.hafner.analysis.registry.AbstractParserTest;

import static edu.hm.hafner.analysis.assertions.Assertions.*;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
* Test class for {@link ProtoLintJsonParser}.
*
* @author [email protected]
*/
class ProtoLintJsonParserTest extends AbstractParserTest {
ProtoLintJsonParserTest() {
super("protolint_0.50.2.json");
}

@Override
public void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) {
assertThat(report).hasSize(462);

softly.assertThat(report.get(4))
.hasSeverity(Severity.WARNING_LOW)
.hasLineStart(3)
.hasColumnStart(5)
.hasMessage("Found an incorrect indentation style \" \". \" \" is correct.")
.hasFileName("/home/jwiesner/Development/github/profhenry/protolint/_example/proto/issue_111/multipleFixersApplicable.proto")
.hasType("INDENT");

softly.assertThat(report.get(12))
.hasSeverity(Severity.ERROR)
.hasLineStart(3)
.hasColumnStart(5)
.hasMessage("EnumField name \"UNKNOWN\" should have the prefix \"ENUM_ALLOWING_ALIAS\"")
.hasFileName("/home/jwiesner/Development/github/profhenry/protolint/_example/proto/issue_111/multipleFixersApplicable.proto")
.hasType("ENUM_FIELD_NAMES_PREFIX");

softly.assertThat(report.get(224))
.hasSeverity(Severity.WARNING_NORMAL)
.hasLineStart(207)
.hasColumnStart(3)
.hasMessage("Field \"amount\" should have a comment")
.hasFileName("/home/jwiesner/Development/github/profhenry/protolint/_example/proto/issue_128/grpc-gateway_a_bit_of_everything.proto")
.hasType("FIELDS_HAVE_COMMENT");
}

@Override
public IssueParser createParser() {
return new ProtoLintJsonParser();
}

@Test
@DisplayName("Parsing json report generated with protolint 0.49.8")
void json0498() {
Report report = parse("protolint_0.49.8.json");

assertThat(report).hasSize(352);

try (SoftAssertions softly = new SoftAssertions()) {
softly.assertThat(report.get(2))
.hasSeverity(Severity.WARNING_LOW)
.hasLineStart(3)
.hasColumnStart(5)
.hasMessage("Found an incorrect indentation style \" \". \" \" is correct.")
.hasFileName("_example/proto/issue_111/multipleFixersApplicable.proto")
.hasType("INDENT");

softly.assertThat(report.get(10))
.hasSeverity(Severity.WARNING_LOW)
.hasLineStart(3)
.hasColumnStart(5)
.hasMessage("EnumField name \"UNKNOWN\" should have the prefix \"ENUM_ALLOWING_ALIAS\"")
.hasFileName("_example/proto/issue_111/multipleFixersApplicable.proto")
.hasType("ENUM_FIELD_NAMES_PREFIX");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -807,12 +807,18 @@ void shouldFindNoJavacIssuesInEclipseOutput() {
findIssuesOfTool(0, "java", "eclipse.txt");
}

/** Runs the ProtoLint parser on an output file that contains 10 issues. */
/** Runs the ProtoLint parser on a plaintext output file that contains 2591 issues. */
@Test
void shouldFindAllProtoLintIssues() {
findIssuesOfTool(2591, "protolint", "protolint.txt");
}

/** Runs the ProtoLint parser on a json output file that contains 462 issues. */
@Test
void shouldFindAllProtoLintIssuesJsonFormat() {
findIssuesOfTool(462, "protolint", "protolint_0.50.2.json");
}

/** Runs the HadoLint parser on an output file that contains 5 issues. */
@Test
void shouldFindAllHadoLintIssues() {
Expand Down
Loading
Loading