Skip to content

Commit af19ba7

Browse files
SONARTEXT-6 Do not analyze every non binary file in SonarQube or SonarCloud context (#109)
1 parent cd063e1 commit af19ba7

File tree

4 files changed

+80
-12
lines changed

4 files changed

+80
-12
lines changed

its/ruling/src/test/java/org/sonarsource/text/TextRulingTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void test() throws Exception {
7272
.setSourceEncoding("UTF-8")
7373
.setProperty("dump.old", FileLocation.of("src/test/resources/expected").getFile().getAbsolutePath())
7474
.setProperty("dump.new", FileLocation.of("target/actual").getFile().getAbsolutePath())
75+
.setProperty("sonar.text.analyzeAllFiles", "true")
7576
.setProperty("sonar.cpd.exclusions", "**/*")
7677
.setProperty("lits.differences", LITS_DIFFERENCES_FILE.getAbsolutePath());
7778
build.setEnvironmentVariable("SONAR_RUNNER_OPTS", "-Xmx1000m");

sonar-text-plugin/src/main/java/org/sonar/plugins/common/TextAndSecretsSensor.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import java.util.List;
2525
import java.util.concurrent.TimeUnit;
2626
import java.util.stream.Collectors;
27+
import org.sonar.api.SonarProduct;
28+
import org.sonar.api.batch.fs.FilePredicate;
2729
import org.sonar.api.batch.fs.FileSystem;
2830
import org.sonar.api.batch.fs.InputFile;
2931
import org.sonar.api.batch.rule.CheckFactory;
@@ -42,8 +44,12 @@ public class TextAndSecretsSensor implements Sensor {
4244

4345
public static final String EXCLUDED_FILE_SUFFIXES_KEY = "sonar.text.excluded.file.suffixes";
4446

47+
private static final String ANALYZE_ALL_FILES_KEY = "sonar.text.analyzeAllFiles";
48+
4549
public static final String TEXT_CATEGORY = "Secrets";
4650

51+
private static final FilePredicate LANGUAGE_FILE_PREDICATE = inputFile -> inputFile.language() != null;
52+
4753
private final CheckFactory checkFactory;
4854

4955
private boolean displayHelpAboutExcludingBinaryFile = true;
@@ -68,17 +74,19 @@ public void execute(SensorContext sensorContext) {
6874
}
6975

7076
NotBinaryFilePredicate notBinaryFilePredicate = binaryFilePredicate(sensorContext);
71-
List<InputFile> allInputFiles = getAllInputFiles(sensorContext, notBinaryFilePredicate);
72-
if (allInputFiles.isEmpty()) {
77+
FilePredicate filePredicate = isSonarLintContext(sensorContext) || analyzeAllFiles(sensorContext)
78+
? notBinaryFilePredicate : LANGUAGE_FILE_PREDICATE;
79+
List<InputFile> inputFiles = getInputFiles(sensorContext, filePredicate);
80+
if (inputFiles.isEmpty()) {
7381
return;
7482
}
7583

76-
List<String> filenames = allInputFiles.stream().map(InputFile::toString).collect(Collectors.toList());
84+
List<String> filenames = inputFiles.stream().map(InputFile::toString).collect(Collectors.toList());
7785
ProgressReport progressReport = new ProgressReport("Progress of the text and secrets analysis", TimeUnit.SECONDS.toMillis(10));
7886
progressReport.start(filenames);
7987
boolean cancelled = false;
8088
try {
81-
for (InputFile inputFile : allInputFiles) {
89+
for (InputFile inputFile : inputFiles) {
8290
if (sensorContext.isCancelled()) {
8391
cancelled = true;
8492
break;
@@ -100,13 +108,25 @@ private static NotBinaryFilePredicate binaryFilePredicate(SensorContext sensorCo
100108
return new NotBinaryFilePredicate(sensorContext.config().getStringArray(TextAndSecretsSensor.EXCLUDED_FILE_SUFFIXES_KEY));
101109
}
102110

103-
private static List<InputFile> getAllInputFiles(SensorContext sensorContext, NotBinaryFilePredicate notBinaryFilePredicate) {
104-
List<InputFile> allInputFiles = new ArrayList<>();
111+
private static boolean isSonarLintContext(SensorContext sensorContext) {
112+
return sensorContext.runtime().getProduct().equals(SonarProduct.SONARLINT);
113+
}
114+
115+
private static boolean analyzeAllFiles(SensorContext sensorContext) {
116+
return "true".equals(sensorContext.config().get(ANALYZE_ALL_FILES_KEY).orElse("false"));
117+
}
118+
119+
/**
120+
* In SonarLint context we want to analyze all non-binary input files, even when they are not analyzed or assigned to a language.
121+
* To avoid analyzing all non-binary files to reduce time and memory consumption in a non SonarLint context only files assigned to a language are analyzed.
122+
*/
123+
private static List<InputFile> getInputFiles(SensorContext sensorContext, FilePredicate filePredicate) {
124+
List<InputFile> inputFiles = new ArrayList<>();
105125
FileSystem fileSystem = sensorContext.fileSystem();
106-
for (InputFile inputFile : fileSystem.inputFiles(notBinaryFilePredicate)) {
107-
allInputFiles.add(inputFile);
126+
for (InputFile inputFile : fileSystem.inputFiles(filePredicate)) {
127+
inputFiles.add(inputFile);
108128
}
109-
return allInputFiles;
129+
return inputFiles;
110130
}
111131

112132
private void analyze(SensorContext sensorContext, List<Check> activeChecks, InputFile inputFile, NotBinaryFilePredicate notBinaryFilePredicate) {

sonar-text-plugin/src/test/java/org/sonar/plugins/common/TestUtils.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import java.util.stream.Collectors;
2929
import java.util.stream.Stream;
3030
import javax.annotation.Nullable;
31+
import org.sonar.api.SonarEdition;
32+
import org.sonar.api.SonarProduct;
33+
import org.sonar.api.SonarQubeSide;
34+
import org.sonar.api.SonarRuntime;
3135
import org.sonar.api.batch.fs.InputFile;
3236
import org.sonar.api.batch.fs.TextRange;
3337
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
@@ -37,14 +41,20 @@
3741
import org.sonar.api.batch.sensor.internal.SensorContextTester;
3842
import org.sonar.api.batch.sensor.issue.Issue;
3943
import org.sonar.api.batch.sensor.issue.IssueLocation;
44+
import org.sonar.api.internal.SonarRuntimeImpl;
4045
import org.sonar.api.rule.RuleKey;
46+
import org.sonar.api.utils.Version;
4147
import org.sonar.plugins.secrets.SecretsRulesDefinition;
4248
import org.sonar.plugins.text.TextRuleDefinition;
4349

4450
import static java.nio.charset.StandardCharsets.UTF_8;
4551

4652
public class TestUtils {
4753

54+
private static final Version VERSION = Version.create(9, 9);
55+
public static final SonarRuntime SONARLINT_RUNTIME = SonarRuntimeImpl.forSonarLint(VERSION);
56+
public static final SonarRuntime SONARQUBE_RUNTIME = SonarRuntimeImpl.forSonarQube(VERSION, SonarQubeSide.SERVER, SonarEdition.COMMUNITY);
57+
4858
public static List<String> analyze(Check check, String fileContent) throws IOException {
4959
return analyze(check, inputFile(fileContent));
5060
}
@@ -133,8 +143,12 @@ public static SensorContextTester sensorContext(String... activeRules) {
133143
return sensorContext(new File(".").getAbsoluteFile(), activeRules);
134144
}
135145

146+
/**
147+
* By default, the SonarLint runtime is chosen because it allows to analyze all files and not only files assigned to a language
148+
*/
136149
public static SensorContextTester sensorContext(File baseDir, String... activeRules) {
137150
return SensorContextTester.create(baseDir)
151+
.setRuntime(SONARLINT_RUNTIME)
138152
.setActiveRules(activeRules(activeRules));
139153
}
140154

sonar-text-plugin/src/test/java/org/sonar/plugins/common/TextAndSecretsSensorTest.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.sonar.api.batch.sensor.error.AnalysisError;
3636
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
3737
import org.sonar.api.batch.sensor.internal.SensorContextTester;
38+
import org.sonar.api.config.internal.MapSettings;
3839
import org.sonar.api.utils.log.LogTesterJUnit5;
3940
import org.sonar.check.Rule;
4041
import org.sonar.plugins.text.api.TextCheck;
@@ -51,6 +52,8 @@
5152

5253
class TextAndSecretsSensorTest {
5354

55+
private static final String SENSITIVE_BIDI_CHARS = "\u0002\u0004";
56+
5457
@RegisterExtension
5558
LogTesterJUnit5 logTester = new LogTesterJUnit5();
5659

@@ -201,6 +204,36 @@ public void analyze(InputFileContext ctx) {
201204
}
202205
}
203206

207+
@Test
208+
void shouldNotAnalyzeNonLanguageAssignedFilesInSonarQubeContext() {
209+
Check check = new ReportIssueAtLineOneCheck();
210+
SensorContextTester context = sensorContext(check);
211+
context.setRuntime(TestUtils.SONARQUBE_RUNTIME);
212+
analyse(sensor(check), context, inputFile(Path.of("Foo.java"), SENSITIVE_BIDI_CHARS, null));
213+
assertThat(logTester.logs()).isEmpty();
214+
}
215+
216+
@Test
217+
void shouldAnalyzeLanguageAssignedFilesInSonarQubeContext() {
218+
Check check = new ReportIssueAtLineOneCheck();
219+
SensorContextTester context = sensorContext(check);
220+
context.setRuntime(TestUtils.SONARQUBE_RUNTIME);
221+
analyse(sensor(check), context, inputFile(Path.of("Foo.java"), SENSITIVE_BIDI_CHARS, "java"));
222+
assertThat(logTester.logs()).containsExactly(
223+
"1 source file to be analyzed",
224+
"1/1 source file has been analyzed");
225+
}
226+
227+
@Test
228+
void shouldNotAnalyzeNonLanguageAssignedFilesInSonarQubeContextWhenPropertyIsSet() {
229+
Check check = new ReportIssueAtLineOneCheck();
230+
SensorContextTester context = sensorContext(check);
231+
context.setRuntime(TestUtils.SONARQUBE_RUNTIME);
232+
context.setSettings(new MapSettings().setProperty("sonar.text.analyzeAllFiles", true));
233+
analyse(sensor(check), context, inputFile(Path.of("Foo.java"), SENSITIVE_BIDI_CHARS, null));
234+
assertThat(logTester.logs()).contains("1 source file to be analyzed");
235+
}
236+
204237
@Test
205238
void should_not_execute_checks_on_binary_file_names() {
206239
Check check = new BoomCheck();
@@ -215,7 +248,7 @@ void should_not_execute_checks_on_binary_file_names() {
215248
void should_not_exclude_binary_file_content_if_language_is_not_null() throws IOException {
216249
Check check = new ReportIssueAtLineOneCheck();
217250
SensorContextTester context = defaultSensorContext();
218-
analyse(sensor(check), context, inputFile(Path.of("Foo.java"), "\u0002\u0004", "java"));
251+
analyse(sensor(check), context, inputFile(Path.of("Foo.java"), SENSITIVE_BIDI_CHARS, "java"));
219252

220253
assertThat(asString(context.allIssues())).containsExactly(
221254
"text:IssueAtLineOne [1:0-1:2] testIssue");
@@ -229,8 +262,8 @@ void should_exclude_binary_file_content_if_language_is_null_and_exclude_the_exte
229262
Check check = new ReportIssueAtLineOneCheck();
230263
SensorContextTester context = defaultSensorContext();
231264
analyse(sensor(check), context,
232-
inputFile(Path.of("Foo.txt"), "\u0002\u0004", null),
233-
inputFile(Path.of("FileWithoutExtension"), "\u0002\u0004", null));
265+
inputFile(Path.of("Foo.txt"), SENSITIVE_BIDI_CHARS, null),
266+
inputFile(Path.of("FileWithoutExtension"), SENSITIVE_BIDI_CHARS, null));
234267

235268
assertThat(asString(context.allIssues())).isEmpty();
236269
assertThat(logTester.logs()).containsExactlyInAnyOrder(

0 commit comments

Comments
 (0)