aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2021-11-23 13:06:28 -0600
committersonartech <sonartech@sonarsource.com>2021-11-29 20:03:39 +0000
commitd91ea92fe22cf1b6b52a8efba122daf8e7e58282 (patch)
treecd9123d893d5f67f66cf30be326f5d61320a9d55
parent331d44eca2bc7e646d91bf8d7d8a18f2f93c872d (diff)
downloadsonarqube-d91ea92fe22cf1b6b52a8efba122daf8e7e58282.tar.gz
sonarqube-d91ea92fe22cf1b6b52a8efba122daf8e7e58282.zip
SONAR-15686 Files provided are restricted when PR for selected sensors
-rw-r--r--sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicate.java38
-rw-r--r--sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptor.java19
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicateTest.java94
-rw-r--r--sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptorTest.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionnary.java)4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnary.java)4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/PostJobsExecutor.java6
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java8
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java3
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MutableFileSystem.java59
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java18
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionnary.java)15
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorWrapper.java6
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorsExecutor.java4
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java (renamed from sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionnary.java)15
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorWrapper.java7
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorsExecutor.java4
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java (renamed from sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionnaryTest.java)43
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionaryTest.java (renamed from sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnaryTest.java)8
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleSensorsExecutorTest.java127
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/PostJobsExecutorTest.java4
-rw-r--r--sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MutableFileSystemTest.java85
24 files changed, 541 insertions, 67 deletions
diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicate.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicate.java
new file mode 100644
index 00000000000..08736a7e61d
--- /dev/null
+++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicate.java
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.fs.internal.predicates;
+
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputFile;
+
+public class ChangedFilePredicate implements FilePredicate {
+
+ private final FilePredicate originalPredicate;
+
+ public ChangedFilePredicate(FilePredicate originalPredicate) {
+ this.originalPredicate = originalPredicate;
+ }
+
+ @Override
+ public boolean apply(InputFile inputFile) {
+ return originalPredicate.apply(inputFile) && InputFile.Status.SAME != inputFile.status();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptor.java b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptor.java
index ee5ced6886b..e0819050190 100644
--- a/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptor.java
+++ b/sonar-plugin-api-impl/src/main/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptor.java
@@ -21,13 +21,23 @@ package org.sonar.api.batch.sensor.internal;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.config.Configuration;
public class DefaultSensorDescriptor implements SensorDescriptor {
+ public static final Set<String> SENSORS_ONLY_CHANGED_IN_PR = Collections.unmodifiableSet(Stream.of(
+ "CSS Metrics",
+ "CSS Rules",
+ "HTML",
+ "XML Sensor"
+ ).collect(Collectors.toSet()));
private String name;
private String[] languages = new String[0];
@@ -35,6 +45,7 @@ public class DefaultSensorDescriptor implements SensorDescriptor {
private String[] ruleRepositories = new String[0];
private boolean global = false;
private Predicate<Configuration> configurationPredicate;
+ private boolean onlyChangedFilesInPullRequests = false;
public String name() {
return name;
@@ -61,8 +72,16 @@ public class DefaultSensorDescriptor implements SensorDescriptor {
return global;
}
+ public boolean onlyChangedFilesInPullRequest() {
+ return onlyChangedFilesInPullRequests;
+ }
+
@Override
public DefaultSensorDescriptor name(String name) {
+ // TODO: Add onlyChangedFilesInPullRequest into API and implement it at sensors
+ if (SENSORS_ONLY_CHANGED_IN_PR.contains(name)) {
+ onlyChangedFilesInPullRequests = true;
+ }
this.name = name;
return this;
}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicateTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicateTest.java
new file mode 100644
index 00000000000..f3fcd9309a2
--- /dev/null
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/fs/internal/predicates/ChangedFilePredicateTest.java
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.fs.internal.predicates;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.InputFile;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ChangedFilePredicateTest {
+
+ private final FilePredicate predicate = mock(FilePredicate.class);
+ private final InputFile inputFile = mock(InputFile.class);
+
+ private final ChangedFilePredicate underTest = new ChangedFilePredicate(predicate);
+
+ @Test
+ public void apply_when_file_is_changed_and_predicate_is_true() {
+ when(inputFile.status()).thenReturn(InputFile.Status.CHANGED);
+ when(predicate.apply(inputFile)).thenReturn(true);
+
+ Assertions.assertThat(underTest.apply(inputFile)).isTrue();
+
+ verify(predicate, times(1)).apply(any());
+ verify(inputFile, times(1)).status();
+ }
+
+ @Test
+ public void apply_when_file_is_added_and_predicate_is_true() {
+ when(inputFile.status()).thenReturn(InputFile.Status.ADDED);
+ when(predicate.apply(inputFile)).thenReturn(true);
+
+ Assertions.assertThat(underTest.apply(inputFile)).isTrue();
+
+ verify(predicate, times(1)).apply(any());
+ verify(inputFile, times(1)).status();
+ }
+
+ @Test
+ public void do_not_apply_when_file_is_same_and_predicate_is_true() {
+ when(inputFile.status()).thenReturn(InputFile.Status.SAME);
+ when(predicate.apply(inputFile)).thenReturn(true);
+
+ Assertions.assertThat(underTest.apply(inputFile)).isFalse();
+
+ verify(predicate, times(1)).apply(any());
+ verify(inputFile, times(1)).status();
+ }
+
+ @Test
+ public void predicate_is_evaluated_before_file_status() {
+ when(predicate.apply(inputFile)).thenReturn(false);
+
+ Assertions.assertThat(underTest.apply(inputFile)).isFalse();
+
+ verify(inputFile, never()).status();
+ }
+
+ @Test
+ public void do_not_apply_when_file_is_same_and_predicate_is_false() {
+ when(inputFile.status()).thenReturn(InputFile.Status.SAME);
+ when(predicate.apply(inputFile)).thenReturn(true);
+
+ Assertions.assertThat(underTest.apply(inputFile)).isFalse();
+
+ verify(predicate, times(1)).apply(any());
+ verify(inputFile, times(1)).status();
+ }
+
+}
diff --git a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptorTest.java b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptorTest.java
index ac6c72c24dd..e34c5385cad 100644
--- a/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptorTest.java
+++ b/sonar-plugin-api-impl/src/test/java/org/sonar/api/batch/sensor/internal/DefaultSensorDescriptorTest.java
@@ -19,12 +19,17 @@
*/
package org.sonar.api.batch.sensor.internal;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.config.internal.MapSettings;
import static org.assertj.core.api.Assertions.assertThat;
+@RunWith(DataProviderRunner.class)
public class DefaultSensorDescriptorTest {
@Test
@@ -48,4 +53,29 @@ public class DefaultSensorDescriptorTest {
assertThat(descriptor.ruleRepositories()).containsOnly("squid-java");
}
+ @Test
+ @UseDataProvider("sensorsOnlyChangedInPR")
+ public void describe_with_restricted_sensor(String sensorName) {
+ DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
+ descriptor
+ .name(sensorName);
+
+ assertThat(descriptor.onlyChangedFilesInPullRequest()).isTrue();
+ }
+
+ @Test
+ @UseDataProvider("sensorsOnlyChangedInPR")
+ public void describe_with_non_restricted_sensor(String sensorName) {
+ DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
+ descriptor
+ .name(sensorName + "other");
+
+ assertThat(descriptor.onlyChangedFilesInPullRequest()).isFalse();
+ }
+
+ @DataProvider
+ public static Object[][] sensorsOnlyChangedInPR() {
+ return new Object[][] {DefaultSensorDescriptor.SENSORS_ONLY_CHANGED_IN_PR.toArray()};
+ }
+
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java
index bd56e76433b..a165751f2ce 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionnary.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java
@@ -37,11 +37,11 @@ import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.dag.DirectAcyclicGraph;
import org.sonar.core.platform.ComponentContainer;
-public abstract class AbstractExtensionDictionnary {
+public abstract class AbstractExtensionDictionary {
private final ComponentContainer componentContainer;
- public AbstractExtensionDictionnary(ComponentContainer componentContainer) {
+ public AbstractExtensionDictionary(ComponentContainer componentContainer) {
this.componentContainer = componentContainer;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java
index b647355a7a1..562792646fe 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnary.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java
@@ -27,12 +27,12 @@ import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.postjob.PostJobWrapper;
-public class PostJobExtensionDictionnary extends AbstractExtensionDictionnary {
+public class PostJobExtensionDictionary extends AbstractExtensionDictionary {
private final PostJobContext postJobContext;
private final PostJobOptimizer postJobOptimizer;
- public PostJobExtensionDictionnary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
+ public PostJobExtensionDictionary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
super(componentContainer);
this.postJobOptimizer = postJobOptimizer;
this.postJobContext = postJobContext;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/PostJobsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/PostJobsExecutor.java
index 098fdea74ff..21486a39536 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/PostJobsExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/postjob/PostJobsExecutor.java
@@ -23,14 +23,14 @@ import java.util.Collection;
import java.util.stream.Collectors;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
public class PostJobsExecutor {
private static final Logger LOG = Loggers.get(PostJobsExecutor.class);
- private final PostJobExtensionDictionnary selector;
+ private final PostJobExtensionDictionary selector;
- public PostJobsExecutor(PostJobExtensionDictionnary selector) {
+ public PostJobsExecutor(PostJobExtensionDictionary selector) {
this.selector = selector;
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
index e67d65da9f1..3ab08728bbd 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
@@ -26,7 +26,7 @@ import org.sonar.scanner.bootstrap.ExtensionInstaller;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.sensor.ModuleSensorContext;
-import org.sonar.scanner.sensor.ModuleSensorExtensionDictionnary;
+import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.sonar.scanner.sensor.ModuleSensorsExecutor;
@@ -65,7 +65,7 @@ public class ModuleScanContainer extends ComponentContainer {
ModuleSensorOptimizer.class,
ModuleSensorContext.class,
- ModuleSensorExtensionDictionnary.class
+ ModuleSensorExtensionDictionary.class
);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
index d77df0452ee..94c44b23a73 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
@@ -41,7 +41,7 @@ import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
import org.sonar.scanner.bootstrap.ExtensionInstaller;
import org.sonar.scanner.bootstrap.ExtensionMatcher;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
import org.sonar.scanner.ci.CiConfigurationProvider;
import org.sonar.scanner.ci.vendors.AppVeyor;
import org.sonar.scanner.ci.vendors.AwsCodeBuild;
@@ -126,7 +126,7 @@ import org.sonar.scanner.scm.ScmPublisher;
import org.sonar.scanner.scm.ScmRevisionImpl;
import org.sonar.scanner.sensor.DefaultSensorStorage;
import org.sonar.scanner.sensor.ProjectSensorContext;
-import org.sonar.scanner.sensor.ProjectSensorExtensionDictionnary;
+import org.sonar.scanner.sensor.ProjectSensorExtensionDictionary;
import org.sonar.scanner.sensor.ProjectSensorOptimizer;
import org.sonar.scanner.sensor.ProjectSensorsExecutor;
import org.sonar.scm.git.GitScmSupport;
@@ -256,7 +256,7 @@ public class ProjectScanContainer extends ComponentContainer {
PostJobsExecutor.class,
PostJobOptimizer.class,
DefaultPostJobContext.class,
- PostJobExtensionDictionnary.class,
+ PostJobExtensionDictionary.class,
// SCM
ScmConfiguration.class,
@@ -269,7 +269,7 @@ public class ProjectScanContainer extends ComponentContainer {
ProjectSensorContext.class,
ProjectSensorOptimizer.class,
ProjectSensorsExecutor.class,
- ProjectSensorExtensionDictionnary.class,
+ ProjectSensorExtensionDictionary.class,
// Filesystem
DefaultProjectFileSystem.class,
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java
index d7b4a93d3ff..fb5263d8d03 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java
@@ -19,11 +19,10 @@
*/
package org.sonar.scanner.scan.filesystem;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
-public class DefaultModuleFileSystem extends DefaultFileSystem {
+public class DefaultModuleFileSystem extends MutableFileSystem {
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) {
super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir()));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java
index fb5082bdefa..1f3a5c1c128 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java
@@ -19,11 +19,10 @@
*/
package org.sonar.scanner.scan.filesystem;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
-public class DefaultProjectFileSystem extends DefaultFileSystem {
+public class DefaultProjectFileSystem extends MutableFileSystem {
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) {
super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir()));
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MutableFileSystem.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MutableFileSystem.java
new file mode 100644
index 00000000000..f17b15eb394
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MutableFileSystem.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.scanner.scan.filesystem;
+
+import java.nio.file.Path;
+import org.sonar.api.batch.fs.FilePredicate;
+import org.sonar.api.batch.fs.FilePredicates;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.predicates.ChangedFilePredicate;
+
+public class MutableFileSystem extends DefaultFileSystem {
+ private boolean restrictToChangedFiles = false;
+
+ public MutableFileSystem(Path baseDir, Cache cache, FilePredicates filePredicates) {
+ super(baseDir, cache, filePredicates);
+ }
+
+ public MutableFileSystem(Path baseDir) {
+ super(baseDir);
+ }
+
+ @Override
+ public Iterable<InputFile> inputFiles(FilePredicate requestPredicate) {
+ if (restrictToChangedFiles) {
+ return super.inputFiles(new ChangedFilePredicate(requestPredicate));
+ }
+ return super.inputFiles(requestPredicate);
+ }
+
+ @Override
+ public InputFile inputFile(FilePredicate requestPredicate) {
+ if (restrictToChangedFiles) {
+ return super.inputFile(new ChangedFilePredicate(requestPredicate));
+ }
+ return super.inputFile(requestPredicate);
+ }
+
+ public void setRestrictToChangedFiles(boolean restrictToChangedFiles) {
+ this.restrictToChangedFiles = restrictToChangedFiles;
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java
index 404bf73dfa2..21e5308d66e 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/AbstractSensorWrapper.java
@@ -22,18 +22,29 @@ package org.sonar.scanner.sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.api.scanner.sensor.ProjectSensor;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
public abstract class AbstractSensorWrapper<G extends ProjectSensor> {
+ private static final Logger LOGGER = Loggers.get(AbstractSensorWrapper.class);
+
private final G wrappedSensor;
private final SensorContext context;
+ private final MutableFileSystem fileSystem;
private final DefaultSensorDescriptor descriptor;
private final AbstractSensorOptimizer optimizer;
+ private final boolean isPullRequest;
- public AbstractSensorWrapper(G sensor, SensorContext context, AbstractSensorOptimizer optimizer) {
+ public AbstractSensorWrapper(G sensor, SensorContext context, AbstractSensorOptimizer optimizer, MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
this.wrappedSensor = sensor;
this.optimizer = optimizer;
this.context = context;
this.descriptor = new DefaultSensorDescriptor();
+ this.fileSystem = fileSystem;
+ this.isPullRequest = branchConfiguration.branchType() == BranchType.PULL_REQUEST;
sensor.describe(this.descriptor);
if (descriptor.name() == null) {
descriptor.name(sensor.getClass().getName());
@@ -45,6 +56,11 @@ public abstract class AbstractSensorWrapper<G extends ProjectSensor> {
}
public void analyse() {
+ boolean sensorIsRestricted = descriptor.onlyChangedFilesInPullRequest() && isPullRequest;
+ if (sensorIsRestricted) {
+ LOGGER.info("Sensor {} is restricted to changed files only", descriptor.name());
+ }
+ fileSystem.setRestrictToChangedFiles(sensorIsRestricted);
wrappedSensor.execute(context);
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java
index 734ebb9192a..3df2f067fbc 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionnary.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java
@@ -23,23 +23,30 @@ import java.util.Collection;
import java.util.stream.Collectors;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.bootstrap.AbstractExtensionDictionnary;
+import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
-public class ModuleSensorExtensionDictionnary extends AbstractExtensionDictionnary {
+public class ModuleSensorExtensionDictionary extends AbstractExtensionDictionary {
private final ModuleSensorContext sensorContext;
private final ModuleSensorOptimizer sensorOptimizer;
+ private final MutableFileSystem fileSystem;
+ private final BranchConfiguration branchConfiguration;
- public ModuleSensorExtensionDictionnary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer) {
+ public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
+ MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer);
this.sensorContext = sensorContext;
this.sensorOptimizer = sensorOptimizer;
+ this.fileSystem = fileSystem;
+ this.branchConfiguration = branchConfiguration;
}
public Collection<ModuleSensorWrapper> selectSensors(boolean global) {
Collection<Sensor> result = sort(getFilteredExtensions(Sensor.class, null));
return result.stream()
- .map(s -> new ModuleSensorWrapper(s, sensorContext, sensorOptimizer))
+ .map(s -> new ModuleSensorWrapper(s, sensorContext, sensorOptimizer, fileSystem, branchConfiguration))
.filter(s -> global == s.isGlobal() && s.shouldExecute())
.collect(Collectors.toList());
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorWrapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorWrapper.java
index 4fbd1eae629..31c28b78a07 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorWrapper.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorWrapper.java
@@ -20,10 +20,12 @@
package org.sonar.scanner.sensor;
import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
public class ModuleSensorWrapper extends AbstractSensorWrapper<Sensor> {
- public ModuleSensorWrapper(Sensor sensor, ModuleSensorContext context, ModuleSensorOptimizer optimizer) {
- super(sensor, context, optimizer);
+ public ModuleSensorWrapper(Sensor sensor, ModuleSensorContext context, ModuleSensorOptimizer optimizer, MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
+ super(sensor, context, optimizer, fileSystem, branchConfiguration);
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorsExecutor.java
index 6b5d59b57cb..4cfa093133b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorsExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorsExecutor.java
@@ -34,12 +34,12 @@ import org.sonar.scanner.fs.InputModuleHierarchy;
public class ModuleSensorsExecutor {
private static final Logger LOG = Loggers.get(ModuleSensorsExecutor.class);
private static final Profiler profiler = Profiler.create(LOG);
- private final ModuleSensorExtensionDictionnary selector;
+ private final ModuleSensorExtensionDictionary selector;
private final SensorStrategy strategy;
private final ScannerPluginRepository pluginRepo;
private final boolean isRoot;
- public ModuleSensorsExecutor(ModuleSensorExtensionDictionnary selector, DefaultInputModule module, InputModuleHierarchy hierarchy,
+ public ModuleSensorsExecutor(ModuleSensorExtensionDictionary selector, DefaultInputModule module, InputModuleHierarchy hierarchy,
SensorStrategy strategy, ScannerPluginRepository pluginRepo) {
this.selector = selector;
this.strategy = strategy;
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionnary.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java
index 00c47e17bde..44180231a10 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionnary.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java
@@ -24,23 +24,30 @@ import java.util.List;
import java.util.stream.Collectors;
import org.sonar.api.scanner.sensor.ProjectSensor;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.bootstrap.AbstractExtensionDictionnary;
+import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
-public class ProjectSensorExtensionDictionnary extends AbstractExtensionDictionnary {
+public class ProjectSensorExtensionDictionary extends AbstractExtensionDictionary {
private final ProjectSensorContext sensorContext;
private final ProjectSensorOptimizer sensorOptimizer;
+ private final MutableFileSystem fileSystem;
+ private final BranchConfiguration branchConfiguration;
- public ProjectSensorExtensionDictionnary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer) {
+ public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
+ MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer);
this.sensorContext = sensorContext;
this.sensorOptimizer = sensorOptimizer;
+ this.fileSystem = fileSystem;
+ this.branchConfiguration = branchConfiguration;
}
public List<ProjectSensorWrapper> selectSensors() {
Collection<ProjectSensor> result = sort(getFilteredExtensions(ProjectSensor.class, null));
return result.stream()
- .map(s -> new ProjectSensorWrapper(s, sensorContext, sensorOptimizer))
+ .map(s -> new ProjectSensorWrapper(s, sensorContext, sensorOptimizer, fileSystem, branchConfiguration))
.filter(ProjectSensorWrapper::shouldExecute)
.collect(Collectors.toList());
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorWrapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorWrapper.java
index d56c733c60c..24e5dc483e9 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorWrapper.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorWrapper.java
@@ -20,11 +20,14 @@
package org.sonar.scanner.sensor;
import org.sonar.api.scanner.sensor.ProjectSensor;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
public class ProjectSensorWrapper extends AbstractSensorWrapper<ProjectSensor> {
- public ProjectSensorWrapper(ProjectSensor sensor, ProjectSensorContext context, ProjectSensorOptimizer optimizer) {
- super(sensor, context, optimizer);
+ public ProjectSensorWrapper(ProjectSensor sensor, ProjectSensorContext context, ProjectSensorOptimizer optimizer,
+ MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
+ super(sensor, context, optimizer, fileSystem, branchConfiguration);
}
}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorsExecutor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorsExecutor.java
index 81ba19409b6..6af61c7c74b 100644
--- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorsExecutor.java
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorsExecutor.java
@@ -29,10 +29,10 @@ import org.sonar.scanner.bootstrap.ScannerPluginRepository;
public class ProjectSensorsExecutor {
private static final Logger LOG = Loggers.get(ProjectSensorsExecutor.class);
private static final Profiler profiler = Profiler.create(LOG);
- private final ProjectSensorExtensionDictionnary selector;
+ private final ProjectSensorExtensionDictionary selector;
private final ScannerPluginRepository pluginRepo;
- public ProjectSensorsExecutor(ProjectSensorExtensionDictionnary selector, ScannerPluginRepository pluginRepo) {
+ public ProjectSensorsExecutor(ProjectSensorExtensionDictionary selector, ScannerPluginRepository pluginRepo) {
this.selector = selector;
this.pluginRepo = pluginRepo;
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionnaryTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java
index 61481a22cdc..a539b0b51d3 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionnaryTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java
@@ -35,8 +35,10 @@ import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.core.platform.ComponentContainer;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
import org.sonar.scanner.sensor.ModuleSensorContext;
-import org.sonar.scanner.sensor.ModuleSensorExtensionDictionnary;
+import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.sonar.scanner.sensor.ModuleSensorWrapper;
@@ -46,20 +48,22 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class ModuleSensorExtensionDictionnaryTest {
- private ModuleSensorOptimizer sensorOptimizer = mock(ModuleSensorOptimizer.class);
+public class ModuleSensorExtensionDictionaryTest {
+ private final ModuleSensorOptimizer sensorOptimizer = mock(ModuleSensorOptimizer.class);
+ private final MutableFileSystem fileSystem = mock(MutableFileSystem.class);
+ private final BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
@Before
public void setUp() {
when(sensorOptimizer.shouldExecute(any(DefaultSensorDescriptor.class))).thenReturn(true);
}
- private ModuleSensorExtensionDictionnary newSelector(Object... extensions) {
+ private ModuleSensorExtensionDictionary newSelector(Object... extensions) {
ComponentContainer iocContainer = new ComponentContainer();
for (Object extension : extensions) {
iocContainer.addSingleton(extension);
}
- return new ModuleSensorExtensionDictionnary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer);
+ return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration);
}
@Test
@@ -67,7 +71,7 @@ public class ModuleSensorExtensionDictionnaryTest {
final Sensor sensor1 = new FakeSensor();
final Sensor sensor2 = new FakeSensor();
- ModuleSensorExtensionDictionnary selector = newSelector(sensor1, sensor2);
+ ModuleSensorExtensionDictionary selector = newSelector(sensor1, sensor2);
Collection<Sensor> sensors = selector.select(Sensor.class, true, extension -> extension.equals(sensor1));
assertThat(sensors).contains(sensor1);
assertEquals(1, sensors.size());
@@ -79,7 +83,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Sensor sensor2 = new FakeSensor();
FieldDecorated.Decorator decorator = mock(FieldDecorated.Decorator.class);
- ModuleSensorExtensionDictionnary selector = newSelector(sensor1, sensor2, decorator);
+ ModuleSensorExtensionDictionary selector = newSelector(sensor1, sensor2, decorator);
Collection<Sensor> sensors = selector.select(Sensor.class, false, null);
assertThat(sensors).containsOnly(sensor1, sensor2);
@@ -100,7 +104,8 @@ public class ModuleSensorExtensionDictionnaryTest {
ComponentContainer child = parent.createChild();
child.addSingleton(c);
- ModuleSensorExtensionDictionnary dictionnary = new ModuleSensorExtensionDictionnary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class));
+ ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class),
+ fileSystem, branchConfiguration);
assertThat(dictionnary.select(Sensor.class, true, null)).containsOnly(a, b, c);
}
@@ -110,7 +115,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object b = new MethodDependentOf(a);
Object c = new MethodDependentOf(b);
- ModuleSensorExtensionDictionnary selector = newSelector(b, c, a);
+ ModuleSensorExtensionDictionary selector = newSelector(b, c, a);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(3);
@@ -124,7 +129,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object a = new GeneratesSomething("foo");
Object b = new MethodDependentOf("foo");
- ModuleSensorExtensionDictionnary selector = newSelector(a, b);
+ ModuleSensorExtensionDictionary selector = newSelector(a, b);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions.size()).isEqualTo(2);
@@ -145,7 +150,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object a = new GeneratesSomething("foo");
Object b = new MethodDependentOf(Arrays.asList("foo"));
- ModuleSensorExtensionDictionnary selector = newSelector(a, b);
+ ModuleSensorExtensionDictionary selector = newSelector(a, b);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(2);
@@ -166,7 +171,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object a = new GeneratesSomething("foo");
Object b = new MethodDependentOf(new String[] {"foo"});
- ModuleSensorExtensionDictionnary selector = newSelector(a, b);
+ ModuleSensorExtensionDictionary selector = newSelector(a, b);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(2);
@@ -187,7 +192,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object a = new ClassDependedUpon();
Object b = new ClassDependsUpon();
- ModuleSensorExtensionDictionnary selector = newSelector(a, b);
+ ModuleSensorExtensionDictionary selector = newSelector(a, b);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(2);
@@ -210,7 +215,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object b = new InterfaceDependsUpon() {
};
- ModuleSensorExtensionDictionnary selector = newSelector(a, b);
+ ModuleSensorExtensionDictionary selector = newSelector(a, b);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(2);
@@ -231,7 +236,7 @@ public class ModuleSensorExtensionDictionnaryTest {
Object a = new SubClass("foo");
Object b = new MethodDependentOf("foo");
- ModuleSensorExtensionDictionnary selector = newSelector(b, a);
+ ModuleSensorExtensionDictionary selector = newSelector(b, a);
List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
assertThat(extensions).hasSize(2);
@@ -249,7 +254,7 @@ public class ModuleSensorExtensionDictionnaryTest {
@Test(expected = IllegalStateException.class)
public void annotatedMethodsCanNotBePrivate() {
- ModuleSensorExtensionDictionnary selector = newSelector();
+ ModuleSensorExtensionDictionary selector = newSelector();
Object wrong = new Object() {
@DependsUpon
private Object foo() {
@@ -265,7 +270,7 @@ public class ModuleSensorExtensionDictionnaryTest {
NormalSensor normal = new NormalSensor();
PostSensor post = new PostSensor();
- ModuleSensorExtensionDictionnary selector = newSelector(normal, post, pre);
+ ModuleSensorExtensionDictionary selector = newSelector(normal, post, pre);
assertThat(selector.selectSensors(false)).extracting("wrappedSensor").containsExactly(pre, normal, post);
}
@@ -275,7 +280,7 @@ public class ModuleSensorExtensionDictionnaryTest {
NormalSensor normal = new NormalSensor();
PostSensorSubclass post = new PostSensorSubclass();
- ModuleSensorExtensionDictionnary selector = newSelector(normal, post, pre);
+ ModuleSensorExtensionDictionary selector = newSelector(normal, post, pre);
List extensions = Lists.newArrayList(selector.select(Sensor.class, true, null));
assertThat(extensions).containsExactly(pre, normal, post);
@@ -285,7 +290,7 @@ public class ModuleSensorExtensionDictionnaryTest {
public void selectSensors() {
FakeSensor nonGlobalSensor = new FakeSensor();
FakeGlobalSensor globalSensor = new FakeGlobalSensor();
- ModuleSensorExtensionDictionnary selector = newSelector(nonGlobalSensor, globalSensor);
+ ModuleSensorExtensionDictionary selector = newSelector(nonGlobalSensor, globalSensor);
// verify non-global sensor
Collection<ModuleSensorWrapper> extensions = selector.selectSensors(false);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnaryTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionaryTest.java
index bfc29675ffa..3a016aa2acc 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionnaryTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionaryTest.java
@@ -37,7 +37,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class PostJobExtensionDictionnaryTest {
+public class PostJobExtensionDictionaryTest {
private PostJobOptimizer postJobOptimizer = mock(PostJobOptimizer.class);
@Before
@@ -45,12 +45,12 @@ public class PostJobExtensionDictionnaryTest {
when(postJobOptimizer.shouldExecute(any(DefaultPostJobDescriptor.class))).thenReturn(true);
}
- private PostJobExtensionDictionnary newSelector(Object... extensions) {
+ private PostJobExtensionDictionary newSelector(Object... extensions) {
ComponentContainer iocContainer = new ComponentContainer();
for (Object extension : extensions) {
iocContainer.addSingleton(extension);
}
- return new PostJobExtensionDictionnary(iocContainer, postJobOptimizer, mock(PostJobContext.class));
+ return new PostJobExtensionDictionary(iocContainer, postJobOptimizer, mock(PostJobContext.class));
}
@Test
@@ -58,7 +58,7 @@ public class PostJobExtensionDictionnaryTest {
PrePostJob pre = new PrePostJob();
NormalPostJob normal = new NormalPostJob();
- PostJobExtensionDictionnary selector = newSelector(normal, pre);
+ PostJobExtensionDictionary selector = newSelector(normal, pre);
assertThat(selector.selectPostJobs()).extracting("wrappedPostJob").containsExactly(pre, normal);
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleSensorsExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleSensorsExecutorTest.java
index 2b0095d23bf..820a528c040 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleSensorsExecutorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/ModuleSensorsExecutorTest.java
@@ -19,41 +19,65 @@
*/
package org.sonar.scanner.phases;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.io.IOException;
import java.util.Collections;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
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.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.api.utils.log.LogTester;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.scanner.sensor.ModuleSensorExtensionDictionnary;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.scanner.scan.filesystem.MutableFileSystem;
+import org.sonar.scanner.sensor.ModuleSensorContext;
+import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
+import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.sonar.scanner.sensor.ModuleSensorWrapper;
import org.sonar.scanner.sensor.ModuleSensorsExecutor;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+@RunWith(DataProviderRunner.class)
public class ModuleSensorsExecutorTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public LogTester logTester = new LogTester();
+
private ModuleSensorsExecutor rootModuleExecutor;
private ModuleSensorsExecutor subModuleExecutor;
- private SensorStrategy strategy = new SensorStrategy();
+ private final SensorStrategy strategy = new SensorStrategy();
- private ModuleSensorWrapper perModuleSensor = mock(ModuleSensorWrapper.class);
- private ModuleSensorWrapper globalSensor = mock(ModuleSensorWrapper.class);
- private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
+ private final ModuleSensorWrapper perModuleSensor = mock(ModuleSensorWrapper.class);
+ private final ModuleSensorWrapper globalSensor = mock(ModuleSensorWrapper.class);
+ private final ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
+ private final ModuleSensorContext context = mock(ModuleSensorContext.class);
+ private final ModuleSensorOptimizer optimizer = mock(ModuleSensorOptimizer.class);
+ private final ScannerPluginRepository pluginRepo = mock(ScannerPluginRepository.class);
+ private final MutableFileSystem fileSystem = mock(MutableFileSystem.class);
+ private final BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
@Before
public void setUp() throws IOException {
@@ -65,7 +89,7 @@ public class ModuleSensorsExecutorTest {
when(globalSensor.shouldExecute()).thenReturn(true);
when(globalSensor.wrappedSensor()).thenReturn(mock(Sensor.class));
- ModuleSensorExtensionDictionnary selector = mock(ModuleSensorExtensionDictionnary.class);
+ ModuleSensorExtensionDictionary selector = mock(ModuleSensorExtensionDictionary.class);
when(selector.selectSensors(false)).thenReturn(Collections.singleton(perModuleSensor));
when(selector.selectSensors(true)).thenReturn(Collections.singleton(globalSensor));
@@ -105,4 +129,91 @@ public class ModuleSensorsExecutorTest {
verifyNoMoreInteractions(perModuleSensor, globalSensor);
}
+
+ @Test
+ @UseDataProvider("sensorsOnlyChangedInPR")
+ public void should_restrict_filesystem_when_pull_request_and_expected_sensor(String sensorName) throws IOException {
+ when(branchConfiguration.branchType()).thenReturn(BranchType.PULL_REQUEST);
+ ModuleSensorsExecutor executor = createModuleExecutor(sensorName);
+
+ executor.execute();
+
+ verify(fileSystem, times(2)).setRestrictToChangedFiles(true);
+
+ assertThat(logTester.logs().stream().anyMatch(
+ p -> p.contains(String.format("Sensor %s is restricted to changed files only", sensorName)))
+ ).isTrue();
+ }
+
+ @Test
+ @UseDataProvider("sensorsOnlyChangedInPR")
+ public void should_not_restrict_filesystem_when_branch(String sensorName) throws IOException {
+ when(branchConfiguration.branchType()).thenReturn(BranchType.BRANCH);
+ ModuleSensorsExecutor executor = createModuleExecutor(sensorName);
+
+ executor.execute();
+
+ verify(fileSystem, times(2)).setRestrictToChangedFiles(false);
+
+ assertThat(logTester.logs().stream().anyMatch(
+ p -> p.contains(String.format("Sensor %s is restricted to changed files only", sensorName)))
+ ).isFalse();
+ }
+
+ @Test
+ public void should_not_restrict_filesystem_when_pull_request_and_non_expected_sensor() throws IOException {
+ String sensorName = "NonRestrictedSensor";
+ when(branchConfiguration.branchType()).thenReturn(BranchType.PULL_REQUEST);
+ ModuleSensorsExecutor executor = createModuleExecutor(sensorName);
+
+ executor.execute();
+
+ verify(fileSystem, times(2)).setRestrictToChangedFiles(false);
+
+ assertThat(logTester.logs().stream().anyMatch(
+ p -> p.contains(String.format("Sensor %s is restricted to changed files only", sensorName)))
+ ).isFalse();
+ }
+
+ @DataProvider
+ public static Object[][] sensorsOnlyChangedInPR() {
+ return new Object[][] {DefaultSensorDescriptor.SENSORS_ONLY_CHANGED_IN_PR.toArray()};
+ }
+
+ private ModuleSensorsExecutor createModuleExecutor(String sensorName) throws IOException {
+ Sensor sensor = new TestSensor(sensorName);
+ ModuleSensorWrapper sensorWrapper = new ModuleSensorWrapper(sensor, context, optimizer, fileSystem, branchConfiguration);
+
+ ModuleSensorExtensionDictionary selector = mock(ModuleSensorExtensionDictionary.class);
+ when(selector.selectSensors(false)).thenReturn(Collections.singleton(sensorWrapper));
+ when(selector.selectSensors(true)).thenReturn(Collections.singleton(sensorWrapper));
+
+ ProjectDefinition rootDef = ProjectDefinition.create().setKey("root").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder());
+
+ DefaultInputModule rootModule = TestInputFileBuilder.newDefaultInputModule(rootDef);
+
+ InputModuleHierarchy hierarchy = mock(InputModuleHierarchy.class);
+ when(hierarchy.isRoot(rootModule)).thenReturn(true);
+
+ return new ModuleSensorsExecutor(selector, rootModule, hierarchy, strategy, pluginRepo);
+ }
+
+ private static class TestSensor implements Sensor {
+
+ private final String name;
+
+ public TestSensor(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.name(name);
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+
+ }
+ }
}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/PostJobsExecutorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/PostJobsExecutorTest.java
index a4888b77686..318b42f6b15 100644
--- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/PostJobsExecutorTest.java
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/phases/PostJobsExecutorTest.java
@@ -22,7 +22,7 @@ package org.sonar.scanner.phases;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
import org.sonar.scanner.postjob.PostJobWrapper;
import org.sonar.scanner.postjob.PostJobsExecutor;
@@ -34,7 +34,7 @@ import static org.mockito.Mockito.when;
public class PostJobsExecutorTest {
private PostJobsExecutor executor;
- private PostJobExtensionDictionnary selector = mock(PostJobExtensionDictionnary.class);
+ private PostJobExtensionDictionary selector = mock(PostJobExtensionDictionary.class);
private PostJobWrapper job1 = mock(PostJobWrapper.class);
private PostJobWrapper job2 = mock(PostJobWrapper.class);
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MutableFileSystemTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MutableFileSystemTest.java
new file mode 100644
index 00000000000..f55a46f65ae
--- /dev/null
+++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MutableFileSystemTest.java
@@ -0,0 +1,85 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.scanner.scan.filesystem;
+
+import java.util.Locale;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MutableFileSystemTest {
+
+ private static final String LANGUAGE = "php";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private MutableFileSystem underTest;
+
+ @Before
+ public void prepare() throws Exception {
+ underTest = new MutableFileSystem(temp.newFolder().toPath());
+ }
+
+ @Test
+ public void return_all_files_when_not_restricted() {
+ assertThat(underTest.inputFiles(underTest.predicates().all())).isEmpty();
+ addFileWithAllStatus();
+ underTest.setRestrictToChangedFiles(false);
+
+ assertThat(underTest.inputFiles(underTest.predicates().all())).hasSize(3);
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.ADDED)))).isNotNull();
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.SAME)))).isNotNull();
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.CHANGED)))).isNotNull();
+ }
+
+ @Test
+ public void return_only_changed_files_when_restricted() {
+ assertThat(underTest.inputFiles(underTest.predicates().all())).isEmpty();
+ addFileWithAllStatus();
+ underTest.setRestrictToChangedFiles(true);
+
+ assertThat(underTest.inputFiles(underTest.predicates().all())).hasSize(2);
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.ADDED)))).isNotNull();
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.SAME)))).isNull();
+ assertThat(underTest.inputFile(underTest.predicates().hasFilename(generateFilename(InputFile.Status.CHANGED)))).isNotNull();
+ }
+
+ private void addFileWithAllStatus() {
+ addFile(InputFile.Status.ADDED);
+ addFile(InputFile.Status.CHANGED);
+ addFile(InputFile.Status.SAME);
+ }
+
+ private void addFile(InputFile.Status status) {
+ underTest.add(new TestInputFileBuilder("foo", String.format("src/%s", generateFilename(status)))
+ .setLanguage(LANGUAGE).setStatus(status).build());
+ }
+
+ private String generateFilename(InputFile.Status status) {
+ return String.format("%s.%s", status.name().toLowerCase(Locale.ROOT), LANGUAGE);
+ }
+
+}