diff --git a/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlPlugin.java b/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlPlugin.java index 7b238270..856c6a8d 100644 --- a/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlPlugin.java +++ b/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlPlugin.java @@ -45,6 +45,12 @@ public void define(Context context) { .category("XML") .onQualifiers(Qualifiers.PROJECT) .build(), + PropertyDefinition.builder(XmlSensor.FILENAME_LIST_TO_EXCLUDE_FROM_LOC_METRIC_KEY) + .name("Filenames to ignore when counting lines of code") + .description("Comma-separated list of file name patterns to skip when counting lines of code. You may use regular expressions as long as they don't contain commas. Usage example: You generate an effective-pom.xml file during your scan and want your Sonarqube rules to run against it BUT don't want the line count for that file captured.") + .defaultValue("") + .category("XML") + .build(), Xml.class, XmlRulesDefinition.class, XmlSonarWayProfile.class, diff --git a/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlSensor.java b/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlSensor.java index 7bc6ff8a..c0528cf5 100644 --- a/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlSensor.java +++ b/sonar-xml-plugin/src/main/java/org/sonar/plugins/xml/XmlSensor.java @@ -21,8 +21,11 @@ import com.google.common.annotations.VisibleForTesting; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.regex.Pattern; + import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; @@ -66,20 +69,24 @@ public class XmlSensor implements Sensor { */ private static final Logger LOG = Loggers.get(XmlSensor.class); + public static final String FILENAME_LIST_TO_EXCLUDE_FROM_LOC_METRIC_KEY = "sonar-xml.filename-list-to-exclude-from-lines-of-code-metric"; private static final Version V6_0 = Version.create(6, 0); private final Checks checks; private final FileSystem fileSystem; private final FilePredicate mainFilesPredicate; private final FileLinesContextFactory fileLinesContextFactory; + private final Pattern linesOfCodeCountingExclusionsRegexPattern; - public XmlSensor(FileSystem fileSystem, CheckFactory checkFactory, FileLinesContextFactory fileLinesContextFactory) { + public XmlSensor(FileSystem fileSystem, CheckFactory checkFactory, FileLinesContextFactory fileLinesContextFactory, SensorContext context) { this.fileLinesContextFactory = fileLinesContextFactory; this.checks = checkFactory.create(CheckRepository.REPOSITORY_KEY).addAnnotatedChecks((Iterable) CheckRepository.getCheckClasses()); this.fileSystem = fileSystem; this.mainFilesPredicate = fileSystem.predicates().and( fileSystem.predicates().hasType(InputFile.Type.MAIN), fileSystem.predicates().hasLanguage(Xml.KEY)); + String locExclusionRegexPatternString = buildLOCCountExclusionFilePatternsRegex(context.settings().getStringArray(FILENAME_LIST_TO_EXCLUDE_FROM_LOC_METRIC_KEY)); + this.linesOfCodeCountingExclusionsRegexPattern = "".equals(locExclusionRegexPatternString) ? null : Pattern.compile(locExclusionRegexPatternString); } public void analyse(SensorContext sensorContext) { @@ -87,7 +94,11 @@ public void analyse(SensorContext sensorContext) { } private void computeLinesMeasures(SensorContext context, XmlFile xmlFile) { - LineCounter.analyse(context, fileLinesContextFactory, xmlFile); + if (shouldCountLinesOfCode(context, xmlFile)) { + LineCounter.analyse(context, fileLinesContextFactory, xmlFile); + } else { + LOG.debug("Skipping lines of code computation for file '" + xmlFile.getInputFile().fileName() + "'"); + } } private void runChecks(SensorContext context, XmlFile xmlFile) { @@ -108,6 +119,37 @@ private void runChecks(SensorContext context, XmlFile xmlFile) { } } + private boolean shouldCountLinesOfCode(SensorContext context, XmlFile xmlFile) { + boolean result = true; + + if (linesOfCodeCountingExclusionsRegexPattern != null && + linesOfCodeCountingExclusionsRegexPattern.matcher(xmlFile.getInputFile().fileName()).matches()) { + result = false; + } + + return result; + } + + private String buildLOCCountExclusionFilePatternsRegex(final String[] exclusionSettingValue) { + List ignoreTheseFiles = Arrays.asList(exclusionSettingValue); + + StringBuilder regex = new StringBuilder(); + boolean firstPass = true; + + for (String currentFilePattern : ignoreTheseFiles) { + if (firstPass) { + firstPass = false; + } + else { + regex.append("|"); + } + + regex.append(currentFilePattern); + } + + return regex.toString(); + } + private static void saveSyntaxHighlighting(SensorContext context, List highlightingDataList, InputFile inputFile) { NewHighlighting highlighting = context.newHighlighting().onFile(inputFile); diff --git a/sonar-xml-plugin/src/test/java/org/sonar/plugins/xml/XmlSensorTest.java b/sonar-xml-plugin/src/test/java/org/sonar/plugins/xml/XmlSensorTest.java index 0f97bdff..5bafa65c 100644 --- a/sonar-xml-plugin/src/test/java/org/sonar/plugins/xml/XmlSensorTest.java +++ b/sonar-xml-plugin/src/test/java/org/sonar/plugins/xml/XmlSensorTest.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collection; import java.util.regex.Pattern; import org.assertj.core.api.Condition; import org.junit.Rule; @@ -42,6 +43,7 @@ import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.sensor.internal.SensorContextTester; import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.FileLinesContext; import org.sonar.api.measures.FileLinesContextFactory; @@ -102,6 +104,48 @@ public void should_execute_on_file_with_chars_before_prolog() throws Exception { assertThat(context.allIssues()).extracting("ruleKey").containsOnly(ruleKey); } + + @Test + public void should_skip_line_count_for_only_specified_filenames() throws Exception { + init(true, "some-data-file.xml,bogus-filename.xml"); + fs.add(createInputFile("xmlsensor/some-data-file.xml")); + fs.add(createInputFile("xmlsensor/some-configuration-is-code-file.xml")); + + // Run + sensor.analyse(context); + + // Check + Measure nclocMeasure = context.measure("modulekey:xmlsensor/some-configuration-is-code-file.xml", "ncloc"); + assertThat(nclocMeasure.value()).isEqualTo(20); + System.out.println(nclocMeasure.value()); + + nclocMeasure = context.measure("xmlsensor/some-data-file.xml", "ncloc"); + assertThat(nclocMeasure).isNull(); + + assertLog("Skipping lines of code computation for file 'some-data-file.xml'", false); + assertNoLog("Skipping lines of code computation for file 'some-configuration-is-code-file.xml'", false); + } + + @Test + public void should_skip_line_count_for_only_specified_filenames_REGEX() throws Exception { + init(true, "some-(data|spring-config)-file.xml,bogus-filename.xml"); + fs.add(createInputFile("xmlsensor/some-data-file.xml")); + fs.add(createInputFile("xmlsensor/some-configuration-is-code-file.xml")); + + // Run + sensor.analyse(context); + + // Check + Measure nclocMeasure = context.measure("modulekey:xmlsensor/some-configuration-is-code-file.xml", "ncloc"); + assertThat(nclocMeasure.value()).isEqualTo(20); + System.out.println(nclocMeasure.value()); + + nclocMeasure = context.measure("xmlsensor/some-data-file.xml", "ncloc"); + assertThat(nclocMeasure).isNull(); + + assertLog("Skipping lines of code computation for file 'some-data-file.xml'", false); + assertNoLog("Skipping lines of code computation for file 'some-configuration-is-code-file.xml'", false); + } /** * Has issue for rule NewlineCheck, but should not be reported. @@ -140,9 +184,17 @@ public void should_not_execute_test_on_corrupted_file_and_should_not_raise_parsi } private void init(boolean activateParsingErrorCheck) throws Exception { + init(activateParsingErrorCheck, null); + } + + private void init(boolean activateParsingErrorCheck, String linesOfCodeCountingExclusionPatternsSetting) throws Exception { File moduleBaseDir = new File("src/test/resources"); context = SensorContextTester.create(moduleBaseDir); - + if (linesOfCodeCountingExclusionPatternsSetting != null) { + context.settings().appendProperty(XmlSensor.FILENAME_LIST_TO_EXCLUDE_FROM_LOC_METRIC_KEY, + linesOfCodeCountingExclusionPatternsSetting); + } + fs = new DefaultFileSystem(moduleBaseDir); fs.setWorkDir(temporaryFolder.newFolder("temp")); @@ -166,7 +218,7 @@ private void init(boolean activateParsingErrorCheck) throws Exception { FileLinesContextFactory fileLinesContextFactory = mock(FileLinesContextFactory.class); when(fileLinesContextFactory.createFor(any(InputFile.class))).thenReturn(mock(FileLinesContext.class)); - sensor = new XmlSensor(fs, checkFactory, fileLinesContextFactory); + sensor = new XmlSensor(fs, checkFactory, fileLinesContextFactory, context); } private DefaultInputFile createInputFile(String name) { @@ -229,7 +281,7 @@ public void should_analyze_file_with_its_own_encoding() throws IOException { FileLinesContextFactory fileLinesContextFactory = mock(FileLinesContextFactory.class); when(fileLinesContextFactory.createFor(any(InputFile.class))).thenReturn(mock(FileLinesContext.class)); - sensor = new XmlSensor(fileSystem, checkFactory, fileLinesContextFactory); + sensor = new XmlSensor(fileSystem, checkFactory, fileLinesContextFactory, context); sensor.analyse(context); String componentKey = modulekey + ":" + filename; diff --git a/sonar-xml-plugin/src/test/resources/xmlsensor/some-configuration-is-code-file.xml b/sonar-xml-plugin/src/test/resources/xmlsensor/some-configuration-is-code-file.xml new file mode 100644 index 00000000..c57a3bcb --- /dev/null +++ b/sonar-xml-plugin/src/test/resources/xmlsensor/some-configuration-is-code-file.xml @@ -0,0 +1,21 @@ + + + + 4.0.0 + test + test + 1.0 + pom + test + + src/main/code + + + src + xml + false + xml + xhtml1-strict + + \ No newline at end of file diff --git a/sonar-xml-plugin/src/test/resources/xmlsensor/some-data-file.xml b/sonar-xml-plugin/src/test/resources/xmlsensor/some-data-file.xml new file mode 100644 index 00000000..fc25af70 --- /dev/null +++ b/sonar-xml-plugin/src/test/resources/xmlsensor/some-data-file.xml @@ -0,0 +1,7 @@ + + + 1 + 2 + 3 + + \ No newline at end of file