Co-authored-by: Zipeng WU <zipeng.wu@sonarsource.com>tags/9.4.0.54424
dependency 'io.netty:netty-all:4.1.70.Final' | dependency 'io.netty:netty-all:4.1.70.Final' | ||||
dependency 'com.sun.mail:javax.mail:1.5.6' | dependency 'com.sun.mail:javax.mail:1.5.6' | ||||
dependency 'javax.annotation:javax.annotation-api:1.3.2' | 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.servlet:javax.servlet-api:3.1.0' | ||||
dependency 'javax.xml.bind:jaxb-api:2.3.0' | dependency 'javax.xml.bind:jaxb-api:2.3.0' | ||||
dependency 'junit:junit:4.13.2' | dependency 'junit:junit:4.13.2' | ||||
dependency 'org.simpleframework:simple:4.1.21' | dependency 'org.simpleframework:simple:4.1.21' | ||||
dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63' | 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.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.subethamail:subethasmtp:3.1.7' | ||||
dependency 'org.yaml:snakeyaml:1.26' | dependency 'org.yaml:snakeyaml:1.26' | ||||
dependency 'xml-apis:xml-apis:1.4.01' | dependency 'xml-apis:xml-apis:1.4.01' |
import com.google.common.collect.Iterables; | import com.google.common.collect.Iterables; | ||||
import org.sonar.ce.task.step.ComputationStep; | import org.sonar.ce.task.step.ComputationStep; | ||||
import org.sonar.ce.task.step.ComputationSteps; | 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()} | * 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 { | 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; | this.container = container; | ||||
} | } | ||||
import org.sonar.ce.task.step.ComputationStepExecutor; | import org.sonar.ce.task.step.ComputationStepExecutor; | ||||
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | ||||
import org.sonar.core.platform.ComponentContainer; | import org.sonar.core.platform.ComponentContainer; | ||||
import org.sonar.core.platform.Container; | |||||
import org.sonar.core.platform.ContainerPopulator; | import org.sonar.core.platform.ContainerPopulator; | ||||
import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE; | import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE; | ||||
public static final class AuditPurgeComputationSteps extends AbstractComputationSteps { | public static final class AuditPurgeComputationSteps extends AbstractComputationSteps { | ||||
public AuditPurgeComputationSteps(ContainerPopulator.Container container) { | |||||
public AuditPurgeComputationSteps(Container container) { | |||||
super(container); | super(container); | ||||
} | } | ||||
import org.sonar.ce.task.step.ComputationStepExecutor; | import org.sonar.ce.task.step.ComputationStepExecutor; | ||||
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | ||||
import org.sonar.core.platform.ComponentContainer; | import org.sonar.core.platform.ComponentContainer; | ||||
import org.sonar.core.platform.Container; | |||||
import org.sonar.core.platform.ContainerPopulator; | import org.sonar.core.platform.ContainerPopulator; | ||||
import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; | import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; | ||||
public static final class SyncComputationSteps extends AbstractComputationSteps { | public static final class SyncComputationSteps extends AbstractComputationSteps { | ||||
public SyncComputationSteps(ContainerPopulator.Container container) { | |||||
public SyncComputationSteps(Container container) { | |||||
super(container); | super(container); | ||||
} | } | ||||
import org.picocontainer.PicoContainer; | import org.picocontainer.PicoContainer; | ||||
import org.sonar.ce.task.CeTask; | import org.sonar.ce.task.CeTask; | ||||
import org.sonar.core.platform.ComponentContainer; | 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}. | * 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(); | ComponentContainer getParent(); | ||||
*/ | */ | ||||
package org.sonar.server.platform.db.migration.engine; | 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. | * A dedicated container used to run DB migrations where all components are lazily instantiated. | ||||
* classes only they really are to be executed. | * classes only they really are to be executed. | ||||
* </p> | * </p> | ||||
*/ | */ | ||||
public interface MigrationContainer extends ContainerPopulator.Container { | |||||
public interface MigrationContainer extends Container { | |||||
/** | /** | ||||
* Cleans up resources after migration has run. | * Cleans up resources after migration has run. |
compile 'commons-codec:commons-codec' | compile 'commons-codec:commons-codec' | ||||
compile 'commons-io:commons-io' | compile 'commons-io:commons-io' | ||||
compile 'commons-lang:commons-lang' | compile 'commons-lang:commons-lang' | ||||
compile 'javax.inject:javax.inject' | |||||
compile 'org.codehaus.sonar:sonar-classloader' | compile 'org.codehaus.sonar:sonar-classloader' | ||||
compile 'org.picocontainer:picocontainer' | compile 'org.picocontainer:picocontainer' | ||||
compile 'org.slf4j:slf4j-api' | compile 'org.slf4j:slf4j-api' | ||||
compile 'org.sonarsource.update-center:sonar-update-center-common' | compile 'org.sonarsource.update-center:sonar-update-center-common' | ||||
compile 'org.springframework:spring-context' | |||||
compile project(path: ':sonar-plugin-api', configuration: 'shadow') | compile project(path: ':sonar-plugin-api', configuration: 'shadow') | ||||
compile project(':sonar-plugin-api-impl') | compile project(':sonar-plugin-api-impl') | ||||
import org.sonar.api.utils.AnnotationUtils; | import org.sonar.api.utils.AnnotationUtils; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | 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; | import static java.util.Objects.requireNonNull; | ||||
private final CoreExtensionRepository coreExtensionRepository; | private final CoreExtensionRepository coreExtensionRepository; | ||||
private final Class<? extends Annotation> supportedAnnotationType; | 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.sonarRuntime = sonarRuntime; | ||||
this.coreExtensionRepository = coreExtensionRepository; | this.coreExtensionRepository = coreExtensionRepository; | ||||
this.supportedAnnotationType = supportedAnnotationType; | this.supportedAnnotationType = supportedAnnotationType; | ||||
* @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether | * @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. | * 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() | coreExtensionRepository.loadedCoreExtensions() | ||||
.forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension)); | .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(); | String coreExtensionName = coreExtension.getName(); | ||||
try { | try { | ||||
addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension); | 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) { | Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | ||||
ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); | ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); | ||||
coreExtension.load(context); | 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) { | private <T> boolean hasSupportedAnnotation(T component) { | ||||
return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null; | return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null; | ||||
} | } | ||||
private class ContextImpl implements CoreExtension.Context { | private class ContextImpl implements CoreExtension.Context { | ||||
private final ComponentContainer container; | |||||
private final ExtensionContainer container; | |||||
private final Predicate<Object> extensionFilter; | private final Predicate<Object> extensionFilter; | ||||
private final Predicate<Object> additionalSideFilter; | private final Predicate<Object> additionalSideFilter; | ||||
private final String extensionCategory; | 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.container = container; | ||||
this.extensionFilter = extensionFilter; | this.extensionFilter = extensionFilter; | ||||
this.additionalSideFilter = additionalSideFilter; | this.additionalSideFilter = additionalSideFilter; | ||||
components.forEach(this::addExtension); | components.forEach(this::addExtension); | ||||
return this; | 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.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import javax.inject.Inject; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.core.util.stream.MoreCollectors; | import org.sonar.core.util.stream.MoreCollectors; | ||||
private final CoreExtensionRepository coreExtensionRepository; | private final CoreExtensionRepository coreExtensionRepository; | ||||
private final ServiceLoaderWrapper serviceLoaderWrapper; | private final ServiceLoaderWrapper serviceLoaderWrapper; | ||||
@Inject | |||||
public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) { | public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) { | ||||
this(coreExtensionRepository, new ServiceLoaderWrapper()); | this(coreExtensionRepository, new ServiceLoaderWrapper()); | ||||
} | } |
import org.sonar.api.measures.Metric; | import org.sonar.api.measures.Metric; | ||||
import org.sonar.api.measures.Metrics; | import org.sonar.api.measures.Metrics; | ||||
import org.sonar.api.scanner.ScannerSide; | 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.CLASSES; | ||||
import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY; | import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY; | ||||
private final Set<Metric> metrics; | private final Set<Metric> metrics; | ||||
@Autowired(required = false) | |||||
public ScannerMetrics() { | public ScannerMetrics() { | ||||
this.metrics = ALLOWED_CORE_METRICS; | this.metrics = ALLOWED_CORE_METRICS; | ||||
} | } | ||||
@Autowired(required = false) | |||||
public ScannerMetrics(Metrics[] metricsRepositories) { | public ScannerMetrics(Metrics[] metricsRepositories) { | ||||
this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet()); | this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet()); | ||||
} | } |
@ScannerSide | @ScannerSide | ||||
@ServerSide | @ServerSide | ||||
@ComputeEngineSide | @ComputeEngineSide | ||||
public class ComponentContainer implements ContainerPopulator.Container { | |||||
public class ComponentContainer implements ExtensionContainer { | |||||
public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2; | public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2; | ||||
private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer { | private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer { | ||||
return this; | return this; | ||||
} | } | ||||
@Override | |||||
public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) { | public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) { | ||||
Object key = componentKeys.of(extension); | Object key = componentKeys.of(extension); | ||||
try { | try { | ||||
return this; | return this; | ||||
} | } | ||||
@Override | |||||
public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) { | public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) { | ||||
Object key = componentKeys.of(extension); | Object key = componentKeys.of(extension); | ||||
try { | try { | ||||
return getName(extension.getClass()); | 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); | 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("")); | propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse("")); | ||||
return this; | |||||
} | } | ||||
public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) { | public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) { |
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | 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 static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+"); | ||||
private final Set<Class> objectsWithoutToString = new HashSet<>(); | private final Set<Class> objectsWithoutToString = new HashSet<>(); | ||||
Object of(Object component) { | Object of(Object component) { | ||||
return of(component, Loggers.get(ComponentKeys.class)); | |||||
return of(component, LOG); | |||||
} | } | ||||
Object of(Object component, Logger log) { | Object of(Object component, Logger log) { | ||||
if (component instanceof Class) { | if (component instanceof Class) { | ||||
return component; | 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(); | String key = component.toString(); | ||||
if (IDENTITY_HASH_PATTERN.matcher(key).matches()) { | if (IDENTITY_HASH_PATTERN.matcher(key).matches()) { | ||||
if (!objectsWithoutToString.add(component.getClass())) { | if (!objectsWithoutToString.add(component.getClass())) { | ||||
} | } | ||||
key += Uuids.create(); | key += Uuids.create(); | ||||
} | } | ||||
return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString(); | |||||
return component.getClass().getCanonicalName() + "-" + key; | |||||
} | } | ||||
} | } |
/* | |||||
* 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; | package org.sonar.core.platform; | ||||
import java.util.List; | |||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface ContainerPopulator<T extends ContainerPopulator.Container> { | |||||
public interface ContainerPopulator<T extends Container> { | |||||
void populateContainer(T 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); | |||||
} | |||||
} | } |
/* | |||||
* 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.Optional; | ||||
import java.util.zip.GZIPInputStream; | import java.util.zip.GZIPInputStream; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import javax.inject.Inject; | |||||
import org.apache.commons.codec.binary.Base64; | import org.apache.commons.codec.binary.Base64; | ||||
import org.apache.commons.io.IOUtils; | import org.apache.commons.io.IOUtils; | ||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
private final Integer readTimeout; | private final Integer readTimeout; | ||||
private final Integer connectTimeout; | private final Integer connectTimeout; | ||||
@Inject | |||||
public DefaultHttpDownloader(Server server, Configuration config) { | public DefaultHttpDownloader(Server server, Configuration config) { | ||||
this(server, config, null); | this(server, config, null); | ||||
} | } |
import java.nio.file.SimpleFileVisitor; | import java.nio.file.SimpleFileVisitor; | ||||
import java.nio.file.attribute.BasicFileAttributes; | import java.nio.file.attribute.BasicFileAttributes; | ||||
import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.utils.TempFolder; | import org.sonar.api.utils.TempFolder; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | 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 static final Logger LOG = Loggers.get(DefaultTempFolder.class); | ||||
private final File tempDir; | private final File tempDir; | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public void start() { | |||||
// nothing to do | |||||
} | |||||
@Override | |||||
public void stop() { | public void stop() { | ||||
if (deleteOnExit) { | if (deleteOnExit) { | ||||
clean(); | clean(); |
@Test | @Test | ||||
public void should_add_several_times_the_same_language() { | public void should_add_several_times_the_same_language() { | ||||
Languages languages = new Languages( | Languages languages = new Languages( | ||||
language("fake"), | |||||
language("fake")); | |||||
language("fake"), | |||||
language("fake")); | |||||
assertThat(languages.get("fake").getKey()).isEqualTo("fake"); | assertThat(languages.get("fake").getKey()).isEqualTo("fake"); | ||||
} | } | ||||
@Test | @Test | ||||
public void should_get_suffixes() { | public void should_get_suffixes() { | ||||
Languages languages = new Languages( | 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()).containsOnly("java", "php4", "php5"); | ||||
assertThat(languages.getSuffixes("java")).containsOnly("java"); | assertThat(languages.getSuffixes("java")).containsOnly("java"); |
compile 'com.google.protobuf:protobuf-java' | compile 'com.google.protobuf:protobuf-java' | ||||
compile 'com.squareup.okhttp3:okhttp' | compile 'com.squareup.okhttp3:okhttp' | ||||
compile 'com.fasterxml.staxmate:staxmate' | compile 'com.fasterxml.staxmate:staxmate' | ||||
compile 'javax.annotation:javax.annotation-api' | |||||
compile 'org.eclipse.jgit:org.eclipse.jgit' | compile 'org.eclipse.jgit:org.eclipse.jgit' | ||||
compile 'org.tmatesoft.svnkit:svnkit' | compile 'org.tmatesoft.svnkit:svnkit' | ||||
compile 'org.picocontainer:picocontainer' | compile 'org.picocontainer:picocontainer' | ||||
compile 'org.slf4j:log4j-over-slf4j' | compile 'org.slf4j:log4j-over-slf4j' | ||||
compile 'org.slf4j:slf4j-api' | compile 'org.slf4j:slf4j-api' | ||||
compile 'org.sonarsource.update-center:sonar-update-center-common' | compile 'org.sonarsource.update-center:sonar-update-center-common' | ||||
compile 'org.springframework:spring-context' | |||||
compile project(':sonar-core') | compile project(':sonar-core') | ||||
compile project(':sonar-scanner-protocol') | compile project(':sonar-scanner-protocol') |
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.api.utils.MessageException; | 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+. | * Entry point for SonarQube Scanner API 2.1+. | ||||
public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) { | public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) { | ||||
configureLogging(); | configureLogging(); | ||||
try { | try { | ||||
GlobalContainer.create(scannerProperties, components).execute(); | |||||
SpringGlobalContainer.create(scannerProperties, components).execute(); | |||||
} catch (RuntimeException e) { | } catch (RuntimeException e) { | ||||
throw handleException(e); | throw handleException(e); | ||||
} | } |
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.function.Predicate; | import java.util.function.Predicate; | ||||
import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.api.utils.DateUtils; | import org.sonar.api.utils.DateUtils; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
*/ | */ | ||||
public class ProjectInfo implements Startable { | public class ProjectInfo implements Startable { | ||||
private final Clock clock; | private final Clock clock; | ||||
private Configuration settings; | |||||
private final Configuration settings; | |||||
private Date analysisDate; | private Date analysisDate; | ||||
private String projectVersion; | private String projectVersion; |
import java.io.IOException; | import java.io.IOException; | ||||
import java.nio.file.Files; | import java.nio.file.Files; | ||||
import java.nio.file.Path; | 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.batch.fs.internal.DefaultInputProject; | ||||
import org.sonar.api.impl.utils.DefaultTempFolder; | import org.sonar.api.impl.utils.DefaultTempFolder; | ||||
import org.sonar.api.utils.TempFolder; | 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"; | static final String TMP_NAME = ".sonartmp"; | ||||
private DefaultTempFolder projectTempFolder; | |||||
private boolean started = false; | |||||
@Bean("TempFolder") | |||||
public TempFolder provide(DefaultInputProject project) { | 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.batch.Phase; | ||||
import org.sonar.api.utils.AnnotationUtils; | import org.sonar.api.utils.AnnotationUtils; | ||||
import org.sonar.api.utils.dag.DirectAcyclicGraph; | import org.sonar.api.utils.dag.DirectAcyclicGraph; | ||||
import org.sonar.core.platform.ComponentContainer; | |||||
import org.sonar.core.platform.ExtensionContainer; | |||||
public abstract class AbstractExtensionDictionary { | public abstract class AbstractExtensionDictionary { | ||||
private final ComponentContainer componentContainer; | |||||
private final ExtensionContainer componentContainer; | |||||
public AbstractExtensionDictionary(ComponentContainer componentContainer) { | |||||
protected AbstractExtensionDictionary(ExtensionContainer componentContainer) { | |||||
this.componentContainer = componentContainer; | this.componentContainer = componentContainer; | ||||
} | } | ||||
return extensions; | 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)); | extensions.addAll(container.getComponentsByType(type)); | ||||
ComponentContainer parentContainer = container.getParent(); | |||||
ExtensionContainer parentContainer = container.getParent(); | |||||
if (parentContainer != null) { | if (parentContainer != null) { | ||||
completeScannerExtensions(parentContainer, extensions, type); | completeScannerExtensions(parentContainer, extensions, type); | ||||
} | } |
/* | |||||
* 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.SonarRuntime; | ||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.api.internal.PluginContextImpl; | 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.PluginInfo; | ||||
import org.sonar.core.platform.PluginRepository; | import org.sonar.core.platform.PluginRepository; | ||||
this.bootConfiguration = bootConfiguration; | this.bootConfiguration = bootConfiguration; | ||||
} | } | ||||
public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) { | |||||
public ExtensionInstaller install(ExtensionContainer container, ExtensionMatcher matcher) { | |||||
// core components | // core components | ||||
for (Object o : BatchComponents.all()) { | for (Object o : BatchComponents.all()) { | ||||
doInstall(container, matcher, null, o); | doInstall(container, matcher, null, o); | ||||
return this; | 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)) { | if (matcher.accept(extension)) { | ||||
container.addExtension(pluginInfo, extension); | container.addExtension(pluginInfo, extension); | ||||
} else { | } else { |
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.concurrent.Immutable; | import javax.annotation.concurrent.Immutable; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.api.config.PropertyDefinitions; | import org.sonar.api.config.PropertyDefinitions; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.scanner.config.DefaultConfiguration; | import org.sonar.scanner.config.DefaultConfiguration; | ||||
@Immutable | @Immutable | ||||
public class GlobalConfiguration extends DefaultConfiguration { | public class GlobalConfiguration extends DefaultConfiguration { | ||||
public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) { | public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) { | ||||
super(propertyDefinitions, encryption, settings); | super(propertyDefinitions, encryption, settings); | ||||
} | } | ||||
} | } |
import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.config.PropertyDefinitions; | 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); | |||||
} | } | ||||
} | } |
import java.util.Map; | import java.util.Map; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | 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 static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class); | ||||
private GlobalServerSettings singleton; | |||||
@Bean("GlobalServerSettings") | |||||
public GlobalServerSettings provide(GlobalSettingsLoader loader) { | 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.nio.file.attribute.BasicFileAttributes; | ||||
import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||
import org.apache.commons.lang.StringUtils; | 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.CoreProperties; | ||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.impl.utils.DefaultTempFolder; | import org.sonar.api.impl.utils.DefaultTempFolder; | ||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.api.utils.TempFolder; | import org.sonar.api.utils.TempFolder; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.springframework.context.annotation.Bean; | |||||
import static org.sonar.core.util.FileUtils.deleteQuietly; | 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 Logger LOG = Loggers.get(GlobalTempFolderProvider.class); | ||||
private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21); | private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21); | ||||
static final String TMP_NAME_PREFIX = ".sonartmp_"; | static final String TMP_NAME_PREFIX = ".sonartmp_"; | ||||
private boolean started = false; | |||||
private System2 system; | private System2 system; | ||||
private DefaultTempFolder tempFolder; | private DefaultTempFolder tempFolder; | ||||
this.system = system; | this.system = system; | ||||
} | } | ||||
@Bean("TempFolder") | |||||
public TempFolder provide(ScannerProperties scannerProps) { | public TempFolder provide(ScannerProperties scannerProps) { | ||||
if (tempFolder == null) { | if (tempFolder == null) { | ||||
} | } | ||||
@Override | @Override | ||||
public void start(PicoContainer container) { | |||||
started = true; | |||||
public void start() { | |||||
// nothing to do | |||||
} | } | ||||
@Override | @Override | ||||
public void stop(PicoContainer container) { | |||||
public void stop() { | |||||
if (tempFolder != null) { | if (tempFolder != null) { | ||||
tempFolder.stop(); | tempFolder.stop(); | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public void dispose(PicoContainer container) { | |||||
// nothing to do | |||||
} | |||||
@Override | |||||
public boolean componentHasLifecycle() { | |||||
return true; | |||||
} | |||||
@Override | |||||
public boolean isStarted() { | |||||
return started; | |||||
} | |||||
} | } |
/* | |||||
* 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); | LOGGER.debug("Unpacking plugin {}", pluginKey); | ||||
File jar = newTempFile(); | File jar = newTempFile(); | ||||
try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile))); | 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); | Pack200.newUnpacker().unpack(input, output); | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e); | throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e); |
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import org.sonar.api.batch.postjob.PostJob; | import org.sonar.api.batch.postjob.PostJob; | ||||
import org.sonar.api.batch.postjob.PostJobContext; | 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.PostJobOptimizer; | ||||
import org.sonar.scanner.postjob.PostJobWrapper; | import org.sonar.scanner.postjob.PostJobWrapper; | ||||
private final PostJobContext postJobContext; | private final PostJobContext postJobContext; | ||||
private final PostJobOptimizer postJobOptimizer; | 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.postJobOptimizer = postJobOptimizer; | ||||
this.postJobContext = postJobContext; | this.postJobContext = postJobContext; | ||||
} | } |
/* | |||||
* 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.Map; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.Plugin; | import org.sonar.api.Plugin; | ||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.core.platform.ExplodedPlugin; | import org.sonar.core.platform.ExplodedPlugin; |
*/ | */ | ||||
package org.sonar.scanner.bootstrap; | package org.sonar.scanner.bootstrap; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.utils.System2; | import org.sonar.api.utils.System2; | ||||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | import org.sonar.batch.bootstrapper.EnvironmentInformation; | ||||
import org.sonarqube.ws.client.HttpConnector; | import org.sonarqube.ws.client.HttpConnector; | ||||
import org.sonarqube.ws.client.WsClientFactories; | import org.sonarqube.ws.client.WsClientFactories; | ||||
import org.springframework.context.annotation.Bean; | |||||
import static java.lang.Integer.parseInt; | import static java.lang.Integer.parseInt; | ||||
import static java.lang.String.valueOf; | import static java.lang.String.valueOf; | ||||
import static org.apache.commons.lang.StringUtils.defaultIfBlank; | 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 int CONNECT_TIMEOUT_MS = 5_000; | ||||
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout"; | static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout"; | ||||
static final int DEFAULT_READ_TIMEOUT_SEC = 60; | 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); | |||||
} | } | ||||
} | } |
/* | |||||
* 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 | |||||
} | |||||
} |
import java.time.Clock; | import java.time.Clock; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.Priority; | |||||
import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.Plugin; | import org.sonar.api.Plugin; | ||||
import org.sonar.api.SonarEdition; | import org.sonar.api.SonarEdition; | ||||
import org.sonar.api.SonarQubeSide; | import org.sonar.api.SonarQubeSide; | ||||
import org.sonar.api.SonarQubeVersion; | import org.sonar.api.SonarQubeVersion; | ||||
import org.sonar.api.SonarRuntime; | |||||
import org.sonar.api.internal.MetadataLoader; | import org.sonar.api.internal.MetadataLoader; | ||||
import org.sonar.api.internal.SonarRuntimeImpl; | import org.sonar.api.internal.SonarRuntimeImpl; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.core.extension.CoreExtensionRepositoryImpl; | import org.sonar.core.extension.CoreExtensionRepositoryImpl; | ||||
import org.sonar.core.extension.CoreExtensionsLoader; | import org.sonar.core.extension.CoreExtensionsLoader; | ||||
import org.sonar.core.platform.ComponentContainer; | |||||
import org.sonar.core.platform.PluginClassLoader; | import org.sonar.core.platform.PluginClassLoader; | ||||
import org.sonar.core.platform.PluginClassloaderFactory; | import org.sonar.core.platform.PluginClassloaderFactory; | ||||
import org.sonar.core.platform.PluginInfo; | import org.sonar.core.platform.PluginInfo; | ||||
import org.sonar.scanner.platform.DefaultServer; | import org.sonar.scanner.platform.DefaultServer; | ||||
import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader; | import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader; | ||||
import org.sonar.scanner.repository.DefaultNewCodePeriodLoader; | import org.sonar.scanner.repository.DefaultNewCodePeriodLoader; | ||||
import org.sonar.scanner.repository.MetricsRepositoryLoader; | |||||
import org.sonar.scanner.repository.MetricsRepositoryProvider; | 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.DefaultGlobalSettingsLoader; | ||||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | |||||
import org.sonar.scanner.scan.ProjectScanContainer; | |||||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||||
public class GlobalContainer extends ComponentContainer { | |||||
private static final Logger LOG = Loggers.get(GlobalContainer.class); | |||||
@Priority(3) | |||||
public class SpringGlobalContainer extends SpringComponentContainer { | |||||
private static final Logger LOG = Loggers.get(SpringGlobalContainer.class); | |||||
private final Map<String, String> scannerProperties; | private final Map<String, String> scannerProperties; | ||||
private GlobalContainer(Map<String, String> scannerProperties) { | |||||
super(); | |||||
private SpringGlobalContainer(Map<String, String> scannerProperties, List<?> addedExternally) { | |||||
super(addedExternally); | |||||
this.scannerProperties = scannerProperties; | this.scannerProperties = scannerProperties; | ||||
} | } | ||||
public static GlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) { | |||||
GlobalContainer container = new GlobalContainer(scannerProperties); | |||||
container.add(extensions); | |||||
return container; | |||||
public static SpringGlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) { | |||||
return new SpringGlobalContainer(scannerProperties, extensions); | |||||
} | } | ||||
@Override | @Override | ||||
protected void doBeforeStart() { | |||||
public void doBeforeStart() { | |||||
ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties); | ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties); | ||||
GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties); | GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties); | ||||
add(rawScannerProperties); | add(rawScannerProperties); | ||||
new ScannerWsClientProvider(), | new ScannerWsClientProvider(), | ||||
DefaultServer.class, | DefaultServer.class, | ||||
new GlobalTempFolderProvider(), | new GlobalTempFolderProvider(), | ||||
DefaultHttpDownloader.class, | |||||
analysisWarnings, | analysisWarnings, | ||||
UriReader.class, | UriReader.class, | ||||
PluginFiles.class, | PluginFiles.class, | ||||
System2.INSTANCE, | System2.INSTANCE, | ||||
Clock.systemDefaultZone(), | Clock.systemDefaultZone(), | ||||
new MetricsRepositoryProvider(), | 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); | |||||
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 | @Override | ||||
if (!analysisMode.equals("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."); | 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(); | |||||
new SpringProjectScanContainer(this).execute(); | |||||
LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime)); | LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime)); | ||||
} | } | ||||
} | } | ||||
private void loadCoreExtensions() { | private void loadCoreExtensions() { | ||||
CoreExtensionsLoader loader = getComponentByType(CoreExtensionsLoader.class); | |||||
loader.load(); | |||||
getComponentByType(CoreExtensionsLoader.class).load(); | |||||
} | } | ||||
static String formatTime(long time) { | static String formatTime(long time) { | ||||
} | } | ||||
return String.format(format, h, m, s, ms); | return String.format(format, h, m, s, ms); | ||||
} | } | ||||
} | } |
/* | |||||
* 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.List; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | 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 Logger LOG = Loggers.get(CiConfigurationProvider.class); | ||||
private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled"; | private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled"; | ||||
@Bean("CiConfiguration") | |||||
public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) { | public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) { | ||||
boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false); | boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false); | ||||
if (disabled) { | if (disabled) { |
import java.util.function.Function; | import java.util.function.Function; | ||||
import java.util.function.Predicate; | import java.util.function.Predicate; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import javax.inject.Inject; | |||||
import org.sonar.api.batch.fs.InputComponent; | import org.sonar.api.batch.fs.InputComponent; | ||||
import org.sonar.api.batch.fs.internal.DefaultInputComponent; | import org.sonar.api.batch.fs.internal.DefaultInputComponent; | ||||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | import org.sonar.api.batch.fs.internal.DefaultInputFile; | ||||
private int count = 0; | private int count = 0; | ||||
private int total; | private int total; | ||||
@Inject | |||||
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) { | public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) { | ||||
this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor()); | 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.settings = settings; | ||||
this.index = index; | this.index = index; | ||||
this.publisher = publisher; | this.publisher = publisher; |
import org.sonar.api.scan.issue.filter.IssueFilter; | import org.sonar.api.scan.issue.filter.IssueFilter; | ||||
import org.sonar.api.scan.issue.filter.IssueFilterChain; | import org.sonar.api.scan.issue.filter.IssueFilterChain; | ||||
import org.sonar.scanner.protocol.output.ScannerReport; | import org.sonar.scanner.protocol.output.ScannerReport; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
/** | /** | ||||
* @deprecated since 7.6, {@link IssueFilter} is deprecated | * @deprecated since 7.6, {@link IssueFilter} is deprecated | ||||
private final IssueFilterChain filterChain; | private final IssueFilterChain filterChain; | ||||
private final DefaultInputProject project; | private final DefaultInputProject project; | ||||
@Autowired(required = false) | |||||
public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) { | public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) { | ||||
this.project = project; | this.project = project; | ||||
this.filterChain = new DefaultIssueFilterChain(exclusionFilters); | this.filterChain = new DefaultIssueFilterChain(exclusionFilters); | ||||
} | } | ||||
@Autowired(required = false) | |||||
public IssueFilters(DefaultInputProject project) { | public IssueFilters(DefaultInputProject project) { | ||||
this(project, new IssueFilter[0]); | this(project, new IssueFilter[0]); | ||||
} | } |
import org.sonar.api.ExtensionPoint; | import org.sonar.api.ExtensionPoint; | ||||
import org.sonar.api.scanner.ScannerSide; | import org.sonar.api.scanner.ScannerSide; | ||||
import org.sonar.scanner.scan.ProjectScanContainer; | |||||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||||
@ScannerSide | @ScannerSide | ||||
@ExtensionPoint | @ExtensionPoint | ||||
@FunctionalInterface | @FunctionalInterface | ||||
public interface AnalysisObserver { | public interface AnalysisObserver { | ||||
void analysisCompleted(ProjectScanContainer container); | |||||
void analysisCompleted(SpringProjectScanContainer container); | |||||
} | } |
*/ | */ | ||||
package org.sonar.scanner.mediumtest; | package org.sonar.scanner.mediumtest; | ||||
import org.sonar.scanner.scan.ProjectScanContainer; | |||||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||||
public class AnalysisObservers { | 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.projectScanContainer = projectScanContainer; | ||||
this.observers = observers; | this.observers = observers; | ||||
} | } | ||||
public AnalysisObservers(ProjectScanContainer projectScanContainer) { | |||||
this(projectScanContainer, new AnalysisObserver[0]); | |||||
} | |||||
public void notifyEndOfScanTask() { | public void notifyEndOfScanTask() { | ||||
for (AnalysisObserver analysisObserver : observers) { | for (AnalysisObserver analysisObserver : observers) { | ||||
analysisObserver.analysisCompleted(projectScanContainer); | analysisObserver.analysisCompleted(projectScanContainer); |
import org.sonar.scanner.protocol.output.ScannerReportReader; | import org.sonar.scanner.protocol.output.ScannerReportReader; | ||||
import org.sonar.scanner.report.ReportPublisher; | import org.sonar.scanner.report.ReportPublisher; | ||||
import org.sonar.scanner.report.ScannerReportUtils; | 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; | import org.sonar.scanner.scan.filesystem.InputComponentStore; | ||||
public class AnalysisResult implements AnalysisObserver { | public class AnalysisResult implements AnalysisObserver { | ||||
private ScannerReportReader reader; | private ScannerReportReader reader; | ||||
@Override | @Override | ||||
public void analysisCompleted(ProjectScanContainer container) { | |||||
public void analysisCompleted(SpringProjectScanContainer container) { | |||||
LOG.info("Store analysis results in memory for later assertions in medium test"); | LOG.info("Store analysis results in memory for later assertions in medium test"); | ||||
ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class); | ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class); | ||||
reader = new ScannerReportReader(reportPublisher.getReportDir().toFile()); | reader = new ScannerReportReader(reportPublisher.getReportDir().toFile()); | ||||
return reader; | return reader; | ||||
} | } | ||||
private void storeFs(ProjectScanContainer container) { | |||||
private void storeFs(SpringProjectScanContainer container) { | |||||
InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class); | InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class); | ||||
for (InputFile inputPath : inputFileCache.inputFiles()) { | for (InputFile inputPath : inputFileCache.inputFiles()) { | ||||
inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath); | inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath); |
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.Priority; | |||||
import org.sonar.api.Plugin; | import org.sonar.api.Plugin; | ||||
import org.sonar.core.platform.PluginInfo; | import org.sonar.core.platform.PluginInfo; | ||||
import org.sonar.scanner.bootstrap.PluginInstaller; | import org.sonar.scanner.bootstrap.PluginInstaller; | ||||
import org.sonar.scanner.bootstrap.ScannerPlugin; | import org.sonar.scanner.bootstrap.ScannerPlugin; | ||||
@Priority(1) | |||||
public class FakePluginInstaller implements PluginInstaller { | public class FakePluginInstaller implements PluginInstaller { | ||||
private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>(); | private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>(); |
import java.time.Duration; | import java.time.Duration; | ||||
import java.time.temporal.ChronoUnit; | import java.time.temporal.ChronoUnit; | ||||
import java.util.EnumSet; | import java.util.EnumSet; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; |
private final ScmConfiguration scmConfiguration; | private final ScmConfiguration scmConfiguration; | ||||
private final CiConfiguration ciConfiguration; | 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.cache = cache; | ||||
this.config = config; | this.config = config; | ||||
this.scmConfiguration = scmConfiguration; | this.scmConfiguration = scmConfiguration; |
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import okhttp3.HttpUrl; | import okhttp3.HttpUrl; | ||||
import org.apache.commons.io.FileUtils; | 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.platform.Server; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.api.utils.TempFolder; | import org.sonar.api.utils.TempFolder; | ||||
this.branchConfiguration = branchConfiguration; | this.branchConfiguration = branchConfiguration; | ||||
this.properties = properties; | this.properties = properties; | ||||
this.ceTaskReportDataHolder = ceTaskReportDataHolder; | this.ceTaskReportDataHolder = ceTaskReportDataHolder; | ||||
this.reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report"); | |||||
this.writer = new ScannerReportWriter(reportDir.toFile()); | |||||
this.reader = new ScannerReportReader(reportDir.toFile()); | |||||
} | } | ||||
@Override | @Override | ||||
public void start() { | public void start() { | ||||
reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report"); | |||||
writer = new ScannerReportWriter(reportDir.toFile()); | |||||
reader = new ScannerReportReader(reportDir.toFile()); | |||||
contextPublisher.init(writer); | contextPublisher.init(writer); | ||||
if (!analysisMode.isMediumTest()) { | if (!analysisMode.isMediumTest()) { |
*/ | */ | ||||
package org.sonar.scanner.repository; | package org.sonar.scanner.repository; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | 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 Logger LOG = Loggers.get(MetricsRepositoryProvider.class); | ||||
private static final String LOG_MSG = "Load metrics repository"; | private static final String LOG_MSG = "Load metrics repository"; | ||||
private MetricsRepository metricsRepository; | |||||
@Bean("MetricsRepository") | |||||
public MetricsRepository provide(MetricsRepositoryLoader loader) { | 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; | return metricsRepository; | ||||
} | } | ||||
} | } |
*/ | */ | ||||
package org.sonar.scanner.repository; | package org.sonar.scanner.repository; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonar.scanner.bootstrap.ScannerProperties; | import org.sonar.scanner.bootstrap.ScannerProperties; | ||||
import org.sonar.scanner.rule.QualityProfiles; | 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 Logger LOG = Loggers.get(QualityProfilesProvider.class); | ||||
private static final String LOG_MSG = "Load quality profiles"; | private static final String LOG_MSG = "Load quality profiles"; | ||||
private QualityProfiles profiles = null; | |||||
@Bean("QualityProfiles") | |||||
public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) { | 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; | return profiles; | ||||
} | } | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import javax.annotation.concurrent.Immutable; | import javax.annotation.concurrent.Immutable; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.resources.Languages; | import org.sonar.api.resources.Languages; | ||||
/** | /** |
package org.sonar.scanner.repository.settings; | package org.sonar.scanner.repository.settings; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.inject.Inject; | |||||
import org.sonar.scanner.bootstrap.DefaultScannerWsClient; | import org.sonar.scanner.bootstrap.DefaultScannerWsClient; | ||||
public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader { | public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader { | ||||
public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) { | |||||
@Inject | |||||
public DefaultGlobalSettingsLoader(DefaultScannerWsClient wsClient) { | |||||
super(wsClient); | super(wsClient); | ||||
} | } | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.batch.rule.LoadedActiveRule; | import org.sonar.api.batch.rule.LoadedActiveRule; | ||||
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; | import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; | ||||
import org.sonar.api.batch.rule.internal.DefaultActiveRules; | import org.sonar.api.batch.rule.internal.DefaultActiveRules; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.springframework.context.annotation.Bean; | |||||
/** | /** | ||||
* Loads the rules that are activated on the Quality profiles | * Loads the rules that are activated on the Quality profiles | ||||
* used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}. | * 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 Logger LOG = Loggers.get(ActiveRulesProvider.class); | ||||
private static final String LOG_MSG = "Load active rules"; | private static final String LOG_MSG = "Load active rules"; | ||||
private DefaultActiveRules singleton = null; | |||||
@Bean("ActiveRules") | |||||
public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) { | 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) { | private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) { |
package org.sonar.scanner.rule; | package org.sonar.scanner.rule; | ||||
import java.util.List; | 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.Rules; | ||||
import org.sonar.api.batch.rule.internal.NewRule; | |||||
import org.sonar.api.batch.rule.internal.RulesBuilder; | import org.sonar.api.batch.rule.internal.RulesBuilder; | ||||
import org.sonar.api.rule.RuleKey; | import org.sonar.api.rule.RuleKey; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonarqube.ws.Rules.ListResponse.Rule; | 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 Logger LOG = Loggers.get(RulesProvider.class); | ||||
private static final String LOG_MSG = "Load server rules"; | private static final String LOG_MSG = "Load server rules"; | ||||
private Rules singleton = null; | |||||
@Bean("Rules") | |||||
public Rules provide(RulesLoader ref) { | 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); | Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | ||||
List<Rule> loadedRules = ref.load(); | List<Rule> loadedRules = ref.load(); | ||||
RulesBuilder builder = new RulesBuilder(); | RulesBuilder builder = new RulesBuilder(); | ||||
} | } | ||||
profiler.stopInfo(); | profiler.stopInfo(); | ||||
return builder.build(); | return builder.build(); | ||||
} | } | ||||
} | } |
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Locale; | import java.util.Locale; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | 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.DefaultInputModule; | ||||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | 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.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 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, | private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator, |
package org.sonar.scanner.scan; | package org.sonar.scanner.scan; | ||||
import java.util.Locale; | import java.util.Locale; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.batch.bootstrap.ProjectReactor; | 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.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||||
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; | 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 static final Logger LOG = Loggers.get(InputProjectProvider.class); | ||||
private DefaultInputProject project = null; | |||||
@Bean("DefaultInputProject") | |||||
public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator, | public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator, | ||||
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) { | 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; | return project; | ||||
} | } | ||||
} | } |
/* | |||||
* 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; | package org.sonar.scanner.scan; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.api.config.PropertyDefinitions; | import org.sonar.api.config.PropertyDefinitions; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.scanner.config.DefaultConfiguration; | import org.sonar.scanner.config.DefaultConfiguration; | ||||
public class ModuleConfiguration extends DefaultConfiguration { | public class ModuleConfiguration extends DefaultConfiguration { | ||||
public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | ||||
super(propertyDefinitions, encryption, props); | super(propertyDefinitions, encryption, props); | ||||
} | } | ||||
} | } |
import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | 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.GlobalConfiguration; | ||||
import org.sonar.scanner.bootstrap.GlobalServerSettings; | 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, | public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings, | ||||
ProjectServerSettings projectServerSettings) { | 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) { | private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) { |
*/ | */ | ||||
package org.sonar.scanner.scan; | 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.api.batch.fs.internal.DefaultInputModule; | ||||
import org.sonar.scanner.fs.InputModuleHierarchy; | import org.sonar.scanner.fs.InputModuleHierarchy; | ||||
import org.sonar.scanner.scan.filesystem.InputComponentStore; | import org.sonar.scanner.scan.filesystem.InputComponentStore; |
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import javax.annotation.Priority; | |||||
import org.sonar.api.config.internal.Settings; | import org.sonar.api.config.internal.Settings; | ||||
import static java.util.Objects.requireNonNull; | 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 since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. | ||||
*/ | */ | ||||
@Deprecated | @Deprecated | ||||
@Priority(1) | |||||
public class MutableModuleSettings extends Settings { | public class MutableModuleSettings extends Settings { | ||||
private final Map<String, String> properties = new HashMap<>(); | private final Map<String, String> properties = new HashMap<>(); |
*/ | */ | ||||
package org.sonar.scanner.scan; | package org.sonar.scanner.scan; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.batch.bootstrap.ProjectReactor; | 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) { | 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.api.config.internal.Settings; | ||||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | import org.sonar.scanner.bootstrap.GlobalConfiguration; | ||||
import javax.annotation.Priority; | |||||
import static java.util.Objects.requireNonNull; | 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 since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. | ||||
*/ | */ | ||||
@Deprecated | @Deprecated | ||||
@Priority(2) | |||||
public class MutableProjectSettings extends Settings { | public class MutableProjectSettings extends Settings { | ||||
private final Map<String, String> properties = new HashMap<>(); | private final Map<String, String> properties = new HashMap<>(); |
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | import org.sonar.scanner.bootstrap.GlobalConfiguration; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
public class ProjectBuildersExecutor { | public class ProjectBuildersExecutor { | ||||
private final GlobalConfiguration globalConfig; | private final GlobalConfiguration globalConfig; | ||||
private final ProjectBuilder[] projectBuilders; | private final ProjectBuilder[] projectBuilders; | ||||
@Autowired(required = false) | |||||
public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) { | public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) { | ||||
this.globalConfig = globalConfig; | this.globalConfig = globalConfig; | ||||
this.projectBuilders = projectBuilders; | this.projectBuilders = projectBuilders; | ||||
} | } | ||||
@Autowired(required = false) | |||||
public ProjectBuildersExecutor(GlobalConfiguration globalConfig) { | public ProjectBuildersExecutor(GlobalConfiguration globalConfig) { | ||||
this(globalConfig, new ProjectBuilder[0]); | this(globalConfig, new ProjectBuilder[0]); | ||||
} | } |
package org.sonar.scanner.scan; | package org.sonar.scanner.scan; | ||||
import java.util.Map; | import java.util.Map; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.api.config.PropertyDefinitions; | import org.sonar.api.config.PropertyDefinitions; | ||||
import org.sonar.api.config.internal.Encryption; | |||||
import org.sonar.scanner.config.DefaultConfiguration; | import org.sonar.scanner.config.DefaultConfiguration; | ||||
public class ProjectConfiguration extends DefaultConfiguration { | public class ProjectConfiguration extends DefaultConfiguration { | ||||
public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | ||||
super(propertyDefinitions, encryption, props); | super(propertyDefinitions, encryption, props); | ||||
} | } | ||||
} | } |
import java.util.LinkedHashMap; | import java.util.LinkedHashMap; | ||||
import java.util.Map; | 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.GlobalConfiguration; | ||||
import org.sonar.scanner.bootstrap.GlobalServerSettings; | 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, | public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, | ||||
ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) { | 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; | return projectConfig; | ||||
} | } | ||||
} | } |
import java.nio.channels.OverlappingFileLockException; | import java.nio.channels.OverlappingFileLockException; | ||||
import java.nio.file.Files; | import java.nio.file.Files; | ||||
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule; | import org.sonar.api.batch.fs.internal.AbstractProjectOrModule; | ||||
public class ProjectLock implements Startable { | public class ProjectLock implements Startable { |
import org.sonar.core.component.ComponentKeys; | import org.sonar.core.component.ComponentKeys; | ||||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | import org.sonar.scanner.bootstrap.GlobalConfiguration; | ||||
import org.sonar.scanner.scan.branch.BranchParamsValidator; | import org.sonar.scanner.scan.branch.BranchParamsValidator; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import static java.lang.String.format; | import static java.lang.String.format; | ||||
import static java.util.Objects.nonNull; | import static java.util.Objects.nonNull; | ||||
@Nullable | @Nullable | ||||
private final BranchParamsValidator branchParamsValidator; | private final BranchParamsValidator branchParamsValidator; | ||||
@Autowired(required = false) | |||||
public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) { | public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) { | ||||
this.settings = settings; | this.settings = settings; | ||||
this.branchParamsValidator = branchParamsValidator; | this.branchParamsValidator = branchParamsValidator; | ||||
} | } | ||||
@Autowired(required = false) | |||||
public ProjectReactorValidator(GlobalConfiguration settings) { | public ProjectReactorValidator(GlobalConfiguration settings) { | ||||
this(settings, null); | this(settings, null); | ||||
} | } |
import java.util.Map; | import java.util.Map; | ||||
import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
import org.picocontainer.injectors.ProviderAdapter; | |||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.notifications.AnalysisWarnings; | import org.sonar.api.notifications.AnalysisWarnings; | ||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.scanner.repository.settings.ProjectSettingsLoader; | 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); | 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 " + | "Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " + | ||||
"displaying this warning."; | "displaying this warning."; | ||||
private ProjectServerSettings singleton = null; | |||||
@Bean("ProjectServerSettings") | |||||
public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) { | 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); | |||||
} | } | ||||
} | } |
*/ | */ | ||||
package org.sonar.scanner.scan; | package org.sonar.scanner.scan; | ||||
import javax.annotation.Priority; | |||||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | import org.sonar.api.batch.fs.internal.DefaultInputModule; | ||||
import org.sonar.api.scan.filesystem.FileExclusions; | import org.sonar.api.scan.filesystem.FileExclusions; | ||||
import org.sonar.core.platform.ComponentContainer; | |||||
import org.sonar.scanner.bootstrap.ExtensionInstaller; | 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.DefaultModuleFileSystem; | ||||
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore; | import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore; | ||||
import org.sonar.scanner.sensor.ModuleSensorContext; | import org.sonar.scanner.sensor.ModuleSensorContext; | ||||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide; | import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide; | ||||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | ||||
public class ModuleScanContainer extends ComponentContainer { | |||||
@Priority(1) | |||||
public class SpringModuleScanContainer extends SpringComponentContainer { | |||||
private final DefaultInputModule module; | private final DefaultInputModule module; | ||||
public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) { | |||||
public SpringModuleScanContainer(SpringComponentContainer parent, DefaultInputModule module) { | |||||
super(parent); | super(parent); | ||||
this.module = module; | this.module = module; | ||||
} | } | ||||
} | } | ||||
private void addExtensions() { | private void addExtensions() { | ||||
ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class); | |||||
ExtensionInstaller pluginInstaller = parent.getComponentByType(ExtensionInstaller.class); | |||||
pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT)); | pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT)); | ||||
} | } | ||||
protected void doAfterStart() { | protected void doAfterStart() { | ||||
getComponentByType(ModuleSensorsExecutor.class).execute(); | getComponentByType(ModuleSensorsExecutor.class).execute(); | ||||
} | } | ||||
} | } |
package org.sonar.scanner.scan; | package org.sonar.scanner.scan; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import javax.annotation.Priority; | |||||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | import org.sonar.api.batch.fs.internal.DefaultInputModule; | ||||
import org.sonar.api.batch.fs.internal.FileMetadata; | import org.sonar.api.batch.fs.internal.FileMetadata; | ||||
import org.sonar.api.batch.fs.internal.SensorStrategy; | import org.sonar.api.batch.fs.internal.SensorStrategy; | ||||
import org.sonar.api.batch.rule.CheckFactory; | import org.sonar.api.batch.rule.CheckFactory; | ||||
import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter; | 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.resources.ResourceTypes; | ||||
import org.sonar.api.scan.filesystem.PathResolver; | import org.sonar.api.scan.filesystem.PathResolver; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.core.config.ScannerProperties; | import org.sonar.core.config.ScannerProperties; | ||||
import org.sonar.core.extension.CoreExtensionsInstaller; | import org.sonar.core.extension.CoreExtensionsInstaller; | ||||
import org.sonar.core.metric.ScannerMetrics; | import org.sonar.core.metric.ScannerMetrics; | ||||
import org.sonar.core.platform.ComponentContainer; | |||||
import org.sonar.scanner.DefaultFileLinesContextFactory; | import org.sonar.scanner.DefaultFileLinesContextFactory; | ||||
import org.sonar.scanner.ProjectInfo; | import org.sonar.scanner.ProjectInfo; | ||||
import org.sonar.scanner.analysis.AnalysisTempFolderProvider; | import org.sonar.scanner.analysis.AnalysisTempFolderProvider; | ||||
import org.sonar.scanner.bootstrap.ExtensionMatcher; | import org.sonar.scanner.bootstrap.ExtensionMatcher; | ||||
import org.sonar.scanner.bootstrap.GlobalAnalysisMode; | import org.sonar.scanner.bootstrap.GlobalAnalysisMode; | ||||
import org.sonar.scanner.bootstrap.PostJobExtensionDictionary; | import org.sonar.scanner.bootstrap.PostJobExtensionDictionary; | ||||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||||
import org.sonar.scanner.ci.CiConfigurationProvider; | import org.sonar.scanner.ci.CiConfigurationProvider; | ||||
import org.sonar.scanner.ci.vendors.AppVeyor; | import org.sonar.scanner.ci.vendors.AppVeyor; | ||||
import org.sonar.scanner.ci.vendors.AwsCodeBuild; | import org.sonar.scanner.ci.vendors.AwsCodeBuild; | ||||
import org.sonar.scanner.repository.ContextPropertiesCache; | import org.sonar.scanner.repository.ContextPropertiesCache; | ||||
import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader; | import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader; | ||||
import org.sonar.scanner.repository.DefaultQualityProfileLoader; | 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.ProjectRepositoriesSupplier; | ||||
import org.sonar.scanner.repository.QualityProfileLoader; | |||||
import org.sonar.scanner.repository.QualityProfilesProvider; | import org.sonar.scanner.repository.QualityProfilesProvider; | ||||
import org.sonar.scanner.repository.ReferenceBranchSupplier; | |||||
import org.sonar.scanner.repository.language.DefaultLanguagesRepository; | import org.sonar.scanner.repository.language.DefaultLanguagesRepository; | ||||
import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader; | 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.ActiveRulesProvider; | ||||
import org.sonar.scanner.rule.DefaultActiveRulesLoader; | import org.sonar.scanner.rule.DefaultActiveRulesLoader; | ||||
import org.sonar.scanner.rule.DefaultRulesLoader; | import org.sonar.scanner.rule.DefaultRulesLoader; | ||||
import org.sonar.scanner.rule.QProfileVerifier; | import org.sonar.scanner.rule.QProfileVerifier; | ||||
import org.sonar.scanner.rule.RulesLoader; | |||||
import org.sonar.scanner.rule.RulesProvider; | import org.sonar.scanner.rule.RulesProvider; | ||||
import org.sonar.scanner.scan.branch.BranchConfiguration; | import org.sonar.scanner.scan.branch.BranchConfiguration; | ||||
import org.sonar.scanner.scan.branch.BranchConfigurationProvider; | import org.sonar.scanner.scan.branch.BranchConfigurationProvider; | ||||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | ||||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; | import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; | ||||
public class ProjectScanContainer extends ComponentContainer { | |||||
private static final Logger LOG = Loggers.get(ProjectScanContainer.class); | |||||
@Priority(2) | |||||
public class SpringProjectScanContainer extends SpringComponentContainer { | |||||
private static final Logger LOG = Loggers.get(SpringProjectScanContainer.class); | |||||
public ProjectScanContainer(ComponentContainer globalContainer) { | |||||
public SpringProjectScanContainer(SpringComponentContainer globalContainer) { | |||||
super(globalContainer); | super(globalContainer); | ||||
} | } | ||||
protected void doBeforeStart() { | protected void doBeforeStart() { | ||||
addScannerExtensions(); | addScannerExtensions(); | ||||
addScannerComponents(); | addScannerComponents(); | ||||
ProjectLock lock = getComponentByType(ProjectLock.class); | |||||
lock.tryLock(); | |||||
getComponentByType(WorkDirectoriesInitializer.class).execute(); | |||||
} | } | ||||
private void addScannerComponents() { | private void addScannerComponents() { | ||||
DefaultMetricFinder.class, | DefaultMetricFinder.class, | ||||
// lang | // lang | ||||
Languages.class, | |||||
LanguagesProvider.class, | |||||
DefaultLanguagesRepository.class, | DefaultLanguagesRepository.class, | ||||
// issue exclusions | // issue exclusions | ||||
add(GitScmSupport.getObjects()); | add(GitScmSupport.getObjects()); | ||||
add(SvnScmSupport.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); | |||||
add(DefaultProjectSettingsLoader.class, | |||||
DefaultRulesLoader.class, | |||||
DefaultActiveRulesLoader.class, | |||||
DefaultQualityProfileLoader.class, | |||||
DefaultProjectRepositoriesLoader.class); | |||||
} | } | ||||
private void addScannerExtensions() { | private void addScannerExtensions() { | ||||
getComponentByType(CoreExtensionsInstaller.class) | |||||
getParent().getComponentByType(CoreExtensionsInstaller.class) | |||||
.install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension)); | .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension)); | ||||
getComponentByType(ExtensionInstaller.class) | |||||
getParent().getComponentByType(ExtensionInstaller.class) | |||||
.install(this, getScannerProjectExtensionsFilter()); | .install(this, getScannerProjectExtensionsFilter()); | ||||
} | } | ||||
@Override | @Override | ||||
protected void doAfterStart() { | protected void doAfterStart() { | ||||
getComponentByType(ProjectLock.class).tryLock(); | |||||
GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class); | GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class); | ||||
InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class); | InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class); | ||||
ScanProperties properties = getComponentByType(ScanProperties.class); | ScanProperties properties = getComponentByType(ScanProperties.class); | ||||
} | } | ||||
void scan(DefaultInputModule module) { | void scan(DefaultInputModule module) { | ||||
new ModuleScanContainer(this, module).execute(); | |||||
new SpringModuleScanContainer(this, module).execute(); | |||||
} | } | ||||
} | } |
* Be careful that sub module work dir might be nested in parent working directory. | * Be careful that sub module work dir might be nested in parent working directory. | ||||
*/ | */ | ||||
public class WorkDirectoriesInitializer { | 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)) { | for (DefaultInputModule sub : moduleHierarchy.children(module)) { | ||||
cleanAllWorkingDirs(sub); | |||||
cleanAllWorkingDirs(moduleHierarchy, sub); | |||||
} | } | ||||
if (Files.exists(module.getWorkDir())) { | if (Files.exists(module.getWorkDir())) { | ||||
deleteAllRecursivelyExceptLockFile(module.getWorkDir()); | deleteAllRecursivelyExceptLockFile(module.getWorkDir()); | ||||
} | } | ||||
} | } | ||||
private void mkdirsAllWorkingDirs(DefaultInputModule module) { | |||||
private static void mkdirsAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) { | |||||
for (DefaultInputModule sub : moduleHierarchy.children(module)) { | for (DefaultInputModule sub : moduleHierarchy.children(module)) { | ||||
mkdirsAllWorkingDirs(sub); | |||||
mkdirsAllWorkingDirs(moduleHierarchy, sub); | |||||
} | } | ||||
try { | try { | ||||
Files.createDirectories(module.getWorkDir()); | Files.createDirectories(module.getWorkDir()); |
*/ | */ | ||||
package org.sonar.scanner.scan.branch; | 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.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonar.scanner.scan.ProjectConfiguration; | 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 Logger LOG = Loggers.get(BranchConfigurationProvider.class); | ||||
private static final String LOG_MSG = "Load branch configuration"; | private static final String LOG_MSG = "Load branch configuration"; | ||||
private BranchConfiguration branchConfiguration = null; | |||||
@Bean("BranchConfiguration") | |||||
public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration, | public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration, | ||||
ProjectBranches branches, ProjectPullRequests pullRequests) { | 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; | package org.sonar.scanner.scan.branch; | ||||
import java.util.Collections; | 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.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonar.scanner.bootstrap.ScannerProperties; | 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 Logger LOG = Loggers.get(ProjectBranchesProvider.class); | ||||
private static final String LOG_MSG = "Load project branches"; | private static final String LOG_MSG = "Load project branches"; | ||||
private ProjectBranches branches = null; | |||||
@Bean("ProjectBranches") | |||||
public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) { | public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) { | ||||
if (this.branches != null) { | |||||
return this.branches; | |||||
} | |||||
if (loader == null) { | 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); | Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | ||||
this.branches = loader.load(scannerProperties.getProjectKey()); | |||||
ProjectBranches branches = loader.load(scannerProperties.getProjectKey()); | |||||
profiler.stopInfo(); | profiler.stopInfo(); | ||||
return this.branches; | |||||
return branches; | |||||
} | } | ||||
} | } |
package org.sonar.scanner.scan.branch; | package org.sonar.scanner.scan.branch; | ||||
import java.util.Collections; | 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.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | import org.sonar.api.utils.log.Profiler; | ||||
import org.sonar.scanner.bootstrap.ScannerProperties; | 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 Logger LOG = Loggers.get(ProjectPullRequestsProvider.class); | ||||
private static final String LOG_MSG = "Load project pull requests"; | 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) { | if (loader == null) { | ||||
pullRequests = new ProjectPullRequests(Collections.emptyList()); | |||||
return pullRequests; | |||||
return new ProjectPullRequests(Collections.emptyList()); | |||||
} | } | ||||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | ||||
pullRequests = loader.load(scannerProperties.getProjectKey()); | |||||
ProjectPullRequests pullRequests = loader.load(scannerProperties.getProjectKey()); | |||||
profiler.stopInfo(); | profiler.stopInfo(); | ||||
return pullRequests; | return pullRequests; | ||||
} | } |
import org.sonar.api.batch.fs.internal.DefaultInputModule; | import org.sonar.api.batch.fs.internal.DefaultInputModule; | ||||
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | ||||
import javax.annotation.Priority; | |||||
import javax.inject.Inject; | |||||
@Priority(1) | |||||
public class DefaultModuleFileSystem extends MutableFileSystem { | public class DefaultModuleFileSystem extends MutableFileSystem { | ||||
@Inject | |||||
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) { | public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) { | ||||
super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir())); | super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir())); | ||||
initFields(module); | initFields(module); |
import org.sonar.api.batch.fs.internal.DefaultInputProject; | import org.sonar.api.batch.fs.internal.DefaultInputProject; | ||||
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | ||||
import javax.annotation.Priority; | |||||
import javax.inject.Inject; | |||||
@Priority(2) | |||||
public class DefaultProjectFileSystem extends MutableFileSystem { | public class DefaultProjectFileSystem extends MutableFileSystem { | ||||
@Inject | |||||
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) { | public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) { | ||||
super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir())); | super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir())); | ||||
setFields(project); | setFields(project); |
this.projectExclusionFilters = projectExclusionFilters; | 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, | void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, | ||||
Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand) | Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand) | ||||
throws IOException { | throws IOException { |
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import javax.annotation.CheckForNull; | 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.batch.scm.ScmProvider; | ||||
import org.sonar.api.impl.utils.ScannerUtils; | |||||
import org.sonar.api.utils.log.Logger; | import org.sonar.api.utils.log.Logger; | ||||
import org.sonar.api.utils.log.Loggers; | import org.sonar.api.utils.log.Loggers; | ||||
import org.sonar.api.utils.log.Profiler; | 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.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 Logger LOG = Loggers.get(ScmChangedFilesProvider.class); | ||||
private static final String LOG_MSG = "SCM collecting changed files in the branch"; | 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) { | public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) { | ||||
if (scmBranchChangedFiles == null) { | |||||
Path rootBaseDir = project.getBaseDir(); | Path rootBaseDir = project.getBaseDir(); | ||||
Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); | Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); | ||||
validatePaths(changedFiles); | validatePaths(changedFiles); | ||||
scmBranchChangedFiles = new ScmChangedFiles(changedFiles); | |||||
} | |||||
return scmBranchChangedFiles; | |||||
return new ScmChangedFiles(changedFiles); | |||||
} | } | ||||
private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) { | private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) { |
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import org.apache.commons.lang.StringUtils; | import org.apache.commons.lang.StringUtils; | ||||
import org.picocontainer.Startable; | |||||
import org.sonar.api.CoreProperties; | import org.sonar.api.CoreProperties; | ||||
import org.sonar.api.Properties; | import org.sonar.api.Properties; | ||||
import org.sonar.api.Property; | import org.sonar.api.Property; | ||||
import org.sonar.api.PropertyType; | import org.sonar.api.PropertyType; | ||||
import org.sonar.api.Startable; | |||||
import org.sonar.api.batch.scm.ScmProvider; | import org.sonar.api.batch.scm.ScmProvider; | ||||
import org.sonar.api.config.Configuration; | import org.sonar.api.config.Configuration; | ||||
import org.sonar.api.notifications.AnalysisWarnings; | import org.sonar.api.notifications.AnalysisWarnings; | ||||
private ScmProvider provider; | 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.moduleHierarchy = moduleHierarchy; | ||||
this.settings = settings; | this.settings = settings; | ||||
this.analysisWarnings = analysisWarnings; | this.analysisWarnings = analysisWarnings; | ||||
} | } | ||||
} | } | ||||
public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings) { | |||||
this(moduleHierarchy, settings, analysisWarnings, new ScmProvider[0]); | |||||
} | |||||
@Override | @Override | ||||
public void start() { | public void start() { | ||||
if (isDisabled()) { | if (isDisabled()) { |
private final InputModule module; | 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) { | SensorStorage sensorStorage, SonarRuntime sonarRuntime) { | ||||
super(project, config, mutableSettings, fs, activeRules, sensorStorage, sonarRuntime); | |||||
super(project, config, mutableModuleSettings, fs, activeRules, sensorStorage, sonarRuntime); | |||||
this.module = module; | this.module = module; | ||||
} | } | ||||
import org.sonar.api.batch.sensor.Sensor; | import org.sonar.api.batch.sensor.Sensor; | ||||
import org.sonar.core.platform.ComponentContainer; | import org.sonar.core.platform.ComponentContainer; | ||||
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | ||||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||||
import org.sonar.scanner.scan.branch.BranchConfiguration; | import org.sonar.scanner.scan.branch.BranchConfiguration; | ||||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | import org.sonar.scanner.scan.filesystem.MutableFileSystem; | ||||
private final MutableFileSystem fileSystem; | private final MutableFileSystem fileSystem; | ||||
private final BranchConfiguration branchConfiguration; | private final BranchConfiguration branchConfiguration; | ||||
public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer, | |||||
public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer, | |||||
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | ||||
super(componentContainer); | super(componentContainer); | ||||
this.sensorContext = sensorContext; | this.sensorContext = sensorContext; |
import java.util.List; | import java.util.List; | ||||
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import org.sonar.api.scanner.sensor.ProjectSensor; | import org.sonar.api.scanner.sensor.ProjectSensor; | ||||
import org.sonar.core.platform.ComponentContainer; | |||||
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | ||||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||||
import org.sonar.scanner.scan.branch.BranchConfiguration; | import org.sonar.scanner.scan.branch.BranchConfiguration; | ||||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | import org.sonar.scanner.scan.filesystem.MutableFileSystem; | ||||
private final MutableFileSystem fileSystem; | private final MutableFileSystem fileSystem; | ||||
private final BranchConfiguration branchConfiguration; | private final BranchConfiguration branchConfiguration; | ||||
public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer, | |||||
public ProjectSensorExtensionDictionary(SpringComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer, | |||||
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | ||||
super(componentContainer); | super(componentContainer); | ||||
this.sensorContext = sensorContext; | this.sensorContext = sensorContext; |
<level value="INFO"/> | <level value="INFO"/> | ||||
</logger> | </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 --> | <!-- sonar.showSql --> | ||||
<!-- see also org.sonar.db.MyBatis#configureLogback() --> | <!-- see also org.sonar.db.MyBatis#configureLogback() --> | ||||
<logger name="org.mybatis"> | <logger name="org.mybatis"> | ||||
<logger name="java.sql.ResultSet"> | <logger name="java.sql.ResultSet"> | ||||
<level value="WARN"/> | <level value="WARN"/> | ||||
</logger> | </logger> | ||||
<logger name="PERSISTIT"> | |||||
<level value="WARN"/> | |||||
</logger> | |||||
<root> | <root> | ||||
<!-- sonar.verbose --> | <!-- sonar.verbose --> |
<level value="WARN"/> | <level value="WARN"/> | ||||
</logger> | </logger> | ||||
<logger name="PERSISTIT"> | |||||
<level value="WARN"/> | |||||
</logger> | |||||
<root> | <root> | ||||
<!-- sonar.verbose --> | <!-- sonar.verbose --> | ||||
<level value="${ROOT_LOGGER_LEVEL}"/> | <level value="${ROOT_LOGGER_LEVEL}"/> |
/* | |||||
* 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 { | |||||
} | |||||
} |
/* | |||||
* 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; | package org.sonar.scanner.bootstrap; | ||||
import com.google.common.collect.Lists; | 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.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.picocontainer.behaviors.FieldDecorated; | import org.picocontainer.behaviors.FieldDecorated; | ||||
import org.sonar.api.batch.DependsUpon; | import org.sonar.api.batch.DependsUpon; | ||||
import org.sonar.api.batch.Phase; | import org.sonar.api.batch.Phase; | ||||
import org.sonar.api.batch.ScannerSide; | 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.Sensor; | ||||
import org.sonar.api.batch.sensor.SensorContext; | import org.sonar.api.batch.sensor.SensorContext; | ||||
import org.sonar.api.batch.sensor.SensorDescriptor; | import org.sonar.api.batch.sensor.SensorDescriptor; | ||||
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; | 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.branch.BranchConfiguration; | ||||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | import org.sonar.scanner.scan.filesystem.MutableFileSystem; | ||||
import org.sonar.scanner.sensor.ModuleSensorContext; | import org.sonar.scanner.sensor.ModuleSensorContext; | ||||
import org.sonar.scanner.sensor.ModuleSensorOptimizer; | import org.sonar.scanner.sensor.ModuleSensorOptimizer; | ||||
import org.sonar.scanner.sensor.ModuleSensorWrapper; | 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.assertj.core.api.Assertions.assertThat; | ||||
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.mockito.ArgumentMatchers.any; | import static org.mockito.ArgumentMatchers.any; | ||||
} | } | ||||
private ModuleSensorExtensionDictionary newSelector(Object... extensions) { | 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); | return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration); | ||||
} | } | ||||
Sensor b = new FakeSensor(); | Sensor b = new FakeSensor(); | ||||
Sensor c = 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), | ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class), | ||||
fileSystem, branchConfiguration); | fileSystem, branchConfiguration); |
/* | |||||
* 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.baseUrl()).isEqualTo("https://here/sonarqube/"); | ||||
assertThat(httpConnector.okHttpClient().proxy()).isNull(); | 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); | |||||
} | |||||
} | } |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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"); | |||||
} | |||||
} |
/* | |||||
* 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 java.util.Properties; | ||||
import javax.annotation.CheckForNull; | import javax.annotation.CheckForNull; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import javax.annotation.Priority; | |||||
import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
import org.junit.rules.ExternalResource; | import org.junit.rules.ExternalResource; | ||||
import org.sonar.api.Plugin; | import org.sonar.api.Plugin; | ||||
private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader(); | private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader(); | ||||
private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader(); | private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader(); | ||||
private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime(); | private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime(); | ||||
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder(); | |||||
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt(); | |||||
private LogOutput logOutput = null; | private LogOutput logOutput = null; | ||||
private static void createWorkingDirs() throws IOException { | private static void createWorkingDirs() throws IOException { | ||||
public static class AnalysisBuilder { | public static class AnalysisBuilder { | ||||
private final Map<String, String> taskProperties = new HashMap<>(); | private final Map<String, String> taskProperties = new HashMap<>(); | ||||
private ScannerMediumTester tester; | |||||
private final ScannerMediumTester tester; | |||||
public AnalysisBuilder(ScannerMediumTester tester) { | public AnalysisBuilder(ScannerMediumTester tester) { | ||||
this.tester = tester; | this.tester = tester; | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeRulesLoader implements RulesLoader { | private static class FakeRulesLoader implements RulesLoader { | ||||
private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>(); | private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>(); | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeActiveRulesLoader implements ActiveRulesLoader { | private static class FakeActiveRulesLoader implements ActiveRulesLoader { | ||||
private List<LoadedActiveRule> activeRules = new LinkedList<>(); | private List<LoadedActiveRule> activeRules = new LinkedList<>(); | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader { | private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader { | ||||
private int metricId = 1; | private int metricId = 1; | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { | private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { | ||||
private Map<String, FileData> fileDataMap = new HashMap<>(); | private Map<String, FileData> fileDataMap = new HashMap<>(); | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeBranchConfiguration implements BranchConfiguration { | private static class FakeBranchConfiguration implements BranchConfiguration { | ||||
private BranchType branchType = BranchType.BRANCH; | private BranchType branchType = BranchType.BRANCH; | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeSonarRuntime implements SonarRuntime { | private static class FakeSonarRuntime implements SonarRuntime { | ||||
private SonarEdition edition; | private SonarEdition edition; | ||||
return this; | return this; | ||||
} | } | ||||
@Priority(1) | |||||
private class FakeBranchConfigurationLoader implements BranchConfigurationLoader { | private class FakeBranchConfigurationLoader implements BranchConfigurationLoader { | ||||
@Override | @Override | ||||
public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) { | public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) { | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeQualityProfileLoader implements QualityProfileLoader { | private static class FakeQualityProfileLoader implements QualityProfileLoader { | ||||
private List<QualityProfile> qualityProfiles = new LinkedList<>(); | private List<QualityProfile> qualityProfiles = new LinkedList<>(); | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader { | private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader { | ||||
private Map<String, String> globalSettings = new HashMap<>(); | private Map<String, String> globalSettings = new HashMap<>(); | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader { | private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader { | ||||
private NewCodePeriods.ShowWSResponse response; | private NewCodePeriods.ShowWSResponse response; | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class FakeProjectSettingsLoader implements ProjectSettingsLoader { | private static class FakeProjectSettingsLoader implements ProjectSettingsLoader { | ||||
private Map<String, String> projectSettings = new HashMap<>(); | private Map<String, String> projectSettings = new HashMap<>(); | ||||
} | } | ||||
} | } | ||||
@Priority(1) | |||||
private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder { | |||||
} | |||||
} | } |
import org.junit.Test; | import org.junit.Test; | ||||
import org.junit.rules.TemporaryFolder; | import org.junit.rules.TemporaryFolder; | ||||
import org.sonar.scanner.mediumtest.ScannerMediumTester; | import org.sonar.scanner.mediumtest.ScannerMediumTester; | ||||
import org.springframework.beans.factory.UnsatisfiedDependencyException; | |||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||||
assertThatThrownBy(() -> tester | assertThatThrownBy(() -> tester | ||||
.newAnalysis(new File(projectDir, "sonar-project.properties")) | .newAnalysis(new File(projectDir, "sonar-project.properties")) | ||||
.execute()) | .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 { | private File copyProject(String path) throws Exception { |
List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | ||||
assertThat(issues).hasSize(8 /* lines */); | assertThat(issues).hasSize(8 /* lines */); | ||||
List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | ||||
assertThat(externalIssues).isEmpty(); | assertThat(externalIssues).isEmpty(); | ||||
} | } | ||||
@Test | @Test | ||||
public void testOneExternalIssuePerLine() throws Exception { | public void testOneExternalIssuePerLine() throws Exception { | ||||
File projectDir = new File("test-resources/mediumtest/xoo/sample"); | File projectDir = new File("test-resources/mediumtest/xoo/sample"); | ||||
.build()) | .build()) | ||||
.execute(); | .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")); | List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | ||||
assertThat(issues).isEmpty(); | assertThat(issues).isEmpty(); | ||||
.build()) | .build()) | ||||
.execute(); | .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")); | List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | ||||
assertThat(issues).hasSize(10); | assertThat(issues).hasSize(10); | ||||
issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo")); | issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo")); | ||||
assertThat(issues).hasSize(10); | assertThat(issues).hasSize(10); | ||||
// SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules | // SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules | ||||
logTester.clear(); | logTester.clear(); | ||||
result = tester.newAnalysis() | result = tester.newAnalysis() | ||||
.build()) | .build()) | ||||
.execute(); | .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")); | List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | ||||
assertThat(issues).hasSize(10); | assertThat(issues).hasSize(10); |
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Map; | import java.util.Map; | ||||
import javax.annotation.Priority; | |||||
import org.junit.BeforeClass; | import org.junit.BeforeClass; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.batch.bootstrapper.Batch; | import org.sonar.batch.bootstrapper.Batch; | ||||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | import org.sonar.batch.bootstrapper.EnvironmentInformation; | ||||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | ||||
import org.springframework.beans.factory.UnsatisfiedDependencyException; | |||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||||
@Test | @Test | ||||
public void testWithVerbose() { | public void testWithVerbose() { | ||||
setUp(true); | setUp(true); | ||||
assertThatThrownBy(() -> batch.execute()) | 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 { | private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader { | ||||
boolean withCause = false; | boolean withCause = false; | ||||
import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
import java.nio.file.Files; | import java.nio.file.Files; | ||||
import java.nio.file.Path; | import java.nio.file.Path; | ||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class); | private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class); | ||||
private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); | private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); | ||||
private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.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 | @Before | ||||
public void setUp() { | public void setUp() { | ||||
when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath() | when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath() | ||||
.resolve("folder") | .resolve("folder") | ||||
.resolve("report-task.txt")); | .resolve("report-task.txt")); | ||||
underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder, | |||||
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder); | |||||
} | } | ||||
@Test | @Test | ||||
underTest.prepareAndDumpMetadata("TASK-123"); | underTest.prepareAndDumpMetadata("TASK-123"); | ||||
assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo( | 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" + | "serverUrl=https://localhost\n" + | ||||
"serverVersion=6.4\n" + | "serverVersion=6.4\n" + | ||||
"dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" + | "dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" + | ||||
public void should_not_delete_report_if_property_is_set() throws IOException { | public void should_not_delete_report_if_property_is_set() throws IOException { | ||||
when(properties.shouldKeepReport()).thenReturn(true); | when(properties.shouldKeepReport()).thenReturn(true); | ||||
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | ||||
Files.createDirectory(reportDir); | |||||
underTest.start(); | underTest.start(); | ||||
underTest.stop(); | underTest.stop(); | ||||
@Test | @Test | ||||
public void should_delete_report_by_default() throws IOException { | public void should_delete_report_by_default() throws IOException { | ||||
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | ||||
Files.createDirectory(reportDir); | |||||
underTest.start(); | underTest.start(); | ||||
underTest.stop(); | underTest.stop(); |
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
public class ProjectScanContainerTest { | |||||
public class SpringProjectScanContainerTest { | |||||
@Test | @Test | ||||
public void should_add_only_batch_extensions() { | public void should_add_only_batch_extensions() { | ||||
ExtensionMatcher filter = ProjectScanContainer.getScannerProjectExtensionsFilter(); | |||||
ExtensionMatcher filter = SpringProjectScanContainer.getScannerProjectExtensionsFilter(); | |||||
assertThat(filter.accept(new MyBatchExtension())).isTrue(); | assertThat(filter.accept(new MyBatchExtension())).isTrue(); | ||||
assertThat(filter.accept(MyBatchExtension.class)).isTrue(); | assertThat(filter.accept(MyBatchExtension.class)).isTrue(); |