-
Notifications
You must be signed in to change notification settings - Fork 183
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3b081b3
commit 1ec6e8e
Showing
10 changed files
with
6,454 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
src/main/java/edu/hm/hafner/analysis/parser/SonarQubeDiffParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.json.JSONObject; | ||
|
||
/** | ||
* Class which parses SonarQube reports taken from Sonarqube differential scan report (preview). | ||
* | ||
* @author Carles Capdevila | ||
*/ | ||
public class SonarQubeDiffParser extends SonarQubeParser { | ||
private static final long serialVersionUID = -47634856667313368L; | ||
|
||
private static final String ISSUE_IS_NEW = "isNew"; | ||
private static final String COMPONENT_MODULE_KEY = "moduleKey"; | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public boolean issueFilter(final JSONObject issue) { | ||
return issue.optBoolean(ISSUE_IS_NEW, false); | ||
} | ||
|
||
@Override | ||
public String parseFilename(final JSONObject issue) { | ||
//Get component | ||
String componentKey = issue.optString(ISSUE_COMPONENT, null); | ||
JSONObject component = findComponentByKey(componentKey); | ||
|
||
if (component != null) { | ||
//Get file path inside module | ||
String filePath = component.optString(COMPONENT_PATH); | ||
|
||
//Get module file path | ||
String modulePath = parseModulePath(component, COMPONENT_MODULE_KEY); | ||
return modulePath + filePath; | ||
} else { | ||
return super.parseFilename(issue); | ||
} | ||
} | ||
|
||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/edu/hm/hafner/analysis/parser/SonarQubeIssuesParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.json.JSONObject; | ||
|
||
/** | ||
* Class which parses SonarQube reports taken from the Sonarqube API (api/issues/search). | ||
* | ||
* @author Carles Capdevila | ||
*/ | ||
public class SonarQubeIssuesParser extends SonarQubeParser { | ||
private static final long serialVersionUID = -8213765181968340929L; | ||
|
||
private static final String ISSUE_SUB_PROJECT= "subProject"; | ||
|
||
@Override | ||
public String parseFilename(final JSONObject issue) { | ||
//Get component | ||
String componentKey = issue.optString(ISSUE_COMPONENT, null); | ||
JSONObject component = findComponentByKey(componentKey); | ||
|
||
if (component != null) { | ||
//Get file path inside module | ||
String filePath = component.optString(COMPONENT_PATH); | ||
|
||
//Get module file path | ||
String modulePath = parseModulePath(issue, ISSUE_SUB_PROJECT); | ||
return modulePath + filePath; | ||
} else { | ||
return super.parseFilename(issue); | ||
} | ||
} | ||
|
||
} |
270 changes: 270 additions & 0 deletions
270
src/main/java/edu/hm/hafner/analysis/parser/SonarQubeParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import java.io.IOException; | ||
import java.io.Reader; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
import org.json.JSONTokener; | ||
|
||
import edu.hm.hafner.analysis.AbstractParser; | ||
import edu.hm.hafner.analysis.Issue; | ||
import edu.hm.hafner.analysis.IssueBuilder; | ||
import edu.hm.hafner.analysis.ParsingCanceledException; | ||
import edu.hm.hafner.analysis.ParsingException; | ||
import edu.hm.hafner.analysis.Priority; | ||
import edu.hm.hafner.analysis.Report; | ||
|
||
/** | ||
* Base class for SonarQube parsers. | ||
* | ||
* @author Carles Capdevila | ||
*/ | ||
public abstract class SonarQubeParser extends AbstractParser { | ||
private static final long serialVersionUID = 1958805067002376816L; | ||
|
||
//Arrays | ||
/** The components array. */ | ||
protected static final String COMPONENTS = "components"; | ||
/** The issues array. */ | ||
protected static final String ISSUES = "issues"; | ||
|
||
//Issues attributes | ||
/** issue.component attribute. */ | ||
protected static final String ISSUE_COMPONENT = "component"; | ||
/** issue.message attribute. */ | ||
protected static final String ISSUE_MESSAGE = "message"; | ||
/** issue.line attribute. */ | ||
protected static final String ISSUE_LINE = "line"; | ||
/** issue.line attribute. */ | ||
protected static final String ISSUE_SEVERITY = "severity"; | ||
/** issue.type attribute. */ | ||
protected static final String ISSUE_TYPE = "type"; | ||
|
||
//Component attributes | ||
/** component.key attribute. */ | ||
protected static final String COMPONENT_KEY = "key"; | ||
/** component.path attribute. */ | ||
protected static final String COMPONENT_PATH = "path"; | ||
|
||
// Severity values | ||
/** severity value: BLOCKER */ | ||
protected static final String SEVERITY_BLOCKER = "BLOCKER"; | ||
/** severity value: CRITICAL */ | ||
protected static final String SEVERITY_CRITICAL = "CRITICAL"; | ||
// Severity MAJOR is omitted as it corresponds with default Priority: NORMAL | ||
/** severity value: MINOR */ | ||
protected static final String SEVERITY_MINOR = "MINOR"; | ||
/** severity value: INFO */ | ||
protected static final String SEVERITY_INFO = "INFO"; | ||
/** Fixed category: SonarQube */ | ||
protected static final String CATEGORY_SONARQUBE = "SonarQube"; | ||
|
||
/** The issues array. */ | ||
protected JSONArray issues; | ||
/** The components array. */ | ||
protected JSONArray components; | ||
|
||
@Override | ||
public Report parse(Reader reader, Function<String, String> preProcessor) | ||
throws ParsingCanceledException, ParsingException { | ||
Report warnings = new Report(); | ||
|
||
JSONObject jsonReport = (JSONObject)new JSONTokener(reader).nextValue(); | ||
|
||
//Get the components part to get the file paths on each issue (the component objects contain the most concise path) | ||
components = new JSONArray(); | ||
if (jsonReport.has(COMPONENTS)) { | ||
components = jsonReport.optJSONArray(COMPONENTS); | ||
} | ||
|
||
issues = new JSONArray(); | ||
if (jsonReport.has(ISSUES)) { | ||
issues = jsonReport.optJSONArray(ISSUES); | ||
} | ||
|
||
//Iterate the issues | ||
for (Object issue : issues) { | ||
if (issue instanceof JSONObject) { | ||
//Filter the issues | ||
if (issueFilter((JSONObject)issue)) { | ||
//Parse each issue | ||
warnings.add(parseIssue((JSONObject)issue)); | ||
} | ||
} | ||
} | ||
|
||
return warnings; | ||
} | ||
|
||
|
||
/** | ||
* Decides whether or not to parse and add an issue. | ||
* @param issue the issue to filter. | ||
* @return true if the issue is to be parsed and added, otherwise false. | ||
*/ | ||
public boolean issueFilter(final JSONObject issue) { | ||
return true;//Parse all issues by default | ||
} | ||
|
||
/** | ||
* The core of the parsing; this can be further overridden to determine how each issue is parsed and shown. | ||
* @param issue the issue to parse. | ||
* @return a FileAnnotation with the data of the issue to show. | ||
*/ | ||
public Issue parseIssue(final JSONObject issue) { | ||
|
||
IssueBuilder issueBuilder = new IssueBuilder(); | ||
|
||
//file | ||
String filename = parseFilename(issue); | ||
|
||
//line | ||
int start = parseStart(issue); | ||
|
||
//type | ||
String type = parseType(issue); | ||
|
||
//category | ||
String category = parseCategory(issue); | ||
|
||
//message | ||
String message = parseMessage(issue); | ||
|
||
//priority | ||
Priority priority = parsePriority(issue); | ||
|
||
return new IssueBuilder() | ||
.setFileName(filename) | ||
.setLineStart(start) | ||
.setType(type) | ||
.setCategory(category) | ||
.setMessage(message) | ||
.setPriority(priority) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Parse function for filename. | ||
* @param issue the object to parse. | ||
* @return the filename. | ||
*/ | ||
public String parseFilename(final JSONObject issue) { | ||
String componentKey = issue.optString(ISSUE_COMPONENT); | ||
return componentKey.substring(componentKey.lastIndexOf(':')); | ||
} | ||
|
||
/** | ||
* Default parse for start. Override to change the default parsing. | ||
* @param issue the object to parse. | ||
* @return the start. | ||
*/ | ||
public int parseStart(final JSONObject issue) { | ||
return issue.optInt(ISSUE_LINE, -1); | ||
} | ||
|
||
/** | ||
* Default parse for type. Override to change the default parsing. | ||
* @param issue the object to parse. | ||
* @return the type. | ||
*/ | ||
public String parseType(final JSONObject issue) { | ||
return issue.optString(ISSUE_TYPE, ""); | ||
} | ||
|
||
/** | ||
* Default parse for category. Override to change the default parsing. | ||
* @param issue the object to parse. | ||
* @return the filename. | ||
*/ | ||
public String parseCategory(final JSONObject issue) { | ||
return CATEGORY_SONARQUBE; | ||
} | ||
|
||
/** | ||
* Default parse for message. Override to change the default parsing. | ||
* @param issue the object to parse. | ||
* @return the message. | ||
*/ | ||
public String parseMessage(final JSONObject issue) { | ||
return issue.optString(ISSUE_MESSAGE, "No message."); | ||
} | ||
|
||
/** | ||
* Default parse for priority. Override to change the default parsing. | ||
* @param issue the object to parse. | ||
* @return the priority. | ||
*/ | ||
public Priority parsePriority(final JSONObject issue) { | ||
String severity = issue.optString(ISSUE_SEVERITY, null); | ||
return severityToPriority(severity); | ||
} | ||
|
||
//UTILITIES | ||
/** | ||
* Find the module path inside the corresponding component. | ||
* @param moduleKeyObject the object which contains the component key. | ||
* @param componentKey the component key. | ||
* @return the module path. | ||
*/ | ||
protected String parseModulePath(final JSONObject moduleKeyObject, final String componentKey) { | ||
String modulePath = ""; | ||
if (moduleKeyObject.has(componentKey)) { | ||
String moduleKey = moduleKeyObject.getString(componentKey); | ||
JSONObject moduleComponent = findComponentByKey(moduleKey); | ||
if (moduleComponent != null && moduleComponent.has(COMPONENT_PATH)) { | ||
modulePath = moduleComponent.getString(COMPONENT_PATH) + "/"; | ||
} | ||
} | ||
return modulePath; | ||
} | ||
|
||
/** | ||
* Find the component in the components array which contains this key. | ||
* @param key the key of the desired component. | ||
* @return the desired JSONObject component, or null if it hasn't been found. | ||
*/ | ||
protected JSONObject findComponentByKey (final String key) { | ||
if (components != null && key != null) { | ||
for (Object component : components) { | ||
if (component instanceof JSONObject) { | ||
JSONObject jsonComponent = (JSONObject)component; | ||
if (key.equals(jsonComponent.optString(COMPONENT_KEY))) { | ||
return (JSONObject)component; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
|
||
|
||
/** | ||
* Maps issue severity to warning priority:<br> | ||
* <strong>HIGH:</strong> BLOCKER, CRITICAL<br> | ||
* <strong>NORMAL:</strong> MAJOR<br> | ||
* <strong>LOW:</strong> MINOR, INFO | ||
* | ||
* @param severity a String containing the SonarQube issue severity. | ||
* @return a priority object corresponding to the passed severity. | ||
*/ | ||
protected Priority severityToPriority (final String severity) { | ||
Priority priority = Priority.NORMAL; | ||
// Severity MAJOR is omitted as it corresponds with default Priority: NORMAL | ||
if (severity != null) { | ||
if (SEVERITY_BLOCKER.equals(severity) || SEVERITY_CRITICAL.equals(severity)) { | ||
priority = Priority.HIGH; | ||
} else if (SEVERITY_MINOR.equals(severity) || SEVERITY_INFO.equals(severity)) { | ||
priority = Priority.LOW; | ||
} | ||
} | ||
return priority; | ||
} | ||
|
||
} | ||
|
Oops, something went wrong.