dependency 'io.netty:netty-all:4.1.70.Final'
dependency 'com.sun.mail:javax.mail:1.5.6'
dependency 'javax.annotation:javax.annotation-api:1.3.2'
+ dependency 'javax.inject:javax.inject:1'
dependency 'javax.servlet:javax.servlet-api:3.1.0'
dependency 'javax.xml.bind:jaxb-api:2.3.0'
dependency 'junit:junit:4.13.2'
dependency 'org.simpleframework:simple:4.1.21'
dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63'
dependency 'org.sonarsource.update-center:sonar-update-center-common:1.23.0.723'
+ dependency('org.springframework:spring-context:5.3.14') {
+ exclude 'commons-logging:commons-logging'
+ }
dependency 'org.subethamail:subethasmtp:3.1.7'
dependency 'org.yaml:snakeyaml:1.26'
dependency 'xml-apis:xml-apis:1.4.01'
import com.google.common.collect.Iterables;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.ce.task.step.ComputationSteps;
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
/**
* Abstract implementation of {@link ComputationStep} which provides the implementation of {@link ComputationSteps#instances()}
- * based on a {@link org.sonar.core.platform.ContainerPopulator.Container}.
+ * based on a {@link org.sonar.core.platform.Container}.
*/
public abstract class AbstractComputationSteps implements ComputationSteps {
- private final ContainerPopulator.Container container;
+ private final Container container;
- protected AbstractComputationSteps(ContainerPopulator.Container container) {
+ protected AbstractComputationSteps(Container container) {
this.container = container;
}
import org.sonar.ce.task.step.ComputationStepExecutor;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
import org.sonar.core.platform.ContainerPopulator;
import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;
public static final class AuditPurgeComputationSteps extends AbstractComputationSteps {
- public AuditPurgeComputationSteps(ContainerPopulator.Container container) {
+ public AuditPurgeComputationSteps(Container container) {
super(container);
}
import org.sonar.ce.task.step.ComputationStepExecutor;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.Container;
import org.sonar.core.platform.ContainerPopulator;
import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
public static final class SyncComputationSteps extends AbstractComputationSteps {
- public SyncComputationSteps(ContainerPopulator.Container container) {
+ public SyncComputationSteps(Container container) {
super(container);
}
import org.picocontainer.PicoContainer;
import org.sonar.ce.task.CeTask;
import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
/**
* The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}.
*/
-public interface TaskContainer extends ContainerPopulator.Container, AutoCloseable {
+public interface TaskContainer extends Container, AutoCloseable {
ComponentContainer getParent();
*/
package org.sonar.server.platform.db.migration.engine;
-import org.sonar.core.platform.ContainerPopulator;
+import org.sonar.core.platform.Container;
/**
* A dedicated container used to run DB migrations where all components are lazily instantiated.
* classes only they really are to be executed.
* </p>
*/
-public interface MigrationContainer extends ContainerPopulator.Container {
+public interface MigrationContainer extends Container {
/**
* Cleans up resources after migration has run.
compile 'commons-codec:commons-codec'
compile 'commons-io:commons-io'
compile 'commons-lang:commons-lang'
+ compile 'javax.inject:javax.inject'
compile 'org.codehaus.sonar:sonar-classloader'
compile 'org.picocontainer:picocontainer'
compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.update-center:sonar-update-center-common'
+ compile 'org.springframework:spring-context'
compile project(path: ':sonar-plugin-api', configuration: 'shadow')
compile project(':sonar-plugin-api-impl')
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
import static java.util.Objects.requireNonNull;
private final CoreExtensionRepository coreExtensionRepository;
private final Class<? extends Annotation> supportedAnnotationType;
- protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository,
- Class<? extends Annotation> supportedAnnotationType) {
+ protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, Class<? extends Annotation> supportedAnnotationType) {
this.sonarRuntime = sonarRuntime;
this.coreExtensionRepository = coreExtensionRepository;
this.supportedAnnotationType = supportedAnnotationType;
* @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether
* extension should be added to container as an object or only as a PropertyDefinition.
*/
- public void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) {
+ public void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) {
coreExtensionRepository.loadedCoreExtensions()
.forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension));
}
- private void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
+ private void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
String coreExtensionName = coreExtension.getName();
try {
addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension);
}
}
- private void addDeclaredExtensions(ComponentContainer container, Predicate<Object> extensionFilter,
+ private void addDeclaredExtensions(ExtensionContainer container, Predicate<Object> extensionFilter,
Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName());
coreExtension.load(context);
}
- private <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> additionalSideFilter,
- String extensionCategory, T component) {
- if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
- container.addExtension(extensionCategory, component);
- return true;
- }
- return false;
- }
-
private <T> boolean hasSupportedAnnotation(T component) {
return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null;
}
private class ContextImpl implements CoreExtension.Context {
- private final ComponentContainer container;
+ private final ExtensionContainer container;
private final Predicate<Object> extensionFilter;
private final Predicate<Object> additionalSideFilter;
private final String extensionCategory;
- public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter,
- Predicate<Object> additionalSideFilter, String extensionCategory) {
+ public ContextImpl(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, String extensionCategory) {
this.container = container;
this.extensionFilter = extensionFilter;
this.additionalSideFilter = additionalSideFilter;
components.forEach(this::addExtension);
return this;
}
+
+ private <T> boolean addSupportedExtension(ExtensionContainer container, Predicate<Object> additionalSideFilter,
+ String extensionCategory, T component) {
+ if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
+ container.addExtension(extensionCategory, component);
+ return true;
+ }
+ return false;
+ }
}
}
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.inject.Inject;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.stream.MoreCollectors;
private final CoreExtensionRepository coreExtensionRepository;
private final ServiceLoaderWrapper serviceLoaderWrapper;
+ @Inject
public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) {
this(coreExtensionRepository, new ServiceLoaderWrapper());
}
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metrics;
import org.sonar.api.scanner.ScannerSide;
+import org.springframework.beans.factory.annotation.Autowired;
import static org.sonar.api.measures.CoreMetrics.CLASSES;
import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY;
private final Set<Metric> metrics;
+ @Autowired(required = false)
public ScannerMetrics() {
this.metrics = ALLOWED_CORE_METRICS;
}
+ @Autowired(required = false)
public ScannerMetrics(Metrics[] metricsRepositories) {
this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet());
}
@ScannerSide
@ServerSide
@ComputeEngineSide
-public class ComponentContainer implements ContainerPopulator.Container {
+public class ComponentContainer implements ExtensionContainer {
public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2;
private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer {
return this;
}
+ @Override
public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
Object key = componentKeys.of(extension);
try {
return this;
}
+ @Override
public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
Object key = componentKeys.of(extension);
try {
return getName(extension.getClass());
}
- public void declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+ @Override
+ public ComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
+ return this;
}
- public void declareExtension(@Nullable String defaultCategory, Object extension) {
+ @Override
+ public ComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
+ return this;
}
public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) {
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-class ComponentKeys {
-
+public class ComponentKeys {
+ private static final Logger LOG = Loggers.get(ComponentKeys.class);
private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+");
private final Set<Class> objectsWithoutToString = new HashSet<>();
Object of(Object component) {
- return of(component, Loggers.get(ComponentKeys.class));
+ return of(component, LOG);
}
Object of(Object component, Logger log) {
if (component instanceof Class) {
return component;
}
+ return ofInstance(component, log);
+ }
+
+ public String ofInstance(Object component) {
+ return ofInstance(component, LOG);
+ }
+
+ String ofInstance(Object component, Logger log) {
String key = component.toString();
if (IDENTITY_HASH_PATTERN.matcher(key).matches()) {
if (!objectsWithoutToString.add(component.getClass())) {
}
key += Uuids.create();
}
- return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString();
+ return component.getClass().getCanonicalName() + "-" + key;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.core.platform;
+
+import java.util.List;
+
+public interface Container {
+ Container add(Object... objects);
+
+ Container addSingletons(Iterable<?> components);
+
+ <T> T getComponentByType(Class<T> type);
+
+ <T> List<T> getComponentsByType(Class<T> type);
+
+ Container getParent();
+}
*/
package org.sonar.core.platform;
-import java.util.List;
-
@FunctionalInterface
-public interface ContainerPopulator<T extends ContainerPopulator.Container> {
+public interface ContainerPopulator<T extends Container> {
void populateContainer(T container);
-
- interface Container {
- Container add(Object... objects);
-
- Container addSingletons(Iterable<?> components);
-
- <T> T getComponentByType(Class<T> type);
-
- <T> List<T> getComponentsByType(Class<T> type);
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.core.platform;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public interface ExtensionContainer extends Container {
+ ExtensionContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension);
+
+ ExtensionContainer addExtension(@Nullable String defaultCategory, Object extension);
+
+ ExtensionContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension);
+
+ ExtensionContainer declareExtension(@Nullable String defaultCategory, Object extension);
+
+ @CheckForNull
+ ExtensionContainer getParent();
+}
import java.util.Optional;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nullable;
+import javax.inject.Inject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.sonar.api.CoreProperties;
private final Integer readTimeout;
private final Integer connectTimeout;
+ @Inject
public DefaultHttpDownloader(Server server, Configuration config) {
this(server, config, null);
}
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import org.apache.commons.io.FileUtils;
+import org.sonar.api.Startable;
import org.sonar.api.utils.TempFolder;
import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-public class DefaultTempFolder implements TempFolder {
+public class DefaultTempFolder implements TempFolder, Startable {
private static final Logger LOG = Loggers.get(DefaultTempFolder.class);
private final File tempDir;
}
}
+ @Override
+ public void start() {
+ // nothing to do
+ }
+
+ @Override
public void stop() {
if (deleteOnExit) {
clean();
@Test
public void should_add_several_times_the_same_language() {
Languages languages = new Languages(
- language("fake"),
- language("fake"));
+ language("fake"),
+ language("fake"));
assertThat(languages.get("fake").getKey()).isEqualTo("fake");
}
@Test
public void should_get_suffixes() {
Languages languages = new Languages(
- language("java", "java"),
- language("php", "php4", "php5"));
+ language("java", "java"),
+ language("php", "php4", "php5"));
assertThat(languages.getSuffixes()).containsOnly("java", "php4", "php5");
assertThat(languages.getSuffixes("java")).containsOnly("java");
compile 'com.google.protobuf:protobuf-java'
compile 'com.squareup.okhttp3:okhttp'
compile 'com.fasterxml.staxmate:staxmate'
+ compile 'javax.annotation:javax.annotation-api'
compile 'org.eclipse.jgit:org.eclipse.jgit'
compile 'org.tmatesoft.svnkit:svnkit'
compile 'org.picocontainer:picocontainer'
compile 'org.slf4j:log4j-over-slf4j'
compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.update-center:sonar-update-center-common'
+ compile 'org.springframework:spring-context'
+
compile project(':sonar-core')
compile project(':sonar-scanner-protocol')
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.utils.MessageException;
-import org.sonar.scanner.bootstrap.GlobalContainer;
+import org.sonar.scanner.bootstrap.SpringGlobalContainer;
/**
* Entry point for SonarQube Scanner API 2.1+.
public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) {
configureLogging();
try {
- GlobalContainer.create(scannerProperties, components).execute();
+ SpringGlobalContainer.create(scannerProperties, components).execute();
} catch (RuntimeException e) {
throw handleException(e);
}
import java.util.Optional;
import java.util.function.Predicate;
import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
+import org.sonar.api.Startable;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.MessageException;
*/
public class ProjectInfo implements Startable {
private final Clock clock;
- private Configuration settings;
+ private final Configuration settings;
private Date analysisDate;
private String projectVersion;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import org.picocontainer.ComponentLifecycle;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.TempFolder;
+import org.springframework.context.annotation.Bean;
-public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
+public class AnalysisTempFolderProvider {
static final String TMP_NAME = ".sonartmp";
- private DefaultTempFolder projectTempFolder;
- private boolean started = false;
+ @Bean("TempFolder")
public TempFolder provide(DefaultInputProject project) {
- if (projectTempFolder == null) {
- Path workingDir = project.getWorkDir();
- Path tempDir = workingDir.normalize().resolve(TMP_NAME);
- try {
- Files.deleteIfExists(tempDir);
- Files.createDirectories(tempDir);
- } catch (IOException e) {
- throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
- }
-
- projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true);
- }
- return projectTempFolder;
- }
-
- @Override
- public void start(PicoContainer container) {
- started = true;
- }
-
- @Override
- public void stop(PicoContainer container) {
- if (projectTempFolder != null) {
- projectTempFolder.stop();
+ Path workingDir = project.getWorkDir();
+ Path tempDir = workingDir.normalize().resolve(TMP_NAME);
+ try {
+ Files.deleteIfExists(tempDir);
+ Files.createDirectories(tempDir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
}
- }
-
- @Override
- public void dispose(PicoContainer container) {
- // nothing to do
- }
-
- @Override
- public boolean componentHasLifecycle() {
- return true;
- }
- @Override
- public boolean isStarted() {
- return started;
+ return new DefaultTempFolder(tempDir.toFile(), true);
}
}
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;
+import org.sonar.core.platform.ExtensionContainer;
public abstract class AbstractExtensionDictionary {
- private final ComponentContainer componentContainer;
+ private final ExtensionContainer componentContainer;
- public AbstractExtensionDictionary(ComponentContainer componentContainer) {
+ protected AbstractExtensionDictionary(ExtensionContainer componentContainer) {
this.componentContainer = componentContainer;
}
return extensions;
}
- private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) {
+ private static <T> void completeScannerExtensions(ExtensionContainer container, List<T> extensions, Class<T> type) {
extensions.addAll(container.getComponentsByType(type));
- ComponentContainer parentContainer = container.getParent();
+ ExtensionContainer parentContainer = container.getParent();
if (parentContainer != null) {
completeScannerExtensions(parentContainer, extensions, type);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.reflect.Constructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.lang.Nullable;
+
+/**
+ * Taken from Spring's GenericApplicationContext.ClassDerivedBeanDefinition.
+ */
+public class ClassDerivedBeanDefinition extends RootBeanDefinition {
+ public ClassDerivedBeanDefinition(Class<?> beanClass) {
+ super(beanClass);
+ }
+
+ public ClassDerivedBeanDefinition(ClassDerivedBeanDefinition original) {
+ super(original);
+ }
+
+ /**
+ * This method gets called from AbstractAutowireCapableBeanFactory#createBeanInstance when a bean is instantiated.
+ * It first tries to look at annotations or any other methods provided by bean post processors. If a constructor can't be determined, it will fallback to this method.
+ */
+ @Override
+ @Nullable
+ public Constructor<?>[] getPreferredConstructors() {
+ Class<?> clazz = getBeanClass();
+ Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz);
+ if (primaryCtor != null) {
+ return new Constructor<?>[] {primaryCtor};
+ }
+ Constructor<?>[] publicCtors = clazz.getConstructors();
+ if (publicCtors.length > 0) {
+ return publicCtors;
+ }
+ return null;
+ }
+
+ @Override
+ public RootBeanDefinition cloneBeanDefinition() {
+ return new ClassDerivedBeanDefinition(this);
+ }
+}
import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration;
import org.sonar.api.internal.PluginContextImpl;
-import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.ExtensionContainer;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
this.bootConfiguration = bootConfiguration;
}
- public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) {
-
+ public ExtensionInstaller install(ExtensionContainer container, ExtensionMatcher matcher) {
// core components
for (Object o : BatchComponents.all()) {
doInstall(container, matcher, null, o);
return this;
}
- private static void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
+ private static void doInstall(ExtensionContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
if (matcher.accept(extension)) {
container.addExtension(pluginInfo, extension);
} else {
import java.util.Map;
import javax.annotation.concurrent.Immutable;
-import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration;
@Immutable
public class GlobalConfiguration extends DefaultConfiguration {
-
public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) {
super(propertyDefinitions, encryption, settings);
}
-
}
import java.util.LinkedHashMap;
import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.config.PropertyDefinitions;
+import org.springframework.context.annotation.Bean;
-public class GlobalConfigurationProvider extends ProviderAdapter {
-
- private GlobalConfiguration globalConfig;
-
- public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps,
- PropertyDefinitions propertyDefinitions) {
- if (globalConfig == null) {
- Map<String, String> mergedSettings = new LinkedHashMap<>();
- mergedSettings.putAll(globalServerSettings.properties());
- mergedSettings.putAll(scannerProps.properties());
-
- globalConfig = new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
- }
- return globalConfig;
+public class GlobalConfigurationProvider {
+ @Bean("GlobalConfiguration")
+ public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, PropertyDefinitions propertyDefinitions) {
+ Map<String, String> mergedSettings = new LinkedHashMap<>();
+ mergedSettings.putAll(globalServerSettings.properties());
+ mergedSettings.putAll(scannerProps.properties());
+ return new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
}
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.time.Clock;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarEdition;
-import org.sonar.api.SonarQubeSide;
-import org.sonar.api.SonarQubeVersion;
-import org.sonar.api.SonarRuntime;
-import org.sonar.api.internal.MetadataLoader;
-import org.sonar.api.internal.SonarRuntimeImpl;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.System2;
-import org.sonar.api.utils.UriReader;
-import org.sonar.api.utils.Version;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.extension.CoreExtensionRepositoryImpl;
-import org.sonar.core.extension.CoreExtensionsLoader;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.core.platform.PluginClassLoader;
-import org.sonar.core.platform.PluginClassloaderFactory;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.core.util.DefaultHttpDownloader;
-import org.sonar.core.util.UuidFactoryImpl;
-import org.sonar.scanner.extension.ScannerCoreExtensionsInstaller;
-import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
-import org.sonar.scanner.platform.DefaultServer;
-import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
-import org.sonar.scanner.repository.DefaultNewCodePeriodLoader;
-import org.sonar.scanner.repository.MetricsRepositoryLoader;
-import org.sonar.scanner.repository.MetricsRepositoryProvider;
-import org.sonar.scanner.repository.NewCodePeriodLoader;
-import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
-import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
-import org.sonar.scanner.scan.ProjectScanContainer;
-
-public class GlobalContainer extends ComponentContainer {
- private static final Logger LOG = Loggers.get(GlobalContainer.class);
- private final Map<String, String> scannerProperties;
-
- private GlobalContainer(Map<String, String> scannerProperties) {
- super();
- this.scannerProperties = scannerProperties;
- }
-
- public static GlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
- GlobalContainer container = new GlobalContainer(scannerProperties);
- container.add(extensions);
- return container;
- }
-
- @Override
- protected void doBeforeStart() {
- ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties);
- GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
- add(rawScannerProperties);
- add(globalMode);
- addBootstrapComponents();
- }
-
- private void addBootstrapComponents() {
- Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
- SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
- DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(System2.INSTANCE);
- LOG.debug("{} {}", edition.getLabel(), apiVersion);
- add(
- // plugins
- ScannerPluginRepository.class,
- PluginClassLoader.class,
- PluginClassloaderFactory.class,
- ScannerPluginJarExploder.class,
- ExtensionInstaller.class,
- new SonarQubeVersion(apiVersion),
- new GlobalServerSettingsProvider(),
- new GlobalConfigurationProvider(),
- new ScannerWsClientProvider(),
- DefaultServer.class,
- new GlobalTempFolderProvider(),
- DefaultHttpDownloader.class,
- analysisWarnings,
- UriReader.class,
- PluginFiles.class,
- System2.INSTANCE,
- Clock.systemDefaultZone(),
- new MetricsRepositoryProvider(),
- UuidFactoryImpl.INSTANCE);
- addIfMissing(SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), SonarRuntime.class);
- addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class);
- add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class);
- addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class);
- addIfMissing(DefaultNewCodePeriodLoader.class, NewCodePeriodLoader.class);
- addIfMissing(DefaultMetricsRepositoryLoader.class, MetricsRepositoryLoader.class);
- }
-
- @Override
- protected void doAfterStart() {
- installPlugins();
- loadCoreExtensions();
-
- long startTime = System.currentTimeMillis();
- String taskKey = StringUtils.defaultIfEmpty(scannerProperties.get(CoreProperties.TASK), CoreProperties.SCAN_TASK);
- if (taskKey.equals("views")) {
- throw MessageException.of("The task 'views' was removed with SonarQube 7.1. " +
- "You can safely remove this call since portfolios and applications are automatically re-calculated.");
- } else if (!taskKey.equals(CoreProperties.SCAN_TASK)) {
- throw MessageException.of("Tasks support was removed in SonarQube 7.6.");
- }
- String analysisMode = StringUtils.defaultIfEmpty(scannerProperties.get("sonar.analysis.mode"), "publish");
- if (!analysisMode.equals("publish")) {
- throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
- }
- new ProjectScanContainer(this).execute();
-
- LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime));
- }
-
- private void installPlugins() {
- PluginRepository pluginRepository = getComponentByType(PluginRepository.class);
- for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
- Plugin instance = pluginRepository.getPluginInstance(pluginInfo.getKey());
- addExtension(pluginInfo, instance);
- }
- }
-
- private void loadCoreExtensions() {
- CoreExtensionsLoader loader = getComponentByType(CoreExtensionsLoader.class);
- loader.load();
- }
-
- static String formatTime(long time) {
- long h = time / (60 * 60 * 1000);
- long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
- long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
- long ms = time % 1000;
- final String format;
- if (h > 0) {
- format = "%1$d:%2$02d:%3$02d.%4$03d s";
- } else if (m > 0) {
- format = "%2$d:%3$02d.%4$03d s";
- } else {
- format = "%3$d.%4$03d s";
- }
- return String.format(format, h, m, s, ms);
- }
-
-}
import java.util.Map;
import java.util.Optional;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.springframework.context.annotation.Bean;
-public class GlobalServerSettingsProvider extends ProviderAdapter {
-
+public class GlobalServerSettingsProvider {
private static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class);
- private GlobalServerSettings singleton;
-
+ @Bean("GlobalServerSettings")
public GlobalServerSettings provide(GlobalSettingsLoader loader) {
- if (singleton == null) {
- Map<String, String> serverSideSettings = loader.loadGlobalSettings();
- singleton = new GlobalServerSettings(serverSideSettings);
- Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
- }
- return singleton;
+ Map<String, String> serverSideSettings = loader.loadGlobalSettings();
+ Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
+ return new GlobalServerSettings(serverSideSettings);
}
}
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
-import org.picocontainer.ComponentLifecycle;
-import org.picocontainer.PicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
+import org.sonar.api.Startable;
import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.springframework.context.annotation.Bean;
import static org.sonar.core.util.FileUtils.deleteQuietly;
-public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
+public class GlobalTempFolderProvider implements Startable {
private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class);
private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21);
static final String TMP_NAME_PREFIX = ".sonartmp_";
- private boolean started = false;
private System2 system;
private DefaultTempFolder tempFolder;
this.system = system;
}
+ @Bean("TempFolder")
public TempFolder provide(ScannerProperties scannerProps) {
if (tempFolder == null) {
}
@Override
- public void start(PicoContainer container) {
- started = true;
+ public void start() {
+ // nothing to do
}
@Override
- public void stop(PicoContainer container) {
+ public void stop() {
if (tempFolder != null) {
tempFolder.stop();
}
}
-
- @Override
- public void dispose(PicoContainer container) {
- // nothing to do
- }
-
- @Override
- public boolean componentHasLifecycle() {
- return true;
- }
-
- @Override
- public boolean isStarted() {
- return started;
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+
+public class LazyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ for (String beanName : beanFactory.getBeanDefinitionNames()) {
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ beanDefinition.setLazyInit(true);
+ }
+ }
+}
LOGGER.debug("Unpacking plugin {}", pluginKey);
File jar = newTempFile();
try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile)));
- JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
+ JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
Pack200.newUnpacker().unpack(input, output);
} catch (IOException e) {
throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e);
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.core.platform.ExtensionContainer;
import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.postjob.PostJobWrapper;
private final PostJobContext postJobContext;
private final PostJobOptimizer postJobOptimizer;
- public PostJobExtensionDictionary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
- super(componentContainer);
+ public PostJobExtensionDictionary(ExtensionContainer container, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
+ super(container);
this.postJobOptimizer = postJobOptimizer;
this.postJobContext = postJobContext;
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+
+public class PriorityBeanFactory extends DefaultListableBeanFactory {
+ /**
+ * Determines highest priority of the bean candidates.
+ * Does not take into account the @Primary annotations.
+ * This gets called from {@link DefaultListableBeanFactory#determineAutowireCandidate} when the bean factory is finding the beans to autowire. That method
+ * checks for @Primary before calling this method.
+ *
+ * The strategy is to look at the @Priority annotations. If there are ties, we give priority to components that were added to child containers over their parents.
+ * If there are still ties, null is returned, which will ultimately cause Spring to throw a NoUniqueBeanDefinitionException.
+ */
+ @Override
+ @Nullable
+ protected String determineHighestPriorityCandidate(Map<String, Object> candidates, Class<?> requiredType) {
+ List<Bean> candidateBeans = candidates.entrySet().stream()
+ .filter(e -> e.getValue() != null)
+ .map(e -> new Bean(e.getKey(), e.getValue()))
+ .collect(Collectors.toUnmodifiableList());
+
+ List<Bean> beansAfterPriority = highestPriority(candidateBeans, b -> getPriority(b.getInstance()));
+ if (beansAfterPriority.isEmpty()) {
+ return null;
+ } else if (beansAfterPriority.size() == 1) {
+ return beansAfterPriority.get(0).getName();
+ }
+
+ List<Bean> beansAfterHierarchy = highestPriority(beansAfterPriority, b -> getHierarchyPriority(b.getName()));
+ if (beansAfterHierarchy.size() == 1) {
+ return beansAfterHierarchy.get(0).getName();
+ }
+
+ return null;
+ }
+
+ private static List<Bean> highestPriority(List<Bean> candidates, PriorityFunction function) {
+ List<Bean> highestPriorityBeans = new ArrayList<>();
+ Integer highestPriority = null;
+
+ for (Bean candidate : candidates) {
+ Integer candidatePriority = function.classify(candidate);
+ if (candidatePriority == null) {
+ candidatePriority = Integer.MAX_VALUE;
+ }
+ if (highestPriority == null) {
+ highestPriority = candidatePriority;
+ highestPriorityBeans.add(candidate);
+ } else if (candidatePriority < highestPriority) {
+ highestPriorityBeans.clear();
+ highestPriority = candidatePriority;
+ highestPriorityBeans.add(candidate);
+ } else if (candidatePriority.equals(highestPriority)) {
+ highestPriorityBeans.add(candidate);
+ }
+ }
+ return highestPriorityBeans;
+ }
+
+ @CheckForNull
+ private Integer getHierarchyPriority(String beanName) {
+ DefaultListableBeanFactory factory = this;
+ int i = 1;
+ while (factory != null) {
+ if (factory.containsBeanDefinition(beanName)) {
+ return i;
+ }
+ factory = (DefaultListableBeanFactory) factory.getParentBeanFactory();
+ i++;
+ }
+ return null;
+ }
+
+ private static class Bean {
+ private final String name;
+ private final Object instance;
+
+ public Bean(String name, Object instance) {
+ this.name = name;
+ this.instance = instance;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Object getInstance() {
+ return instance;
+ }
+ }
+
+ @FunctionalInterface
+ private interface PriorityFunction {
+ @Nullable
+ Integer classify(Bean candidate);
+ }
+}
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
-import org.picocontainer.Startable;
import org.sonar.api.Plugin;
+import org.sonar.api.Startable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.platform.ExplodedPlugin;
*/
package org.sonar.scanner.bootstrap;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
import org.sonar.api.utils.System2;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.WsClientFactories;
+import org.springframework.context.annotation.Bean;
import static java.lang.Integer.parseInt;
import static java.lang.String.valueOf;
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
-public class ScannerWsClientProvider extends ProviderAdapter {
-
+public class ScannerWsClientProvider {
static final int CONNECT_TIMEOUT_MS = 5_000;
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout";
static final int DEFAULT_READ_TIMEOUT_SEC = 60;
- private DefaultScannerWsClient wsClient;
-
- public synchronized DefaultScannerWsClient provide(final ScannerProperties scannerProps,
- final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
- if (wsClient == null) {
- String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
- HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();
-
- String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
- String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
- String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
- connectorBuilder
- .readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
- .connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
- .userAgent(env.toString())
- .url(url)
- .credentials(login, scannerProps.property(CoreProperties.PASSWORD));
-
- // OkHttp detect 'http.proxyHost' java property, but credentials should be filled
- final String proxyUser = System.getProperty("http.proxyUser", "");
- if (!proxyUser.isEmpty()) {
- connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
- }
-
- wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
+ @Bean("DefaultScannerWsClient")
+ public DefaultScannerWsClient provide(ScannerProperties scannerProps, EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
+ String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
+ HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();
+
+ String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
+ String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
+ String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
+ connectorBuilder
+ .readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
+ .connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
+ .userAgent(env.toString())
+ .url(url)
+ .credentials(login, scannerProps.property(CoreProperties.PASSWORD));
+
+ // OkHttp detect 'http.proxyHost' java property, but credentials should be filled
+ final String proxyUser = System.getProperty("http.proxyUser", "");
+ if (!proxyUser.isEmpty()) {
+ connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
}
- return wsClient;
+
+ return new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.Iterables;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+import javax.annotation.CheckForNull;
+import org.jetbrains.annotations.Nullable;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.utils.System2;
+import org.sonar.core.platform.ComponentKeys;
+import org.sonar.core.platform.Container;
+import org.sonar.core.platform.ExtensionContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;
+
+import static java.util.Collections.emptyList;
+import static java.util.Optional.ofNullable;
+
+public class SpringComponentContainer implements ExtensionContainer {
+ protected final AnnotationConfigApplicationContext context;
+ @Nullable
+ protected final SpringComponentContainer parent;
+
+ private final PropertyDefinitions propertyDefinitions;
+ private final ComponentKeys componentKeys = new ComponentKeys();
+
+ protected SpringComponentContainer() {
+ this(null, new PropertyDefinitions(System2.INSTANCE), emptyList());
+ }
+
+ protected SpringComponentContainer(List<?> externalExtensions) {
+ this(null, new PropertyDefinitions(System2.INSTANCE), externalExtensions);
+ }
+
+ protected SpringComponentContainer(SpringComponentContainer parent) {
+ this(parent, parent.propertyDefinitions, emptyList());
+ }
+
+ private SpringComponentContainer(@Nullable SpringComponentContainer parent, PropertyDefinitions propertyDefinitions, List<?> externalExtensions) {
+ this.parent = parent;
+ this.propertyDefinitions = propertyDefinitions;
+ this.context = new AnnotationConfigApplicationContext(new PriorityBeanFactory());
+ // it won't set the name of beans created with @Bean annotated methods
+ this.context.setBeanNameGenerator(new FullyQualifiedAnnotationBeanNameGenerator());
+ if (parent != null) {
+ context.setParent(parent.context);
+ }
+ add(this);
+ add(new StartableBeanPostProcessor());
+ add(externalExtensions);
+ add(propertyDefinitions);
+ }
+
+ /**
+ * Beans need to have a unique name, otherwise they'll override each other.
+ * The strategy is:
+ * - For classes, use the fully qualified class name as the name of the bean
+ * - For instances, use the FQCN + toString()
+ * - If the object is a collection, iterate through the elements and apply the same strategy for each of them
+ */
+ @Override
+ public Container add(Object... objects) {
+ for (Object o : objects) {
+ if (o instanceof Class) {
+ Class<?> clazz = (Class<?>) o;
+ context.registerBean(clazz);
+ } else if (o instanceof Iterable) {
+ add(Iterables.toArray((Iterable<?>) o, Object.class));
+ } else {
+ registerInstance(o);
+ }
+ }
+ return this;
+ }
+
+ private <T> void registerInstance(T instance) {
+ Supplier<T> supplier = () -> instance;
+ Class<T> clazz = (Class<T>) instance.getClass();
+ context.registerBean(componentKeys.ofInstance(instance), clazz, supplier);
+ declareExtension("", instance);
+ }
+
+ /**
+ * Extensions are usually added by plugins and we assume they don't support any injection-related annotations.
+ * Spring contexts supporting annotations will fail if multiple constructors are present without any annotations indicating which one to use for injection.
+ * For that reason, we need to create the beans ourselves, using ClassDerivedBeanDefinition, which will declare that all constructors can be used for injection.
+ */
+ private Container addExtension(Object o) {
+ if (o instanceof Class) {
+ Class<?> clazz = (Class<?>) o;
+ ClassDerivedBeanDefinition bd = new ClassDerivedBeanDefinition(clazz);
+ context.registerBeanDefinition(clazz.getName(), bd);
+ } else if (o instanceof Iterable) {
+ ((Iterable<?>) o).forEach(this::addExtension);
+ } else {
+ ClassDerivedBeanDefinition bd = new ClassDerivedBeanDefinition(o.getClass());
+ bd.setInstanceSupplier(() -> o);
+ context.registerBeanDefinition(componentKeys.ofInstance(o), bd);
+ }
+ return this;
+ }
+
+ @Override
+ public Container addSingletons(Iterable<?> components) {
+ return add(components);
+ }
+
+ @Override
+ public <T> T getComponentByType(Class<T> type) {
+ try {
+ return context.getBean(type);
+ } catch (Exception t) {
+ throw new IllegalStateException("Unable to load component " + type, t);
+ }
+ }
+
+ @Override
+ public <T> List<T> getComponentsByType(Class<T> type) {
+ try {
+ return new ArrayList<>(context.getBeansOfType(type).values());
+ } catch (Exception t) {
+ throw new IllegalStateException("Unable to load components " + type, t);
+ }
+ }
+
+ public void execute() {
+ RuntimeException r = null;
+ try {
+ startComponents();
+ } catch (RuntimeException e) {
+ r = e;
+ } finally {
+ try {
+ stopComponents();
+ } catch (RuntimeException e) {
+ if (r == null) {
+ r = e;
+ }
+ }
+ }
+ if (r != null) {
+ throw r;
+ }
+ }
+
+ public SpringComponentContainer startComponents() {
+ doBeforeStart();
+ context.refresh();
+ doAfterStart();
+ return this;
+ }
+
+ public SpringComponentContainer stopComponents() {
+ if (context.isActive()) {
+ context.close();
+ }
+ return this;
+ }
+
+ public SpringComponentContainer createChild() {
+ return new SpringComponentContainer(this);
+ }
+
+ @Override
+ @CheckForNull
+ public SpringComponentContainer getParent() {
+ return parent;
+ }
+
+ @Override
+ public SpringComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+ addExtension(extension);
+ declareExtension(pluginInfo, extension);
+ return this;
+ }
+
+ @Override
+ public SpringComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
+ addExtension(extension);
+ declareExtension(defaultCategory, extension);
+ return this;
+ }
+
+ @Override
+ public SpringComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+ declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
+ return this;
+ }
+
+ @Override
+ public SpringComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
+ this.propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
+ return this;
+ }
+
+ /**
+ * This method aims to be overridden
+ */
+ protected void doBeforeStart() {
+ // nothing
+ }
+
+ /**
+ * This method aims to be overridden
+ */
+ protected void doAfterStart() {
+ // nothing
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.time.Clock;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Priority;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.Plugin;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.SonarQubeVersion;
+import org.sonar.api.internal.MetadataLoader;
+import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.UriReader;
+import org.sonar.api.utils.Version;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.extension.CoreExtensionRepositoryImpl;
+import org.sonar.core.extension.CoreExtensionsLoader;
+import org.sonar.core.platform.PluginClassLoader;
+import org.sonar.core.platform.PluginClassloaderFactory;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.core.util.DefaultHttpDownloader;
+import org.sonar.core.util.UuidFactoryImpl;
+import org.sonar.scanner.extension.ScannerCoreExtensionsInstaller;
+import org.sonar.scanner.notifications.DefaultAnalysisWarnings;
+import org.sonar.scanner.platform.DefaultServer;
+import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
+import org.sonar.scanner.repository.DefaultNewCodePeriodLoader;
+import org.sonar.scanner.repository.MetricsRepositoryProvider;
+import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
+
+@Priority(3)
+public class SpringGlobalContainer extends SpringComponentContainer {
+ private static final Logger LOG = Loggers.get(SpringGlobalContainer.class);
+ private final Map<String, String> scannerProperties;
+
+ private SpringGlobalContainer(Map<String, String> scannerProperties, List<?> addedExternally) {
+ super(addedExternally);
+ this.scannerProperties = scannerProperties;
+ }
+
+ public static SpringGlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
+ return new SpringGlobalContainer(scannerProperties, extensions);
+ }
+
+ @Override
+ public void doBeforeStart() {
+ ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties);
+ GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
+ add(rawScannerProperties);
+ add(globalMode);
+ addBootstrapComponents();
+ }
+
+ private void addBootstrapComponents() {
+ Version apiVersion = MetadataLoader.loadVersion(System2.INSTANCE);
+ SonarEdition edition = MetadataLoader.loadEdition(System2.INSTANCE);
+ DefaultAnalysisWarnings analysisWarnings = new DefaultAnalysisWarnings(System2.INSTANCE);
+ LOG.debug("{} {}", edition.getLabel(), apiVersion);
+ add(
+ // plugins
+ ScannerPluginRepository.class,
+ PluginClassLoader.class,
+ PluginClassloaderFactory.class,
+ ScannerPluginJarExploder.class,
+ ExtensionInstaller.class,
+ new SonarQubeVersion(apiVersion),
+ new GlobalServerSettingsProvider(),
+ new GlobalConfigurationProvider(),
+ new ScannerWsClientProvider(),
+ DefaultServer.class,
+ new GlobalTempFolderProvider(),
+ analysisWarnings,
+ UriReader.class,
+ PluginFiles.class,
+ System2.INSTANCE,
+ Clock.systemDefaultZone(),
+ new MetricsRepositoryProvider(),
+ UuidFactoryImpl.INSTANCE,
+ DefaultHttpDownloader.class,
+ SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition),
+ ScannerPluginInstaller.class,
+ CoreExtensionRepositoryImpl.class,
+ CoreExtensionsLoader.class,
+ ScannerCoreExtensionsInstaller.class,
+ DefaultGlobalSettingsLoader.class,
+ DefaultNewCodePeriodLoader.class,
+ DefaultMetricsRepositoryLoader.class);
+ }
+
+ @Override
+ protected void doAfterStart() {
+ installPlugins();
+ loadCoreExtensions();
+
+ long startTime = System.currentTimeMillis();
+ String taskKey = StringUtils.defaultIfEmpty(scannerProperties.get(CoreProperties.TASK), CoreProperties.SCAN_TASK);
+ if (taskKey.equals("views")) {
+ throw MessageException.of("The task 'views' was removed with SonarQube 7.1. " +
+ "You can safely remove this call since portfolios and applications are automatically re-calculated.");
+ } else if (!taskKey.equals(CoreProperties.SCAN_TASK)) {
+ throw MessageException.of("Tasks support was removed in SonarQube 7.6.");
+ }
+ String analysisMode = StringUtils.defaultIfEmpty(scannerProperties.get("sonar.analysis.mode"), "publish");
+ if (!analysisMode.equals("publish")) {
+ throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
+ }
+ new SpringProjectScanContainer(this).execute();
+
+ LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime));
+ }
+
+ private void installPlugins() {
+ PluginRepository pluginRepository = getComponentByType(PluginRepository.class);
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ Plugin instance = pluginRepository.getPluginInstance(pluginInfo.getKey());
+ addExtension(pluginInfo, instance);
+ }
+ }
+
+ private void loadCoreExtensions() {
+ getComponentByType(CoreExtensionsLoader.class).load();
+ }
+
+ static String formatTime(long time) {
+ long h = time / (60 * 60 * 1000);
+ long m = (time - h * 60 * 60 * 1000) / (60 * 1000);
+ long s = (time - h * 60 * 60 * 1000 - m * 60 * 1000) / 1000;
+ long ms = time % 1000;
+ final String format;
+ if (h > 0) {
+ format = "%1$d:%2$02d:%3$02d.%4$03d s";
+ } else if (m > 0) {
+ format = "%2$d:%3$02d.%4$03d s";
+ } else {
+ format = "%3$d.%4$03d s";
+ }
+ return String.format(format, h, m, s, ms);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.api.Startable;
+import org.sonar.api.utils.log.Loggers;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
+import org.springframework.lang.Nullable;
+
+public class StartableBeanPostProcessor implements DestructionAwareBeanPostProcessor {
+ @Override
+ @Nullable
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof Startable) {
+ ((Startable) bean).start();
+ } else if (bean instanceof org.picocontainer.Startable) {
+ ((org.picocontainer.Startable) bean).start();
+ }
+ return bean;
+ }
+
+ @Override
+ public boolean requiresDestruction(Object bean) {
+ return (bean instanceof Startable) || (bean instanceof org.picocontainer.Startable) || (bean instanceof AutoCloseable);
+ }
+
+ @Override
+ public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
+ try {
+ if (bean instanceof Startable) {
+ ((Startable) bean).stop();
+ } else if (bean instanceof org.picocontainer.Startable) {
+ ((org.picocontainer.Startable) bean).stop();
+ } else if (bean instanceof AutoCloseable) {
+ ((AutoCloseable) bean).close();
+ }
+ } catch (Exception e) {
+ Loggers.get(StartableBeanPostProcessor.class)
+ .warn("Dispose of component {} failed", bean.getClass().getCanonicalName(), e);
+ }
+ }
+}
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.springframework.context.annotation.Bean;
-public class CiConfigurationProvider extends ProviderAdapter {
+public class CiConfigurationProvider {
private static final Logger LOG = Loggers.get(CiConfigurationProvider.class);
private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled";
+ @Bean("CiConfiguration")
public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) {
boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false);
if (disabled) {
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import javax.inject.Inject;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
private int count = 0;
private int total;
+ @Inject
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) {
this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor());
}
- public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache,
- ExecutorService executorService) {
+ public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, ExecutorService executorService) {
this.settings = settings;
this.index = index;
this.publisher = publisher;
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.scanner.protocol.output.ScannerReport;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* @deprecated since 7.6, {@link IssueFilter} is deprecated
private final IssueFilterChain filterChain;
private final DefaultInputProject project;
+ @Autowired(required = false)
public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) {
this.project = project;
this.filterChain = new DefaultIssueFilterChain(exclusionFilters);
}
+ @Autowired(required = false)
public IssueFilters(DefaultInputProject project) {
this(project, new IssueFilter[0]);
}
import org.sonar.api.ExtensionPoint;
import org.sonar.api.scanner.ScannerSide;
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
@ScannerSide
@ExtensionPoint
@FunctionalInterface
public interface AnalysisObserver {
- void analysisCompleted(ProjectScanContainer container);
+ void analysisCompleted(SpringProjectScanContainer container);
}
*/
package org.sonar.scanner.mediumtest;
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
public class AnalysisObservers {
- private AnalysisObserver[] observers;
- private ProjectScanContainer projectScanContainer;
+ private final AnalysisObserver[] observers;
+ private final SpringProjectScanContainer projectScanContainer;
- public AnalysisObservers(ProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
+ public AnalysisObservers(SpringProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
this.projectScanContainer = projectScanContainer;
this.observers = observers;
}
- public AnalysisObservers(ProjectScanContainer projectScanContainer) {
- this(projectScanContainer, new AnalysisObserver[0]);
- }
-
public void notifyEndOfScanTask() {
for (AnalysisObserver analysisObserver : observers) {
analysisObserver.analysisCompleted(projectScanContainer);
import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.report.ScannerReportUtils;
-import org.sonar.scanner.scan.ProjectScanContainer;
+import org.sonar.scanner.scan.SpringProjectScanContainer;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
public class AnalysisResult implements AnalysisObserver {
private ScannerReportReader reader;
@Override
- public void analysisCompleted(ProjectScanContainer container) {
+ public void analysisCompleted(SpringProjectScanContainer container) {
LOG.info("Store analysis results in memory for later assertions in medium test");
ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class);
reader = new ScannerReportReader(reportPublisher.getReportDir().toFile());
return reader;
}
- private void storeFs(ProjectScanContainer container) {
+ private void storeFs(SpringProjectScanContainer container) {
InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class);
for (InputFile inputPath : inputFileCache.inputFiles()) {
inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath);
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.annotation.Priority;
import org.sonar.api.Plugin;
import org.sonar.core.platform.PluginInfo;
import org.sonar.scanner.bootstrap.PluginInstaller;
import org.sonar.scanner.bootstrap.ScannerPlugin;
+@Priority(1)
public class FakePluginInstaller implements PluginInstaller {
private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>();
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.EnumSet;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
private final ScmConfiguration scmConfiguration;
private final CiConfiguration ciConfiguration;
- public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration,
- CiConfiguration ciConfiguration) {
+ public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration, CiConfiguration ciConfiguration) {
this.cache = cache;
this.config = config;
this.scmConfiguration = scmConfiguration;
import javax.annotation.Nullable;
import okhttp3.HttpUrl;
import org.apache.commons.io.FileUtils;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder;
this.branchConfiguration = branchConfiguration;
this.properties = properties;
this.ceTaskReportDataHolder = ceTaskReportDataHolder;
+ this.reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
+ this.writer = new ScannerReportWriter(reportDir.toFile());
+ this.reader = new ScannerReportReader(reportDir.toFile());
}
@Override
public void start() {
- reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
- writer = new ScannerReportWriter(reportDir.toFile());
- reader = new ScannerReportReader(reportDir.toFile());
contextPublisher.init(writer);
if (!analysisMode.isMediumTest()) {
*/
package org.sonar.scanner.repository;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.springframework.context.annotation.Bean;
-public class MetricsRepositoryProvider extends ProviderAdapter {
+public class MetricsRepositoryProvider {
private static final Logger LOG = Loggers.get(MetricsRepositoryProvider.class);
private static final String LOG_MSG = "Load metrics repository";
- private MetricsRepository metricsRepository;
+ @Bean("MetricsRepository")
public MetricsRepository provide(MetricsRepositoryLoader loader) {
- if (metricsRepository == null) {
- Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- metricsRepository = loader.load();
- profiler.stopInfo();
- }
+ Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+ MetricsRepository metricsRepository = loader.load();
+ profiler.stopInfo();
return metricsRepository;
}
}
*/
package org.sonar.scanner.repository;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties;
import org.sonar.scanner.rule.QualityProfiles;
+import org.springframework.context.annotation.Bean;
-public class QualityProfilesProvider extends ProviderAdapter {
+public class QualityProfilesProvider {
private static final Logger LOG = Loggers.get(QualityProfilesProvider.class);
private static final String LOG_MSG = "Load quality profiles";
- private QualityProfiles profiles = null;
+ @Bean("QualityProfiles")
public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) {
- if (this.profiles == null) {
- Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- profiles = new QualityProfiles(loader.load(props.getProjectKey()));
- profiler.stopInfo();
- }
-
+ Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+ QualityProfiles profiles = new QualityProfiles(loader.load(props.getProjectKey()));
+ profiler.stopInfo();
return profiles;
}
import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
import org.sonar.api.resources.Languages;
/**
package org.sonar.scanner.repository.settings;
import java.util.Map;
+import javax.inject.Inject;
import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader {
- public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) {
+ @Inject
+ public DefaultGlobalSettingsLoader(DefaultScannerWsClient wsClient) {
super(wsClient);
}
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
+import org.springframework.context.annotation.Bean;
/**
* Loads the rules that are activated on the Quality profiles
* used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}.
*/
-public class ActiveRulesProvider extends ProviderAdapter {
+public class ActiveRulesProvider {
private static final Logger LOG = Loggers.get(ActiveRulesProvider.class);
private static final String LOG_MSG = "Load active rules";
- private DefaultActiveRules singleton = null;
+ @Bean("ActiveRules")
public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
- if (singleton == null) {
- Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- singleton = load(loader, qProfiles);
- profiler.stopInfo();
- }
- return singleton;
+ Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+ DefaultActiveRules activeRules = load(loader, qProfiles);
+ profiler.stopInfo();
+ return activeRules;
}
private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {
package org.sonar.scanner.rule;
import java.util.List;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.internal.RulesBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonarqube.ws.Rules.ListResponse.Rule;
+import org.springframework.context.annotation.Bean;
-public class RulesProvider extends ProviderAdapter {
+public class RulesProvider {
private static final Logger LOG = Loggers.get(RulesProvider.class);
private static final String LOG_MSG = "Load server rules";
- private Rules singleton = null;
+ @Bean("Rules")
public Rules provide(RulesLoader ref) {
- if (singleton == null) {
- singleton = load(ref);
- }
- return singleton;
- }
-
- private static Rules load(RulesLoader ref) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
List<Rule> loadedRules = ref.load();
RulesBuilder builder = new RulesBuilder();
}
profiler.stopInfo();
-
return builder.build();
}
}
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.springframework.context.annotation.Bean;
-public class InputModuleHierarchyProvider extends ProviderAdapter {
+public class InputModuleHierarchyProvider {
private static final Logger LOG = Loggers.get(InputModuleHierarchyProvider.class);
- private DefaultInputModuleHierarchy hierarchy = null;
-
- public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, DefaultInputProject project) {
- if (hierarchy == null) {
- LOG.debug("Creating module hierarchy");
- DefaultInputModule root = createModule(project.definition(), project.scannerId());
- Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
- if (parents.isEmpty()) {
- hierarchy = new DefaultInputModuleHierarchy(root);
- } else {
- hierarchy = new DefaultInputModuleHierarchy(root, parents);
- }
+ @Bean("DefaultInputModuleHierarchy")
+ public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, WorkDirectoriesInitializer workDirectoriesInit, DefaultInputProject project) {
+ LOG.debug("Creating module hierarchy");
+ DefaultInputModule root = createModule(project.definition(), project.scannerId());
+ Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
+ DefaultInputModuleHierarchy inputModuleHierarchy;
+ if (parents.isEmpty()) {
+ inputModuleHierarchy = new DefaultInputModuleHierarchy(root);
+ } else {
+ inputModuleHierarchy = new DefaultInputModuleHierarchy(root, parents);
}
- return hierarchy;
+ workDirectoriesInit.execute(inputModuleHierarchy);
+ return inputModuleHierarchy;
}
private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator,
package org.sonar.scanner.scan;
import java.util.Locale;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.springframework.context.annotation.Bean;
-public class InputProjectProvider extends ProviderAdapter {
-
+public class InputProjectProvider {
private static final Logger LOG = Loggers.get(InputProjectProvider.class);
- private DefaultInputProject project = null;
-
+ @Bean("DefaultInputProject")
public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
- if (project == null) {
- // 1 Apply project builders
- projectBuildersExecutor.execute(projectReactor);
+ // 1 Apply project builders
+ projectBuildersExecutor.execute(projectReactor);
- // 2 Validate final reactor
- validator.validate(projectReactor);
+ // 2 Validate final reactor
+ validator.validate(projectReactor);
- // 3 Create project
- project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
+ // 3 Create project
+ DefaultInputProject project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
- LOG.info("Project key: {}", project.key());
- LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
- LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
- LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
- }
+ LOG.info("Project key: {}", project.key());
+ LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
+ LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
+ LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
return project;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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;
+
+import java.util.List;
+import java.util.Optional;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
+import org.springframework.context.annotation.Bean;
+
+public class LanguagesProvider {
+ @Bean("Languages")
+ public Languages provide(Optional<List<Language>> languages) {
+ if (languages.isEmpty()) {
+ return new Languages();
+ }
+ return new Languages(languages.get().toArray(new Language[0]));
+ }
+}
package org.sonar.scanner.scan;
import java.util.Map;
-import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration;
public class ModuleConfiguration extends DefaultConfiguration {
-
public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
super(propertyDefinitions, encryption, props);
}
-
}
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-
-public class ModuleConfigurationProvider extends ProviderAdapter {
-
- private ModuleConfiguration moduleConfiguration;
+import org.springframework.context.annotation.Bean;
+public class ModuleConfigurationProvider {
+ @Bean("ModuleConfiguration")
public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings) {
- if (moduleConfiguration == null) {
-
- Map<String, String> settings = new LinkedHashMap<>();
- settings.putAll(globalServerSettings.properties());
- settings.putAll(projectServerSettings.properties());
- addScannerSideProperties(settings, module.definition());
+ Map<String, String> settings = new LinkedHashMap<>();
+ settings.putAll(globalServerSettings.properties());
+ settings.putAll(projectServerSettings.properties());
+ addScannerSideProperties(settings, module.definition());
- moduleConfiguration = new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
- }
- return moduleConfiguration;
+ return new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
}
private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) {
*/
package org.sonar.scanner.scan;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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;
-
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.scan.filesystem.FileExclusions;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.bootstrap.ExtensionInstaller;
-import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
-import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
-import org.sonar.scanner.sensor.ModuleSensorContext;
-import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
-import org.sonar.scanner.sensor.ModuleSensorOptimizer;
-import org.sonar.scanner.sensor.ModuleSensorsExecutor;
-
-import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
-
-public class ModuleScanContainer extends ComponentContainer {
- private final DefaultInputModule module;
-
- public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) {
- super(parent);
- this.module = module;
- }
-
- @Override
- protected void doBeforeStart() {
- addCoreComponents();
- addExtensions();
- }
-
- private void addCoreComponents() {
- add(
- module.definition(),
- module,
- MutableModuleSettings.class,
- new ModuleConfigurationProvider(),
-
- ModuleSensorsExecutor.class,
-
- // file system
- ModuleInputComponentStore.class,
- FileExclusions.class,
- DefaultModuleFileSystem.class,
-
- ModuleSensorOptimizer.class,
-
- ModuleSensorContext.class,
- ModuleSensorExtensionDictionary.class
- );
- }
-
- private void addExtensions() {
- ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class);
- pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT));
- }
-
- @Override
- protected void doAfterStart() {
- getComponentByType(ModuleSensorsExecutor.class).execute();
- }
-
-}
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import javax.annotation.Priority;
import org.sonar.api.config.internal.Settings;
import static java.util.Objects.requireNonNull;
* @deprecated since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
*/
@Deprecated
+@Priority(1)
public class MutableModuleSettings extends Settings {
private final Map<String, String> properties = new HashMap<>();
*/
package org.sonar.scanner.scan;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectReactor;
+import org.springframework.context.annotation.Bean;
-public class MutableProjectReactorProvider extends ProviderAdapter {
- private ProjectReactor reactor = null;
-
+public class MutableProjectReactorProvider {
+ @Bean("ProjectReactor")
public ProjectReactor provide(ProjectReactorBuilder builder) {
- if (reactor == null) {
- reactor = builder.execute();
- }
- return reactor;
+ return builder.execute();
}
}
import org.sonar.api.config.internal.Settings;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
+import javax.annotation.Priority;
+
import static java.util.Objects.requireNonNull;
/**
* @deprecated since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
*/
@Deprecated
+@Priority(2)
public class MutableProjectSettings extends Settings {
private final Map<String, String> properties = new HashMap<>();
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
public class ProjectBuildersExecutor {
private final GlobalConfiguration globalConfig;
private final ProjectBuilder[] projectBuilders;
+ @Autowired(required = false)
public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) {
this.globalConfig = globalConfig;
this.projectBuilders = projectBuilders;
}
+ @Autowired(required = false)
public ProjectBuildersExecutor(GlobalConfiguration globalConfig) {
this(globalConfig, new ProjectBuilder[0]);
}
package org.sonar.scanner.scan;
import java.util.Map;
-import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration;
public class ProjectConfiguration extends DefaultConfiguration {
-
public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
super(propertyDefinitions, encryption, props);
}
-
}
import java.util.LinkedHashMap;
import java.util.Map;
-import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
-
-public class ProjectConfigurationProvider extends ProviderAdapter {
-
- private ProjectConfiguration projectConfig;
+import org.springframework.context.annotation.Bean;
+public class ProjectConfigurationProvider {
+ @Bean("ProjectConfiguration")
public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) {
- if (projectConfig == null) {
-
- Map<String, String> settings = new LinkedHashMap<>();
- settings.putAll(globalServerSettings.properties());
- settings.putAll(projectServerSettings.properties());
- settings.putAll(project.properties());
+ Map<String, String> settings = new LinkedHashMap<>();
+ settings.putAll(globalServerSettings.properties());
+ settings.putAll(projectServerSettings.properties());
+ settings.putAll(project.properties());
- projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
- projectSettings.complete(projectConfig);
- }
+ ProjectConfiguration projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
+ projectSettings.complete(projectConfig);
return projectConfig;
}
}
import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Files;
import java.nio.file.Path;
-import org.picocontainer.Startable;
+import org.sonar.api.Startable;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
public class ProjectLock implements Startable {
import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.scan.branch.BranchParamsValidator;
+import org.springframework.beans.factory.annotation.Autowired;
import static java.lang.String.format;
import static java.util.Objects.nonNull;
@Nullable
private final BranchParamsValidator branchParamsValidator;
+ @Autowired(required = false)
public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) {
this.settings = settings;
this.branchParamsValidator = branchParamsValidator;
}
+ @Autowired(required = false)
public ProjectReactorValidator(GlobalConfiguration settings) {
this(settings, null);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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;
-
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.internal.DefaultInputModule;
-import org.sonar.api.batch.fs.internal.FileMetadata;
-import org.sonar.api.batch.fs.internal.SensorStrategy;
-import org.sonar.api.batch.rule.CheckFactory;
-import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.resources.ResourceTypes;
-import org.sonar.api.scan.filesystem.PathResolver;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.config.ScannerProperties;
-import org.sonar.core.extension.CoreExtensionsInstaller;
-import org.sonar.core.metric.ScannerMetrics;
-import org.sonar.core.platform.ComponentContainer;
-import org.sonar.scanner.DefaultFileLinesContextFactory;
-import org.sonar.scanner.ProjectInfo;
-import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
-import org.sonar.scanner.bootstrap.ExtensionInstaller;
-import org.sonar.scanner.bootstrap.ExtensionMatcher;
-import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
-import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
-import org.sonar.scanner.ci.CiConfigurationProvider;
-import org.sonar.scanner.ci.vendors.AppVeyor;
-import org.sonar.scanner.ci.vendors.AwsCodeBuild;
-import org.sonar.scanner.ci.vendors.AzureDevops;
-import org.sonar.scanner.ci.vendors.Bamboo;
-import org.sonar.scanner.ci.vendors.BitbucketPipelines;
-import org.sonar.scanner.ci.vendors.Bitrise;
-import org.sonar.scanner.ci.vendors.Buildkite;
-import org.sonar.scanner.ci.vendors.CircleCi;
-import org.sonar.scanner.ci.vendors.CirrusCi;
-import org.sonar.scanner.ci.vendors.CodeMagic;
-import org.sonar.scanner.ci.vendors.DroneCi;
-import org.sonar.scanner.ci.vendors.GithubActions;
-import org.sonar.scanner.ci.vendors.GitlabCi;
-import org.sonar.scanner.ci.vendors.Jenkins;
-import org.sonar.scanner.ci.vendors.SemaphoreCi;
-import org.sonar.scanner.ci.vendors.TravisCi;
-import org.sonar.scanner.cpd.CpdExecutor;
-import org.sonar.scanner.cpd.CpdSettings;
-import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
-import org.sonar.scanner.fs.InputModuleHierarchy;
-import org.sonar.scanner.issue.IssueFilters;
-import org.sonar.scanner.issue.IssuePublisher;
-import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
-import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
-import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
-import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
-import org.sonar.scanner.mediumtest.AnalysisObservers;
-import org.sonar.scanner.postjob.DefaultPostJobContext;
-import org.sonar.scanner.postjob.PostJobOptimizer;
-import org.sonar.scanner.postjob.PostJobsExecutor;
-import org.sonar.scanner.qualitygate.QualityGateCheck;
-import org.sonar.scanner.report.ActiveRulesPublisher;
-import org.sonar.scanner.report.AnalysisContextReportPublisher;
-import org.sonar.scanner.report.AnalysisWarningsPublisher;
-import org.sonar.scanner.report.CeTaskReportDataHolder;
-import org.sonar.scanner.report.ChangedLinesPublisher;
-import org.sonar.scanner.report.ComponentsPublisher;
-import org.sonar.scanner.report.ContextPropertiesPublisher;
-import org.sonar.scanner.report.MetadataPublisher;
-import org.sonar.scanner.report.ReportPublisher;
-import org.sonar.scanner.report.SourcePublisher;
-import org.sonar.scanner.report.TestExecutionPublisher;
-import org.sonar.scanner.repository.ContextPropertiesCache;
-import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
-import org.sonar.scanner.repository.DefaultQualityProfileLoader;
-import org.sonar.scanner.repository.ReferenceBranchSupplier;
-import org.sonar.scanner.repository.ProjectRepositoriesLoader;
-import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
-import org.sonar.scanner.repository.QualityProfileLoader;
-import org.sonar.scanner.repository.QualityProfilesProvider;
-import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
-import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
-import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
-import org.sonar.scanner.rule.ActiveRulesLoader;
-import org.sonar.scanner.rule.ActiveRulesProvider;
-import org.sonar.scanner.rule.DefaultActiveRulesLoader;
-import org.sonar.scanner.rule.DefaultRulesLoader;
-import org.sonar.scanner.rule.QProfileVerifier;
-import org.sonar.scanner.rule.RulesLoader;
-import org.sonar.scanner.rule.RulesProvider;
-import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
-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.MetadataGenerator;
-import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
-import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
-import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
-import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
-import org.sonar.scanner.scan.filesystem.StatusDetection;
-import org.sonar.scanner.scan.measure.DefaultMetricFinder;
-import org.sonar.scanner.scm.ScmChangedFilesProvider;
-import org.sonar.scanner.scm.ScmConfiguration;
-import org.sonar.scanner.scm.ScmPublisher;
-import org.sonar.scanner.scm.ScmRevisionImpl;
-import org.sonar.scanner.sensor.DefaultSensorStorage;
-import org.sonar.scanner.sensor.ProjectSensorContext;
-import org.sonar.scanner.sensor.ProjectSensorExtensionDictionary;
-import org.sonar.scanner.sensor.ProjectSensorOptimizer;
-import org.sonar.scanner.sensor.ProjectSensorsExecutor;
-import org.sonar.scm.git.GitScmSupport;
-import org.sonar.scm.svn.SvnScmSupport;
-
-import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
-import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
-import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide;
-
-public class ProjectScanContainer extends ComponentContainer {
-
- private static final Logger LOG = Loggers.get(ProjectScanContainer.class);
-
- public ProjectScanContainer(ComponentContainer globalContainer) {
- super(globalContainer);
- }
-
- @Override
- protected void doBeforeStart() {
- addScannerExtensions();
- addScannerComponents();
- ProjectLock lock = getComponentByType(ProjectLock.class);
- lock.tryLock();
- getComponentByType(WorkDirectoriesInitializer.class).execute();
- }
-
- private void addScannerComponents() {
- add(
- ScanProperties.class,
- ProjectReactorBuilder.class,
- WorkDirectoriesInitializer.class,
- new MutableProjectReactorProvider(),
- ProjectBuildersExecutor.class,
- ProjectLock.class,
- ResourceTypes.class,
- ProjectReactorValidator.class,
- ProjectInfo.class,
- new RulesProvider(),
- new BranchConfigurationProvider(),
- new ProjectBranchesProvider(),
- new ProjectPullRequestsProvider(),
- ProjectRepositoriesSupplier.class,
- new ProjectServerSettingsProvider(),
-
- // temp
- new AnalysisTempFolderProvider(),
-
- // file system
- ModuleIndexer.class,
- InputComponentStore.class,
- PathResolver.class,
- new InputProjectProvider(),
- new InputModuleHierarchyProvider(),
- ScannerComponentIdGenerator.class,
- new ScmChangedFilesProvider(),
- StatusDetection.class,
- LanguageDetection.class,
- MetadataGenerator.class,
- FileMetadata.class,
- FileIndexer.class,
- ProjectFileIndexer.class,
- ProjectExclusionFilters.class,
-
- // rules
- new ActiveRulesProvider(),
- new QualityProfilesProvider(),
- CheckFactory.class,
- QProfileVerifier.class,
-
- // issues
- DefaultNoSonarFilter.class,
- IssueFilters.class,
- IssuePublisher.class,
-
- // metrics
- DefaultMetricFinder.class,
-
- // lang
- Languages.class,
- DefaultLanguagesRepository.class,
-
- // issue exclusions
- IssueInclusionPatternInitializer.class,
- IssueExclusionPatternInitializer.class,
- IssueExclusionsLoader.class,
- EnforceIssuesFilter.class,
- IgnoreIssuesFilter.class,
-
- // context
- ContextPropertiesCache.class,
- ContextPropertiesPublisher.class,
-
- SensorStrategy.class,
-
- MutableProjectSettings.class,
- ScannerProperties.class,
- new ProjectConfigurationProvider(),
-
- ProjectCoverageAndDuplicationExclusions.class,
-
- // Report
- ReferenceBranchSupplier.class,
- ScannerMetrics.class,
- ReportPublisher.class,
- AnalysisContextReportPublisher.class,
- MetadataPublisher.class,
- ActiveRulesPublisher.class,
- AnalysisWarningsPublisher.class,
- ComponentsPublisher.class,
- TestExecutionPublisher.class,
- SourcePublisher.class,
- ChangedLinesPublisher.class,
-
- CeTaskReportDataHolder.class,
-
- // QualityGate check
- QualityGateCheck.class,
-
- // Cpd
- CpdExecutor.class,
- CpdSettings.class,
- SonarCpdBlockIndex.class,
-
- // PostJobs
- PostJobsExecutor.class,
- PostJobOptimizer.class,
- DefaultPostJobContext.class,
- PostJobExtensionDictionary.class,
-
- // SCM
- ScmConfiguration.class,
- ScmPublisher.class,
- ScmRevisionImpl.class,
-
- // Sensors
- DefaultSensorStorage.class,
- DefaultFileLinesContextFactory.class,
- ProjectSensorContext.class,
- ProjectSensorOptimizer.class,
- ProjectSensorsExecutor.class,
- ProjectSensorExtensionDictionary.class,
-
- // Filesystem
- DefaultProjectFileSystem.class,
-
- // CI
- new CiConfigurationProvider(),
- AppVeyor.class,
- AwsCodeBuild.class,
- AzureDevops.class,
- Bamboo.class,
- BitbucketPipelines.class,
- Bitrise.class,
- Buildkite.class,
- CircleCi.class,
- CirrusCi.class,
- DroneCi.class,
- GithubActions.class,
- CodeMagic.class,
- GitlabCi.class,
- Jenkins.class,
- SemaphoreCi.class,
- TravisCi.class,
-
- AnalysisObservers.class);
-
- add(GitScmSupport.getObjects());
- add(SvnScmSupport.getObjects());
-
- addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class);
- addIfMissing(DefaultRulesLoader.class, RulesLoader.class);
- addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class);
- addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class);
- addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class);
- }
-
- private void addScannerExtensions() {
- getComponentByType(CoreExtensionsInstaller.class)
- .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension));
- getComponentByType(ExtensionInstaller.class)
- .install(this, getScannerProjectExtensionsFilter());
- }
-
- static ExtensionMatcher getScannerProjectExtensionsFilter() {
- return extension -> {
- if (isDeprecatedScannerSide(extension)) {
- return isInstantiationStrategy(extension, PER_BATCH);
- }
- return isScannerSide(extension);
- };
- }
-
- @Override
- protected void doAfterStart() {
- GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
- InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
- ScanProperties properties = getComponentByType(ScanProperties.class);
- properties.validate();
-
- properties.get("sonar.branch").ifPresent(deprecatedBranch -> {
- throw MessageException.of("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
- "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information.");
- });
-
- BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
- if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
- LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()),
- branchConfig.branchName());
- } else if (branchConfig.branchName() != null) {
- LOG.info("Branch name: {}", branchConfig.branchName());
- }
-
- getComponentByType(ProjectFileIndexer.class).index();
-
- // Log detected languages and their profiles after FS is indexed and languages detected
- getComponentByType(QProfileVerifier.class).execute();
-
- scanRecursively(tree, tree.root());
-
- LOG.info("------------- Run sensors on project");
- getComponentByType(ProjectSensorsExecutor.class).execute();
-
- getComponentByType(ScmPublisher.class).publish();
-
- getComponentByType(CpdExecutor.class).execute();
- getComponentByType(ReportPublisher.class).execute();
-
- if (properties.shouldWaitForQualityGate()) {
- LOG.info("------------- Check Quality Gate status");
- getComponentByType(QualityGateCheck.class).await();
- }
-
- getComponentByType(PostJobsExecutor.class).execute();
-
- if (analysisMode.isMediumTest()) {
- getComponentByType(AnalysisObservers.class).notifyEndOfScanTask();
- }
- }
-
- private static String pullRequestBaseToDisplayName(@Nullable String pullRequestBase) {
- return pullRequestBase != null ? pullRequestBase : "default branch";
- }
-
- private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module) {
- for (DefaultInputModule child : tree.children(module)) {
- scanRecursively(tree, child);
- }
- LOG.info("------------- Run sensors on module {}", module.definition().getName());
- scan(module);
- }
-
- void scan(DefaultInputModule module) {
- new ModuleScanContainer(this, module).execute();
- }
-
-}
import java.util.Map;
import org.apache.commons.lang.StringUtils;
-import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
+import org.springframework.context.annotation.Bean;
-public class ProjectServerSettingsProvider extends ProviderAdapter {
+public class ProjectServerSettingsProvider {
private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class);
"Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " +
"displaying this warning.";
- private ProjectServerSettings singleton = null;
-
+ @Bean("ProjectServerSettings")
public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) {
- if (singleton == null) {
- Map<String, String> serverSideSettings = loader.loadProjectSettings();
- if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
- LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
- analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
- }
- singleton = new ProjectServerSettings(serverSideSettings);
+ Map<String, String> serverSideSettings = loader.loadProjectSettings();
+ if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
+ LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
+ analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
}
- return singleton;
+ return new ProjectServerSettings(serverSideSettings);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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;
+
+import javax.annotation.Priority;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.scan.filesystem.FileExclusions;
+import org.sonar.scanner.bootstrap.ExtensionInstaller;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
+import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
+import org.sonar.scanner.sensor.ModuleSensorContext;
+import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary;
+import org.sonar.scanner.sensor.ModuleSensorOptimizer;
+import org.sonar.scanner.sensor.ModuleSensorsExecutor;
+
+import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
+
+@Priority(1)
+public class SpringModuleScanContainer extends SpringComponentContainer {
+ private final DefaultInputModule module;
+
+ public SpringModuleScanContainer(SpringComponentContainer parent, DefaultInputModule module) {
+ super(parent);
+ this.module = module;
+ }
+
+ @Override
+ protected void doBeforeStart() {
+ addCoreComponents();
+ addExtensions();
+ }
+
+ private void addCoreComponents() {
+ add(
+ module.definition(),
+ module,
+ MutableModuleSettings.class,
+ new ModuleConfigurationProvider(),
+
+ ModuleSensorsExecutor.class,
+
+ // file system
+ ModuleInputComponentStore.class,
+ FileExclusions.class,
+ DefaultModuleFileSystem.class,
+
+ ModuleSensorOptimizer.class,
+
+ ModuleSensorContext.class,
+ ModuleSensorExtensionDictionary.class
+ );
+ }
+
+ private void addExtensions() {
+ ExtensionInstaller pluginInstaller = parent.getComponentByType(ExtensionInstaller.class);
+ pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT));
+ }
+
+ @Override
+ protected void doAfterStart() {
+ getComponentByType(ModuleSensorsExecutor.class).execute();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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;
+
+import javax.annotation.Nullable;
+import javax.annotation.Priority;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.api.batch.fs.internal.SensorStrategy;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter;
+import org.sonar.api.resources.ResourceTypes;
+import org.sonar.api.scan.filesystem.PathResolver;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.config.ScannerProperties;
+import org.sonar.core.extension.CoreExtensionsInstaller;
+import org.sonar.core.metric.ScannerMetrics;
+import org.sonar.scanner.DefaultFileLinesContextFactory;
+import org.sonar.scanner.ProjectInfo;
+import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
+import org.sonar.scanner.bootstrap.ExtensionInstaller;
+import org.sonar.scanner.bootstrap.ExtensionMatcher;
+import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
+import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
+import org.sonar.scanner.ci.CiConfigurationProvider;
+import org.sonar.scanner.ci.vendors.AppVeyor;
+import org.sonar.scanner.ci.vendors.AwsCodeBuild;
+import org.sonar.scanner.ci.vendors.AzureDevops;
+import org.sonar.scanner.ci.vendors.Bamboo;
+import org.sonar.scanner.ci.vendors.BitbucketPipelines;
+import org.sonar.scanner.ci.vendors.Bitrise;
+import org.sonar.scanner.ci.vendors.Buildkite;
+import org.sonar.scanner.ci.vendors.CircleCi;
+import org.sonar.scanner.ci.vendors.CirrusCi;
+import org.sonar.scanner.ci.vendors.CodeMagic;
+import org.sonar.scanner.ci.vendors.DroneCi;
+import org.sonar.scanner.ci.vendors.GithubActions;
+import org.sonar.scanner.ci.vendors.GitlabCi;
+import org.sonar.scanner.ci.vendors.Jenkins;
+import org.sonar.scanner.ci.vendors.SemaphoreCi;
+import org.sonar.scanner.ci.vendors.TravisCi;
+import org.sonar.scanner.cpd.CpdExecutor;
+import org.sonar.scanner.cpd.CpdSettings;
+import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
+import org.sonar.scanner.fs.InputModuleHierarchy;
+import org.sonar.scanner.issue.IssueFilters;
+import org.sonar.scanner.issue.IssuePublisher;
+import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
+import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
+import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
+import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
+import org.sonar.scanner.mediumtest.AnalysisObservers;
+import org.sonar.scanner.postjob.DefaultPostJobContext;
+import org.sonar.scanner.postjob.PostJobOptimizer;
+import org.sonar.scanner.postjob.PostJobsExecutor;
+import org.sonar.scanner.qualitygate.QualityGateCheck;
+import org.sonar.scanner.report.ActiveRulesPublisher;
+import org.sonar.scanner.report.AnalysisContextReportPublisher;
+import org.sonar.scanner.report.AnalysisWarningsPublisher;
+import org.sonar.scanner.report.CeTaskReportDataHolder;
+import org.sonar.scanner.report.ChangedLinesPublisher;
+import org.sonar.scanner.report.ComponentsPublisher;
+import org.sonar.scanner.report.ContextPropertiesPublisher;
+import org.sonar.scanner.report.MetadataPublisher;
+import org.sonar.scanner.report.ReportPublisher;
+import org.sonar.scanner.report.SourcePublisher;
+import org.sonar.scanner.report.TestExecutionPublisher;
+import org.sonar.scanner.repository.ContextPropertiesCache;
+import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
+import org.sonar.scanner.repository.DefaultQualityProfileLoader;
+import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
+import org.sonar.scanner.repository.QualityProfilesProvider;
+import org.sonar.scanner.repository.ReferenceBranchSupplier;
+import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
+import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
+import org.sonar.scanner.rule.ActiveRulesProvider;
+import org.sonar.scanner.rule.DefaultActiveRulesLoader;
+import org.sonar.scanner.rule.DefaultRulesLoader;
+import org.sonar.scanner.rule.QProfileVerifier;
+import org.sonar.scanner.rule.RulesProvider;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
+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.MetadataGenerator;
+import org.sonar.scanner.scan.filesystem.ProjectCoverageAndDuplicationExclusions;
+import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
+import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
+import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
+import org.sonar.scanner.scan.filesystem.StatusDetection;
+import org.sonar.scanner.scan.measure.DefaultMetricFinder;
+import org.sonar.scanner.scm.ScmChangedFilesProvider;
+import org.sonar.scanner.scm.ScmConfiguration;
+import org.sonar.scanner.scm.ScmPublisher;
+import org.sonar.scanner.scm.ScmRevisionImpl;
+import org.sonar.scanner.sensor.DefaultSensorStorage;
+import org.sonar.scanner.sensor.ProjectSensorContext;
+import org.sonar.scanner.sensor.ProjectSensorExtensionDictionary;
+import org.sonar.scanner.sensor.ProjectSensorOptimizer;
+import org.sonar.scanner.sensor.ProjectSensorsExecutor;
+import org.sonar.scm.git.GitScmSupport;
+import org.sonar.scm.svn.SvnScmSupport;
+
+import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH;
+import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
+import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide;
+
+@Priority(2)
+public class SpringProjectScanContainer extends SpringComponentContainer {
+ private static final Logger LOG = Loggers.get(SpringProjectScanContainer.class);
+
+ public SpringProjectScanContainer(SpringComponentContainer globalContainer) {
+ super(globalContainer);
+ }
+
+ @Override
+ protected void doBeforeStart() {
+ addScannerExtensions();
+ addScannerComponents();
+ }
+
+ private void addScannerComponents() {
+ add(
+ ScanProperties.class,
+ ProjectReactorBuilder.class,
+ WorkDirectoriesInitializer.class,
+ new MutableProjectReactorProvider(),
+ ProjectBuildersExecutor.class,
+ ProjectLock.class,
+ ResourceTypes.class,
+ ProjectReactorValidator.class,
+ ProjectInfo.class,
+ new RulesProvider(),
+ new BranchConfigurationProvider(),
+ new ProjectBranchesProvider(),
+ new ProjectPullRequestsProvider(),
+ ProjectRepositoriesSupplier.class,
+ new ProjectServerSettingsProvider(),
+
+ // temp
+ new AnalysisTempFolderProvider(),
+
+ // file system
+ ModuleIndexer.class,
+ InputComponentStore.class,
+ PathResolver.class,
+ new InputProjectProvider(),
+ new InputModuleHierarchyProvider(),
+ ScannerComponentIdGenerator.class,
+ new ScmChangedFilesProvider(),
+ StatusDetection.class,
+ LanguageDetection.class,
+ MetadataGenerator.class,
+ FileMetadata.class,
+ FileIndexer.class,
+ ProjectFileIndexer.class,
+ ProjectExclusionFilters.class,
+
+ // rules
+ new ActiveRulesProvider(),
+ new QualityProfilesProvider(),
+ CheckFactory.class,
+ QProfileVerifier.class,
+
+ // issues
+ DefaultNoSonarFilter.class,
+ IssueFilters.class,
+ IssuePublisher.class,
+
+ // metrics
+ DefaultMetricFinder.class,
+
+ // lang
+ LanguagesProvider.class,
+ DefaultLanguagesRepository.class,
+
+ // issue exclusions
+ IssueInclusionPatternInitializer.class,
+ IssueExclusionPatternInitializer.class,
+ IssueExclusionsLoader.class,
+ EnforceIssuesFilter.class,
+ IgnoreIssuesFilter.class,
+
+ // context
+ ContextPropertiesCache.class,
+ ContextPropertiesPublisher.class,
+
+ SensorStrategy.class,
+
+ MutableProjectSettings.class,
+ ScannerProperties.class,
+ new ProjectConfigurationProvider(),
+
+ ProjectCoverageAndDuplicationExclusions.class,
+
+ // Report
+ ReferenceBranchSupplier.class,
+ ScannerMetrics.class,
+ ReportPublisher.class,
+ AnalysisContextReportPublisher.class,
+ MetadataPublisher.class,
+ ActiveRulesPublisher.class,
+ AnalysisWarningsPublisher.class,
+ ComponentsPublisher.class,
+ TestExecutionPublisher.class,
+ SourcePublisher.class,
+ ChangedLinesPublisher.class,
+
+ CeTaskReportDataHolder.class,
+
+ // QualityGate check
+ QualityGateCheck.class,
+
+ // Cpd
+ CpdExecutor.class,
+ CpdSettings.class,
+ SonarCpdBlockIndex.class,
+
+ // PostJobs
+ PostJobsExecutor.class,
+ PostJobOptimizer.class,
+ DefaultPostJobContext.class,
+ PostJobExtensionDictionary.class,
+
+ // SCM
+ ScmConfiguration.class,
+ ScmPublisher.class,
+ ScmRevisionImpl.class,
+
+ // Sensors
+ DefaultSensorStorage.class,
+ DefaultFileLinesContextFactory.class,
+ ProjectSensorContext.class,
+ ProjectSensorOptimizer.class,
+ ProjectSensorsExecutor.class,
+ ProjectSensorExtensionDictionary.class,
+
+ // Filesystem
+ DefaultProjectFileSystem.class,
+
+ // CI
+ new CiConfigurationProvider(),
+ AppVeyor.class,
+ AwsCodeBuild.class,
+ AzureDevops.class,
+ Bamboo.class,
+ BitbucketPipelines.class,
+ Bitrise.class,
+ Buildkite.class,
+ CircleCi.class,
+ CirrusCi.class,
+ DroneCi.class,
+ GithubActions.class,
+ CodeMagic.class,
+ GitlabCi.class,
+ Jenkins.class,
+ SemaphoreCi.class,
+ TravisCi.class,
+
+ AnalysisObservers.class);
+
+ add(GitScmSupport.getObjects());
+ add(SvnScmSupport.getObjects());
+
+ add(DefaultProjectSettingsLoader.class,
+ DefaultRulesLoader.class,
+ DefaultActiveRulesLoader.class,
+ DefaultQualityProfileLoader.class,
+ DefaultProjectRepositoriesLoader.class);
+ }
+
+ private void addScannerExtensions() {
+ getParent().getComponentByType(CoreExtensionsInstaller.class)
+ .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension));
+ getParent().getComponentByType(ExtensionInstaller.class)
+ .install(this, getScannerProjectExtensionsFilter());
+ }
+
+ static ExtensionMatcher getScannerProjectExtensionsFilter() {
+ return extension -> {
+ if (isDeprecatedScannerSide(extension)) {
+ return isInstantiationStrategy(extension, PER_BATCH);
+ }
+ return isScannerSide(extension);
+ };
+ }
+
+ @Override
+ protected void doAfterStart() {
+ getComponentByType(ProjectLock.class).tryLock();
+ GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
+ InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
+ ScanProperties properties = getComponentByType(ScanProperties.class);
+ properties.validate();
+
+ properties.get("sonar.branch").ifPresent(deprecatedBranch -> {
+ throw MessageException.of("The 'sonar.branch' parameter is no longer supported. You should stop using it. " +
+ "Branch analysis is available in Developer Edition and above. See https://redirect.sonarsource.com/editions/developer.html for more information.");
+ });
+
+ BranchConfiguration branchConfig = getComponentByType(BranchConfiguration.class);
+ if (branchConfig.branchType() == BranchType.PULL_REQUEST) {
+ LOG.info("Pull request {} for merge into {} from {}", branchConfig.pullRequestKey(), pullRequestBaseToDisplayName(branchConfig.targetBranchName()),
+ branchConfig.branchName());
+ } else if (branchConfig.branchName() != null) {
+ LOG.info("Branch name: {}", branchConfig.branchName());
+ }
+
+ getComponentByType(ProjectFileIndexer.class).index();
+
+ // Log detected languages and their profiles after FS is indexed and languages detected
+ getComponentByType(QProfileVerifier.class).execute();
+
+ scanRecursively(tree, tree.root());
+
+ LOG.info("------------- Run sensors on project");
+ getComponentByType(ProjectSensorsExecutor.class).execute();
+
+ getComponentByType(ScmPublisher.class).publish();
+
+ getComponentByType(CpdExecutor.class).execute();
+ getComponentByType(ReportPublisher.class).execute();
+
+ if (properties.shouldWaitForQualityGate()) {
+ LOG.info("------------- Check Quality Gate status");
+ getComponentByType(QualityGateCheck.class).await();
+ }
+
+ getComponentByType(PostJobsExecutor.class).execute();
+
+ if (analysisMode.isMediumTest()) {
+ getComponentByType(AnalysisObservers.class).notifyEndOfScanTask();
+ }
+ }
+
+ private static String pullRequestBaseToDisplayName(@Nullable String pullRequestBase) {
+ return pullRequestBase != null ? pullRequestBase : "default branch";
+ }
+
+ private void scanRecursively(InputModuleHierarchy tree, DefaultInputModule module) {
+ for (DefaultInputModule child : tree.children(module)) {
+ scanRecursively(tree, child);
+ }
+ LOG.info("------------- Run sensors on module {}", module.definition().getName());
+ scan(module);
+ }
+
+ void scan(DefaultInputModule module) {
+ new SpringModuleScanContainer(this, module).execute();
+ }
+
+}
* Be careful that sub module work dir might be nested in parent working directory.
*/
public class WorkDirectoriesInitializer {
-
- private InputModuleHierarchy moduleHierarchy;
-
- public WorkDirectoriesInitializer(InputModuleHierarchy moduleHierarchy) {
- this.moduleHierarchy = moduleHierarchy;
- }
-
- public void execute() {
- cleanAllWorkingDirs(moduleHierarchy.root());
- mkdirsAllWorkingDirs(moduleHierarchy.root());
+ public void execute(InputModuleHierarchy moduleHierarchy) {
+ cleanAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
+ mkdirsAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
}
- private void cleanAllWorkingDirs(DefaultInputModule module) {
+ private static void cleanAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
for (DefaultInputModule sub : moduleHierarchy.children(module)) {
- cleanAllWorkingDirs(sub);
+ cleanAllWorkingDirs(moduleHierarchy, sub);
}
if (Files.exists(module.getWorkDir())) {
deleteAllRecursivelyExceptLockFile(module.getWorkDir());
}
}
- private void mkdirsAllWorkingDirs(DefaultInputModule module) {
+ private static void mkdirsAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
for (DefaultInputModule sub : moduleHierarchy.children(module)) {
- mkdirsAllWorkingDirs(sub);
+ mkdirsAllWorkingDirs(moduleHierarchy, sub);
}
try {
Files.createDirectories(module.getWorkDir());
*/
package org.sonar.scanner.scan.branch;
-import org.picocontainer.annotations.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.scan.ProjectConfiguration;
+import org.springframework.context.annotation.Bean;
-public class BranchConfigurationProvider extends ProviderAdapter {
+public class BranchConfigurationProvider {
private static final Logger LOG = Loggers.get(BranchConfigurationProvider.class);
private static final String LOG_MSG = "Load branch configuration";
- private BranchConfiguration branchConfiguration = null;
-
+ @Bean("BranchConfiguration")
public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration,
ProjectBranches branches, ProjectPullRequests pullRequests) {
- if (branchConfiguration == null) {
- if (loader == null) {
- branchConfiguration = new DefaultBranchConfiguration();
- } else {
- Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
- profiler.stopInfo();
- }
+ if (loader == null) {
+ return new DefaultBranchConfiguration();
+ } else {
+ Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
+ BranchConfiguration branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
+ profiler.stopInfo();
+ return branchConfiguration;
}
- return branchConfiguration;
}
}
package org.sonar.scanner.scan.branch;
import java.util.Collections;
-import org.picocontainer.annotations.Nullable;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.springframework.context.annotation.Bean;
-public class ProjectBranchesProvider extends ProviderAdapter {
+public class ProjectBranchesProvider {
private static final Logger LOG = Loggers.get(ProjectBranchesProvider.class);
private static final String LOG_MSG = "Load project branches";
- private ProjectBranches branches = null;
-
+ @Bean("ProjectBranches")
public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) {
- if (this.branches != null) {
- return this.branches;
- }
-
if (loader == null) {
- this.branches = new ProjectBranches(Collections.emptyList());
- return this.branches;
+ return new ProjectBranches(Collections.emptyList());
}
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- this.branches = loader.load(scannerProperties.getProjectKey());
+ ProjectBranches branches = loader.load(scannerProperties.getProjectKey());
profiler.stopInfo();
- return this.branches;
+ return branches;
}
}
package org.sonar.scanner.scan.branch;
import java.util.Collections;
-import org.picocontainer.injectors.ProviderAdapter;
+import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties;
+import org.springframework.context.annotation.Bean;
-public class ProjectPullRequestsProvider extends ProviderAdapter {
+public class ProjectPullRequestsProvider {
private static final Logger LOG = Loggers.get(ProjectPullRequestsProvider.class);
private static final String LOG_MSG = "Load project pull requests";
- private ProjectPullRequests pullRequests = null;
-
- public ProjectPullRequests provide(@org.picocontainer.annotations.Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
- if (pullRequests != null) {
- return pullRequests;
- }
-
+ @Bean("ProjectPullRequests")
+ public ProjectPullRequests provide(@Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
if (loader == null) {
- pullRequests = new ProjectPullRequests(Collections.emptyList());
- return pullRequests;
+ return new ProjectPullRequests(Collections.emptyList());
}
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
- pullRequests = loader.load(scannerProperties.getProjectKey());
+ ProjectPullRequests pullRequests = loader.load(scannerProperties.getProjectKey());
profiler.stopInfo();
return pullRequests;
}
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
+import javax.annotation.Priority;
+import javax.inject.Inject;
+
+@Priority(1)
public class DefaultModuleFileSystem extends MutableFileSystem {
+ @Inject
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) {
super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir()));
initFields(module);
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;
+import javax.annotation.Priority;
+import javax.inject.Inject;
+
+@Priority(2)
public class DefaultProjectFileSystem extends MutableFileSystem {
+ @Inject
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) {
super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir()));
setFields(project);
this.projectExclusionFilters = projectExclusionFilters;
}
- public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
- ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions,
- IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
- LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
- this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader,
- metadataGenerator, sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]);
- }
-
void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions,
Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand)
throws IOException {
import java.nio.file.Path;
import java.util.Collection;
import javax.annotation.CheckForNull;
-import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.scm.ScmProvider;
+import org.sonar.api.impl.utils.ScannerUtils;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration;
-import org.sonar.api.impl.utils.ScannerUtils;
+import org.springframework.context.annotation.Bean;
-public class ScmChangedFilesProvider extends ProviderAdapter {
+public class ScmChangedFilesProvider {
private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class);
private static final String LOG_MSG = "SCM collecting changed files in the branch";
- private ScmChangedFiles scmBranchChangedFiles;
-
+ @Bean("ScmChangedFiles")
public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) {
- if (scmBranchChangedFiles == null) {
Path rootBaseDir = project.getBaseDir();
Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir);
validatePaths(changedFiles);
- scmBranchChangedFiles = new ScmChangedFiles(changedFiles);
- }
- return scmBranchChangedFiles;
+ return new ScmChangedFiles(changedFiles);
}
private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) {
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import org.apache.commons.lang.StringUtils;
-import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
import org.sonar.api.Properties;
import org.sonar.api.Property;
import org.sonar.api.PropertyType;
+import org.sonar.api.Startable;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.config.Configuration;
import org.sonar.api.notifications.AnalysisWarnings;
private ScmProvider provider;
- public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings, ScmProvider... providers) {
+ public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings,
+ ScmProvider... providers) {
this.moduleHierarchy = moduleHierarchy;
this.settings = settings;
this.analysisWarnings = analysisWarnings;
}
}
- public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings) {
- this(moduleHierarchy, settings, analysisWarnings, new ScmProvider[0]);
- }
-
@Override
public void start() {
if (isDisabled()) {
private final InputModule module;
- public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableSettings, FileSystem fs, ActiveRules activeRules,
+ public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableModuleSettings, FileSystem fs, ActiveRules activeRules,
SensorStorage sensorStorage, SonarRuntime sonarRuntime) {
- super(project, config, mutableSettings, fs, activeRules, sensorStorage, sonarRuntime);
+ super(project, config, mutableModuleSettings, fs, activeRules, sensorStorage, sonarRuntime);
this.module = module;
}
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem;
private final MutableFileSystem fileSystem;
private final BranchConfiguration branchConfiguration;
- public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
+ public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer);
this.sensorContext = sensorContext;
import java.util.List;
import java.util.stream.Collectors;
import org.sonar.api.scanner.sensor.ProjectSensor;
-import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
+import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem;
private final MutableFileSystem fileSystem;
private final BranchConfiguration branchConfiguration;
- public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
+ public ProjectSensorExtensionDictionary(SpringComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer);
this.sensorContext = sensorContext;
<level value="INFO"/>
</logger>
+ <!-- Spring generates too many DEBUG logs when sonar.verbose is set -->
+ <logger name="org.springframework">
+ <level value="INFO"/>
+ </logger>
+
+ <logger name="org.sonar.scanner.bootstrap.PriorityBeanFactory">
+ <level value="INFO"/>
+ </logger>
+
<!-- sonar.showSql -->
<!-- see also org.sonar.db.MyBatis#configureLogback() -->
<logger name="org.mybatis">
<logger name="java.sql.ResultSet">
<level value="WARN"/>
</logger>
- <logger name="PERSISTIT">
- <level value="WARN"/>
- </logger>
<root>
<!-- sonar.verbose -->
<level value="WARN"/>
</logger>
- <logger name="PERSISTIT">
- <level value="WARN"/>
- </logger>
-
<root>
<!-- sonar.verbose -->
<level value="${ROOT_LOGGER_LEVEL}"/>
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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.ImmutableMap;
-import com.google.common.collect.Lists;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.utils.TempFolder;
-import org.sonar.batch.bootstrapper.EnvironmentInformation;
-import org.sonar.core.util.UuidFactory;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class GlobalContainerTest {
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private GlobalContainer createContainer(List<Object> extensions) {
- Map<String, String> props = ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.getRoot().getAbsolutePath(),
- CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.getRoot().getAbsolutePath());
-
- GlobalContainer container = GlobalContainer.create(props, extensions);
- container.doBeforeStart();
- return container;
- }
-
- @Test
- public void should_add_components() {
- GlobalContainer container = createContainer(Collections.singletonList(new EnvironmentInformation("maven", "3.1.0")));
-
- assertThat(container.getComponentByType(UuidFactory.class)).isNotNull();
- assertThat(container.getComponentByType(TempFolder.class)).isNotNull();
- }
-
- @Test
- public void should_add_bootstrap_extensions() {
- GlobalContainer container = createContainer(Lists.newArrayList(Foo.class, new Bar()));
-
- assertThat(container.getComponentByType(Foo.class)).isNotNull();
- assertThat(container.getComponentByType(Bar.class)).isNotNull();
- }
-
- @Test
- public void shouldFormatTime() {
- assertThat(GlobalContainer.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400 s");
- assertThat(GlobalContainer.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400 s");
- assertThat(GlobalContainer.formatTime(3 * 1000 + 400)).isEqualTo("3.400 s");
- assertThat(GlobalContainer.formatTime(400)).isEqualTo("0.400 s");
- }
-
- @ScannerSide
- public static class Foo {
-
- }
-
- @ScannerSide
- public static class Bar {
-
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.Test;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class LazyBeanFactoryPostProcessorTest {
+ private final LazyBeanFactoryPostProcessor postProcessor = new LazyBeanFactoryPostProcessor();
+
+ @Test
+ public void sets_all_beans_lazy() {
+ DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
+ beanFactory.registerBeanDefinition("bean1", new RootBeanDefinition());
+ assertThat(beanFactory.getBeanDefinition("bean1").isLazyInit()).isFalse();
+
+ postProcessor.postProcessBeanFactory(beanFactory);
+ assertThat(beanFactory.getBeanDefinition("bean1").isLazyInit()).isTrue();
+ }
+
+}
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.DependsUpon;
import org.sonar.api.batch.Phase;
import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.batch.bootstrap.ProjectDefinition;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
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.scan.SpringModuleScanContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem;
import org.sonar.scanner.sensor.ModuleSensorContext;
import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.sonar.scanner.sensor.ModuleSensorWrapper;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
}
private ModuleSensorExtensionDictionary newSelector(Object... extensions) {
- ComponentContainer iocContainer = new ComponentContainer();
- for (Object extension : extensions) {
- iocContainer.addSingleton(extension);
- }
+ DefaultInputModule inputModule = mock(DefaultInputModule.class);
+ when(inputModule.definition()).thenReturn(mock(ProjectDefinition.class));
+
+ SpringComponentContainer parent = new SpringComponentContainer();
+ parent.context.refresh();
+
+ SpringComponentContainer iocContainer = new SpringModuleScanContainer(parent, inputModule);
+ iocContainer.add(Arrays.asList(extensions));
+ iocContainer.context.refresh();
+
return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration);
}
Sensor b = new FakeSensor();
Sensor c = new FakeSensor();
- ComponentContainer grandParent = new ComponentContainer();
- grandParent.addSingleton(a);
+ SpringComponentContainer grandParent = new SpringComponentContainer();
+ grandParent.add(a);
+ grandParent.context.refresh();
- ComponentContainer parent = grandParent.createChild();
- parent.addSingleton(b);
+ SpringComponentContainer parent = grandParent.createChild();
+ parent.add(b);
+ parent.context.refresh();
- ComponentContainer child = parent.createChild();
- child.addSingleton(c);
+ SpringComponentContainer child = parent.createChild();
+ child.add(c);
+ child.context.refresh();
ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class),
fileSystem, branchConfiguration);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 javax.annotation.Priority;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
+import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.core.annotation.AnnotationAwareOrderComparator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+public class PriorityBeanFactoryTest {
+ private final DefaultListableBeanFactory parentBeanFactory = new PriorityBeanFactory();
+ private final DefaultListableBeanFactory beanFactory = new PriorityBeanFactory();
+
+ @Before
+ public void setUp() {
+ // needed to support autowiring with @Inject
+ beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
+ //needed to read @Priority
+ beanFactory.setDependencyComparator(new AnnotationAwareOrderComparator());
+ beanFactory.setParentBeanFactory(parentBeanFactory);
+ }
+
+ @Test
+ public void give_priority_to_child_container() {
+ parentBeanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+
+ beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+ beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+ assertThat(beanFactory.getBean(B.class).dep.getClass()).isEqualTo(A2.class);
+ }
+
+ @Test
+ public void follow_priority_annotations() {
+ parentBeanFactory.registerBeanDefinition("A3", new RootBeanDefinition(A3.class));
+
+ beanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+ beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+ beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+ assertThat(beanFactory.getBean(B.class).dep.getClass()).isEqualTo(A3.class);
+ }
+
+ @Test
+ public void throw_NoUniqueBeanDefinitionException_if_cant_find_single_bean_with_higher_priority() {
+ beanFactory.registerBeanDefinition("A1", new RootBeanDefinition(A1.class));
+ beanFactory.registerBeanDefinition("A2", new RootBeanDefinition(A2.class));
+ beanFactory.registerBeanDefinition("B", new RootBeanDefinition(B.class));
+
+ assertThatThrownBy(() -> beanFactory.getBean(B.class))
+ .hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
+ }
+
+ private static class B {
+ private final A dep;
+
+ public B(A dep) {
+ this.dep = dep;
+ }
+ }
+
+ private interface A {
+
+ }
+
+ private static class A1 implements A {
+
+ }
+
+ private static class A2 implements A {
+
+ }
+
+ @Priority(1)
+ private static class A3 implements A {
+
+ }
+
+}
assertThat(httpConnector.baseUrl()).isEqualTo("https://here/sonarqube/");
assertThat(httpConnector.okHttpClient().proxy()).isNull();
}
-
- @Test
- public void build_singleton() {
- System2 system = mock(System2.class);
-
- ScannerProperties settings = new ScannerProperties(new HashMap<>());
- DefaultScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
- DefaultScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
- assertThat(first).isSameAs(second);
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import org.junit.Test;
+import org.sonar.api.Startable;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+
+public class SpringComponentContainerTest {
+
+ @Test
+ public void should_stop_after_failing() {
+ ApiStartable startStop = new ApiStartable();
+ SpringComponentContainer container = new SpringComponentContainer() {
+ @Override
+ public void doBeforeStart() {
+ add(startStop);
+ }
+
+ @Override
+ public void doAfterStart() {
+ getComponentByType(ApiStartable.class);
+ throw new IllegalStateException("doBeforeStart");
+ }
+ };
+
+ assertThrows("doBeforeStart", IllegalStateException.class, container::execute);
+ assertThat(startStop.start).isTrue();
+ assertThat(startStop.stop).isTrue();
+ }
+
+ @Test
+ public void register_instance_with_toString() {
+ SpringComponentContainer container = new SimpleContainer(new ToString("a"), new ToString("b"));
+ container.startComponents();
+ assertThat(container.context.getBeanDefinitionNames())
+ .contains("org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-a", "org.sonar.scanner.bootstrap.SpringComponentContainerTest.ToString-b");
+ assertThat(container.getComponentsByType(ToString.class)).hasSize(2);
+ }
+
+ @Test
+ public void register_class_with_fqcn() {
+ SpringComponentContainer container = new SimpleContainer(A.class, B.class);
+ container.startComponents();
+ assertThat(container.context.getBeanDefinitionNames())
+ .contains("org.sonar.scanner.bootstrap.SpringComponentContainerTest$A", "org.sonar.scanner.bootstrap.SpringComponentContainerTest$B");
+ assertThat(container.getComponentByType(A.class)).isNotNull();
+ assertThat(container.getComponentByType(B.class)).isNotNull();
+ }
+
+ @Test
+ public void should_throw_start_exception_if_stop_also_throws_exception() {
+ ErrorStopClass errorStopClass = new ErrorStopClass();
+ SpringComponentContainer container = new SpringComponentContainer() {
+ @Override
+ public void doBeforeStart() {
+ add(errorStopClass);
+ }
+
+ @Override
+ public void doAfterStart() {
+ getComponentByType(ErrorStopClass.class);
+ throw new IllegalStateException("doBeforeStart");
+ }
+ };
+ assertThrows("doBeforeStart", IllegalStateException.class, container::execute);
+ assertThat(errorStopClass.stopped).isTrue();
+ }
+
+ @Test
+ public void should_support_extensions_without_annotations() {
+ SpringComponentContainer container = new SimpleContainer(A.class, B.class);
+ container.addExtension("", ExtensionWithMultipleConstructorsAndNoAnnotations.class);
+ container.startComponents();
+ assertThat(container.getComponentByType(ExtensionWithMultipleConstructorsAndNoAnnotations.class).gotBothArgs).isTrue();
+ }
+
+ @Test
+ public void support_start_stop_callbacks() {
+ JsrLifecycleCallbacks jsr = new JsrLifecycleCallbacks();
+ ApiStartable api = new ApiStartable();
+ PicoStartable pico = new PicoStartable();
+
+ SpringComponentContainer container = new SimpleContainer(jsr, api, pico) {
+ @Override
+ public void doAfterStart() {
+ // force lazy instantiation
+ getComponentByType(JsrLifecycleCallbacks.class);
+ getComponentByType(ApiStartable.class);
+ getComponentByType(PicoStartable.class);
+ }
+ };
+ container.execute();
+
+ assertThat(jsr.postConstruct).isTrue();
+ assertThat(jsr.preDestroy).isTrue();
+ assertThat(api.start).isTrue();
+ assertThat(api.stop).isTrue();
+ assertThat(pico.start).isTrue();
+ assertThat(pico.stop).isTrue();
+ }
+
+ private static class JsrLifecycleCallbacks {
+ private boolean postConstruct = false;
+ private boolean preDestroy = false;
+
+ @PostConstruct
+ public void postConstruct() {
+ postConstruct = true;
+ }
+
+ @PreDestroy
+ public void preDestroy() {
+ preDestroy = true;
+ }
+ }
+
+ private static class ApiStartable implements Startable {
+ private boolean start = false;
+ private boolean stop = false;
+
+ public void start() {
+ start = true;
+ }
+
+ public void stop() {
+ stop = true;
+ }
+ }
+
+ private static class PicoStartable implements org.picocontainer.Startable {
+ private boolean start = false;
+ private boolean stop = false;
+
+ public void start() {
+ start = true;
+ }
+
+ public void stop() {
+ stop = true;
+ }
+ }
+
+ private static class ToString {
+ private final String toString;
+
+ public ToString(String toString) {
+ this.toString = toString;
+ }
+
+ @Override
+ public String toString() {
+ return toString;
+ }
+ }
+
+ private static class A {
+ }
+
+ private static class B {
+ }
+
+ private static class ExtensionWithMultipleConstructorsAndNoAnnotations {
+ private boolean gotBothArgs = false;
+ public ExtensionWithMultipleConstructorsAndNoAnnotations(A a) {
+ }
+
+ public ExtensionWithMultipleConstructorsAndNoAnnotations(A a, B b) {
+ gotBothArgs = true;
+ }
+ }
+
+ private static class ErrorStopClass implements Startable {
+ private boolean stopped = false;
+
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void stop() {
+ stopped = true;
+ throw new IllegalStateException("stop");
+ }
+ }
+
+ private static class SimpleContainer extends SpringComponentContainer {
+ public SimpleContainer(Object... objects) {
+ add(objects);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SpringGlobalContainerTest {
+ @Test
+ public void shouldFormatTime() {
+ assertThat(SpringGlobalContainer.formatTime(1 * 60 * 60 * 1000 + 2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("1:02:03.400 s");
+ assertThat(SpringGlobalContainer.formatTime(2 * 60 * 1000 + 3 * 1000 + 400)).isEqualTo("2:03.400 s");
+ assertThat(SpringGlobalContainer.formatTime(3 * 1000 + 400)).isEqualTo("3.400 s");
+ assertThat(SpringGlobalContainer.formatTime(400)).isEqualTo("0.400 s");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.Test;
+import org.picocontainer.Startable;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+public class StartableBeanPostProcessorTest {
+ private final StartableBeanPostProcessor underTest = new StartableBeanPostProcessor();
+
+ @Test
+ public void starts_pico_startable() {
+ Startable startable = mock(Startable.class);
+ underTest.postProcessBeforeInitialization(startable, "startable");
+ verify(startable).start();
+ verifyNoMoreInteractions(startable);
+ }
+
+ @Test
+ public void starts_api_startable() {
+ org.sonar.api.Startable startable = mock(org.sonar.api.Startable.class);
+ underTest.postProcessBeforeInitialization(startable, "startable");
+ verify(startable).start();
+ verifyNoMoreInteractions(startable);
+ }
+
+ @Test
+ public void stops_pico_startable() {
+ Startable startable = mock(Startable.class);
+ underTest.postProcessBeforeDestruction(startable, "startable");
+ verify(startable).stop();
+ verifyNoMoreInteractions(startable);
+ }
+
+ @Test
+ public void stops_api_startable() {
+ org.sonar.api.Startable startable = mock(org.sonar.api.Startable.class);
+ underTest.postProcessBeforeDestruction(startable, "startable");
+ verify(startable).stop();
+ verifyNoMoreInteractions(startable);
+ }
+
+}
import java.util.Properties;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import javax.annotation.Priority;
import org.apache.commons.io.FileUtils;
import org.junit.rules.ExternalResource;
import org.sonar.api.Plugin;
private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
- private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder();
+ private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt();
private LogOutput logOutput = null;
private static void createWorkingDirs() throws IOException {
public static class AnalysisBuilder {
private final Map<String, String> taskProperties = new HashMap<>();
- private ScannerMediumTester tester;
+ private final ScannerMediumTester tester;
public AnalysisBuilder(ScannerMediumTester tester) {
this.tester = tester;
}
+ @Priority(1)
private static class FakeRulesLoader implements RulesLoader {
private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>();
}
}
+ @Priority(1)
private static class FakeActiveRulesLoader implements ActiveRulesLoader {
private List<LoadedActiveRule> activeRules = new LinkedList<>();
}
}
+ @Priority(1)
private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {
private int metricId = 1;
}
+ @Priority(1)
private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
private Map<String, FileData> fileDataMap = new HashMap<>();
}
+ @Priority(1)
private static class FakeBranchConfiguration implements BranchConfiguration {
private BranchType branchType = BranchType.BRANCH;
}
}
+ @Priority(1)
private static class FakeSonarRuntime implements SonarRuntime {
private SonarEdition edition;
return this;
}
+ @Priority(1)
private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
@Override
public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) {
}
}
+ @Priority(1)
private static class FakeQualityProfileLoader implements QualityProfileLoader {
private List<QualityProfile> qualityProfiles = new LinkedList<>();
}
}
+ @Priority(1)
private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {
private Map<String, String> globalSettings = new HashMap<>();
}
}
+ @Priority(1)
private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader {
private NewCodePeriods.ShowWSResponse response;
}
}
+ @Priority(1)
private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {
private Map<String, String> projectSettings = new HashMap<>();
}
}
+ @Priority(1)
+ private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder {
+
+ }
+
}
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
assertThatThrownBy(() -> tester
.newAnalysis(new File(projectDir, "sonar-project.properties"))
.execute())
- .isInstanceOf(IllegalStateException.class)
- .hasMessage("No language plugins are installed.");
+ .isInstanceOf(UnsatisfiedDependencyException.class)
+ .hasRootCauseMessage("No language plugins are installed.");
}
private File copyProject(String path) throws Exception {
List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
assertThat(issues).hasSize(8 /* lines */);
-
+
List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
assertThat(externalIssues).isEmpty();
}
-
+
@Test
public void testOneExternalIssuePerLine() throws Exception {
File projectDir = new File("test-resources/mediumtest/xoo/sample");
.build())
.execute();
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+ "Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).isEmpty();
.build())
.execute();
- assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
+ assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly(
+ "Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).hasSize(10);
issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
assertThat(issues).hasSize(10);
-
// SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules
logTester.clear();
result = tester.newAnalysis()
.build())
.execute();
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
+ assertThat(logTester.logs(LoggerLevel.WARN)).contains(
+ "Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).hasSize(10);
import java.util.Collections;
import java.util.Map;
+import javax.annotation.Priority;
import org.junit.BeforeClass;
import org.junit.Test;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
+import org.springframework.beans.factory.UnsatisfiedDependencyException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@Test
public void testWithVerbose() {
setUp(true);
-
assertThatThrownBy(() -> batch.execute())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Unable to load component class");
+ .isInstanceOf(UnsatisfiedDependencyException.class)
+ .hasMessageContaining("Error loading settings");
}
+ @Priority(1)
private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
boolean withCause = false;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
- private ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
- new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
+ private ReportPublisher underTest;
@Before
public void setUp() {
when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath()
.resolve("folder")
.resolve("report-task.txt"));
+ underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
+ new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
}
@Test
underTest.prepareAndDumpMetadata("TASK-123");
assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
- "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
+ "projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://localhost\n" +
"serverVersion=6.4\n" +
"dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" +
public void should_not_delete_report_if_property_is_set() throws IOException {
when(properties.shouldKeepReport()).thenReturn(true);
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
- Files.createDirectory(reportDir);
underTest.start();
underTest.stop();
@Test
public void should_delete_report_by_default() throws IOException {
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
- Files.createDirectory(reportDir);
underTest.start();
underTest.stop();
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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;
-
-import org.junit.Test;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.server.ServerSide;
-import org.sonar.scanner.bootstrap.ExtensionMatcher;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ProjectScanContainerTest {
-
- @Test
- public void should_add_only_batch_extensions() {
- ExtensionMatcher filter = ProjectScanContainer.getScannerProjectExtensionsFilter();
-
- assertThat(filter.accept(new MyBatchExtension())).isTrue();
- assertThat(filter.accept(MyBatchExtension.class)).isTrue();
-
- assertThat(filter.accept(new MyProjectExtension())).isFalse();
- assertThat(filter.accept(MyProjectExtension.class)).isFalse();
- assertThat(filter.accept(new MyServerExtension())).isFalse();
- assertThat(filter.accept(MyServerExtension.class)).isFalse();
- }
-
- @ScannerSide
- @InstantiationStrategy(InstantiationStrategy.PER_BATCH)
- static class MyBatchExtension {
-
- }
-
- @ScannerSide
- @InstantiationStrategy(InstantiationStrategy.PER_PROJECT)
- static class MyProjectExtension {
-
- }
-
- @ServerSide
- static class MyServerExtension {
-
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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;
+
+import org.junit.Test;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.server.ServerSide;
+import org.sonar.scanner.bootstrap.ExtensionMatcher;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SpringProjectScanContainerTest {
+
+ @Test
+ public void should_add_only_batch_extensions() {
+ ExtensionMatcher filter = SpringProjectScanContainer.getScannerProjectExtensionsFilter();
+
+ assertThat(filter.accept(new MyBatchExtension())).isTrue();
+ assertThat(filter.accept(MyBatchExtension.class)).isTrue();
+
+ assertThat(filter.accept(new MyProjectExtension())).isFalse();
+ assertThat(filter.accept(MyProjectExtension.class)).isFalse();
+ assertThat(filter.accept(new MyServerExtension())).isFalse();
+ assertThat(filter.accept(MyServerExtension.class)).isFalse();
+ }
+
+ @ScannerSide
+ @InstantiationStrategy(InstantiationStrategy.PER_BATCH)
+ static class MyBatchExtension {
+
+ }
+
+ @ScannerSide
+ @InstantiationStrategy(InstantiationStrategy.PER_PROJECT)
+ static class MyProjectExtension {
+
+ }
+
+ @ServerSide
+ static class MyServerExtension {
+
+ }
+}
when(root.getWorkDir()).thenReturn(rootWorkDir.toPath());
assertThat(rootWorkDir.list().length).isGreaterThan(1);
- initializer = new WorkDirectoriesInitializer(hierarchy);
+ initializer = new WorkDirectoriesInitializer();
}
@Test
public void testNonExisting() {
temp.delete();
- initializer.execute();
+ initializer.execute(hierarchy);
}
@Test
public void testClean() {
- initializer.execute();
+ initializer.execute(hierarchy);
assertThat(rootWorkDir).exists();
assertThat(lock).exists();
moduleAWorkdir.mkdir();
new File(moduleAWorkdir, "fooA.txt").createNewFile();
- initializer.execute();
+ initializer.execute(hierarchy);
assertThat(rootWorkDir).exists();
assertThat(lock).exists();
when(reactor.getRoot()).thenReturn(root);
}
- @Test
- public void should_cache_config() {
- BranchConfiguration configuration = provider.provide(null, projectConfiguration, branches, pullRequests);
- assertThat(provider.provide(null, projectConfiguration, branches, pullRequests)).isSameAs(configuration);
- }
-
@Test
public void should_use_loader() {
when(loader.load(eq(projectSettings), eq(branches), eq(pullRequests))).thenReturn(config);
}
- @Test
- public void should_cache_branches() {
- when(scannerProperties.getProjectKey()).thenReturn("project");
- ProjectBranches branches = provider.provide(null, scannerProperties);
- assertThat(provider.provide(null, scannerProperties)).isSameAs(branches);
- }
-
@Test
public void should_use_loader() {
when(scannerProperties.getProjectKey()).thenReturn("key");
scannerProperties = mock(ScannerProperties.class);
}
- @Test
- public void cache_pull_requests() {
- when(scannerProperties.getProjectKey()).thenReturn("project");
- ProjectPullRequests pullRequests = provider.provide(null, scannerProperties);
-
- assertThat(provider.provide(null, scannerProperties)).isSameAs(pullRequests);
- }
-
@Test
public void should_use_loader() {
when(scannerProperties.getProjectKey()).thenReturn("key");
verify(scmProvider).branchChangedFiles("target", rootBaseDir);
}
- @Test
- public void testCacheObject() {
- provider.provide(scmConfiguration, branchConfiguration, project);
- provider.provide(scmConfiguration, branchConfiguration, project);
- verify(branchConfiguration).isPullRequest();
- }
-
}