diff --git a/README.md b/README.md
index d5019f3e..44769222 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ In SonarQube under Quality Profiles the used Linter can be specified by selectin
| Complexity |YES |Uses [Lizard](https://github.com/terryyin/lizard)| Uses [Lizard](https://github.com/terryyin/lizard)|
| Design |NO | | |
| Documentation |YES | | |
-| Duplications |YES | | |
+| Duplications |Only on Sonarqube < 7.3 | | |
| Issues |YES | Uses [SwiftLint](https://github.com/realm/SwiftLint) and/or [Tailor](https://github.com/sleekbyte/tailor) for Swift. [OCLint](http://oclint-docs.readthedocs.io/en/stable/) and [Faux Pas](http://fauxpasapp.com/) for Objective-C| Uses [Tailor](https://github.com/sleekbyte/tailor)|
| Size |YES | | |
| Tests |YES | Uses xcodebuild + xcpretty [xcpretty](https://github.com/supermarin/xcpretty) | Not Supported |
diff --git a/commons/pom.xml b/commons/pom.xml
index b8deb794..efac25cd 100644
--- a/commons/pom.xml
+++ b/commons/pom.xml
@@ -24,7 +24,7 @@
backelite-swift
com.backelite.sonarqube
- 0.4.4
+ 0.4.5-develop2
4.0.0
@@ -90,11 +90,6 @@
org.slf4j
slf4j-api
-
- commons-lang
- commons-lang
- 2.6
-
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/MeasureUtil.java b/commons/src/main/java/com/backelite/sonarqube/commons/MeasureUtil.java
index 3518743b..9408af76 100644
--- a/commons/src/main/java/com/backelite/sonarqube/commons/MeasureUtil.java
+++ b/commons/src/main/java/com/backelite/sonarqube/commons/MeasureUtil.java
@@ -18,8 +18,8 @@
package com.backelite.sonarqube.commons;
import org.sonar.api.batch.fs.InputComponent;
+import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.measures.Metric;
/**
* Created by gillesgrousset on 29/08/2018.
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/TestFileFinders.java b/commons/src/main/java/com/backelite/sonarqube/commons/TestFileFinders.java
index b523407e..37216a91 100644
--- a/commons/src/main/java/com/backelite/sonarqube/commons/TestFileFinders.java
+++ b/commons/src/main/java/com/backelite/sonarqube/commons/TestFileFinders.java
@@ -39,7 +39,7 @@ public void addFinder(TestFileFinder finder) {
finders.add(finder);
}
- public InputFile getUnitTestResource(FileSystem fileSystem, String classname) {
+ InputFile getUnitTestResource(FileSystem fileSystem, String classname) {
for (TestFileFinder finder : finders) {
InputFile result = finder.getUnitTestResource(fileSystem, classname);
if (result != null) {
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/StaxParser.java b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/StaxParser.java
deleted file mode 100644
index 26f41f7f..00000000
--- a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/StaxParser.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * commons - Enables analysis of Swift and Objective-C projects into SonarQube.
- * Copyright © 2015 Backelite (${email})
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package com.backelite.sonarqube.commons.surefire;
-
-import org.codehaus.staxmate.SMInputFactory;
-import com.ctc.wstx.stax.WstxInputFactory;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-
-public class StaxParser {
-
- private SMInputFactory inf;
- private SurefireStaxHandler streamHandler;
-
- public StaxParser(UnitTestIndex index) {
- this.streamHandler = new SurefireStaxHandler(index);
- XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
- if (xmlInputFactory instanceof WstxInputFactory) {
- WstxInputFactory wstxInputfactory = (WstxInputFactory) xmlInputFactory;
- wstxInputfactory.configureForLowMemUsage();
- wstxInputfactory.getConfig().setUndeclaredEntityResolver((String publicID, String systemID, String baseURI, String namespace) -> namespace);
- }
- this.inf = new SMInputFactory(xmlInputFactory);
- }
-
- public void parse(File xmlFile) throws XMLStreamException {
- try(FileInputStream input = new FileInputStream(xmlFile)) {
- parse(inf.rootElementCursor(input));
- } catch (IOException e) {
- throw new XMLStreamException(e);
- }
- }
-
- private void parse(SMHierarchicCursor rootCursor) throws XMLStreamException {
- try {
- streamHandler.stream(rootCursor);
- } finally {
- rootCursor.getStreamReader().closeCompletely();
- }
- }
-}
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireReportParser.java b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireReportParser.java
index 608572b0..dca2ce6c 100644
--- a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireReportParser.java
+++ b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireReportParser.java
@@ -17,32 +17,24 @@
*/
package com.backelite.sonarqube.commons.surefire;
-import com.backelite.sonarqube.commons.TestFileFinders;
+import com.backelite.sonarqube.commons.MeasureUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.test.MutableTestPlan;
-import org.sonar.api.test.TestCase;
-import org.sonar.squidbridge.api.AnalysisException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
-import javax.annotation.CheckForNull;
+import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.stream.XMLStreamException;
+import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.Serializable;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
public class SurefireReportParser {
private static final Logger LOGGER = LoggerFactory.getLogger(SurefireReportParser.class);
@@ -52,110 +44,130 @@ public class SurefireReportParser {
protected final SensorContext context;
private final DocumentBuilderFactory dbfactory;
private final UnitTestIndex index;
- private final ResourcePerspectives perspectives;
- private final FileSystem fileSystem;
- protected SurefireReportParser(FileSystem fileSystem, ResourcePerspectives perspectives, SensorContext context) {
- this.fileSystem = fileSystem;
+ protected SurefireReportParser(SensorContext context) {
this.context = context;
- this.perspectives = perspectives;
this.dbfactory = DocumentBuilderFactory.newInstance();
this.index = new UnitTestIndex();
}
- public void collect(File reportsDir) {
- List xmlFiles = new ArrayList<>();
- try (DirectoryStream stream = Files.newDirectoryStream(reportsDir.toPath(), "{TEST}*.{xml}")) {
- for (Path p: stream) {
- LOGGER.info("Processing Surefire report {}", p.getFileName());
- xmlFiles.add(p.toFile());
- }
- } catch (IOException e) {
- LOGGER.error( "Error while finding test files.", e);
+ public void parseReport(final File xmlFile) {
+ try {
+ DocumentBuilder builder = dbfactory.newDocumentBuilder();
+ Document document = builder.parse(xmlFile);
+ collectTestSuites(document.getElementsByTagName(TESTSUITE));
+ } catch (final FileNotFoundException e) {
+ LOGGER.error("Cobertura Report not found {}", xmlFile, e);
+ } catch (final IOException e) {
+ LOGGER.error("Error processing file named {}", xmlFile, e);
+ } catch (final ParserConfigurationException e) {
+ LOGGER.error("Error in parser config {}", e);
+ } catch (final SAXException e) {
+ LOGGER.error("Error processing file named {}", xmlFile, e);
}
+ }
- if (!xmlFiles.isEmpty()) {
- parseFiles(xmlFiles);
+ private void collectTestSuites(NodeList nodeList) {
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+ String testSuiteClassName = element.getAttribute("name");
+ if(testSuiteClassName != null && !testSuiteClassName.contains("$")){
+ NodeList nl = element.getElementsByTagName(TESTCASE);
+ collectTestCases(testSuiteClassName, nl);
+ }
+ }
}
}
- private void parseFiles(List reports) {
- UnitTestIndex index = new UnitTestIndex();
- parseFiles(reports, index);
- save(index, context);
+ private void collectTestCases(String testSuiteName, NodeList nodeList) {
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+
+ String className = element.getAttribute("classname");
+ if(className != null && className.endsWith(")") && className.indexOf("(") >= 0){
+ className = className.substring(0, className.indexOf("("));
+ }
+ if(className == null || className.trim().isEmpty())
+ className = testSuiteName;
+
+ String testName = element.getAttribute("name");
+ if(className != null && className.contains("$"))
+ testName = className.substring(className.indexOf("$")) + "/" + testName;
+
+ UnitTestClassReport classReport = index.index(className);
+ UnitTestResult detail = new UnitTestResult();
+ detail.setName(testName);
+
+ String status = UnitTestResult.STATUS_OK;
+ Long duration = parseDuration(element.getAttribute("time"));
+ if(element.hasChildNodes()){
+ Element item = (Element) element.getChildNodes().item(0);
+ if ("skipped".equals(item.getLocalName())) {
+ status = UnitTestResult.STATUS_SKIPPED;
+ duration = 0L;
+
+ } else if ("failure".equals(item.getLocalName())) {
+ status = UnitTestResult.STATUS_FAILURE;
+ detail.setMessage(item.getAttribute("message"));
+ detail.setStackTrace(item.getTextContent());
+
+ } else if ("error".equals(item.getLocalName())) {
+ status = UnitTestResult.STATUS_ERROR;
+ detail.setMessage(item.getAttribute("message"));
+ detail.setStackTrace(item.getTextContent());
+ }
+ }
+ detail.setDurationMilliseconds(duration);
+ detail.setStatus(status);
+ classReport.add(detail);
+ }
+ }
}
- private static void parseFiles(List reports, UnitTestIndex index) {
- StaxParser parser = new StaxParser(index);
- for (File report : reports) {
- try {
- parser.parse(report);
- } catch (XMLStreamException e) {
- throw new AnalysisException("Fail to parse the Surefire report: " + report, e);
- }
+ private Long parseDuration(String value) {
+ Long duration = null;
+ if(value != null && !value.isEmpty()){
+ Double time = Double.parseDouble(value);
+ duration = (long)(time * 1000);
}
+ return duration;
}
- private void save(UnitTestIndex index, SensorContext context) {
+ public void save() {
long negativeTimeTestNumber = 0;
- Map indexByInputFile = mapToInputFile(index.getIndexByClassname());
- for (Map.Entry entry : indexByInputFile.entrySet()) {
- UnitTestClassReport report = entry.getValue();
+ int testsCount = 0;
+ int testsSkipped = 0;
+ int testsErrors = 0;
+ int testsFailures = 0;
+ long testsTime = 0;
+
+ for (UnitTestClassReport report : index.getIndexByClassname().values()) {
+ testsCount += report.getTests() - report.getSkipped();
+ testsSkipped += report.getSkipped();
+ testsErrors += report.getErrors();
+ testsFailures += report.getFailures();
+
if (report.getTests() > 0) {
negativeTimeTestNumber += report.getNegativeTimeTestNumber();
- save(report, entry.getKey(), context);
}
}
- if (negativeTimeTestNumber > 0) {
- LOGGER.warn("There is {} test(s) reported with negative time by surefire, total duration may not be accurate.", negativeTimeTestNumber);
- }
- }
- private Map mapToInputFile(Map indexByClassname) {
- Map result = new HashMap<>();
- indexByClassname.forEach((className, index) -> {
- InputFile resource = getUnitTestResource(className, index);
- if (resource != null) {
- UnitTestClassReport report = result.computeIfAbsent(resource, r -> new UnitTestClassReport());
- // in case of repeated/parameterized tests (JUnit 5.x) we may end up with tests having the same name
- index.getResults().forEach(report::add);
- } else {
- LOGGER.debug("Resource not found: {}", className);
- }
- });
- return result;
- }
-
- private void save(UnitTestClassReport report, InputFile inputFile, SensorContext context) {
- int testsCount = report.getTests() - report.getSkipped();
- saveMeasure(context, inputFile, CoreMetrics.SKIPPED_TESTS, report.getSkipped());
- saveMeasure(context, inputFile, CoreMetrics.TESTS, testsCount);
- saveMeasure(context, inputFile, CoreMetrics.TEST_ERRORS, report.getErrors());
- saveMeasure(context, inputFile, CoreMetrics.TEST_FAILURES, report.getFailures());
- saveMeasure(context, inputFile, CoreMetrics.TEST_EXECUTION_TIME, report.getDurationMilliseconds());
- saveResults(inputFile, report);
- }
- protected void saveResults(InputFile testFile, UnitTestClassReport report) {
- for (UnitTestResult unitTestResult : report.getResults()) {
- MutableTestPlan testPlan = perspectives.as(MutableTestPlan.class, testFile);
- if (testPlan != null) {
- testPlan.addTestCase(unitTestResult.getName())
- .setDurationInMs(Math.max(unitTestResult.getDurationMilliseconds(), 0))
- .setStatus(TestCase.Status.of(unitTestResult.getStatus()))
- .setMessage(unitTestResult.getMessage())
- .setStackTrace(unitTestResult.getStackTrace());
- }
+ if (negativeTimeTestNumber > 0) {
+ LOGGER.warn("There is {} test(s) reported with negative time by data, total duration may not be accurate.", negativeTimeTestNumber);
}
- }
-
- @CheckForNull
- private InputFile getUnitTestResource(String className, UnitTestClassReport unitTestClassReport) {
- return TestFileFinders.getInstance().getUnitTestResource(fileSystem, className);
- }
- private static void saveMeasure(SensorContext context, InputFile inputFile, Metric metric, T value) {
- context.newMeasure().forMetric(metric).on(inputFile).withValue(value).save();
+ if (testsCount > 0) {
+ InputComponent module = context.module();
+ MeasureUtil.saveMeasure(context, module, CoreMetrics.TESTS, testsCount);
+ MeasureUtil.saveMeasure(context, module, CoreMetrics.SKIPPED_TESTS, testsSkipped);
+ MeasureUtil.saveMeasure(context, module, CoreMetrics.TEST_ERRORS, testsErrors);
+ MeasureUtil.saveMeasure(context, module, CoreMetrics.TEST_FAILURES, testsFailures);
+ MeasureUtil.saveMeasure(context, module, CoreMetrics.TEST_EXECUTION_TIME, testsTime);
+ }
}
-
}
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireSensor.java b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireSensor.java
index b0b204d5..e5920e87 100644
--- a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireSensor.java
+++ b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireSensor.java
@@ -20,17 +20,12 @@
import com.backelite.sonarqube.commons.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.component.ResourcePerspectives;
import java.io.File;
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
public class SurefireSensor implements Sensor {
private static final Logger LOGGER = LoggerFactory.getLogger(SurefireSensor.class);
@@ -38,12 +33,8 @@ public class SurefireSensor implements Sensor {
public static final String DEFAULT_REPORT_PATH = "sonar-reports/";
private final SensorContext context;
- private final ResourcePerspectives perspectives;
- private final FileSystem fileSystem;
- public SurefireSensor(FileSystem fileSystem, ResourcePerspectives perspectives, SensorContext context) {
- this.fileSystem = fileSystem;
- this.perspectives = perspectives;
+ public SurefireSensor(SensorContext context) {
this.context = context;
}
@@ -57,23 +48,24 @@ protected String reportPath() {
public void describe(SensorDescriptor descriptor) {
descriptor
.name("Surefire")
- .onlyOnLanguages("swift","objc");
+ .onlyOnLanguages("swift","objc")
+ .onlyOnFileType(InputFile.Type.MAIN);
}
@Override
public void execute(SensorContext context) {
- SurefireReportParser surefireParser = new SurefireReportParser(fileSystem, perspectives, context);
- String reportFileName = context.fileSystem().baseDir().getAbsolutePath() + "/"+ reportPath();
+ SurefireReportParser surefireParser = new SurefireReportParser(context);
+ String reportFileName = context.fileSystem().baseDir().getAbsolutePath() + File.separator + reportPath();
File reportsDir = new File(reportFileName);
if (!reportsDir.isDirectory()) {
LOGGER.warn("JUnit report directory not found at {}", reportsDir);
return;
- } else {
- surefireParser.collect(reportsDir);
}
-
-
+ for (File file : reportsDir.listFiles((file,name) -> (name.startsWith("TEST") && name.endsWith(".xml")) || name.endsWith(".junit"))){
+ LOGGER.info("Processing Surefire report {}", file.getName());
+ surefireParser.parseReport(file);
+ }
+ surefireParser.save();
}
-
}
diff --git a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireStaxHandler.java b/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireStaxHandler.java
deleted file mode 100644
index 58787c8b..00000000
--- a/commons/src/main/java/com/backelite/sonarqube/commons/surefire/SurefireStaxHandler.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * commons - Enables analysis of Swift and Objective-C projects into SonarQube.
- * Copyright © 2015 Backelite (${email})
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package com.backelite.sonarqube.commons.surefire;
-
-import java.text.ParseException;
-import java.util.Locale;
-import javax.xml.stream.XMLStreamException;
-import org.apache.commons.lang.StringUtils;
-import org.codehaus.staxmate.in.ElementFilter;
-import org.codehaus.staxmate.in.SMEvent;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.sonar.api.utils.ParsingUtils;
-
-public class SurefireStaxHandler {
-
- private final UnitTestIndex index;
-
- public SurefireStaxHandler(UnitTestIndex index) {
- this.index = index;
- }
-
- public void stream(SMHierarchicCursor rootCursor) throws XMLStreamException {
- SMInputCursor testSuite = rootCursor.constructDescendantCursor(new ElementFilter("testsuite"));
- SMEvent testSuiteEvent;
- for (testSuiteEvent = testSuite.getNext(); testSuiteEvent != null; testSuiteEvent = testSuite.getNext()) {
- if (testSuiteEvent.compareTo(SMEvent.START_ELEMENT) == 0) {
- String testSuiteClassName = testSuite.getAttrValue("name");
- if (StringUtils.contains(testSuiteClassName, "$")) {
- // test suites for inner classes are ignored
- return;
- }
- parseTestCase(testSuiteClassName, testSuite.childCursor(new ElementFilter("testcase")));
- }
- }
- }
-
- private void parseTestCase(String testSuiteClassName, SMInputCursor testCase) throws XMLStreamException {
- for (SMEvent event = testCase.getNext(); event != null; event = testCase.getNext()) {
- if (event.compareTo(SMEvent.START_ELEMENT) == 0) {
- String testClassName = getClassname(testCase, testSuiteClassName);
- UnitTestClassReport classReport = index.index(testClassName);
- parseTestCase(testCase, testSuiteClassName, classReport);
- }
- }
- }
-
- private static String getClassname(SMInputCursor testCaseCursor, String defaultClassname) throws XMLStreamException {
- String testClassName = testCaseCursor.getAttrValue("classname");
- if (StringUtils.isNotBlank(testClassName) && testClassName.endsWith(")")) {
- int openParenthesisIndex = testClassName.indexOf('(');
- if (openParenthesisIndex > 0) {
- testClassName = testClassName.substring(0, openParenthesisIndex);
- }
- }
- return StringUtils.defaultIfBlank(testClassName, defaultClassname);
- }
-
- private static void parseTestCase(SMInputCursor testCaseCursor, String testSuiteClassName, UnitTestClassReport report) throws XMLStreamException {
- report.add(parseTestResult(testCaseCursor, testSuiteClassName));
- }
-
- private static void setStackAndMessage(UnitTestResult result, SMInputCursor stackAndMessageCursor) throws XMLStreamException {
- result.setMessage(stackAndMessageCursor.getAttrValue("message"));
- String stack = stackAndMessageCursor.collectDescendantText();
- result.setStackTrace(stack);
- }
-
- private static UnitTestResult parseTestResult(SMInputCursor testCaseCursor, String testSuiteClassName) throws XMLStreamException {
- UnitTestResult detail = new UnitTestResult();
- String name = getTestCaseName(testCaseCursor);
- detail.setName(name);
- detail.setTestSuiteClassName(testSuiteClassName);
-
- String status = UnitTestResult.STATUS_OK;
- String time = testCaseCursor.getAttrValue("time");
- Long duration = null;
-
- SMInputCursor childNode = testCaseCursor.descendantElementCursor();
- if (childNode.getNext() != null) {
- String elementName = childNode.getLocalName();
- if ("skipped".equals(elementName)) {
- status = UnitTestResult.STATUS_SKIPPED;
- // bug with surefire reporting wrong time for skipped tests
- duration = 0L;
-
- } else if ("failure".equals(elementName)) {
- status = UnitTestResult.STATUS_FAILURE;
- setStackAndMessage(detail, childNode);
-
- } else if ("error".equals(elementName)) {
- status = UnitTestResult.STATUS_ERROR;
- setStackAndMessage(detail, childNode);
- }
- }
- while (childNode.getNext() != null) {
- // make sure we loop till the end of the elements cursor
- }
- if (duration == null) {
- duration = getTimeAttributeInMS(time);
- }
- detail.setDurationMilliseconds(duration);
- detail.setStatus(status);
- return detail;
- }
-
- private static long getTimeAttributeInMS(String value) throws XMLStreamException {
- // hardcoded to Locale.ENGLISH see http://jira.codehaus.org/browse/SONAR-602
- try {
- Double time = ParsingUtils.parseNumber(value, Locale.ENGLISH);
- return !Double.isNaN(time) ? (long) ParsingUtils.scaleValue(time * 1000, 3) : 0L;
- } catch (ParseException e) {
- throw new XMLStreamException(e);
- }
- }
-
- private static String getTestCaseName(SMInputCursor testCaseCursor) throws XMLStreamException {
- String classname = testCaseCursor.getAttrValue("classname");
- String name = testCaseCursor.getAttrValue("name");
- if (StringUtils.contains(classname, "$")) {
- return StringUtils.substringAfter(classname, "$") + "/" + name;
- }
- return name;
- }
-
-}
diff --git a/docs/sonarqube-fastlane.md b/docs/sonarqube-fastlane.md
index 7b28f8f1..7b8a88d9 100644
--- a/docs/sonarqube-fastlane.md
+++ b/docs/sonarqube-fastlane.md
@@ -9,7 +9,7 @@ Then add the following lane.
lane :metrics do
scan(scheme: "[SCHEME]", code_coverage: true, derived_data_path: "./DerivedData", output_directory: "./reports")
slather(cobertura_xml: true, jenkins: true, scheme: "[SCHEME]", build_directory: "./DerivedData", output_directory: "./reports", proj: "./[PROJECT].xcodeproj")
- lizard(source_folder: "[SOURCE_FOLDER]", language: "swift", export_type: "xml", report_file: "report/lizard-report.xml")
+ lizard(source_folder: "[SOURCE_FOLDER]", language: "swift", export_type: "xml", report_file: "reports/lizard-report.xml")
swiftlint(output_file: "./reports/swiftlint.txt", ignore_exit_status: true)
sonar
end
diff --git a/objclang/pom.xml b/objclang/pom.xml
index e11ab42d..62a08a2f 100644
--- a/objclang/pom.xml
+++ b/objclang/pom.xml
@@ -24,7 +24,7 @@
backelite-swift
com.backelite.sonarqube
- 0.4.4
+ 0.4.5-develop2
4.0.0
@@ -37,7 +37,7 @@
com.backelite.sonarqube
commons
- 0.4.4
+ 0.4.5-develop2
diff --git a/objclang/src/main/java/com/backelite/sonarqube/objectivec/ObjectiveCSquidSensor.java b/objclang/src/main/java/com/backelite/sonarqube/objectivec/ObjectiveCSquidSensor.java
index 4491a3db..692299a3 100644
--- a/objclang/src/main/java/com/backelite/sonarqube/objectivec/ObjectiveCSquidSensor.java
+++ b/objclang/src/main/java/com/backelite/sonarqube/objectivec/ObjectiveCSquidSensor.java
@@ -33,7 +33,6 @@
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.filesystem.PathResolver;
@@ -67,7 +66,7 @@ public class ObjectiveCSquidSensor implements Sensor {
public ObjectiveCSquidSensor(SensorContext context, PathResolver pathResolver, CheckFactory checkFactory) {
this.context = context;
this.pathResolver = pathResolver;
- this.checks = checkFactory.>create(CheckList.REPOSITORY_KEY).addAnnotatedChecks((Iterable)CheckList.getChecks());
+ this.checks = checkFactory.>create(CheckList.REPOSITORY_KEY).addAnnotatedChecks((Iterable) CheckList.getChecks());
}
private ObjectiveCConfiguration createConfiguration() {
@@ -86,7 +85,6 @@ private void save(Collection squidSourceFiles) {
}
private void saveMeasures(InputFile inputFile, SourceFile squidFile) {
- MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.FILES, squidFile.getInt(ObjectiveCMetric.FILES));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.LINES, squidFile.getInt(ObjectiveCMetric.LINES));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.NCLOC, squidFile.getInt(ObjectiveCMetric.LINES_OF_CODE));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.STATEMENTS, squidFile.getInt(ObjectiveCMetric.STATEMENTS));
@@ -99,16 +97,21 @@ private void saveIssues(InputFile inputFile, SourceFile squidFile) {
if (inputFile != null) {
for (CheckMessage message : messages) {
RuleKey ruleKey = checks.ruleKey((SquidCheck) message.getCheck());
- NewIssue issue = context.newIssue()
- .forRule(ruleKey);
- NewIssueLocation dil = new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(message.getLine()))
- .message(message.getText(Locale.ENGLISH));
- issue.at(dil);
+ NewIssue issue = context.newIssue();
+
+ NewIssueLocation issueLocation = issue.newLocation()
+ .message(message.getText(Locale.ENGLISH))
+ .on(inputFile)
+ .at(inputFile.selectLine(message.getLine()));
+
+ issue
+ .forRule(ruleKey)
+ .at(issueLocation);
+
if (message.getCost() != null) {
issue.gap(message.getCost());
}
+
issue.save();
}
}
@@ -133,7 +136,7 @@ public void execute(SensorContext context) {
FilePredicate isMain = context.fileSystem().predicates().hasType(InputFile.Type.MAIN);
FilePredicate and = context.fileSystem().predicates().and(hasObjC, isMain);
List files = new ArrayList<>();
- for(InputFile inf : context.fileSystem().inputFiles(and)){
+ for (InputFile inf : context.fileSystem().inputFiles(and)) {
files.add(inf.file());
}
diff --git a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasReportParser.java b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasReportParser.java
index ff4bb570..aa8daf8d 100644
--- a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasReportParser.java
+++ b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasReportParser.java
@@ -25,8 +25,8 @@
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.rule.RuleKey;
import java.io.File;
@@ -91,15 +91,20 @@ private void recordIssue(final JSONObject diagnosticJson) {
}
InputFile inputFile = context.fileSystem().inputFile(fp);
- NewIssueLocation dil = new DefaultIssueLocation()
+ NewIssue issue = context.newIssue();
+
+ NewIssueLocation issueLocation = issue.newLocation()
+ .message(info)
.on(inputFile)
- .at(inputFile.selectLine(lineNum))
- .message(info);
- context.newIssue()
+ .at(inputFile.selectLine(lineNum));
+
+ issue
.forRule(RuleKey.of(FauxPasRulesDefinition.REPOSITORY_KEY, (String) diagnosticJson.get("ruleShortName")))
- .at(dil)
- .save();
+ .at(issueLocation);
+
+ issue.save();
+
}
}
-}
\ No newline at end of file
+}
diff --git a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasSensor.java b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasSensor.java
index 75864049..408827a1 100644
--- a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasSensor.java
+++ b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/fauxpas/FauxPasSensor.java
@@ -22,13 +22,10 @@
import org.apache.tools.ant.DirectoryScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.config.Settings;
import java.io.File;
@@ -43,20 +40,6 @@ public FauxPasSensor(SensorContext context) {
this.context = context;
}
- private void parseReportIn(final String baseDir, final FauxPasReportParser parser) {
- DirectoryScanner scanner = new DirectoryScanner();
- scanner.setIncludes(new String[]{reportPath()});
- scanner.setBasedir(baseDir);
- scanner.setCaseSensitive(false);
- scanner.scan();
- String[] files = scanner.getIncludedFiles();
-
- for (String filename : files) {
- LOGGER.info("Processing FauxPas report {}", filename);
- parser.parseReport(new File(filename));
- }
- }
-
private String reportPath() {
return context.config()
.get(REPORT_PATH_KEY)
@@ -73,9 +56,17 @@ public void describe(SensorDescriptor descriptor) {
@Override
public void execute(SensorContext context) {
- final String projectBaseDir = context.fileSystem().baseDir().getAbsolutePath();
-
FauxPasReportParser parser = new FauxPasReportParser(context);
- parseReportIn(projectBaseDir, parser);
+ DirectoryScanner scanner = new DirectoryScanner();
+ scanner.setIncludes(new String[]{reportPath()});
+ scanner.setBasedir(context.fileSystem().baseDir().getAbsolutePath());
+ scanner.setCaseSensitive(false);
+ scanner.scan();
+ String[] files = scanner.getIncludedFiles();
+
+ for (String filename : files) {
+ LOGGER.info("Processing FauxPas report {}", filename);
+ parser.parseReport(new File(filename));
+ }
}
}
diff --git a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintParser.java b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintParser.java
index 6d79b8b0..01360d1e 100644
--- a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintParser.java
+++ b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintParser.java
@@ -22,8 +22,8 @@
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.rule.RuleKey;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -88,24 +88,26 @@ private void collectFileViolations(String filePath, NodeList nodeList) {
FilePredicate fp = context.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath());
if(!context.fileSystem().hasFiles(fp)){
LOGGER.warn("file not included in sonar {}", filePath);
- } else {
- InputFile inputFile = context.fileSystem().inputFile(fp);
- for (int i = 0; i < nodeList.getLength(); i++) {
- Node node = nodeList.item(i);
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- Element element = (Element) node;
- NewIssueLocation dil = new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(Integer.valueOf(element.getAttribute(LINE))))
- .message(element.getTextContent());
- context.newIssue()
- .forRule(RuleKey.of(OCLintRulesDefinition.REPOSITORY_KEY, element.getAttribute(RULE)))
- .at(dil)
- .save();
- }
- }
+ return;
}
+ InputFile inputFile = context.fileSystem().inputFile(fp);
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+
+ NewIssue issue = context.newIssue();
+ NewIssueLocation issueLocation = issue.newLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(Integer.valueOf(element.getAttribute(LINE))))
+ .message(element.getTextContent());
+ issue
+ .forRule(RuleKey.of(OCLintRulesDefinition.REPOSITORY_KEY, element.getAttribute(RULE)))
+ .at(issueLocation)
+ .save();
+ }
+ }
}
}
diff --git a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintXMLStreamHandler.java b/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintXMLStreamHandler.java
deleted file mode 100644
index 592501f8..00000000
--- a/objclang/src/main/java/com/backelite/sonarqube/objectivec/issues/oclint/OCLintXMLStreamHandler.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Swift SonarQube Plugin - Objective-C module - Enables analysis of Swift and Objective-C projects into SonarQube.
- * Copyright © 2015 Backelite (${email})
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package com.backelite.sonarqube.objectivec.issues.oclint;
-
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.component.ResourcePerspectives;
-import org.sonar.api.issue.Issuable;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.StaxParser.XmlStreamHandler;
-
-import javax.xml.stream.XMLStreamException;
-import java.io.File;
-
-final class OCLintXMLStreamHandler implements XmlStreamHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(OCLintXMLStreamHandler.class);
- private static final int PMD_MINIMUM_PRIORITY = 5;
- private final ResourcePerspectives resourcePerspectives;
- private final FileSystem fileSystem;
-
- public OCLintXMLStreamHandler(final ResourcePerspectives resourcePerspectives, final FileSystem fileSystem) {
- this.resourcePerspectives = resourcePerspectives;
- this.fileSystem = fileSystem;
- }
-
- public void stream(final SMHierarchicCursor rootCursor) throws XMLStreamException {
-
- final SMInputCursor file = rootCursor.advance().childElementCursor("file");
- while (null != file.getNext()) {
- collectIssuesFor(file);
- }
- }
-
- private void collectIssuesFor(final SMInputCursor file) throws XMLStreamException {
-
- final String filePath = file.getAttrValue("name");
- LoggerFactory.getLogger(getClass()).debug("Collection issues for {}", filePath);
- final InputFile inputFile = findResource(filePath);
- if (fileExists(inputFile)) {
- LoggerFactory.getLogger(getClass()).debug("File {} was found in the project.", filePath);
- collectFileIssues(inputFile, file);
- }
- }
-
- private void collectFileIssues(final InputFile inputFile, final SMInputCursor file) throws XMLStreamException {
-
- final SMInputCursor line = file.childElementCursor("violation");
-
- while (null != line.getNext()) {
- recordViolation(inputFile, line);
- }
- }
-
- private InputFile findResource(final String filePath) {
-
- File file = new File(filePath);
- return fileSystem.inputFile(fileSystem.predicates().hasAbsolutePath(file.getAbsolutePath()));
-
- }
-
- private void recordViolation(InputFile inputFile, final SMInputCursor line) throws XMLStreamException {
-
- Issuable issuable = resourcePerspectives.as(Issuable.class, inputFile);
-
- if (issuable != null) {
-
- Issue issue = issuable.newIssueBuilder()
- .ruleKey(RuleKey.of(OCLintRulesDefinition.REPOSITORY_KEY, line.getAttrValue("rule")))
- .line(Integer.valueOf(line.getAttrValue("beginline")))
- .message(line.getElemStringValue())
- .build();
-
- try {
- issuable.addIssue(issue);
- } catch (Exception e) {
- // Unable to add issue : probably because does not exist in the repository
- LOGGER.warn(e.getMessage());
- }
-
-
- }
- }
-
- private boolean fileExists(InputFile file) {
- if (file == null) {
- return false;
- }
-
- return file.file().exists();
- }
-
-}
diff --git a/objclang/src/main/resources/org/sonar/plugins/oclint/profile-oclint.xml b/objclang/src/main/resources/org/sonar/plugins/oclint/profile-oclint.xml
index 3c7b24e5..e34ca67d 100755
--- a/objclang/src/main/resources/org/sonar/plugins/oclint/profile-oclint.xml
+++ b/objclang/src/main/resources/org/sonar/plugins/oclint/profile-oclint.xml
@@ -27,6 +27,18 @@
OCLint
collapsible if statements
+
+ OCLint
+ compiler error
+
+
+ OCLint
+ compiler warning
+
+
+ OCLint
+ clang static analyzer
+
OCLint
constant conditional operator
diff --git a/objclang/src/main/resources/org/sonar/plugins/oclint/rules.txt b/objclang/src/main/resources/org/sonar/plugins/oclint/rules.txt
index 3304844d..e82e92bd 100755
--- a/objclang/src/main/resources/org/sonar/plugins/oclint/rules.txt
+++ b/objclang/src/main/resources/org/sonar/plugins/oclint/rules.txt
@@ -54,6 +54,30 @@ Category: OCLint
constant conditional operator
----------
+Summary: Name: compiler error
+
+Severity: 2
+Category: OCLint
+
+compiler error
+----------
+
+Summary: Name: compiler warning
+
+Severity: 3
+Category: OCLint
+
+compiler warning
+----------
+
+Summary: Name: clang static analyzer
+
+Severity: 3
+Category: OCLint
+
+clang static analyzer
+----------
+
Summary: Name: constant conditional operator
Severity: 3
@@ -70,7 +94,7 @@ Category: OCLint
high cyclomatic complexity
----------
-Summary:
+Summary:
Severity: 2
Category: OCLint
@@ -158,7 +182,7 @@ Category: OCLint
empty while statement
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -166,7 +190,7 @@ Category: OCLint
feature envy
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -182,7 +206,7 @@ Category: OCLint
goto statement
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -246,7 +270,7 @@ Category: OCLint
misplaced nil check
----------
-Summary:
+Summary:
Severity: 4
Category: OCLint
@@ -270,7 +294,7 @@ Category: OCLint
must override hash with isEqual
----------
-Summary:
+Summary:
Severity: 1
Category: OCLint
@@ -302,7 +326,7 @@ Category: OCLint
high npath complexity
----------
-Summary:
+Summary:
Severity: 2
Category: OCLint
@@ -358,7 +382,7 @@ Category: OCLint
short variable name
----------
-Summary:
+Summary:
Severity: 2
Category: OCLint
@@ -366,7 +390,7 @@ Category: OCLint
switch statements don't need default when fully covered
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -374,7 +398,7 @@ Category: OCLint
throw exception from finally block
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -382,7 +406,7 @@ Category: OCLint
too few branches in switch statement
----------
-Summary:
+Summary:
Severity: 2
Category: OCLint
@@ -406,7 +430,7 @@ Category: OCLint
too many parameters
----------
-Summary:
+Summary:
Severity: 3
Category: OCLint
@@ -430,7 +454,7 @@ Category: OCLint
unused method parameter
----------
-Summary:
+Summary:
Severity: 0
Category: OCLint
@@ -438,7 +462,7 @@ Category: OCLint
useless parentheses
----------
-Summary:
+Summary:
Severity: 1
Category: OCLint
@@ -526,7 +550,7 @@ Category: OCLint
use object subscripting
----------
-Summary:
+Summary:
Severity: 1
Category: OCLint
@@ -561,5 +585,4 @@ missing abstract method implementation
Summary: Name: missing abstract method implementation
Severity: 1
-Category: OCLint
-
+Category: OCLint
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0405d855..1281cc8f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,7 +39,7 @@
com.backelite.sonarqube
backelite-swift
- 0.4.4
+ 0.4.5-develop2
pom
@@ -88,7 +88,7 @@
true
- 6.7
+ 7.0
3.5.2
17.0
@@ -96,12 +96,13 @@
1.0.13
1.9.0
1.7.21
- 6.7
- 3.22.0.1791
- 4.0.0.2052
+ 7.7
+ 3.24.0.1993
+ 4.1.0.2218
1.23
2.6.1
1.6
+ 1.1.1
@@ -165,7 +166,7 @@
com.googlecode.json-simple
json-simple
- 1.1.1
+ ${json-simple.version}
diff --git a/sonar-swift-plugin/pom.xml b/sonar-swift-plugin/pom.xml
index e941627d..e57c63ea 100644
--- a/sonar-swift-plugin/pom.xml
+++ b/sonar-swift-plugin/pom.xml
@@ -26,12 +26,11 @@
com.backelite.sonarqube
backelite-swift
- 0.4.4
+ 0.4.5-develop2
- com.backelite.sonarqube
backelite-sonar-swift-plugin
- 0.4.4
+ 0.4.5-develop2
sonar-plugin
@@ -40,12 +39,12 @@
com.backelite.sonarqube
swift-lang
- 0.4.4
+ 0.4.5-develop2
com.backelite.sonarqube
objc-lang
- 0.4.4
+ 0.4.5-develop2
@@ -67,12 +66,12 @@
junit
junit
- compile
+ test
org.mockito
mockito-all
- compile
+ test
org.assertj
@@ -85,7 +84,7 @@
org.sonarsource.sslr
sslr-testing-harness
- compile
+ test
org.sonarsource.sonarlint.core
@@ -123,6 +122,7 @@
maven-shade-plugin
+ 3.2.0
package
diff --git a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardReportParser.java b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardReportParser.java
index 3fb4b46f..8d577aa5 100644
--- a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardReportParser.java
+++ b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardReportParser.java
@@ -20,8 +20,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.InputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.measures.CoreMetrics;
import org.w3c.dom.Document;
@@ -36,6 +37,7 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.Optional;
public class LizardReportParser {
private static final Logger LOGGER = LoggerFactory.getLogger(LizardReportParser.class);
@@ -96,11 +98,11 @@ private void updateIndexes(NodeList nodeList) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
String label = element.getTextContent();
- if(LINE_COUNT_LABEL.equalsIgnoreCase(label))
+ if (LINE_COUNT_LABEL.equalsIgnoreCase(label))
lineCountIndex = i;
- else if(CYCLOMATIC_COMPLEXITY_LABEL.equalsIgnoreCase(label))
+ else if (CYCLOMATIC_COMPLEXITY_LABEL.equalsIgnoreCase(label))
cyclomaticComplexityIndex = i;
- else if(FUNCTION_COUNT_LABEL.equalsIgnoreCase(label))
+ else if (FUNCTION_COUNT_LABEL.equalsIgnoreCase(label))
functionCountIndex = i;
}
}
@@ -115,22 +117,62 @@ private void parseMeasure(String type, NodeList itemList) {
NodeList values = itemElement.getElementsByTagName(VALUE);
if (FILE_MEASURE.equalsIgnoreCase(type)) {
- addComplexityFileMeasures(name,values);
+ Optional.ofNullable(getFile(name)).ifPresent(inputFile -> addComplexityFileMeasures(inputFile, values));
} else if (FUNCTION_MEASURE.equalsIgnoreCase(type)) {
- addComplexityFunctionMeasures(new SwiftFunction(name),values);
+ addComplexityFunctionMeasures(new SwiftFunction(0,name), values);
}
}
}
}
- private void addComplexityFileMeasures(String fileName, NodeList values) {
+ private InputFile getFile(String fileName){
FilePredicate fp = context.fileSystem().predicates().hasRelativePath(fileName);
- if(!context.fileSystem().hasFiles(fp)){
+ if (!context.fileSystem().hasFiles(fp)) {
LOGGER.warn("file not included in sonar {}", fileName);
- return;
+ return null;
}
- InputFile component = context.fileSystem().inputFile(fp);
+ return context.fileSystem().inputFile(fp);
+ }
+
+ static class SwiftFunction extends DefaultInputComponent implements InputComponent {
+ private String name;
+ private String key;
+ private String file;
+ private int lineNumber;
+ SwiftFunction(int scannerId, String name) {
+ super(scannerId);
+ String[] vals = name.split(" at ");
+ if (vals.length >= 2) {
+ this.name = vals[0].replaceAll("\\W","");
+
+ if (vals[1].contains(":")) {
+ String[] sp = vals[1].split(":");
+ this.file = sp[0].substring(0,sp[0].lastIndexOf("."));
+ this.lineNumber = Integer.parseInt(sp[1]);
+ } else {
+ this.file = vals[1];
+ this.lineNumber = 0;
+ }
+
+ this.key = String.format("%s.%s:%d", this.file, this.name, this.lineNumber);
+ } else {
+ this.key = name;
+ }
+ }
+ @Override
+ public String key() {
+ return key;
+ }
+ @Override
+ public boolean isFile() {
+ return false;
+ }
+ }
+
+ private void addComplexityFileMeasures(InputFile component, NodeList values) {
+ LOGGER.debug("File measures for {}",component.toString());
int complexity = Integer.parseInt(values.item(cyclomaticComplexityIndex).getTextContent());
+
context.newMeasure()
.on(component)
.forMetric(CoreMetrics.COMPLEXITY)
@@ -152,7 +194,8 @@ private void addComplexityFileMeasures(String fileName, NodeList values) {
.save();
}
- private void addComplexityFunctionMeasures(SwiftFunction component, NodeList values) {
+ private void addComplexityFunctionMeasures(InputComponent component, NodeList values) {
+ LOGGER.debug("Function measures for {}",component.key());
int complexity = Integer.parseInt(values.item(cyclomaticComplexityIndex).getTextContent());
context.newMeasure()
.on(component)
@@ -167,45 +210,4 @@ private void addComplexityFunctionMeasures(SwiftFunction component, NodeList val
.withValue(numberOfLines)
.save();
}
-
- private static class SwiftFunction implements InputModule {
- private String name;
- private String key;
- private String file;
- private int lineNumber;
-
- public SwiftFunction(String name) {
- String[] vals = name.split(" ");
- if(vals.length >= 3){
- this.name = vals[0].substring(0,vals[0].indexOf("("));
- this.file = vals[2].substring(0,vals[2].lastIndexOf(":"));
- this.lineNumber = Integer.parseInt(vals[2].substring(vals[2].lastIndexOf(":")+1));
- this.key = file.substring(0,file.lastIndexOf('.')+1)+name;
- }else{
- this.key = name;
- }
- }
-
- @Override
- public String key() {
- return key;
- }
-
- public String getName(){
- return name;
- }
-
- public String getFile(){
- return file;
- }
-
- public int getLineNumber(){
- return lineNumber;
- }
-
- @Override
- public boolean isFile() {
- return false;
- }
- }
}
diff --git a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardSensor.java b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardSensor.java
index 56b11801..6896fcb9 100644
--- a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardSensor.java
+++ b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/complexity/LizardSensor.java
@@ -56,10 +56,14 @@ public void describe(SensorDescriptor descriptor) {
@Override
public void execute(SensorContext context) {
- String reportFileName = context.fileSystem().baseDir().getPath() + File.separator + reportPath();
- LOGGER.info("Processing complexity report: {}",reportFileName);
+ File reportFile = new File(context.fileSystem().baseDir(), reportPath());
+ if (!reportFile.isFile()) {
+ LOGGER.warn("Lizard report file not found at {}", reportFile.getAbsolutePath());
+ return;
+ }
+ LOGGER.info("Processing complexity report: {}", reportFile.getAbsolutePath());
LizardReportParser parser = new LizardReportParser(context);
- parser.parseReport(new File(reportFileName));
+ parser.parseReport(reportFile);
}
}
diff --git a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/coverage/CoberturaReportParser.java b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/coverage/CoberturaReportParser.java
index 1d24c1e8..453612dd 100644
--- a/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/coverage/CoberturaReportParser.java
+++ b/sonar-swift-plugin/src/main/java/com/backelite/sonarqube/swift/coverage/CoberturaReportParser.java
@@ -36,7 +36,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
-public final class CoberturaReportParser {
+final class CoberturaReportParser {
+
private static final Logger LOGGER = LoggerFactory.getLogger(CoberturaReportParser.class);
private static final String PACKAGES = "packages";
private static final String CLASSES = "class";
diff --git a/sonar-swift-plugin/src/main/shell/run-sonar-swift.sh b/sonar-swift-plugin/src/main/shell/run-sonar-swift.sh
index 44640803..9a06f933 100755
--- a/sonar-swift-plugin/src/main/shell/run-sonar-swift.sh
+++ b/sonar-swift-plugin/src/main/shell/run-sonar-swift.sh
@@ -283,7 +283,7 @@ if [[ "$workspaceFile" != "" ]] ; then
else
buildCmdPrefix="-project $projectFile"
fi
-buildCmd=($XCODEBUILD_CMD clean build $buildCmdPrefix -scheme $appScheme)
+buildCmd=($XCODEBUILD_CMD clean build $buildCmdPrefix -scheme "$appScheme")
if [[ ! -z "$destinationSimulator" ]]; then
buildCmd+=(-destination "$destinationSimulator" -destination-timeout 360 COMPILER_INDEX_STORE_ENABLE=NO)
fi
@@ -445,7 +445,7 @@ if [ "$fauxpas" = "on" ] && [ "$hasObjC" = "yes" ]; then
if [ "$projectCount" = "1" ]
then
- fauxpas -o json check $projectFile --workspace $workspaceFile --scheme $appScheme > sonar-reports/fauxpas.json
+ fauxpas -o json check $projectFile --workspace $workspaceFile --scheme "$appScheme" > sonar-reports/fauxpas.json
else
diff --git a/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/LizardReportParserTest.java b/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/LizardReportParserTest.java
new file mode 100644
index 00000000..5b6e4531
--- /dev/null
+++ b/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/LizardReportParserTest.java
@@ -0,0 +1,98 @@
+/**
+ * backelite-sonar-swift-plugin - Enables analysis of Swift and Objective-C projects into SonarQube.
+ * Copyright © 2015 Backelite (${email})
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package com.backelite.sonarqube.swift;
+
+import com.backelite.sonarqube.swift.complexity.LizardReportParser;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.fs.*;
+import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.measure.NewMeasure;
+
+import java.io.File;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LizardReportParserTest {
+
+ @Mock
+ SensorContext sensorContext;
+
+ @Mock
+ FileSystem fileSystem;
+
+ @Mock
+ FilePredicates filePredicates;
+
+ @Mock
+ FilePredicate filePredicate;
+
+ @Mock
+ InputFile inputFile;
+
+ @Mock
+ NewMeasure newMeasure;
+
+ @Captor
+ ArgumentCaptor hasRelativePathCaptor;
+
+ @Captor
+ ArgumentCaptor onCaptor;
+
+ @Captor
+ ArgumentCaptor> forMetricCaptor;
+
+ @Captor
+ ArgumentCaptor withValueCaptor;
+
+
+ @Test
+ public void parseSimpleFile() {
+
+ LizardReportParser parser = new LizardReportParser(sensorContext);
+ File xmlFile = new File("src/test/resources/lizard-report.xml");
+
+ when(sensorContext.newMeasure()).thenReturn(newMeasure);
+ when(newMeasure.on(onCaptor.capture())).thenReturn(newMeasure);
+ when(newMeasure.forMetric(forMetricCaptor.capture())).thenReturn(newMeasure);
+ when(newMeasure.withValue(withValueCaptor.capture())).thenReturn(newMeasure);
+
+ when(sensorContext.fileSystem()).thenReturn(fileSystem);
+ when(fileSystem.predicates()).thenReturn(filePredicates);
+ when(filePredicates.hasRelativePath(hasRelativePathCaptor.capture())).thenReturn(filePredicate);
+ when(fileSystem.hasFiles(filePredicate)).thenReturn(true);
+ when(fileSystem.inputFile(filePredicate)).thenReturn(inputFile);
+
+ parser.parseReport(xmlFile);
+
+ assertEquals(5, onCaptor.getAllValues().size());
+ assertEquals(5, forMetricCaptor.getAllValues().size());
+
+ assertEquals(Arrays.asList(1, 4, 8, 5, 46), withValueCaptor.getAllValues());
+ assertEquals(Arrays.asList("./Folder With Space/File With Space.swift"), hasRelativePathCaptor.getAllValues());
+ }
+
+}
diff --git a/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/complexity/LizardReportParserTest.java b/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/complexity/LizardReportParserTest.java
new file mode 100644
index 00000000..8ffaed19
--- /dev/null
+++ b/sonar-swift-plugin/src/test/java/com/backelite/sonarqube/swift/complexity/LizardReportParserTest.java
@@ -0,0 +1,97 @@
+/**
+ * backelite-sonar-swift-plugin - Enables analysis of Swift and Objective-C projects into SonarQube.
+ * Copyright © 2015 Backelite (${email})
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package com.backelite.sonarqube.swift.complexity;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.fs.*;
+import org.sonar.api.batch.measure.Metric;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.measure.NewMeasure;
+
+import java.io.File;
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LizardReportParserTest {
+
+ @Mock
+ SensorContext sensorContext;
+
+ @Mock
+ FileSystem fileSystem;
+
+ @Mock
+ FilePredicates filePredicates;
+
+ @Mock
+ FilePredicate filePredicate;
+
+ @Mock
+ InputFile inputFile;
+
+ @Mock
+ NewMeasure newMeasure;
+
+ @Captor
+ ArgumentCaptor hasRelativePathCaptor;
+
+ @Captor
+ ArgumentCaptor onCaptor;
+
+ @Captor
+ ArgumentCaptor> forMetricCaptor;
+
+ @Captor
+ ArgumentCaptor withValueCaptor;
+
+
+ @Test
+ public void parseSimpleFile() {
+
+ LizardReportParser parser = new LizardReportParser(sensorContext);
+ File xmlFile = new File("src/test/resources/lizard-report.xml");
+
+ when(sensorContext.newMeasure()).thenReturn(newMeasure);
+ when(newMeasure.on(onCaptor.capture())).thenReturn(newMeasure);
+ when(newMeasure.forMetric(forMetricCaptor.capture())).thenReturn(newMeasure);
+ when(newMeasure.withValue(withValueCaptor.capture())).thenReturn(newMeasure);
+
+ when(sensorContext.fileSystem()).thenReturn(fileSystem);
+ when(fileSystem.predicates()).thenReturn(filePredicates);
+ when(filePredicates.hasRelativePath(hasRelativePathCaptor.capture())).thenReturn(filePredicate);
+ when(fileSystem.hasFiles(filePredicate)).thenReturn(true);
+ when(fileSystem.inputFile(filePredicate)).thenReturn(inputFile);
+
+ parser.parseReport(xmlFile);
+
+ assertEquals(5, onCaptor.getAllValues().size());
+ assertEquals(5, forMetricCaptor.getAllValues().size());
+
+ assertEquals(Arrays.asList(1, 4, 8, 5, 46), withValueCaptor.getAllValues());
+ assertEquals(Arrays.asList("./Folder With Space/File With Space.swift"), hasRelativePathCaptor.getAllValues());
+ }
+
+}
\ No newline at end of file
diff --git a/sonar-swift-plugin/src/test/resources/coverage/dir3/cobertura.xml b/sonar-swift-plugin/src/test/resources/coverage/dir3/cobertura.xml
deleted file mode 100644
index e69de29b..00000000
diff --git a/sonar-swift-plugin/src/test/resources/lizard-report.xml b/sonar-swift-plugin/src/test/resources/lizard-report.xml
new file mode 100644
index 00000000..04693b13
--- /dev/null
+++ b/sonar-swift-plugin/src/test/resources/lizard-report.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ -
+ 1
+ 4
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ -
+ 1
+ 46
+ 8
+ 5
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/swiftlang/pom.xml b/swiftlang/pom.xml
index 2adbbae2..1d31dd7b 100644
--- a/swiftlang/pom.xml
+++ b/swiftlang/pom.xml
@@ -24,7 +24,7 @@
backelite-swift
com.backelite.sonarqube
- 0.4.4
+ 0.4.5-develop2
4.0.0
@@ -36,7 +36,7 @@
com.backelite.sonarqube
commons
- 0.4.4
+ 0.4.5-develop2
diff --git a/swiftlang/src/main/java/com/backelite/sonarqube/swift/SwiftSquidSensor.java b/swiftlang/src/main/java/com/backelite/sonarqube/swift/SwiftSquidSensor.java
index 0fc4edf3..52433534 100644
--- a/swiftlang/src/main/java/com/backelite/sonarqube/swift/SwiftSquidSensor.java
+++ b/swiftlang/src/main/java/com/backelite/sonarqube/swift/SwiftSquidSensor.java
@@ -33,7 +33,6 @@
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.filesystem.PathResolver;
@@ -82,7 +81,6 @@ private void save(Collection squidSourceFiles) {
}
private void saveMeasures(InputFile inputFile, SourceFile squidFile) {
- MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.FILES, squidFile.getInt(SwiftMetric.FILES));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.LINES, squidFile.getInt(SwiftMetric.LINES));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.NCLOC, squidFile.getInt(SwiftMetric.LINES_OF_CODE));
MeasureUtil.saveMeasure(context, inputFile, CoreMetrics.STATEMENTS, squidFile.getInt(SwiftMetric.STATEMENTS));
@@ -97,14 +95,17 @@ private void saveIssues(InputFile inputFile, SourceFile squidFile) {
RuleKey ruleKey = checks.ruleKey((SquidCheck) message.getCheck());
NewIssue issue = context.newIssue()
.forRule(ruleKey);
- NewIssueLocation dil = new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(message.getLine()))
- .message(message.getText(Locale.ENGLISH));
+
+ NewIssueLocation dil = issue.newLocation()
+ .message(message.getText(Locale.ENGLISH))
+ .on(inputFile)
+ .at(inputFile.selectLine(message.getLine()));
issue.at(dil);
+
if (message.getCost() != null) {
issue.gap(message.getCost());
}
+
issue.save();
}
}
diff --git a/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/swiftlint/SwiftLintReportParser.java b/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/swiftlint/SwiftLintReportParser.java
index 14bc9b98..0661345e 100644
--- a/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/swiftlint/SwiftLintReportParser.java
+++ b/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/swiftlint/SwiftLintReportParser.java
@@ -22,8 +22,8 @@
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.rule.RuleKey;
import java.io.*;
@@ -68,13 +68,15 @@ private void recordIssue(final String line) {
}
InputFile inputFile = context.fileSystem().inputFile(fp);
- NewIssueLocation dil = new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(lineNum))
- .message(message);
- context.newIssue()
- .forRule(RuleKey.of(SwiftLintRulesDefinition.REPOSITORY_KEY, ruleId))
- .at(dil)
+ NewIssue issue = context.newIssue();
+
+ NewIssueLocation issueLocation = issue.newLocation()
+ .message(message)
+ .on(inputFile)
+ .at(inputFile.selectLine(lineNum));
+
+ issue.forRule(RuleKey.of(SwiftLintRulesDefinition.REPOSITORY_KEY, ruleId))
+ .at(issueLocation)
.save();
}
}
diff --git a/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/tailor/TailorReportParser.java b/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/tailor/TailorReportParser.java
index 4c3d8e53..806c202b 100644
--- a/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/tailor/TailorReportParser.java
+++ b/swiftlang/src/main/java/com/backelite/sonarqube/swift/issues/tailor/TailorReportParser.java
@@ -22,8 +22,8 @@
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation;
import org.sonar.api.rule.RuleKey;
import java.io.*;
@@ -73,13 +73,16 @@ private void recordIssue(final String line) {
}
InputFile inputFile = context.fileSystem().inputFile(fp);
- NewIssueLocation dil = new DefaultIssueLocation()
- .on(inputFile)
- .at(inputFile.selectLine(lineNum))
- .message(message);
- context.newIssue()
+ NewIssue issue = context.newIssue();
+
+ NewIssueLocation issueLocation = issue.newLocation()
+ .message(message)
+ .on(inputFile)
+ .at(inputFile.selectLine(lineNum));
+
+ issue
.forRule(RuleKey.of(TailorRulesDefinition.REPOSITORY_KEY, ruleId))
- .at(dil)
+ .at(issueLocation)
.save();
}
}
diff --git a/swiftlang/src/main/java/com/backelite/sonarqube/swift/lang/SwiftFileSystem.java b/swiftlang/src/main/java/com/backelite/sonarqube/swift/lang/SwiftFileSystem.java
index b00f0418..82ba8ef4 100644
--- a/swiftlang/src/main/java/com/backelite/sonarqube/swift/lang/SwiftFileSystem.java
+++ b/swiftlang/src/main/java/com/backelite/sonarqube/swift/lang/SwiftFileSystem.java
@@ -18,18 +18,17 @@
package com.backelite.sonarqube.swift.lang;
import com.backelite.sonarqube.swift.lang.core.Swift;
-import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.FilePredicate;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.scanner.ScannerSide;
import javax.annotation.CheckForNull;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
-
@ScannerSide
public class SwiftFileSystem {
@@ -49,10 +48,10 @@ public boolean hasSwiftFiles() {
return fileSystem.hasFiles(isSwiftLanguage);
}
- public List sourceFiles() {
- Iterable files = fileSystem.files(predicates.and(isSwiftLanguage, isMainTypeFile));
- List list = new ArrayList<>();
- files.iterator().forEachRemaining(list::add);
+ public List sourceFiles() {
+ Iterable inputFiles = fileSystem.inputFiles(predicates.and(isSwiftLanguage, isMainTypeFile));
+ List list = new ArrayList<>();
+ inputFiles.iterator().forEachRemaining(list::add);
return list;
}
diff --git a/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/profile-swiftlint.xml b/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/profile-swiftlint.xml
index f5937220..80dfd4b6 100644
--- a/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/profile-swiftlint.xml
+++ b/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/profile-swiftlint.xml
@@ -27,6 +27,10 @@
SwiftLint
closing_brace
+
+ SwiftLint
+ closure_body_length
+
SwiftLint
closure_end_indentation
@@ -39,6 +43,10 @@
SwiftLint
closure_spacing
+
+ SwiftLint
+ collection_alignment
+
SwiftLint
colon
@@ -75,6 +83,10 @@
SwiftLint
cyclomatic_complexity
+
+ SwiftLint
+ deployment_target
+
SwiftLint
discarded_notification_center_observer
@@ -95,6 +107,10 @@
SwiftLint
discouraged_optional_collection
+
+ SwiftLint
+ duplicate_imports
+
SwiftLint
dynamic_inline
@@ -135,6 +151,10 @@
SwiftLint
explicit_init
+
+ SwiftLint
+ explicit_self
+
SwiftLint
explicit_top_level_acl
@@ -203,6 +223,10 @@
SwiftLint
generic_type_name
+
+ SwiftLint
+ identical_operands
+
SwiftLint
identifier_name
@@ -219,6 +243,10 @@
SwiftLint
implicitly_unwrapped_optional
+
+ SwiftLint
+ inert_defer
+
SwiftLint
is_disjoint
@@ -231,6 +259,10 @@
SwiftLint
large_tuple
+
+ SwiftLint
+ last_where
+
SwiftLint
leading_whitespace
@@ -247,10 +279,18 @@
SwiftLint
legacy_constructor
+
+ SwiftLint
+ legacy_hashing
+
SwiftLint
legacy_nsgeometry_functions
+
+ SwiftLint
+ legacy_random
+
SwiftLint
let_var_whitespace
@@ -283,14 +323,26 @@
SwiftLint
multiline_arguments
+
+ SwiftLint
+ multiline_arguments_brackets
+
SwiftLint
multiline_function_chains
+
+ SwiftLint
+ multiline_literal_brackets
+
SwiftLint
multiline_parameters
+
+ SwiftLint
+ multiline_parameters_brackets
+
SwiftLint
multiple_closures_with_trailing_closure
@@ -319,6 +371,10 @@
SwiftLint
notification_center_detachment
+
+ SwiftLint
+ nslocalizedstring_key
+
SwiftLint
number_separator
@@ -371,6 +427,10 @@
SwiftLint
private_unit_test
+
+ SwiftLint
+ prohibited_interface_builder
+
SwiftLint
prohibited_super_call
@@ -399,6 +459,10 @@
SwiftLint
redundant_nil_coalescing
+
+ SwiftLint
+ redundant_objc_attribute
+
SwiftLint
redundant_optional_initialization
@@ -419,6 +483,10 @@
SwiftLint
redundant_void_return
+
+ SwiftLint
+ required_deinit
+
SwiftLint
required_enum_case
@@ -447,10 +515,18 @@
SwiftLint
statement_position
+
+ SwiftLint
+ static_operator
+
SwiftLint
strict_fileprivate
+
+ SwiftLint
+ strong_iboutlet
+
SwiftLint
superfluous_disable_command
@@ -471,6 +547,10 @@
SwiftLint
todo
+
+ SwiftLint
+ toggle_bool
+
SwiftLint
trailing_closure
@@ -519,14 +599,30 @@
SwiftLint
unused_closure_parameter
+
+ SwiftLint
+ unused_control_flow_label
+
SwiftLint
unused_enumerated
+
+ SwiftLint
+ unused_import
+
SwiftLint
unused_optional_binding
+
+ SwiftLint
+ unused_private_declaration
+
+
+ SwiftLint
+ unused_setter_value
+
SwiftLint
valid_ibinspectable
@@ -543,14 +639,34 @@
SwiftLint
vertical_whitespace
+
+ SwiftLint
+ vertical_whitespace_between_cases
+
+
+ SwiftLint
+ vertical_whitespace_closing_braces
+
+
+ SwiftLint
+ vertical_whitespace_opening_braces
+
SwiftLint
void_return
+
+ SwiftLint
+ weak_computed_property
+
SwiftLint
weak_delegate
+
+ SwiftLint
+ xct_specific_matcher
+
SwiftLint
xctfail_message
diff --git a/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/rules.json b/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/rules.json
index f1b08ff3..e1762d17 100644
--- a/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/rules.json
+++ b/swiftlang/src/main/resources/org/sonar/plugins/swiftlint/rules.json
@@ -41,6 +41,13 @@
"description": "Closing brace with closing parenthesis should not have any whitespaces in the middle.",
"severity": "MINOR"
},
+ {
+ "key": "closure_body_length",
+ "category": "SwiftLint",
+ "name": "Closure Body Length",
+ "description": "Closure bodies should not span too many lines.",
+ "severity": "MAJOR"
+ },
{
"key": "closure_end_indentation",
"category": "SwiftLint",
@@ -62,6 +69,13 @@
"description": "Closure expressions should have a single space inside each brace.",
"severity": "MINOR"
},
+ {
+ "key": "collection_alignment",
+ "category": "SwiftLint",
+ "name": "Collection Element Alignment",
+ "description": "All elements in a collection literal should be vertically aligned",
+ "severity": "MINOR"
+ },
{
"key": "colon",
"category": "SwiftLint",
@@ -125,6 +139,13 @@
"description": "Complexity of function bodies should be limited.",
"severity": "CRITICAL"
},
+ {
+ "key": "deployment_target",
+ "category": "SwiftLint",
+ "name": "Deployment Target",
+ "description": "Availability checks or attributes shouldn't be using older versions that are satisfied by the deployment target.",
+ "severity": "MINOR"
+ },
{
"key": "discarded_notification_center_observer",
"category": "SwiftLint",
@@ -160,6 +181,13 @@
"description": "Prefer empty collection over optional collection.",
"severity": "MINOR"
},
+ {
+ "key": "duplicate_imports",
+ "category": "SwiftLint",
+ "name": "Duplicate Imports",
+ "description": "Imports should be unique.",
+ "severity": "MINOR"
+ },
{
"key": "dynamic_inline",
"category": "SwiftLint",
@@ -230,6 +258,13 @@
"description": "Explicitly calling .init() should be avoided.",
"severity": "MINOR"
},
+ {
+ "key": "explicit_self",
+ "category": "SwiftLint",
+ "name": "Explicit Self",
+ "description": "Instance variables and functions should be explicitly accessed with 'self.'.",
+ "severity": "MINOR"
+ },
{
"key": "explicit_top_level_acl",
"category": "SwiftLint",
@@ -349,6 +384,13 @@
"description": "Generic type name should only contain alphanumeric characters, start with an uppercase character and span between 1 and 20 characters in length.",
"severity": "MINOR"
},
+ {
+ "key": "identical_operands",
+ "category": "SwiftLint",
+ "name": "Identical Operands",
+ "description": "Comparing two identical operands is likely a mistake.",
+ "severity": "MINOR"
+ },
{
"key": "identifier_name",
"category": "SwiftLint",
@@ -377,6 +419,13 @@
"description": "Implicitly unwrapped optionals should be avoided when possible.",
"severity": "MINOR"
},
+ {
+ "key": "inert_defer",
+ "category": "SwiftLint",
+ "name": "Inert Defer",
+ "description": "If defer is at the end of its parent scope, it will be executed right where it is anyway.",
+ "severity": "MINOR"
+ },
{
"key": "is_disjoint",
"category": "SwiftLint",
@@ -398,6 +447,13 @@
"description": "Tuples shouldn't have too many members. Create a custom type instead.",
"severity": "MINOR"
},
+ {
+ "key": "last_where",
+ "category": "SwiftLint",
+ "name": "Last Where",
+ "description": "Prefer using `.last(where:)` over `.filter { }.last` in collections.",
+ "severity": "MINOR"
+ },
{
"key": "leading_whitespace",
"category": "SwiftLint",
@@ -426,6 +482,13 @@
"description": "Swift constructors are preferred over legacy convenience functions.",
"severity": "MINOR"
},
+ {
+ "key": "legacy_hashing",
+ "category": "SwiftLint",
+ "name": "Legacy Hashing",
+ "description": "Prefer using the `hash(into:)` function instead of overriding `hashValue`",
+ "severity": "MINOR"
+ },
{
"key": "legacy_nsgeometry_functions",
"category": "SwiftLint",
@@ -433,6 +496,13 @@
"description": "Struct extension properties and methods are preferred over legacy functions",
"severity": "MINOR"
},
+ {
+ "key": "legacy_random",
+ "category": "SwiftLint",
+ "name": "Legacy Random",
+ "description": "Prefer using `type.random(in:)` over legacy functions.",
+ "severity": "MINOR"
+ },
{
"key": "let_var_whitespace",
"category": "SwiftLint",
@@ -489,6 +559,13 @@
"description": "Arguments should be either on the same line, or one per line.",
"severity": "MINOR"
},
+ {
+ "key": "multiline_arguments_brackets",
+ "category": "SwiftLint",
+ "name": "Multiline Arguments Brackets",
+ "description": "Multiline arguments should have their surrounding brackets in a new line.",
+ "severity": "MINOR"
+ },
{
"key": "multiline_function_chains",
"category": "SwiftLint",
@@ -496,6 +573,13 @@
"description": "Chained function calls should be either on the same line, or one per line.",
"severity": "MINOR"
},
+ {
+ "key": "multiline_literal_brackets",
+ "category": "SwiftLint",
+ "name": "Multiline Literal Brackets",
+ "description": "Multiline literals should have their surrounding brackets in a new line.",
+ "severity": "MINOR"
+ },
{
"key": "multiline_parameters",
"category": "SwiftLint",
@@ -503,6 +587,13 @@
"description": "Functions and methods parameters should be either on the same line, or one per line.",
"severity": "MINOR"
},
+ {
+ "key": "multiline_parameters_brackets",
+ "category": "SwiftLint",
+ "name": "Multiline Parameters Brackets",
+ "description": "Multiline parameters should have their surrounding brackets in a new line.",
+ "severity": "MINOR"
+ },
{
"key": "multiple_closures_with_trailing_closure",
"category": "SwiftLint",
@@ -552,6 +643,13 @@
"description": "An object should only remove itself as an observer in `deinit`.",
"severity": "MINOR"
},
+ {
+ "key": "nslocalizedstring_key",
+ "category": "SwiftLint",
+ "name": "NSLocalizedString Key",
+ "description": "Static strings should be used as key in NSLocalizedString in order to genstrings work.",
+ "severity": "MINOR"
+ },
{
"key": "number_separator",
"category": "SwiftLint",
@@ -643,6 +741,13 @@
"description": "Unit tests marked private are silently skipped.",
"severity": "MINOR"
},
+ {
+ "key": "prohibited_interface_builder",
+ "category": "SwiftLint",
+ "name": "Prohibited Interface Builder",
+ "description": "Creating views using Interface Builder should be avoided.",
+ "severity": "MINOR"
+ },
{
"key": "prohibited_super_call",
"category": "SwiftLint",
@@ -692,6 +797,13 @@
"description": "nil coalescing operator is only evaluated if the lhs is nil, coalescing operator with nil as rhs is redundant",
"severity": "MINOR"
},
+ {
+ "key": "redundant_objc_attribute",
+ "category": "SwiftLint",
+ "name": "Redundant @objc Attribute",
+ "description": "Objective-C attribute (@objc) is redundant in declaration.",
+ "severity": "MINOR"
+ },
{
"key": "redundant_optional_initialization",
"category": "SwiftLint",
@@ -727,6 +839,13 @@
"description": "Returning Void in a function declaration is redundant.",
"severity": "MINOR"
},
+ {
+ "key": "required_deinit",
+ "category": "SwiftLint",
+ "name": "Required Deinit",
+ "description": "Classes should have an explicit deinit method.",
+ "severity": "MINOR"
+ },
{
"key": "required_enum_case",
"category": "SwiftLint",
@@ -776,6 +895,13 @@
"description": "Else and catch should be on the same line, one space after the previous declaration.",
"severity": "MINOR"
},
+ {
+ "key": "static_operator",
+ "category": "SwiftLint",
+ "name": "Static Operator",
+ "description": "Operators should be declared as static functions, not free functions.",
+ "severity": "MINOR"
+ },
{
"key": "strict_fileprivate",
"category": "SwiftLint",
@@ -783,6 +909,13 @@
"description": "`fileprivate` should be avoided.",
"severity": "MINOR"
},
+ {
+ "key": "strong_iboutlet",
+ "category": "SwiftLint",
+ "name": "Strong IBOutlet",
+ "description": "@IBOutlets shouldn't be declared as weak.",
+ "severity": "MINOR"
+ },
{
"key": "superfluous_disable_command",
"category": "SwiftLint",
@@ -818,6 +951,13 @@
"description": "TODOs and FIXMEs should be resolved.",
"severity": "MINOR"
},
+ {
+ "key": "toggle_bool",
+ "category": "SwiftLint",
+ "name": "Toggle Bool",
+ "description": "Prefer `someBool.toggle()` over `someBool = !someBool`.",
+ "severity": "MINOR"
+ },
{
"key": "trailing_closure",
"category": "SwiftLint",
@@ -902,6 +1042,13 @@
"description": "Unused parameter in a closure should be replaced with _.",
"severity": "MINOR"
},
+ {
+ "key": "unused_control_flow_label",
+ "category": "SwiftLint",
+ "name": "Unused Control Flow Label",
+ "description": "Unused control flow label should be removed.",
+ "severity": "MINOR"
+ },
{
"key": "unused_enumerated",
"category": "SwiftLint",
@@ -909,6 +1056,13 @@
"description": "When the index or the item is not used, `.enumerated()` can be removed.",
"severity": "MINOR"
},
+ {
+ "key": "unused_import",
+ "category": "SwiftLint",
+ "name": "Unused Import",
+ "description": "All imported modules should be required to make the file compile.",
+ "severity": "MINOR"
+ },
{
"key": "unused_optional_binding",
"category": "SwiftLint",
@@ -916,6 +1070,20 @@
"description": "Prefer `!= nil` over `let _ =`",
"severity": "MINOR"
},
+ {
+ "key": "unused_private_declaration",
+ "category": "SwiftLint",
+ "name": "Unused Private Declaration",
+ "description": "Private declarations should be referenced in that file.",
+ "severity": "MINOR"
+ },
+ {
+ "key": "unused_setter_value",
+ "category": "SwiftLint",
+ "name": "Unused Setter Value",
+ "description": "Setter value is not used.",
+ "severity": "MINOR"
+ },
{
"key": "valid_ibinspectable",
"category": "SwiftLint",
@@ -944,6 +1112,27 @@
"description": "Limit vertical whitespace to a single empty line.",
"severity": "MINOR"
},
+ {
+ "key": "vertical_whitespace_between_cases",
+ "category": "SwiftLint",
+ "name": "Vertical Whitespace Between Cases",
+ "description": "Include a single empty line between switch cases.",
+ "severity": "MINOR"
+ },
+ {
+ "key": "vertical_whitespace_closing_braces",
+ "category": "SwiftLint",
+ "name": "Vertical Whitespace before Closing Braces",
+ "description": "Don't include vertical whitespace (empty line) before closing braces.",
+ "severity": "MINOR"
+ },
+ {
+ "key": "vertical_whitespace_opening_braces",
+ "category": "SwiftLint",
+ "name": "Vertical Whitespace after Opening Braces",
+ "description": "Don't include vertical whitespace (empty line) after opening braces.",
+ "severity": "MINOR"
+ },
{
"key": "void_return",
"category": "SwiftLint",
@@ -951,6 +1140,13 @@
"description": "Prefer `-> Void` over `-> ()`.",
"severity": "MINOR"
},
+ {
+ "key": "weak_computed_property",
+ "category": "SwiftLint",
+ "name": "Weak Computed Property",
+ "description": "Adding weak to a computed property has no effect.",
+ "severity": "MINOR"
+ },
{
"key": "weak_delegate",
"category": "SwiftLint",
@@ -958,6 +1154,13 @@
"description": "Delegates should be weak to avoid reference cycles.",
"severity": "MINOR"
},
+ {
+ "key": "xct_specific_matcher",
+ "category": "SwiftLint",
+ "name": "XCTest Specific Matcher",
+ "description": "Prefer specific XCTest matchers over `XCTAssertEqual` and `XCTAssertNotEqual`",
+ "severity": "MINOR"
+ },
{
"key": "xctfail_message",
"category": "SwiftLint",