*/
public class SensorStrategy {
- private boolean global = false;
+ private boolean global = true;
public boolean isGlobal() {
return global;
package org.sonar.api.batch.postjob;
import org.sonar.api.ExtensionPoint;
-import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.scanner.ScannerSide;
/**
* PostJobs are executed at the very end of scanner analysis. A PostJob can't do any modification
* asynchronous process to compute data on server side in 5.x series.
*
* @since 5.2
+ * @since 7.6 postjobs are loaded in the project container
*/
@ScannerSide
@ExtensionPoint
*/
package org.sonar.api.batch.scm;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.InstantiationStrategy;
+import java.util.List;
+import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
-import java.util.List;
-
/**
* This class should be implemented by SCM providers.
* @since 5.0
*/
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
@ScannerSide
public abstract class BlameCommand {
assertThat(inputFile.getModuleRelativePath()).isEqualTo(MODULE_RELATIVE_PATH);
assertThat(inputFile.getProjectRelativePath()).isEqualTo(PROJECT_RELATIVE_PATH);
+ sensorStrategy.setGlobal(false);
assertThat(inputFile.relativePath()).isEqualTo(MODULE_RELATIVE_PATH);
assertThat(new File(inputFile.relativePath())).isRelative();
sensorStrategy.setGlobal(true);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.bootstrap;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.ClassUtils;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.batch.Phase;
+import org.sonar.api.utils.AnnotationUtils;
+import org.sonar.api.utils.dag.DirectAcyclicGraph;
+import org.sonar.core.platform.ComponentContainer;
+
+public abstract class AbstractExtensionDictionnary {
+
+ private final ComponentContainer componentContainer;
+
+ public AbstractExtensionDictionnary(ComponentContainer componentContainer) {
+ this.componentContainer = componentContainer;
+ }
+
+ public <T> Collection<T> select(Class<T> type, boolean sort, @Nullable ExtensionMatcher matcher) {
+ List<T> result = getFilteredExtensions(type, matcher);
+ if (sort) {
+ return sort(result);
+ }
+ return result;
+ }
+
+ private static Phase.Name evaluatePhase(Object extension) {
+ Phase phaseAnnotation = AnnotationUtils.getAnnotation(extension, Phase.class);
+ if (phaseAnnotation != null) {
+ return phaseAnnotation.name();
+ }
+ return Phase.Name.DEFAULT;
+ }
+
+ protected <T> List<T> getFilteredExtensions(Class<T> type, @Nullable ExtensionMatcher matcher) {
+ List<T> result = new ArrayList<>();
+
+ for (Object extension : getExtensions(type)) {
+ if (shouldKeep(type, extension, matcher)) {
+ result.add((T) extension);
+ }
+ }
+ return result;
+ }
+
+ private <T> List<T> getExtensions(Class<T> type) {
+ List<T> extensions = new ArrayList<>();
+ completeScannerExtensions(componentContainer, extensions, type);
+ return extensions;
+ }
+
+ private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) {
+ extensions.addAll(container.getComponentsByType(type));
+ ComponentContainer parentContainer = container.getParent();
+ if (parentContainer != null) {
+ completeScannerExtensions(parentContainer, extensions, type);
+ }
+ }
+
+ protected <T> Collection<T> sort(Collection<T> extensions) {
+ DirectAcyclicGraph dag = new DirectAcyclicGraph();
+
+ for (T extension : extensions) {
+ dag.add(extension);
+ for (Object dependency : getDependencies(extension)) {
+ dag.add(extension, dependency);
+ }
+ for (Object generates : getDependents(extension)) {
+ dag.add(generates, extension);
+ }
+ completePhaseDependencies(dag, extension);
+ }
+ List<?> sortedList = dag.sort();
+
+ return (Collection<T>) sortedList.stream()
+ .filter(extensions::contains)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Extension dependencies
+ */
+ private <T> List<Object> getDependencies(T extension) {
+ return new ArrayList<>(evaluateAnnotatedClasses(extension, DependsUpon.class));
+ }
+
+ /**
+ * Objects that depend upon this extension.
+ */
+ private <T> List<Object> getDependents(T extension) {
+ return new ArrayList<>(evaluateAnnotatedClasses(extension, DependedUpon.class));
+ }
+
+ private static void completePhaseDependencies(DirectAcyclicGraph dag, Object extension) {
+ Phase.Name phase = evaluatePhase(extension);
+ dag.add(extension, phase);
+ for (Phase.Name name : Phase.Name.values()) {
+ if (phase.compareTo(name) < 0) {
+ dag.add(name, extension);
+ } else if (phase.compareTo(name) > 0) {
+ dag.add(extension, name);
+ }
+ }
+ }
+
+ List<Object> evaluateAnnotatedClasses(Object extension, Class<? extends Annotation> annotation) {
+ List<Object> results = new ArrayList<>();
+ Class<?> aClass = extension.getClass();
+ while (aClass != null) {
+ evaluateClass(aClass, annotation, results);
+
+ for (Method method : aClass.getDeclaredMethods()) {
+ if (method.getAnnotation(annotation) != null) {
+ checkAnnotatedMethod(method);
+ evaluateMethod(extension, method, results);
+ }
+ }
+ aClass = aClass.getSuperclass();
+ }
+
+ return results;
+ }
+
+ private static void evaluateClass(Class<?> extensionClass, Class<? extends Annotation> annotationClass, List<Object> results) {
+ Annotation annotation = extensionClass.getAnnotation(annotationClass);
+ if (annotation != null) {
+ if (annotation.annotationType().isAssignableFrom(DependsUpon.class)) {
+ results.addAll(Arrays.asList(((DependsUpon) annotation).value()));
+
+ } else if (annotation.annotationType().isAssignableFrom(DependedUpon.class)) {
+ results.addAll(Arrays.asList(((DependedUpon) annotation).value()));
+ }
+ }
+
+ Class<?>[] interfaces = extensionClass.getInterfaces();
+ for (Class<?> anInterface : interfaces) {
+ evaluateClass(anInterface, annotationClass, results);
+ }
+ }
+
+ private void evaluateMethod(Object extension, Method method, List<Object> results) {
+ try {
+ Object result = method.invoke(extension);
+ if (result != null) {
+ if (result instanceof Class<?>) {
+ results.addAll(componentContainer.getComponentsByType((Class<?>) result));
+
+ } else if (result instanceof Collection<?>) {
+ results.addAll((Collection<?>) result);
+
+ } else if (result.getClass().isArray()) {
+ for (int i = 0; i < Array.getLength(result); i++) {
+ results.add(Array.get(result, i));
+ }
+
+ } else {
+ results.add(result);
+ }
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Can not invoke method " + method, e);
+ }
+ }
+
+ private static void checkAnnotatedMethod(Method method) {
+ if (!Modifier.isPublic(method.getModifiers())) {
+ throw new IllegalStateException("Annotated method must be public:" + method);
+ }
+ if (method.getParameterTypes().length > 0) {
+ throw new IllegalStateException("Annotated method must not have parameters:" + method);
+ }
+ }
+
+ private static boolean shouldKeep(Class<?> type, Object extension, @Nullable ExtensionMatcher matcher) {
+ return ClassUtils.isAssignable(extension.getClass(), type) && (matcher == null || matcher.accept(extension));
+ }
+}
import org.sonar.scanner.issue.tracking.ServerIssueFromWs;
import org.sonar.scanner.issue.tracking.TrackedIssue;
import org.sonar.scanner.scan.report.JSONReport;
-import org.sonar.scanner.scm.ScmConfiguration;
-import org.sonar.scanner.scm.ScmPublisher;
import org.sonar.scanner.source.ZeroCoverageSensor;
public class BatchComponents {
DefaultResourceTypes.get());
components.addAll(CorePropertyDefinitions.all());
if (!analysisMode.isIssues()) {
- // SCM
- components.add(ScmConfiguration.class);
- components.add(ScmPublisher.class);
-
components.add(ZeroCoverageSensor.class);
// Generic coverage
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.bootstrap;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+import org.sonar.api.batch.postjob.PostJob;
+import org.sonar.api.batch.postjob.PostJobContext;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.scanner.postjob.PostJobOptimizer;
+import org.sonar.scanner.postjob.PostJobWrapper;
+
+public class PostJobExtensionDictionnary extends AbstractExtensionDictionnary {
+
+ private final PostJobContext postJobContext;
+ private final PostJobOptimizer postJobOptimizer;
+
+ public PostJobExtensionDictionnary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
+ super(componentContainer);
+ this.postJobOptimizer = postJobOptimizer;
+ this.postJobContext = postJobContext;
+ }
+
+ public Collection<PostJobWrapper> selectPostJobs() {
+ Collection<PostJob> result = sort(getFilteredExtensions(PostJob.class, null));
+ return result.stream()
+ .map(j -> new PostJobWrapper(j, postJobContext, postJobOptimizer))
+ .filter(PostJobWrapper::shouldExecute)
+ .collect(Collectors.toList());
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.bootstrap;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.ClassUtils;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.batch.Phase;
-import org.sonar.api.batch.postjob.PostJob;
-import org.sonar.api.batch.postjob.PostJobContext;
-import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.utils.AnnotationUtils;
-import org.sonar.api.utils.dag.DirectAcyclicGraph;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.postjob.PostJobOptimizer;
-import org.sonar.scanner.postjob.PostJobWrapper;
-import org.sonar.scanner.sensor.SensorOptimizer;
-import org.sonar.scanner.sensor.SensorWrapper;
-
-/**
- * @since 2.6
- */
-public class ScannerExtensionDictionnary {
-
- private final ComponentContainer componentContainer;
- private final SensorContext sensorContext;
- private final SensorOptimizer sensorOptimizer;
- private final PostJobOptimizer postJobOptimizer;
- private final PostJobContext postJobContext;
-
- public ScannerExtensionDictionnary(ComponentContainer componentContainer, SensorContext sensorContext, SensorOptimizer sensorOptimizer,
- PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
- this.componentContainer = componentContainer;
- this.sensorContext = sensorContext;
- this.sensorOptimizer = sensorOptimizer;
- this.postJobOptimizer = postJobOptimizer;
- this.postJobContext = postJobContext;
- }
-
- public <T> Collection<T> select(Class<T> type, boolean sort, @Nullable ExtensionMatcher matcher) {
- List<T> result = getFilteredExtensions(type, matcher);
- if (sort) {
- return sort(result);
- }
- return result;
- }
-
- public Collection<SensorWrapper> selectSensors(boolean global) {
- Collection<Sensor> result = sort(getFilteredExtensions(Sensor.class, null));
- return result.stream()
- .map(s -> new SensorWrapper(s, sensorContext, sensorOptimizer))
- .filter(s -> global == s.isGlobal() && s.shouldExecute())
- .collect(Collectors.toList());
- }
-
- public Collection<PostJobWrapper> selectPostJobs() {
- Collection<PostJob> result = sort(getFilteredExtensions(PostJob.class, null));
- return result.stream()
- .map(j -> new PostJobWrapper(j, postJobContext, postJobOptimizer))
- .filter(PostJobWrapper::shouldExecute)
- .collect(Collectors.toList());
- }
-
- private static Phase.Name evaluatePhase(Object extension) {
- Phase phaseAnnotation = AnnotationUtils.getAnnotation(extension, Phase.class);
- if (phaseAnnotation != null) {
- return phaseAnnotation.name();
- }
- return Phase.Name.DEFAULT;
- }
-
- private <T> List<T> getFilteredExtensions(Class<T> type, @Nullable ExtensionMatcher matcher) {
- List<T> result = new ArrayList<>();
-
- for (Object extension : getExtensions(type)) {
- if (shouldKeep(type, extension, matcher)) {
- result.add((T) extension);
- }
- }
- return result;
- }
-
- private <T> List<T> getExtensions(Class<T> type) {
- List<T> extensions = new ArrayList<>();
- completeScannerExtensions(componentContainer, extensions, type);
- return extensions;
- }
-
- private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) {
- extensions.addAll(container.getComponentsByType(type));
- ComponentContainer parentContainer = container.getParent();
- if (parentContainer != null) {
- completeScannerExtensions(parentContainer, extensions, type);
- }
- }
-
- private <T> Collection<T> sort(Collection<T> extensions) {
- DirectAcyclicGraph dag = new DirectAcyclicGraph();
-
- for (T extension : extensions) {
- dag.add(extension);
- for (Object dependency : getDependencies(extension)) {
- dag.add(extension, dependency);
- }
- for (Object generates : getDependents(extension)) {
- dag.add(generates, extension);
- }
- completePhaseDependencies(dag, extension);
- }
- List<?> sortedList = dag.sort();
-
- return (Collection<T>) sortedList.stream()
- .filter(extensions::contains)
- .collect(Collectors.toList());
- }
-
- /**
- * Extension dependencies
- */
- private <T> List<Object> getDependencies(T extension) {
- return new ArrayList<>(evaluateAnnotatedClasses(extension, DependsUpon.class));
- }
-
- /**
- * Objects that depend upon this extension.
- */
- private <T> List<Object> getDependents(T extension) {
- return new ArrayList<>(evaluateAnnotatedClasses(extension, DependedUpon.class));
- }
-
- private static void completePhaseDependencies(DirectAcyclicGraph dag, Object extension) {
- Phase.Name phase = evaluatePhase(extension);
- dag.add(extension, phase);
- for (Phase.Name name : Phase.Name.values()) {
- if (phase.compareTo(name) < 0) {
- dag.add(name, extension);
- } else if (phase.compareTo(name) > 0) {
- dag.add(extension, name);
- }
- }
- }
-
- List<Object> evaluateAnnotatedClasses(Object extension, Class<? extends Annotation> annotation) {
- List<Object> results = new ArrayList<>();
- Class<?> aClass = extension.getClass();
- while (aClass != null) {
- evaluateClass(aClass, annotation, results);
-
- for (Method method : aClass.getDeclaredMethods()) {
- if (method.getAnnotation(annotation) != null) {
- checkAnnotatedMethod(method);
- evaluateMethod(extension, method, results);
- }
- }
- aClass = aClass.getSuperclass();
- }
-
- return results;
- }
-
- private static void evaluateClass(Class<?> extensionClass, Class<? extends Annotation> annotationClass, List<Object> results) {
- Annotation annotation = extensionClass.getAnnotation(annotationClass);
- if (annotation != null) {
- if (annotation.annotationType().isAssignableFrom(DependsUpon.class)) {
- results.addAll(Arrays.asList(((DependsUpon) annotation).value()));
-
- } else if (annotation.annotationType().isAssignableFrom(DependedUpon.class)) {
- results.addAll(Arrays.asList(((DependedUpon) annotation).value()));
- }
- }
-
- Class<?>[] interfaces = extensionClass.getInterfaces();
- for (Class<?> anInterface : interfaces) {
- evaluateClass(anInterface, annotationClass, results);
- }
- }
-
- private void evaluateMethod(Object extension, Method method, List<Object> results) {
- try {
- Object result = method.invoke(extension);
- if (result != null) {
- if (result instanceof Class<?>) {
- results.addAll(componentContainer.getComponentsByType((Class<?>) result));
-
- } else if (result instanceof Collection<?>) {
- results.addAll((Collection<?>) result);
-
- } else if (result.getClass().isArray()) {
- for (int i = 0; i < Array.getLength(result); i++) {
- results.add(Array.get(result, i));
- }
-
- } else {
- results.add(result);
- }
- }
- } catch (Exception e) {
- throw new IllegalStateException("Can not invoke method " + method, e);
- }
- }
-
- private static void checkAnnotatedMethod(Method method) {
- if (!Modifier.isPublic(method.getModifiers())) {
- throw new IllegalStateException("Annotated method must be public:" + method);
- }
- if (method.getParameterTypes().length > 0) {
- throw new IllegalStateException("Annotated method must not have parameters:" + method);
- }
- }
-
- private static boolean shouldKeep(Class<?> type, Object extension, @Nullable ExtensionMatcher matcher) {
- return ClassUtils.isAssignable(extension.getClass(), type) && (matcher == null || matcher.accept(extension));
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.bootstrap;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.scanner.sensor.SensorOptimizer;
+import org.sonar.scanner.sensor.SensorWrapper;
+
+public class SensorExtensionDictionnary extends AbstractExtensionDictionnary {
+
+ private final SensorContext sensorContext;
+ private final SensorOptimizer sensorOptimizer;
+
+ public SensorExtensionDictionnary(ComponentContainer componentContainer, SensorContext sensorContext, SensorOptimizer sensorOptimizer) {
+ super(componentContainer);
+ this.sensorContext = sensorContext;
+ this.sensorOptimizer = sensorOptimizer;
+ }
+
+ public Collection<SensorWrapper> selectSensors(boolean global) {
+ Collection<Sensor> result = sort(getFilteredExtensions(Sensor.class, null));
+ return result.stream()
+ .map(s -> new SensorWrapper(s, sensorContext, sensorOptimizer))
+ .filter(s -> global == s.isGlobal() && s.shouldExecute())
+ .collect(Collectors.toList());
+ }
+}
private void storeFs(ProjectScanContainer container) {
InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class);
- for (InputFile inputPath : inputFileCache.allFiles()) {
+ for (InputFile inputPath : inputFileCache.inputFiles()) {
inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath);
}
}
import org.slf4j.LoggerFactory;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.WildcardPattern;
@Immutable
private Collection<WildcardPattern> exclusionPatterns;
- public AbstractCoverageExclusions(Configuration config, Function<DefaultInputFile, String> pathExtractor) {
+ public AbstractCoverageExclusions(Function<String, String[]> configProvider, Function<DefaultInputFile, String> pathExtractor) {
this.pathExtractor = pathExtractor;
Builder<WildcardPattern> builder = ImmutableList.builder();
- coverageExclusionConfig = config.getStringArray(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY);
+ coverageExclusionConfig = configProvider.apply(CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY);
for (String pattern : coverageExclusionConfig) {
builder.add(WildcardPattern.create(pattern));
}
}
}
- boolean isExcluded(DefaultInputFile file) {
+ public boolean isExcluded(DefaultInputFile file) {
boolean found = false;
Iterator<WildcardPattern> iterator = exclusionPatterns.iterator();
while (!found && iterator.hasNext()) {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.phases;
-
-import java.util.Arrays;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-
-public abstract class AbstractModulePhaseExecutor {
-
- private static final Logger LOG = Loggers.get(AbstractModulePhaseExecutor.class);
-
- private final PostJobsExecutor postJobsExecutor;
- private final SensorsExecutor sensorsExecutor;
- private final DefaultModuleFileSystem fs;
- private final IssueExclusionsLoader issueExclusionsLoader;
- private final InputModuleHierarchy hierarchy;
- private final ModuleCoverageExclusions moduleCoverageExclusions;
- private final ProjectCoverageExclusions projectCoverageExclusions;
- private final AnalysisWarnings analysisWarnings;
- private boolean warnCoverageAlreadyLogged;
-
- public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
- IssueExclusionsLoader issueExclusionsLoader,
- ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
- AnalysisWarnings analysisWarnings) {
- this.postJobsExecutor = postJobsExecutor;
- this.sensorsExecutor = sensorsExecutor;
- this.fs = fs;
- this.issueExclusionsLoader = issueExclusionsLoader;
- this.hierarchy = hierarchy;
- this.moduleCoverageExclusions = moduleCoverageExclusions;
- this.projectCoverageExclusions = projectCoverageExclusions;
- this.analysisWarnings = analysisWarnings;
- }
-
- /**
- * Executed on each module
- */
- public final void execute(DefaultInputModule module) {
- // Initialize coverage exclusions
- evaluateCoverageExclusions(module);
-
- sensorsExecutor.execute();
-
- afterSensors();
-
- if (hierarchy.isRoot(module)) {
- executeOnRoot();
- postJobsExecutor.execute();
- }
- }
-
- private void evaluateCoverageExclusions(AbstractProjectOrModule module) {
- if (!Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
- moduleCoverageExclusions.log();
- }
- for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
- boolean excludedByProjectConfiguration = projectCoverageExclusions.isExcluded((DefaultInputFile) inputFile);
- if (excludedByProjectConfiguration) {
- ((DefaultInputFile) inputFile).setExcludedForCoverage(true);
- LOG.debug("File {} excluded for coverage", inputFile);
- continue;
- }
- boolean excludedByModuleConfig = moduleCoverageExclusions.isExcluded((DefaultInputFile) inputFile);
- if (excludedByModuleConfig) {
- ((DefaultInputFile) inputFile).setExcludedForCoverage(true);
- if (Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
- warnOnce("File '" + inputFile + "' was excluded from coverage because patterns are still evaluated using module relative paths but this is deprecated. " +
- "Please update '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' configuration so that patterns refer to project relative paths");
- } else {
- warnOnce("Defining coverage exclusions at module level is deprecated. " +
- "Move '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' from module '" + module.getName() + "' " +
- "to the root project and update patterns to refer to project relative paths");
- }
- LOG.debug("File {} excluded for coverage", inputFile);
- }
- }
-
- }
-
- private void warnOnce(String msg) {
- if (!warnCoverageAlreadyLogged) {
- LOG.warn(msg);
- analysisWarnings.addUnique(msg);
- warnCoverageAlreadyLogged = true;
- }
- }
-
- protected void afterSensors() {
- }
-
- protected abstract void executeOnRoot();
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.phases;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.issue.tracking.IssueTransition;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.report.IssuesReports;
-
-public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
-
- private static final Logger LOG = LoggerFactory.getLogger(IssuesPhaseExecutor.class);
-
- private final IssuesReports issuesReport;
- private final IssueTransition localIssueTracking;
-
- public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- IssuesReports jsonReport, DefaultModuleFileSystem fs,
- IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy,
- ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
- AnalysisWarnings analysisWarnings) {
- super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, issueExclusionsLoader,
- moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
- this.issuesReport = jsonReport;
- this.localIssueTracking = localIssueTracking;
- }
-
- @Override
- protected void executeOnRoot() {
- localIssueTracking.execute();
- issuesReport.execute();
- LOG.info("ANALYSIS SUCCESSFUL");
- }
-}
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.scanner.scan.ModuleConfiguration;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+
+import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;
@Immutable
public class ModuleCoverageExclusions extends AbstractCoverageExclusions {
- public ModuleCoverageExclusions(ModuleConfiguration config) {
- super(config, DefaultInputFile::getModuleRelativePath);
+ public ModuleCoverageExclusions(DefaultInputModule module) {
+ super(k -> {
+ String value = module.properties().get(k);
+ return value != null ? parseAsCsv(k, value) : new String[0];
+ }, DefaultInputFile::getModuleRelativePath);
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.phases;
-
-import java.util.Collection;
-import java.util.stream.Collectors;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
-import org.sonar.scanner.postjob.PostJobWrapper;
-
-@ScannerSide
-public class PostJobsExecutor {
- private static final Logger LOG = Loggers.get(PostJobsExecutor.class);
-
- private final ScannerExtensionDictionnary selector;
-
- public PostJobsExecutor(ScannerExtensionDictionnary selector) {
- this.selector = selector;
- }
-
- public void execute() {
- Collection<PostJobWrapper> postJobs = selector.selectPostJobs();
- execute(postJobs);
- }
-
- private static void execute(Collection<PostJobWrapper> postJobs) {
- logPostJobs(postJobs);
-
- for (PostJobWrapper postJob : postJobs) {
- if (postJob.shouldExecute()) {
- LOG.info("Executing post-job '{}'", postJob);
- postJob.execute();
- }
- }
- }
-
- private static void logPostJobs(Collection<PostJobWrapper> postJobs) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(() -> "Post-jobs : " + postJobs.stream().map(Object::toString).collect(Collectors.joining(" -> ")));
- }
- }
-}
public class ProjectCoverageExclusions extends AbstractCoverageExclusions {
public ProjectCoverageExclusions(ProjectConfiguration projectConfig) {
- super(projectConfig, DefaultInputFile::getProjectRelativePath);
+ super(projectConfig::getStringArray, DefaultInputFile::getProjectRelativePath);
log();
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.phases;
-
-import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
-import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.scanner.cpd.CpdExecutor;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scm.ScmPublisher;
-
-public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
-
- private final ReportPublisher reportPublisher;
- private final CpdExecutor cpdExecutor;
- private final ScmPublisher scm;
-
- public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- ReportPublisher reportPublisher, DefaultModuleFileSystem fs, IssueExclusionsLoader issueExclusionsLoader,
- CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy,
- ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
- AnalysisWarnings analysisWarnings) {
- super(postJobsExecutor, sensorsExecutor, hierarchy, fs, issueExclusionsLoader, moduleCoverageExclusions,
- projectCoverageExclusions, analysisWarnings);
- this.reportPublisher = reportPublisher;
- this.cpdExecutor = cpdExecutor;
- this.scm = scm;
- }
-
- @Override
- protected void executeOnRoot() {
- cpdExecutor.execute();
- reportPublisher.execute();
- }
-
- @Override
- protected void afterSensors() {
- scm.publish();
- }
-}
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.logs.Profiler;
-import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
+import org.sonar.scanner.bootstrap.SensorExtensionDictionnary;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.sensor.SensorWrapper;
-@ScannerSide
public class SensorsExecutor {
private static final Logger LOG = Loggers.get(SensorsExecutor.class);
private static final Profiler profiler = Profiler.create(LOG);
- private final ScannerExtensionDictionnary selector;
+ private final SensorExtensionDictionnary selector;
private final SensorStrategy strategy;
private final ScannerPluginRepository pluginRepo;
private final boolean isRoot;
- public SensorsExecutor(ScannerExtensionDictionnary selector, DefaultInputModule module, InputModuleHierarchy hierarchy,
+ public SensorsExecutor(SensorExtensionDictionnary selector, DefaultInputModule module, InputModuleHierarchy hierarchy,
SensorStrategy strategy, ScannerPluginRepository pluginRepo) {
this.selector = selector;
this.strategy = strategy;
}
public void execute() {
- Collection<SensorWrapper> moduleSensors = selector.selectSensors(false);
+ Collection<SensorWrapper> moduleSensors = new ArrayList<>();
+ withModuleStrategy(() -> moduleSensors.addAll(selector.selectSensors(false)));
Collection<SensorWrapper> globalSensors = new ArrayList<>();
if (isRoot) {
- withGlobalStrategy(() -> globalSensors.addAll(selector.selectSensors(true)));
+ globalSensors.addAll(selector.selectSensors(true));
}
printSensors(moduleSensors, globalSensors);
- execute(moduleSensors);
+ withModuleStrategy(() -> execute(moduleSensors));
if (isRoot) {
- withGlobalStrategy(() -> execute(globalSensors));
+ execute(globalSensors);
}
}
LOG.debug("Sensors : {}", sensors);
}
- private void withGlobalStrategy(Runnable r) {
+ private void withModuleStrategy(Runnable r) {
boolean orig = strategy.isGlobal();
- strategy.setGlobal(true);
+ strategy.setGlobal(false);
r.run();
strategy.setGlobal(orig);
}
this.optimizer = optimizer;
this.descriptor = new DefaultPostJobDescriptor();
newPostJob.describe(descriptor);
+ if (descriptor.name() == null) {
+ descriptor.name(newPostJob.getClass().getName());
+ }
this.adaptor = adaptor;
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.postjob;
+
+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;
+
+public class PostJobsExecutor {
+ private static final Logger LOG = Loggers.get(PostJobsExecutor.class);
+
+ private final PostJobExtensionDictionnary selector;
+
+ public PostJobsExecutor(PostJobExtensionDictionnary selector) {
+ this.selector = selector;
+ }
+
+ public void execute() {
+ Collection<PostJobWrapper> postJobs = selector.selectPostJobs();
+ execute(postJobs);
+ }
+
+ private static void execute(Collection<PostJobWrapper> postJobs) {
+ logPostJobs(postJobs);
+
+ for (PostJobWrapper postJob : postJobs) {
+ if (postJob.shouldExecute()) {
+ LOG.info("Executing post-job '{}'", postJob);
+ postJob.execute();
+ }
+ }
+ }
+
+ private static void logPostJobs(Collection<PostJobWrapper> postJobs) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(() -> "Post-jobs : " + postJobs.stream().map(Object::toString).collect(Collectors.joining(" -> ")));
+ }
+ }
+}
public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoader {
private static final Logger LOG = LoggerFactory.getLogger(DefaultProjectRepositoriesLoader.class);
private static final String BATCH_PROJECT_URL = "/batch/project.protobuf";
- private ScannerWsClient wsClient;
+ private final ScannerWsClient wsClient;
public DefaultProjectRepositoriesLoader(ScannerWsClient wsClient) {
this.wsClient = wsClient;
return false;
}
- private static ProjectRepositories processStream(InputStream is, String projectKey) {
+ private ProjectRepositories processStream(InputStream is, String projectKey) {
try {
WsProjectResponse response = WsProjectResponse.parseFrom(is);
if (response.getFileDataByModuleAndPathCount() == 0) {
void execute(Logger logger) {
String defaultName = config.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
boolean defaultNameUsed = StringUtils.isBlank(defaultName);
- for (String lang : store.getLanguages()) {
+ for (String lang : store.languages()) {
QProfile profile = profiles.findByLanguage(lang);
if (profile == null) {
logger.warn("No Quality profile found for language {}", lang);
}
}
}
- if (!defaultNameUsed && !store.getLanguages().isEmpty()) {
+ if (!defaultNameUsed && !store.languages().isEmpty()) {
throw MessageException.of("sonar.profile was set to '" + defaultName + "' but didn't match any profile for any language. Please check your configuration.");
}
}
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.DefaultFileLinesContextFactory;
import org.sonar.scanner.bootstrap.ExtensionInstaller;
-import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
+import org.sonar.scanner.bootstrap.SensorExtensionDictionnary;
import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
import org.sonar.scanner.issue.ModuleIssueFilters;
import org.sonar.scanner.issue.ModuleIssues;
-import org.sonar.scanner.phases.AbstractModulePhaseExecutor;
-import org.sonar.scanner.phases.IssuesPhaseExecutor;
import org.sonar.scanner.phases.ModuleCoverageExclusions;
-import org.sonar.scanner.phases.PostJobsExecutor;
-import org.sonar.scanner.phases.PublishPhaseExecutor;
import org.sonar.scanner.phases.SensorsExecutor;
-import org.sonar.scanner.postjob.DefaultPostJobContext;
-import org.sonar.scanner.postjob.PostJobOptimizer;
-import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
-import org.sonar.scanner.scan.report.IssuesReports;
import org.sonar.scanner.sensor.DefaultSensorContext;
import org.sonar.scanner.sensor.DefaultSensorStorage;
import org.sonar.scanner.sensor.SensorOptimizer;
public class ModuleScanContainer extends ComponentContainer {
private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class);
private final DefaultInputModule module;
- private final GlobalAnalysisMode analysisMode;
- public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module, GlobalAnalysisMode analysisMode) {
+ public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) {
super(parent);
this.module = module;
- this.analysisMode = analysisMode;
}
@Override
module.definition(),
module,
MutableModuleSettings.class,
- new ModuleConfigurationProvider());
+ new ModuleConfigurationProvider(),
- if (analysisMode.isIssues()) {
- add(
- IssuesPhaseExecutor.class,
- IssuesReports.class);
- } else {
- add(
- PublishPhaseExecutor.class);
- }
-
- add(
- PostJobsExecutor.class,
SensorsExecutor.class,
// file system
DefaultModuleFileSystem.class,
SensorOptimizer.class,
- PostJobOptimizer.class,
- DefaultPostJobContext.class,
DefaultSensorStorage.class,
DefaultSensorContext.class,
- ScannerExtensionDictionnary.class,
+ SensorExtensionDictionnary.class,
ModuleIssueFilters.class,
ModuleCoverageExclusions.class,
@Override
protected void doAfterStart() {
- getComponentByType(AbstractModulePhaseExecutor.class).execute(module);
+ getComponentByType(SensorsExecutor.class).execute();
}
}
import org.sonar.scanner.bootstrap.ExtensionMatcher;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.bootstrap.MetricProvider;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.cpd.JavaCpdBlockIndexerSensor;
import org.sonar.scanner.mediumtest.AnalysisObservers;
import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
import org.sonar.scanner.phases.ProjectCoverageExclusions;
+import org.sonar.scanner.postjob.DefaultPostJobContext;
+import org.sonar.scanner.postjob.PostJobOptimizer;
+import org.sonar.scanner.postjob.PostJobsExecutor;
import org.sonar.scanner.report.ActiveRulesPublisher;
import org.sonar.scanner.report.AnalysisContextReportPublisher;
import org.sonar.scanner.report.AnalysisWarningsPublisher;
import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
+import org.sonar.scanner.scan.filesystem.DefaultProjectFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.filesystem.LanguageDetection;
import org.sonar.scanner.scan.filesystem.StatusDetection;
import org.sonar.scanner.scan.measure.DefaultMetricFinder;
import org.sonar.scanner.scan.measure.MeasureCache;
+import org.sonar.scanner.scan.report.JSONReport;
import org.sonar.scanner.scm.ScmChangedFilesProvider;
+import org.sonar.scanner.scm.ScmConfiguration;
+import org.sonar.scanner.scm.ScmPublisher;
import org.sonar.scanner.storage.Storages;
import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
ProjectFileIndexer.class,
ProjectExclusionFilters.class,
-
// rules
new ActiveRulesProvider(),
new QualityProfilesProvider(),
SonarCpdBlockIndex.class,
JavaCpdBlockIndexerSensor.class,
+ // PostJobs
+ PostJobsExecutor.class,
+ PostJobOptimizer.class,
+ DefaultPostJobContext.class,
+ PostJobExtensionDictionnary.class,
+
+ // SCM
+ ScmConfiguration.class,
+ ScmPublisher.class,
+
+ // Filesystem
+ DefaultProjectFileSystem.class,
+
AnalysisObservers.class);
addIfMissing(DefaultRulesLoader.class, RulesLoader.class);
getComponentByType(QProfileVerifier.class).execute();
LOG.debug("Start recursive analysis of project modules");
- scanRecursively(tree, tree.root(), analysisMode);
+ scanRecursively(tree, tree.root());
+
+ getComponentByType(ScmPublisher.class).publish();
+
+ if (analysisMode.isIssues()) {
+ getComponentByType(IssueTransition.class).execute();
+ getComponentByType(JSONReport.class).execute();
+ } else {
+ getComponentByType(CpdExecutor.class).execute();
+ getComponentByType(ReportPublisher.class).execute();
+ }
+
+ getComponentByType(PostJobsExecutor.class).execute();
+
+ LOG.info("ANALYSIS SUCCESSFUL");
if (analysisMode.isMediumTest()) {
getComponentByType(AnalysisObservers.class).notifyEndOfScanTask();
}
}
- private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module, GlobalAnalysisMode analysisMode) {
+ private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module) {
for (DefaultInputModule child : tree.children(module)) {
- scanRecursively(tree, child, analysisMode);
+ scanRecursively(tree, child);
}
- scan(module, analysisMode);
+ scan(module);
}
@VisibleForTesting
- void scan(DefaultInputModule module, GlobalAnalysisMode analysisMode) {
- new ModuleScanContainer(this, module, analysisMode).execute();
+ void scan(DefaultInputModule module) {
+ new ModuleScanContainer(this, module).execute();
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 com.google.common.annotations.VisibleForTesting;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.scanner.analysis.DefaultAnalysisMode;
+
+public class DefaultProjectFileSystem extends DefaultFileSystem {
+
+ public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project, DefaultAnalysisMode mode,
+ StatusDetection statusDetection) {
+ super(project.getBaseDir(), inputComponentStore);
+ setFields(project, mode, statusDetection);
+ }
+
+ @VisibleForTesting
+ public DefaultProjectFileSystem(DefaultInputProject project, DefaultAnalysisMode mode, StatusDetection statusDetection) {
+ super(project.getBaseDir());
+ setFields(project, mode, statusDetection);
+ }
+
+ private void setFields(DefaultInputProject project, DefaultAnalysisMode mode, StatusDetection statusDetection) {
+ setWorkDir(project.getWorkDir());
+ setEncoding(project.getEncoding());
+
+ // filter the files sensors have access to
+ if (!mode.scanAllFiles()) {
+ setDefaultPredicate(p -> new SameInputFilePredicate(p, statusDetection, project.definition().getKeyWithBranch()));
+ }
+ }
+
+}
import java.io.IOException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
+import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
+import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputFileFilter;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.phases.ModuleCoverageExclusions;
+import org.sonar.scanner.phases.ProjectCoverageExclusions;
import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.util.ProgressReport;
private final ScanProperties properties;
private final InputFileFilter[] filters;
private final ProjectExclusionFilters projectExclusionFilters;
+ private final ProjectCoverageExclusions projectCoverageExclusions;
private final IssueExclusionsLoader issueExclusionsLoader;
private final MetadataGenerator metadataGenerator;
private final DefaultInputProject project;
private final LanguageDetection langDetection;
private boolean warnExclusionsAlreadyLogged;
+ private boolean warnCoverageExclusionsAlreadyLogged;
- public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
- IssueExclusionsLoader issueExclusionsLoader,
- MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
- LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
+ public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
+ ProjectExclusionFilters projectExclusionFilters, ProjectCoverageExclusions projectCoverageExclusions, IssueExclusionsLoader issueExclusionsLoader,
+ MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
InputFileFilter[] filters) {
this.project = project;
this.scannerComponentIdGenerator = scannerComponentIdGenerator;
this.componentStore = componentStore;
+ this.projectCoverageExclusions = projectCoverageExclusions;
this.issueExclusionsLoader = issueExclusionsLoader;
this.metadataGenerator = metadataGenerator;
this.sensorStrategy = sensorStrategy;
this.projectExclusionFilters = projectExclusionFilters;
}
- public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
- IssueExclusionsLoader issueExclusionsLoader,
+ public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
+ ProjectExclusionFilters projectExclusionFilters, ProjectCoverageExclusions projectCoverageExclusions, IssueExclusionsLoader issueExclusionsLoader,
MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
- this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, issueExclusionsLoader, metadataGenerator, sensorStrategy, languageDetection, analysisWarnings,
+ this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageExclusions, issueExclusionsLoader, metadataGenerator, sensorStrategy,
+ languageDetection,
+ analysisWarnings,
properties, new InputFileFilter[0]);
}
- public void indexFile(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path sourceFile, InputFile.Type type, ProgressReport progressReport,
- AtomicInteger excludedByPatternsCount)
+ public void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Path sourceFile,
+ InputFile.Type type, ProgressReport progressReport,
+ AtomicInteger excludedByPatternsCount)
throws IOException {
// get case of real file without resolving link
Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize();
}
if (!moduleExclusionFilters.accept(realAbsoluteFile, moduleRelativePath, type)) {
if (projectExclusionFilters.equals(moduleExclusionFilters)) {
- warnOnce("File '" + projectRelativePath + "' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+ warnOnceDeprecatedExclusion("File '" + projectRelativePath + "' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
"Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
} else {
- warnOnce("Defining inclusion/exclusions at module level is deprecated. " +
+ warnOnceDeprecatedExclusion("Defining inclusion/exclusions at module level is deprecated. " +
"Move file inclusion/exclusion configuration from module '" + module.getName() + "' " +
"to the root project and update patterns to refer to project relative paths.");
}
if (!accept(inputFile)) {
return;
}
- if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
- throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
- + "disjoint sets for main and test files");
- }
+ checkIfAlreadyIndexed(inputFile);
componentStore.put(module.key(), inputFile);
if (issueExclusionsLoader.shouldExecute()) {
issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key());
}
LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
+ evaluateCoverageExclusions(module, moduleCoverageExclusions, inputFile);
if (properties.preloadFileMetadata()) {
inputFile.checkMetadata();
}
- int count = componentStore.allFiles().size();
+ int count = componentStore.inputFiles().size();
progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")");
}
- private void warnOnce(String msg) {
+ private void checkIfAlreadyIndexed(DefaultInputFile inputFile) {
+ if (componentStore.inputFile(inputFile.getProjectRelativePath()) != null) {
+ throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ + "disjoint sets for main and test files");
+ }
+ }
+
+ private void evaluateCoverageExclusions(DefaultInputModule module, ModuleCoverageExclusions moduleCoverageExclusions, DefaultInputFile inputFile) {
+ boolean excludedByProjectConfiguration = projectCoverageExclusions.isExcluded(inputFile);
+ if (excludedByProjectConfiguration) {
+ inputFile.setExcludedForCoverage(true);
+ LOG.debug("File {} excluded for coverage", inputFile);
+ } else if (moduleCoverageExclusions.isExcluded(inputFile)) {
+ inputFile.setExcludedForCoverage(true);
+ if (Arrays.equals(moduleCoverageExclusions.getCoverageExclusionConfig(), projectCoverageExclusions.getCoverageExclusionConfig())) {
+ warnOnceDeprecatedCoverageExclusion(
+ "File '" + inputFile + "' was excluded from coverage because patterns are still evaluated using module relative paths but this is deprecated. " +
+ "Please update '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' configuration so that patterns refer to project relative paths");
+ } else {
+ warnOnceDeprecatedCoverageExclusion("Defining coverage exclusions at module level is deprecated. " +
+ "Move '" + CoreProperties.PROJECT_COVERAGE_EXCLUSIONS_PROPERTY + "' from module '" + module.getName() + "' " +
+ "to the root project and update patterns to refer to project relative paths");
+ }
+ LOG.debug("File {} excluded for coverage", inputFile);
+ }
+ }
+
+ private void warnOnceDeprecatedExclusion(String msg) {
if (!warnExclusionsAlreadyLogged) {
LOG.warn(msg);
analysisWarnings.addUnique(msg);
}
}
+ private void warnOnceDeprecatedCoverageExclusion(String msg) {
+ if (!warnCoverageExclusionsAlreadyLogged) {
+ LOG.warn(msg);
+ analysisWarnings.addUnique(msg);
+ warnCoverageExclusionsAlreadyLogged = true;
+ }
+ }
+
private boolean accept(InputFile indexedFile) {
// InputFileFilter extensions. Might trigger generation of metadata
for (InputFileFilter filter : filters) {
import javax.annotation.CheckForNull;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileExtensionPredicate;
* Store of all files and dirs. Inclusion and
* exclusion patterns are already applied.
*/
-public class InputComponentStore {
+public class InputComponentStore extends DefaultFileSystem.Cache {
private final SortedSet<String> globalLanguagesCache = new TreeSet<>();
private final Map<String, SortedSet<String>> languagesCache = new HashMap<>();
}
private Stream<DefaultInputFile> allFilesToPublishStream() {
- return inputFileByModuleCache.values().stream()
+ return globalInputFileCache.values().stream()
.map(f -> (DefaultInputFile) f)
.filter(DefaultInputFile::isPublished);
}
::iterator;
}
- public Collection<InputFile> allFiles() {
+ @Override
+ public Collection<InputFile> inputFiles() {
return globalInputFileCache.values();
}
return inputFileByModuleCache.get(moduleKey, relativePath);
}
+ @Override
@CheckForNull
- public InputFile getFile(String relativePath) {
+ public InputFile inputFile(String relativePath) {
return globalInputFileCache.get(relativePath);
}
return inputModuleCache.get(moduleKeyWithBranch);
}
+ @CheckForNull
+ public DefaultInputModule findModule(DefaultInputFile file) {
+ return inputFileByModuleCache
+ .cellSet()
+ .stream()
+ .filter(c -> c.getValue().equals(file))
+ .findFirst()
+ .map(c -> (DefaultInputModule) inputComponents.get(c.getRowKey()))
+ .orElse(null);
+ }
+
public void put(DefaultInputModule inputModule) {
String key = inputModule.key();
String keyWithBranch = inputModule.getKeyWithBranch();
inputModuleCache.put(keyWithBranch, inputModule);
}
+ @Override
public Iterable<InputFile> getFilesByName(String filename) {
return filesByNameCache.get(filename);
}
+ @Override
public Iterable<InputFile> getFilesByExtension(String extension) {
return filesByExtensionCache.get(extension);
}
- public SortedSet<String> getLanguages() {
+ @Override
+ public SortedSet<String> languages() {
return globalLanguagesCache;
}
- public SortedSet<String> getLanguages(String moduleKey) {
+ public SortedSet<String> languages(String moduleKey) {
return languagesCache.getOrDefault(moduleKey, Collections.emptySortedSet());
}
public Collection<DefaultInputModule> allModules() {
return inputModuleCache.values();
}
+
+ @Override
+ protected void doAdd(InputFile inputFile) {
+ throw new UnsupportedOperationException();
+ }
+
}
@Override
public Iterable<InputFile> inputFiles() {
if (strategy.isGlobal()) {
- return inputComponentStore.allFiles();
+ return inputComponentStore.inputFiles();
} else {
return inputComponentStore.filesByModule(moduleKey);
}
@Override
public InputFile inputFile(String relativePath) {
if (strategy.isGlobal()) {
- return inputComponentStore.getFile(relativePath);
+ return inputComponentStore.inputFile(relativePath);
} else {
return inputComponentStore.getFile(moduleKey, relativePath);
}
@Override
public SortedSet<String> languages() {
if (strategy.isGlobal()) {
- return inputComponentStore.getLanguages();
+ return inputComponentStore.languages();
} else {
- return inputComponentStore.getLanguages(moduleKey);
+ return inputComponentStore.languages(moduleKey);
}
}
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
+import org.sonar.scanner.phases.ModuleCoverageExclusions;
+import org.sonar.scanner.phases.ProjectCoverageExclusions;
import org.sonar.scanner.util.ProgressReport;
/**
private final DefaultInputProject project;
private final InputComponentStore componentStore;
private final InputModuleHierarchy inputModuleHierarchy;
+ private final ProjectCoverageExclusions projectCoverageExclusions;
private final FileIndexer fileIndexer;
private ProgressReport progressReport;
public ProjectFileIndexer(DefaultInputProject project, InputComponentStore componentStore, AbstractExclusionFilters exclusionFilters,
- InputModuleHierarchy inputModuleHierarchy,
+ InputModuleHierarchy inputModuleHierarchy, ProjectCoverageExclusions projectCoverageExclusions,
FileIndexer fileIndexer) {
this.project = project;
this.componentStore = componentStore;
this.inputModuleHierarchy = inputModuleHierarchy;
+ this.projectCoverageExclusions = projectCoverageExclusions;
this.fileIndexer = fileIndexer;
this.projectExclusionFilters = exclusionFilters;
}
indexModulesRecursively(inputModuleHierarchy.root(), excludedByPatternsCount);
- int totalIndexed = componentStore.allFiles().size();
+ int totalIndexed = componentStore.inputFiles().size();
progressReport.stop(totalIndexed + " " + pluralizeFiles(totalIndexed) + " indexed");
if (projectExclusionFilters.hasPattern()) {
}
private void indexModulesRecursively(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
- inputModuleHierarchy.children(module).forEach(m -> indexModulesRecursively(m, excludedByPatternsCount));
+ inputModuleHierarchy.children(module).stream().sorted(Comparator.comparing(DefaultInputModule::key)).forEach(m -> indexModulesRecursively(m, excludedByPatternsCount));
index(module, excludedByPatternsCount);
}
private void index(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
+ if (componentStore.allModules().size() > 1) {
+ LOG.info("Indexing files from module {}", module.getName());
+ }
ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(module);
- indexFiles(module, moduleExclusionFilters, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
- indexFiles(module, moduleExclusionFilters, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
+ ModuleCoverageExclusions moduleCoverageExclusions = new ModuleCoverageExclusions(module);
+ indexFiles(module, moduleExclusionFilters, moduleCoverageExclusions, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
+ indexFiles(module, moduleExclusionFilters, moduleCoverageExclusions, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
}
private static String pluralizeFiles(int count) {
return count == 1 ? "file" : "files";
}
- private void indexFiles(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, List<Path> sources, Type type, AtomicInteger excludedByPatternsCount) {
+ private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, List<Path> sources,
+ Type type, AtomicInteger excludedByPatternsCount) {
try {
for (Path dirOrFile : sources) {
if (dirOrFile.toFile().isDirectory()) {
- indexDirectory(module, moduleExclusionFilters, dirOrFile, type, excludedByPatternsCount);
+ indexDirectory(module, moduleExclusionFilters, moduleCoverageExclusions, dirOrFile, type, excludedByPatternsCount);
} else {
- fileIndexer.indexFile(module, moduleExclusionFilters, dirOrFile, type, progressReport, excludedByPatternsCount);
+ fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageExclusions, dirOrFile, type, progressReport, excludedByPatternsCount);
}
}
} catch (IOException e) {
}
}
- private void indexDirectory(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path dirToIndex, Type type, AtomicInteger excludedByPatternsCount)
+ private void indexDirectory(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Path dirToIndex,
+ Type type, AtomicInteger excludedByPatternsCount)
throws IOException {
Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
- new IndexFileVisitor(module, moduleExclusionFilters, type, excludedByPatternsCount));
+ new IndexFileVisitor(module, moduleExclusionFilters, moduleCoverageExclusions, type, excludedByPatternsCount));
}
private class IndexFileVisitor implements FileVisitor<Path> {
private final DefaultInputModule module;
- private final AbstractExclusionFilters moduleExclusionFilters;
+ private final ModuleExclusionFilters moduleExclusionFilters;
+ private final ModuleCoverageExclusions moduleCoverageExclusions;
private final Type type;
private final AtomicInteger excludedByPatternsCount;
- IndexFileVisitor(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Type type, AtomicInteger excludedByPatternsCount) {
+ IndexFileVisitor(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageExclusions moduleCoverageExclusions, Type type,
+ AtomicInteger excludedByPatternsCount) {
this.module = module;
this.moduleExclusionFilters = moduleExclusionFilters;
+ this.moduleCoverageExclusions = moduleCoverageExclusions;
this.type = type;
this.excludedByPatternsCount = excludedByPatternsCount;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(file)) {
- fileIndexer.indexFile(module, moduleExclusionFilters, file, type, progressReport, excludedByPatternsCount);
+ fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageExclusions, file, type, progressReport, excludedByPatternsCount);
}
return FileVisitResult.CONTINUE;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.report;
-
-import org.sonar.api.batch.ScannerSide;
-
-@ScannerSide
-public class IssuesReports {
-
- private final Reporter[] reporters;
-
- public IssuesReports(Reporter... reporters) {
- this.reporters = reporters;
- }
-
- public void execute() {
- for (Reporter reporter : reporters) {
- reporter.execute();
- }
- }
-}
import org.sonar.api.config.Configuration;
import org.sonar.api.platform.Server;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.issue.IssueCache;
name = "Report Results Export File",
type = PropertyType.STRING,
global = false, project = false)})
-public class JSONReport implements Reporter {
+@ScannerSide
+public class JSONReport {
static final String SONAR_REPORT_EXPORT_PATH = "sonar.report.export.path";
private static final Logger LOG = LoggerFactory.getLogger(JSONReport.class);
this.componentStore = componentStore;
}
- @Override
public void execute() {
settings.get(SONAR_REPORT_EXPORT_PATH).ifPresent(this::exportResults);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.report;
-
-import org.sonar.api.batch.ScannerSide;
-
-@ScannerSide
-@FunctionalInterface
-public interface Reporter {
-
- void execute();
-
-}
import org.sonar.api.Property;
import org.sonar.api.PropertyType;
import org.sonar.api.batch.AnalysisMode;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.config.Configuration;
global = false,
type = PropertyType.BOOLEAN)
})
-@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
-@ScannerSide
public class ScmConfiguration implements Startable {
private static final Logger LOG = Loggers.get(ScmConfiguration.class);
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
-import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.utils.log.Logger;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositories;
import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
-@InstantiationStrategy(InstantiationStrategy.PER_PROJECT)
-@ScannerSide
public final class ScmPublisher {
private static final Logger LOG = Loggers.get(ScmPublisher.class);
- private final AbstractProjectOrModule inputModule;
private final ScmConfiguration configuration;
private final ProjectRepositories projectRepositories;
- private final ModuleInputComponentStore componentStore;
- private final DefaultModuleFileSystem fs;
+ private final InputComponentStore componentStore;
+ private final FileSystem fs;
private final ScannerReportWriter writer;
private final BranchConfiguration branchConfiguration;
- public ScmPublisher(AbstractProjectOrModule inputModule, ScmConfiguration configuration, ProjectRepositories projectRepositories,
- ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
- this.inputModule = inputModule;
+ public ScmPublisher(ScmConfiguration configuration, ProjectRepositories projectRepositories,
+ InputComponentStore componentStore, FileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
this.configuration = configuration;
this.projectRepositories = projectRepositories;
this.componentStore = componentStore;
LOG.warn("Forced reloading of SCM data for all files.");
}
List<InputFile> filesToBlame = new LinkedList<>();
- for (InputFile f : componentStore.inputFiles()) {
- DefaultInputFile inputFile = (DefaultInputFile) f;
- if (!inputFile.isPublished()) {
- continue;
- }
+ for (DefaultInputFile f : componentStore.allFilesToPublish()) {
if (configuration.forceReloadAll() || f.status() != Status.SAME) {
addIfNotEmpty(filesToBlame, f);
} else if (!branchConfiguration.isShortOrPullRequest()) {
// File status is SAME so that mean fileData exists
- FileData fileData = projectRepositories.fileData(inputModule.definition().getKeyWithBranch(), inputFile);
+ FileData fileData = projectRepositories.fileData(componentStore.findModule(f).getKeyWithBranch(), f);
if (StringUtils.isEmpty(fileData.revision())) {
addIfNotEmpty(filesToBlame, f);
} else {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.bootstrap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.batch.Phase;
+import org.sonar.api.batch.postjob.PostJob;
+import org.sonar.api.batch.postjob.PostJobContext;
+import org.sonar.api.batch.postjob.PostJobDescriptor;
+import org.sonar.api.batch.postjob.internal.DefaultPostJobDescriptor;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.scanner.postjob.PostJobOptimizer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PostJobExtensionDictionnaryTest {
+ private PostJobOptimizer postJobOptimizer = mock(PostJobOptimizer.class);
+
+ @Before
+ public void setUp() {
+ when(postJobOptimizer.shouldExecute(any(DefaultPostJobDescriptor.class))).thenReturn(true);
+ }
+
+ private PostJobExtensionDictionnary newSelector(Object... extensions) {
+ ComponentContainer iocContainer = new ComponentContainer();
+ for (Object extension : extensions) {
+ iocContainer.addSingleton(extension);
+ }
+ return new PostJobExtensionDictionnary(iocContainer, postJobOptimizer, mock(PostJobContext.class));
+ }
+
+ @Test
+ public void dependsUponPhaseForPostJob() {
+ PrePostJob pre = new PrePostJob();
+ NormalPostJob normal = new NormalPostJob();
+
+ PostJobExtensionDictionnary selector = newSelector(normal, pre);
+ assertThat(selector.selectPostJobs()).extracting("wrappedPostJob").containsExactly(pre, normal);
+ }
+
+ interface Marker {
+
+ }
+
+ @Phase(name = Phase.Name.POST)
+ class PostSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ }
+
+ }
+
+ class PostSensorSubclass extends PostSensor {
+
+ }
+
+ class NormalPostJob implements PostJob {
+
+ @Override
+ public void describe(PostJobDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(PostJobContext context) {
+ }
+
+ }
+
+ @Phase(name = Phase.Name.PRE)
+ class PrePostJob implements PostJob {
+
+ @Override
+ public void describe(PostJobDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(PostJobContext context) {
+ }
+
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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.bootstrap;
-
-import com.google.common.collect.Lists;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Test;
-import org.picocontainer.behaviors.FieldDecorated;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.batch.Phase;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.postjob.PostJob;
-import org.sonar.api.batch.postjob.PostJobContext;
-import org.sonar.api.batch.postjob.PostJobDescriptor;
-import org.sonar.api.batch.postjob.internal.DefaultPostJobDescriptor;
-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.core.platform.ComponentContainer;
-import org.sonar.scanner.postjob.PostJobOptimizer;
-import org.sonar.scanner.sensor.DefaultSensorContext;
-import org.sonar.scanner.sensor.SensorOptimizer;
-import org.sonar.scanner.sensor.SensorWrapper;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ScannerExtensionDictionnaryTest {
- private SensorOptimizer sensorOptimizer = mock(SensorOptimizer.class);
- private PostJobOptimizer postJobOptimizer = mock(PostJobOptimizer.class);
-
- @Before
- public void setUp() {
- when(sensorOptimizer.shouldExecute(any(DefaultSensorDescriptor.class))).thenReturn(true);
- when(postJobOptimizer.shouldExecute(any(DefaultPostJobDescriptor.class))).thenReturn(true);
- }
-
- private ScannerExtensionDictionnary newSelector(Object... extensions) {
- ComponentContainer iocContainer = new ComponentContainer();
- for (Object extension : extensions) {
- iocContainer.addSingleton(extension);
- }
- return new ScannerExtensionDictionnary(iocContainer, mock(DefaultSensorContext.class), sensorOptimizer, postJobOptimizer, mock(PostJobContext.class));
- }
-
- @Test
- public void testGetFilteredExtensionWithExtensionMatcher() {
- final Sensor sensor1 = new FakeSensor();
- final Sensor sensor2 = new FakeSensor();
-
- ScannerExtensionDictionnary selector = newSelector(sensor1, sensor2);
- Collection<Sensor> sensors = selector.select(Sensor.class, true, extension -> extension.equals(sensor1));
- assertThat(sensors).contains(sensor1);
- assertEquals(1, sensors.size());
- }
-
- @Test
- public void testGetFilteredExtensions() {
- Sensor sensor1 = new FakeSensor();
- Sensor sensor2 = new FakeSensor();
- FieldDecorated.Decorator decorator = mock(FieldDecorated.Decorator.class);
-
- ScannerExtensionDictionnary selector = newSelector(sensor1, sensor2, decorator);
- Collection<Sensor> sensors = selector.select(Sensor.class, false, null);
-
- assertThat(sensors).containsOnly(sensor1, sensor2);
- }
-
- @Test
- public void shouldSearchInParentContainers() {
- Sensor a = new FakeSensor();
- Sensor b = new FakeSensor();
- Sensor c = new FakeSensor();
-
- ComponentContainer grandParent = new ComponentContainer();
- grandParent.addSingleton(a);
-
- ComponentContainer parent = grandParent.createChild();
- parent.addSingleton(b);
-
- ComponentContainer child = parent.createChild();
- child.addSingleton(c);
-
- ScannerExtensionDictionnary dictionnary = new ScannerExtensionDictionnary(child, mock(DefaultSensorContext.class),
- mock(SensorOptimizer.class), mock(PostJobOptimizer.class), mock(PostJobContext.class));
- assertThat(dictionnary.select(Sensor.class, true, null)).containsOnly(a, b, c);
- }
-
- @Test
- public void sortExtensionsByDependency() {
- Object a = new MethodDependentOf(null);
- Object b = new MethodDependentOf(a);
- Object c = new MethodDependentOf(b);
-
- ScannerExtensionDictionnary selector = newSelector(b, c, a);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(3);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- assertThat(extensions.get(2)).isEqualTo(c);
- }
-
- @Test
- public void useMethodAnnotationsToSortExtensions() {
- Object a = new GeneratesSomething("foo");
- Object b = new MethodDependentOf("foo");
-
- ScannerExtensionDictionnary selector = newSelector(a, b);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions.size()).isEqualTo(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // different initial order
- selector = newSelector(b, a);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test
- public void methodDependsUponCollection() {
- Object a = new GeneratesSomething("foo");
- Object b = new MethodDependentOf(Arrays.asList("foo"));
-
- ScannerExtensionDictionnary selector = newSelector(a, b);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // different initial order
- selector = newSelector(b, a);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test
- public void methodDependsUponArray() {
- Object a = new GeneratesSomething("foo");
- Object b = new MethodDependentOf(new String[] {"foo"});
-
- ScannerExtensionDictionnary selector = newSelector(a, b);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // different initial order
- selector = newSelector(b, a);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test
- public void useClassAnnotationsToSortExtensions() {
- Object a = new ClassDependedUpon();
- Object b = new ClassDependsUpon();
-
- ScannerExtensionDictionnary selector = newSelector(a, b);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // different initial order
- selector = newSelector(b, a);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test
- public void useClassAnnotationsOnInterfaces() {
- Object a = new InterfaceDependedUpon() {
- };
- Object b = new InterfaceDependsUpon() {
- };
-
- ScannerExtensionDictionnary selector = newSelector(a, b);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // different initial order
- selector = newSelector(b, a);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test
- public void inheritAnnotations() {
- Object a = new SubClass("foo");
- Object b = new MethodDependentOf("foo");
-
- ScannerExtensionDictionnary selector = newSelector(b, a);
- List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
-
- // change initial order
- selector = newSelector(a, b);
- extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
-
- assertThat(extensions).hasSize(2);
- assertThat(extensions.get(0)).isEqualTo(a);
- assertThat(extensions.get(1)).isEqualTo(b);
- }
-
- @Test(expected = IllegalStateException.class)
- public void annotatedMethodsCanNotBePrivate() {
- ScannerExtensionDictionnary selector = newSelector();
- Object wrong = new Object() {
- @DependsUpon
- private Object foo() {
- return "foo";
- }
- };
- selector.evaluateAnnotatedClasses(wrong, DependsUpon.class);
- }
-
- @Test
- public void dependsUponPhaseForSensors() {
- PreSensor pre = new PreSensor();
- NormalSensor normal = new NormalSensor();
- PostSensor post = new PostSensor();
-
- ScannerExtensionDictionnary selector = newSelector(normal, post, pre);
- assertThat(selector.selectSensors(false)).extracting("wrappedSensor").containsExactly(pre, normal, post);
- }
-
- @Test
- public void dependsUponPhaseForPostJob() {
- PrePostJob pre = new PrePostJob();
- NormalPostJob normal = new NormalPostJob();
-
- ScannerExtensionDictionnary selector = newSelector(normal, pre);
- assertThat(selector.selectPostJobs()).extracting("wrappedPostJob").containsExactly(pre, normal);
- }
-
- @Test
- public void dependsUponInheritedPhase() {
- PreSensorSubclass pre = new PreSensorSubclass();
- NormalSensor normal = new NormalSensor();
- PostSensorSubclass post = new PostSensorSubclass();
-
- ScannerExtensionDictionnary selector = newSelector(normal, post, pre);
- List extensions = Lists.newArrayList(selector.select(Sensor.class, true, null));
-
- assertThat(extensions).containsExactly(pre, normal, post);
- }
-
- @Test
- public void selectSensors() {
- FakeSensor nonGlobalSensor = new FakeSensor();
- FakeGlobalSensor globalSensor = new FakeGlobalSensor();
- ScannerExtensionDictionnary selector = newSelector(nonGlobalSensor, globalSensor);
-
- // verify non-global sensor
- Collection<SensorWrapper> extensions = selector.selectSensors(false);
- assertThat(extensions).hasSize(1);
- assertThat(extensions).extracting("wrappedSensor").containsExactly(nonGlobalSensor);
-
- // verify global sensor
- extensions = selector.selectSensors(true);
- assertThat(extensions).extracting("wrappedSensor").containsExactly(globalSensor);
- }
-
- interface Marker {
-
- }
-
- class FakeSensor implements Sensor {
-
- @Override public void describe(SensorDescriptor descriptor) {
-
- }
-
- @Override public void execute(SensorContext context) {
-
- }
- }
-
- class FakeGlobalSensor implements Sensor {
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- descriptor.global();
- }
-
- @Override
- public void execute(SensorContext context) {
- }
-
- }
-
- @ScannerSide class MethodDependentOf implements Marker {
- private Object dep;
-
- MethodDependentOf(Object o) {
- this.dep = o;
- }
-
- @DependsUpon
- public Object dependsUponObject() {
- return dep;
- }
- }
-
- @ScannerSide
- @DependsUpon("flag") class ClassDependsUpon implements Marker {
- }
-
- @ScannerSide
- @DependedUpon("flag") class ClassDependedUpon implements Marker {
- }
-
- @ScannerSide
- @DependsUpon("flag") interface InterfaceDependsUpon extends Marker {
- }
-
- @ScannerSide
- @DependedUpon("flag") interface InterfaceDependedUpon extends Marker {
- }
-
- @ScannerSide class GeneratesSomething implements Marker {
- private Object gen;
-
- GeneratesSomething(Object o) {
- this.gen = o;
- }
-
- @DependedUpon
- public Object generates() {
- return gen;
- }
- }
-
- class SubClass extends GeneratesSomething implements Marker {
- SubClass(Object o) {
- super(o);
- }
- }
-
- class NormalSensor implements Sensor {
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- }
-
- @Override
- public void execute(SensorContext context) {
- }
-
- }
-
- @Phase(name = Phase.Name.PRE) class PreSensor implements Sensor {
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- }
-
- @Override
- public void execute(SensorContext context) {
- }
-
- }
-
- class PreSensorSubclass extends PreSensor {
-
- }
-
- @Phase(name = Phase.Name.POST) class PostSensor implements Sensor {
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- }
-
- @Override
- public void execute(SensorContext context) {
- }
-
- }
-
- class PostSensorSubclass extends PostSensor {
-
- }
-
- class NormalPostJob implements PostJob {
-
- @Override
- public void describe(PostJobDescriptor descriptor) {
- }
-
- @Override
- public void execute(PostJobContext context) {
- }
-
- }
-
- @Phase(name = Phase.Name.PRE) class PrePostJob implements PostJob {
-
- @Override
- public void describe(PostJobDescriptor descriptor) {
- }
-
- @Override
- public void execute(PostJobContext context) {
- }
-
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.bootstrap;
+
+import com.google.common.collect.Lists;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.picocontainer.behaviors.FieldDecorated;
+import org.sonar.api.batch.DependedUpon;
+import org.sonar.api.batch.DependsUpon;
+import org.sonar.api.batch.Phase;
+import org.sonar.api.batch.ScannerSide;
+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.core.platform.ComponentContainer;
+import org.sonar.scanner.sensor.DefaultSensorContext;
+import org.sonar.scanner.sensor.SensorOptimizer;
+import org.sonar.scanner.sensor.SensorWrapper;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class SensorExtensionDictionnaryTest {
+ private SensorOptimizer sensorOptimizer = mock(SensorOptimizer.class);
+
+ @Before
+ public void setUp() {
+ when(sensorOptimizer.shouldExecute(any(DefaultSensorDescriptor.class))).thenReturn(true);
+ }
+
+ private SensorExtensionDictionnary newSelector(Object... extensions) {
+ ComponentContainer iocContainer = new ComponentContainer();
+ for (Object extension : extensions) {
+ iocContainer.addSingleton(extension);
+ }
+ return new SensorExtensionDictionnary(iocContainer, mock(DefaultSensorContext.class), sensorOptimizer);
+ }
+
+ @Test
+ public void testGetFilteredExtensionWithExtensionMatcher() {
+ final Sensor sensor1 = new FakeSensor();
+ final Sensor sensor2 = new FakeSensor();
+
+ SensorExtensionDictionnary selector = newSelector(sensor1, sensor2);
+ Collection<Sensor> sensors = selector.select(Sensor.class, true, extension -> extension.equals(sensor1));
+ assertThat(sensors).contains(sensor1);
+ assertEquals(1, sensors.size());
+ }
+
+ @Test
+ public void testGetFilteredExtensions() {
+ Sensor sensor1 = new FakeSensor();
+ Sensor sensor2 = new FakeSensor();
+ FieldDecorated.Decorator decorator = mock(FieldDecorated.Decorator.class);
+
+ SensorExtensionDictionnary selector = newSelector(sensor1, sensor2, decorator);
+ Collection<Sensor> sensors = selector.select(Sensor.class, false, null);
+
+ assertThat(sensors).containsOnly(sensor1, sensor2);
+ }
+
+ @Test
+ public void shouldSearchInParentContainers() {
+ Sensor a = new FakeSensor();
+ Sensor b = new FakeSensor();
+ Sensor c = new FakeSensor();
+
+ ComponentContainer grandParent = new ComponentContainer();
+ grandParent.addSingleton(a);
+
+ ComponentContainer parent = grandParent.createChild();
+ parent.addSingleton(b);
+
+ ComponentContainer child = parent.createChild();
+ child.addSingleton(c);
+
+ SensorExtensionDictionnary dictionnary = new SensorExtensionDictionnary(child, mock(DefaultSensorContext.class), mock(SensorOptimizer.class));
+ assertThat(dictionnary.select(Sensor.class, true, null)).containsOnly(a, b, c);
+ }
+
+ @Test
+ public void sortExtensionsByDependency() {
+ Object a = new MethodDependentOf(null);
+ Object b = new MethodDependentOf(a);
+ Object c = new MethodDependentOf(b);
+
+ SensorExtensionDictionnary selector = newSelector(b, c, a);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(3);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ assertThat(extensions.get(2)).isEqualTo(c);
+ }
+
+ @Test
+ public void useMethodAnnotationsToSortExtensions() {
+ Object a = new GeneratesSomething("foo");
+ Object b = new MethodDependentOf("foo");
+
+ SensorExtensionDictionnary selector = newSelector(a, b);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions.size()).isEqualTo(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // different initial order
+ selector = newSelector(b, a);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test
+ public void methodDependsUponCollection() {
+ Object a = new GeneratesSomething("foo");
+ Object b = new MethodDependentOf(Arrays.asList("foo"));
+
+ SensorExtensionDictionnary selector = newSelector(a, b);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // different initial order
+ selector = newSelector(b, a);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test
+ public void methodDependsUponArray() {
+ Object a = new GeneratesSomething("foo");
+ Object b = new MethodDependentOf(new String[] {"foo"});
+
+ SensorExtensionDictionnary selector = newSelector(a, b);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // different initial order
+ selector = newSelector(b, a);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test
+ public void useClassAnnotationsToSortExtensions() {
+ Object a = new ClassDependedUpon();
+ Object b = new ClassDependsUpon();
+
+ SensorExtensionDictionnary selector = newSelector(a, b);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // different initial order
+ selector = newSelector(b, a);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test
+ public void useClassAnnotationsOnInterfaces() {
+ Object a = new InterfaceDependedUpon() {
+ };
+ Object b = new InterfaceDependsUpon() {
+ };
+
+ SensorExtensionDictionnary selector = newSelector(a, b);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // different initial order
+ selector = newSelector(b, a);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test
+ public void inheritAnnotations() {
+ Object a = new SubClass("foo");
+ Object b = new MethodDependentOf("foo");
+
+ SensorExtensionDictionnary selector = newSelector(b, a);
+ List<Object> extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+
+ // change initial order
+ selector = newSelector(a, b);
+ extensions = Lists.newArrayList(selector.select(Marker.class, true, null));
+
+ assertThat(extensions).hasSize(2);
+ assertThat(extensions.get(0)).isEqualTo(a);
+ assertThat(extensions.get(1)).isEqualTo(b);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void annotatedMethodsCanNotBePrivate() {
+ SensorExtensionDictionnary selector = newSelector();
+ Object wrong = new Object() {
+ @DependsUpon
+ private Object foo() {
+ return "foo";
+ }
+ };
+ selector.evaluateAnnotatedClasses(wrong, DependsUpon.class);
+ }
+
+ @Test
+ public void dependsUponPhaseForSensors() {
+ PreSensor pre = new PreSensor();
+ NormalSensor normal = new NormalSensor();
+ PostSensor post = new PostSensor();
+
+ SensorExtensionDictionnary selector = newSelector(normal, post, pre);
+ assertThat(selector.selectSensors(false)).extracting("wrappedSensor").containsExactly(pre, normal, post);
+ }
+
+ @Test
+ public void dependsUponInheritedPhase() {
+ PreSensorSubclass pre = new PreSensorSubclass();
+ NormalSensor normal = new NormalSensor();
+ PostSensorSubclass post = new PostSensorSubclass();
+
+ SensorExtensionDictionnary selector = newSelector(normal, post, pre);
+ List extensions = Lists.newArrayList(selector.select(Sensor.class, true, null));
+
+ assertThat(extensions).containsExactly(pre, normal, post);
+ }
+
+ @Test
+ public void selectSensors() {
+ FakeSensor nonGlobalSensor = new FakeSensor();
+ FakeGlobalSensor globalSensor = new FakeGlobalSensor();
+ SensorExtensionDictionnary selector = newSelector(nonGlobalSensor, globalSensor);
+
+ // verify non-global sensor
+ Collection<SensorWrapper> extensions = selector.selectSensors(false);
+ assertThat(extensions).hasSize(1);
+ assertThat(extensions).extracting("wrappedSensor").containsExactly(nonGlobalSensor);
+
+ // verify global sensor
+ extensions = selector.selectSensors(true);
+ assertThat(extensions).extracting("wrappedSensor").containsExactly(globalSensor);
+ }
+
+ interface Marker {
+
+ }
+
+ class FakeSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+
+ }
+ }
+
+ class FakeGlobalSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.global();
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ }
+
+ }
+
+ @ScannerSide
+ class MethodDependentOf implements Marker {
+ private Object dep;
+
+ MethodDependentOf(Object o) {
+ this.dep = o;
+ }
+
+ @DependsUpon
+ public Object dependsUponObject() {
+ return dep;
+ }
+ }
+
+ @ScannerSide
+ @DependsUpon("flag")
+ class ClassDependsUpon implements Marker {
+ }
+
+ @ScannerSide
+ @DependedUpon("flag")
+ class ClassDependedUpon implements Marker {
+ }
+
+ @ScannerSide
+ @DependsUpon("flag")
+ interface InterfaceDependsUpon extends Marker {
+ }
+
+ @ScannerSide
+ @DependedUpon("flag")
+ interface InterfaceDependedUpon extends Marker {
+ }
+
+ @ScannerSide
+ class GeneratesSomething implements Marker {
+ private Object gen;
+
+ GeneratesSomething(Object o) {
+ this.gen = o;
+ }
+
+ @DependedUpon
+ public Object generates() {
+ return gen;
+ }
+ }
+
+ class SubClass extends GeneratesSomething implements Marker {
+ SubClass(Object o) {
+ super(o);
+ }
+ }
+
+ class NormalSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ }
+
+ }
+
+ @Phase(name = Phase.Name.PRE)
+ class PreSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ }
+
+ }
+
+ class PreSensorSubclass extends PreSensor {
+
+ }
+
+ @Phase(name = Phase.Name.POST)
+ class PostSensor implements Sensor {
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ }
+
+ }
+
+ class PostSensorSubclass extends PostSensor {
+
+ }
+
+}
assertThat(fileB).isNull();
assertThat(logTester.logs(LoggerLevel.WARN))
- .contains("File 'moduleB/src/sample.xoo' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
+ .contains("File 'moduleA/src/sample.xoo' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
"Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
}
package org.sonar.scanner.phases;
import java.io.File;
+import java.util.Arrays;
+import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.scanner.scan.ModuleConfiguration;
assertThat(coverageExclusions.isExcluded(file)).isFalse();
}
- private ModuleConfiguration mockConfig(String... values) {
+ private DefaultInputModule mockConfig(String... values) {
ModuleConfiguration config = mock(ModuleConfiguration.class);
when(config.getStringArray("sonar.coverage.exclusions")).thenReturn(values);
- return config;
+ return new DefaultInputModule(ProjectDefinition.create()
+ .setBaseDir(baseDir)
+ .setWorkDir(baseDir)
+ .setProperty("sonar.coverage.exclusions", Arrays.asList(values).stream().collect(Collectors.joining(","))));
}
}
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
-import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionnary;
import org.sonar.scanner.postjob.PostJobWrapper;
+import org.sonar.scanner.postjob.PostJobsExecutor;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class PostJobsExecutorTest {
private PostJobsExecutor executor;
- private ScannerExtensionDictionnary selector = mock(ScannerExtensionDictionnary.class);
+ private PostJobExtensionDictionnary selector = mock(PostJobExtensionDictionnary.class);
private PostJobWrapper job1 = mock(PostJobWrapper.class);
private PostJobWrapper job2 = mock(PostJobWrapper.class);
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.scanner.bootstrap.ScannerExtensionDictionnary;
+import org.sonar.scanner.bootstrap.SensorExtensionDictionnary;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.sensor.SensorWrapper;
when(globalSensor.shouldExecute()).thenReturn(true);
when(globalSensor.wrappedSensor()).thenReturn(mock(Sensor.class));
- ScannerExtensionDictionnary selector = mock(ScannerExtensionDictionnary.class);
+ SensorExtensionDictionnary selector = mock(SensorExtensionDictionnary.class);
when(selector.selectSensors(false)).thenReturn(Collections.singleton(perModuleSensor));
when(selector.selectSensors(true)).thenReturn(Collections.singleton(globalSensor));
assertThat(store.filesByModule(rootModuleKey)).hasSize(1);
assertThat(store.filesByModule(subModuleKey)).hasSize(1);
- assertThat(store.allFiles()).hasSize(2);
- for (InputPath inputPath : store.allFiles()) {
+ assertThat(store.inputFiles()).hasSize(2);
+ for (InputPath inputPath : store.inputFiles()) {
assertThat(inputPath.relativePath()).startsWith("src/main/java/");
}
String mod2Key = "mod2";
tester.addFile(mod2Key, "src/main/groovy/Foo.groovy", "groovy");
- assertThat(tester.getLanguages(mod1Key)).containsExactly("java");
- assertThat(tester.getLanguages(mod2Key)).containsExactly("groovy");
- assertThat(tester.getLanguages()).containsExactlyInAnyOrder("java", "groovy");
+ assertThat(tester.languages(mod1Key)).containsExactly("java");
+ assertThat(tester.languages(mod2Key)).containsExactly("groovy");
+ assertThat(tester.languages()).containsExactlyInAnyOrder("java", "groovy");
}
@Test
assertThat(tester.filesByModule(mod1Key)).containsExactly(mod1File);
assertThat(tester.filesByModule(mod2Key)).containsExactly(mod2File);
- assertThat(tester.allFiles()).containsExactlyInAnyOrder(mod1File, mod2File);
+ assertThat(tester.inputFiles()).containsExactlyInAnyOrder(mod1File, mod2File);
}
}
when(module.key()).thenReturn("foo");
ModuleInputComponentStore store = new ModuleInputComponentStore(module, inputComponentStore, strategy);
+ strategy.setGlobal(false);
+
store.inputFiles();
verify(inputComponentStore).filesByModule("foo");
verify(inputComponentStore).getFile(any(String.class), eq(relativePath));
store.languages();
- verify(inputComponentStore).getLanguages(any(String.class));
+ verify(inputComponentStore).languages(any(String.class));
}
@Test
strategy.setGlobal(true);
store.inputFiles();
- verify(inputComponentStore).allFiles();
+ verify(inputComponentStore).inputFiles();
String relativePath = "somepath";
store.inputFile(relativePath);
- verify(inputComponentStore).getFile(relativePath);
+ verify(inputComponentStore).inputFile(relativePath);
store.languages();
- verify(inputComponentStore).getLanguages();
+ verify(inputComponentStore).languages();
}
}