Skip to content

Commit

Permalink
Added a plugin setting to enable an administrator to define a list of…
Browse files Browse the repository at this point in the history
… XML file patterns that should not be included in the lines of code metric.

An example case is where we generate an xml report such as "effective-pom.xml" or "classloader-collisions.xml" prior to scanning the project with Sonarqube. In those cases we need Sonar to see the files so that our custom XML rules will raise issues based on their content. They do not represent lines of code for the project though so we need a way to prevent their content from being included in the project's LOC metric. This change provides that capability.
  • Loading branch information
gjd6640 committed Jul 8, 2017
1 parent 9337bce commit 47b471b
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -66,28 +69,36 @@ 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<Object> 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) {
execute(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) {
Expand All @@ -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<String> 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<HighlightingData> highlightingDataList, InputFile inputFile) {
NewHighlighting highlighting = context.newHighlighting().onFile(inputFile);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<Integer> 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<Integer> 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.
Expand Down Expand Up @@ -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"));

Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- could be a Spring, Maven, or other config file. This file is used to validate that lines of code are counted for this kind of XML resource. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<name>test</name>
<build>
<sourceDirectory>src/main/code</sourceDirectory>
</build>
<properties>
<sonar.xml.sourceDirectory>src</sonar.xml.sourceDirectory>
<sonar.language>xml</sonar.language>
<sonar.dynamicAnalysis>false</sonar.dynamicAnalysis>
<sonar.xml.fileExtensions>xml</sonar.xml.fileExtensions>
<sonar.xml.schemas>xhtml1-strict</sonar.xml.schemas>
</properties>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<content>
<item-list>
<item>1</item>
<item>2</item>
<item>3</item>
</item-list>
</content>

0 comments on commit 47b471b

Please sign in to comment.