Co-authored-by: Zipeng WU <zipeng.wu@sonarsource.com>tags/9.4.0.54424
@@ -350,6 +350,7 @@ subprojects { | |||
dependency 'io.netty:netty-all:4.1.70.Final' | |||
dependency 'com.sun.mail:javax.mail:1.5.6' | |||
dependency 'javax.annotation:javax.annotation-api:1.3.2' | |||
dependency 'javax.inject:javax.inject:1' | |||
dependency 'javax.servlet:javax.servlet-api:3.1.0' | |||
dependency 'javax.xml.bind:jaxb-api:2.3.0' | |||
dependency 'junit:junit:4.13.2' | |||
@@ -417,6 +418,9 @@ subprojects { | |||
dependency 'org.simpleframework:simple:4.1.21' | |||
dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63' | |||
dependency 'org.sonarsource.update-center:sonar-update-center-common:1.23.0.723' | |||
dependency('org.springframework:spring-context:5.3.14') { | |||
exclude 'commons-logging:commons-logging' | |||
} | |||
dependency 'org.subethamail:subethasmtp:3.1.7' | |||
dependency 'org.yaml:snakeyaml:1.26' | |||
dependency 'xml-apis:xml-apis:1.4.01' |
@@ -22,16 +22,16 @@ package org.sonar.ce.task.projectanalysis.step; | |||
import com.google.common.collect.Iterables; | |||
import org.sonar.ce.task.step.ComputationStep; | |||
import org.sonar.ce.task.step.ComputationSteps; | |||
import org.sonar.core.platform.ContainerPopulator; | |||
import org.sonar.core.platform.Container; | |||
/** | |||
* Abstract implementation of {@link ComputationStep} which provides the implementation of {@link ComputationSteps#instances()} | |||
* based on a {@link org.sonar.core.platform.ContainerPopulator.Container}. | |||
* based on a {@link org.sonar.core.platform.Container}. | |||
*/ | |||
public abstract class AbstractComputationSteps implements ComputationSteps { | |||
private final ContainerPopulator.Container container; | |||
private final Container container; | |||
protected AbstractComputationSteps(ContainerPopulator.Container container) { | |||
protected AbstractComputationSteps(Container container) { | |||
this.container = container; | |||
} | |||
@@ -32,6 +32,7 @@ import org.sonar.ce.task.step.ComputationStep; | |||
import org.sonar.ce.task.step.ComputationStepExecutor; | |||
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.Container; | |||
import org.sonar.core.platform.ContainerPopulator; | |||
import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE; | |||
@@ -72,7 +73,7 @@ public class AuditPurgeTaskProcessor implements CeTaskProcessor { | |||
public static final class AuditPurgeComputationSteps extends AbstractComputationSteps { | |||
public AuditPurgeComputationSteps(ContainerPopulator.Container container) { | |||
public AuditPurgeComputationSteps(Container container) { | |||
super(container); | |||
} | |||
@@ -33,6 +33,7 @@ import org.sonar.ce.task.step.ComputationStep; | |||
import org.sonar.ce.task.step.ComputationStepExecutor; | |||
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.Container; | |||
import org.sonar.core.platform.ContainerPopulator; | |||
import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; | |||
@@ -73,7 +74,7 @@ public class IssueSyncTaskProcessor implements CeTaskProcessor { | |||
public static final class SyncComputationSteps extends AbstractComputationSteps { | |||
public SyncComputationSteps(ContainerPopulator.Container container) { | |||
public SyncComputationSteps(Container container) { | |||
super(container); | |||
} | |||
@@ -22,12 +22,12 @@ package org.sonar.ce.task.container; | |||
import org.picocontainer.PicoContainer; | |||
import org.sonar.ce.task.CeTask; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.ContainerPopulator; | |||
import org.sonar.core.platform.Container; | |||
/** | |||
* The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}. | |||
*/ | |||
public interface TaskContainer extends ContainerPopulator.Container, AutoCloseable { | |||
public interface TaskContainer extends Container, AutoCloseable { | |||
ComponentContainer getParent(); | |||
@@ -19,7 +19,7 @@ | |||
*/ | |||
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. | |||
@@ -32,7 +32,7 @@ import org.sonar.core.platform.ContainerPopulator; | |||
* classes only they really are to be executed. | |||
* </p> | |||
*/ | |||
public interface MigrationContainer extends ContainerPopulator.Container { | |||
public interface MigrationContainer extends Container { | |||
/** | |||
* Cleans up resources after migration has run. |
@@ -16,10 +16,12 @@ dependencies { | |||
compile 'commons-codec:commons-codec' | |||
compile 'commons-io:commons-io' | |||
compile 'commons-lang:commons-lang' | |||
compile 'javax.inject:javax.inject' | |||
compile 'org.codehaus.sonar:sonar-classloader' | |||
compile 'org.picocontainer:picocontainer' | |||
compile 'org.slf4j:slf4j-api' | |||
compile 'org.sonarsource.update-center:sonar-update-center-common' | |||
compile 'org.springframework:spring-context' | |||
compile project(path: ':sonar-plugin-api', configuration: 'shadow') | |||
compile project(':sonar-plugin-api-impl') | |||
@@ -30,7 +30,7 @@ import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.utils.AnnotationUtils; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.ExtensionContainer; | |||
import static java.util.Objects.requireNonNull; | |||
@@ -41,8 +41,7 @@ public abstract class CoreExtensionsInstaller { | |||
private final CoreExtensionRepository coreExtensionRepository; | |||
private final Class<? extends Annotation> supportedAnnotationType; | |||
protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, | |||
Class<? extends Annotation> supportedAnnotationType) { | |||
protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, Class<? extends Annotation> supportedAnnotationType) { | |||
this.sonarRuntime = sonarRuntime; | |||
this.coreExtensionRepository = coreExtensionRepository; | |||
this.supportedAnnotationType = supportedAnnotationType; | |||
@@ -63,12 +62,12 @@ public abstract class CoreExtensionsInstaller { | |||
* @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether | |||
* extension should be added to container as an object or only as a PropertyDefinition. | |||
*/ | |||
public void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) { | |||
public void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) { | |||
coreExtensionRepository.loadedCoreExtensions() | |||
.forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension)); | |||
} | |||
private void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | |||
private void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | |||
String coreExtensionName = coreExtension.getName(); | |||
try { | |||
addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension); | |||
@@ -80,33 +79,23 @@ public abstract class CoreExtensionsInstaller { | |||
} | |||
} | |||
private void addDeclaredExtensions(ComponentContainer container, Predicate<Object> extensionFilter, | |||
private void addDeclaredExtensions(ExtensionContainer container, Predicate<Object> extensionFilter, | |||
Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { | |||
ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); | |||
coreExtension.load(context); | |||
} | |||
private <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> additionalSideFilter, | |||
String extensionCategory, T component) { | |||
if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) { | |||
container.addExtension(extensionCategory, component); | |||
return true; | |||
} | |||
return false; | |||
} | |||
private <T> boolean hasSupportedAnnotation(T component) { | |||
return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null; | |||
} | |||
private class ContextImpl implements CoreExtension.Context { | |||
private final ComponentContainer container; | |||
private final ExtensionContainer container; | |||
private final Predicate<Object> extensionFilter; | |||
private final Predicate<Object> additionalSideFilter; | |||
private final String extensionCategory; | |||
public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter, | |||
Predicate<Object> additionalSideFilter, String extensionCategory) { | |||
public ContextImpl(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, String extensionCategory) { | |||
this.container = container; | |||
this.extensionFilter = extensionFilter; | |||
this.additionalSideFilter = additionalSideFilter; | |||
@@ -150,5 +139,14 @@ public abstract class CoreExtensionsInstaller { | |||
components.forEach(this::addExtension); | |||
return this; | |||
} | |||
private <T> boolean addSupportedExtension(ExtensionContainer container, Predicate<Object> additionalSideFilter, | |||
String extensionCategory, T component) { | |||
if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) { | |||
container.addExtension(extensionCategory, component); | |||
return true; | |||
} | |||
return false; | |||
} | |||
} | |||
} |
@@ -22,6 +22,7 @@ package org.sonar.core.extension; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.inject.Inject; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
@@ -37,6 +38,7 @@ public class CoreExtensionsLoader { | |||
private final CoreExtensionRepository coreExtensionRepository; | |||
private final ServiceLoaderWrapper serviceLoaderWrapper; | |||
@Inject | |||
public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) { | |||
this(coreExtensionRepository, new ServiceLoaderWrapper()); | |||
} |
@@ -30,6 +30,7 @@ import org.sonar.api.ce.ComputeEngineSide; | |||
import org.sonar.api.measures.Metric; | |||
import org.sonar.api.measures.Metrics; | |||
import org.sonar.api.scanner.ScannerSide; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import static org.sonar.api.measures.CoreMetrics.CLASSES; | |||
import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY; | |||
@@ -96,10 +97,12 @@ public class ScannerMetrics { | |||
private final Set<Metric> metrics; | |||
@Autowired(required = false) | |||
public ScannerMetrics() { | |||
this.metrics = ALLOWED_CORE_METRICS; | |||
} | |||
@Autowired(required = false) | |||
public ScannerMetrics(Metrics[] metricsRepositories) { | |||
this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet()); | |||
} |
@@ -49,7 +49,7 @@ import static java.util.Optional.ofNullable; | |||
@ScannerSide | |||
@ServerSide | |||
@ComputeEngineSide | |||
public class ComponentContainer implements ContainerPopulator.Container { | |||
public class ComponentContainer implements ExtensionContainer { | |||
public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2; | |||
private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer { | |||
@@ -235,6 +235,7 @@ public class ComponentContainer implements ContainerPopulator.Container { | |||
return this; | |||
} | |||
@Override | |||
public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) { | |||
Object key = componentKeys.of(extension); | |||
try { | |||
@@ -246,6 +247,7 @@ public class ComponentContainer implements ContainerPopulator.Container { | |||
return this; | |||
} | |||
@Override | |||
public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) { | |||
Object key = componentKeys.of(extension); | |||
try { | |||
@@ -264,12 +266,16 @@ public class ComponentContainer implements ContainerPopulator.Container { | |||
return getName(extension.getClass()); | |||
} | |||
public void declareExtension(@Nullable PluginInfo pluginInfo, Object extension) { | |||
@Override | |||
public ComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) { | |||
declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension); | |||
return this; | |||
} | |||
public void declareExtension(@Nullable String defaultCategory, Object extension) { | |||
@Override | |||
public ComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) { | |||
propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse("")); | |||
return this; | |||
} | |||
public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) { |
@@ -26,19 +26,27 @@ import org.sonar.core.util.Uuids; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
class ComponentKeys { | |||
public class ComponentKeys { | |||
private static final Logger LOG = Loggers.get(ComponentKeys.class); | |||
private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+"); | |||
private final Set<Class> objectsWithoutToString = new HashSet<>(); | |||
Object of(Object component) { | |||
return of(component, Loggers.get(ComponentKeys.class)); | |||
return of(component, LOG); | |||
} | |||
Object of(Object component, Logger log) { | |||
if (component instanceof Class) { | |||
return component; | |||
} | |||
return ofInstance(component, log); | |||
} | |||
public String ofInstance(Object component) { | |||
return ofInstance(component, LOG); | |||
} | |||
String ofInstance(Object component, Logger log) { | |||
String key = component.toString(); | |||
if (IDENTITY_HASH_PATTERN.matcher(key).matches()) { | |||
if (!objectsWithoutToString.add(component.getClass())) { | |||
@@ -46,6 +54,6 @@ class ComponentKeys { | |||
} | |||
key += Uuids.create(); | |||
} | |||
return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString(); | |||
return component.getClass().getCanonicalName() + "-" + key; | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* 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(); | |||
} |
@@ -19,19 +19,7 @@ | |||
*/ | |||
package org.sonar.core.platform; | |||
import java.util.List; | |||
@FunctionalInterface | |||
public interface ContainerPopulator<T extends ContainerPopulator.Container> { | |||
public interface ContainerPopulator<T extends Container> { | |||
void populateContainer(T container); | |||
interface Container { | |||
Container add(Object... objects); | |||
Container addSingletons(Iterable<?> components); | |||
<T> T getComponentByType(Class<T> type); | |||
<T> List<T> getComponentsByType(Class<T> type); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* 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(); | |||
} |
@@ -39,6 +39,7 @@ import java.util.List; | |||
import java.util.Optional; | |||
import java.util.zip.GZIPInputStream; | |||
import javax.annotation.Nullable; | |||
import javax.inject.Inject; | |||
import org.apache.commons.codec.binary.Base64; | |||
import org.apache.commons.io.IOUtils; | |||
import org.sonar.api.CoreProperties; | |||
@@ -62,6 +63,7 @@ public class DefaultHttpDownloader extends HttpDownloader { | |||
private final Integer readTimeout; | |||
private final Integer connectTimeout; | |||
@Inject | |||
public DefaultHttpDownloader(Server server, Configuration config) { | |||
this(server, config, null); | |||
} |
@@ -23,6 +23,7 @@ import java.nio.file.FileVisitResult; | |||
import java.nio.file.SimpleFileVisitor; | |||
import java.nio.file.attribute.BasicFileAttributes; | |||
import org.apache.commons.io.FileUtils; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.utils.TempFolder; | |||
import javax.annotation.Nullable; | |||
@@ -34,7 +35,7 @@ import java.nio.file.Path; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
public class DefaultTempFolder implements TempFolder { | |||
public class DefaultTempFolder implements TempFolder, Startable { | |||
private static final Logger LOG = Loggers.get(DefaultTempFolder.class); | |||
private final File tempDir; | |||
@@ -101,6 +102,12 @@ public class DefaultTempFolder implements TempFolder { | |||
} | |||
} | |||
@Override | |||
public void start() { | |||
// nothing to do | |||
} | |||
@Override | |||
public void stop() { | |||
if (deleteOnExit) { | |||
clean(); |
@@ -29,8 +29,8 @@ public class LanguagesTest { | |||
@Test | |||
public void should_add_several_times_the_same_language() { | |||
Languages languages = new Languages( | |||
language("fake"), | |||
language("fake")); | |||
language("fake"), | |||
language("fake")); | |||
assertThat(languages.get("fake").getKey()).isEqualTo("fake"); | |||
} | |||
@@ -38,8 +38,8 @@ public class LanguagesTest { | |||
@Test | |||
public void should_get_suffixes() { | |||
Languages languages = new Languages( | |||
language("java", "java"), | |||
language("php", "php4", "php5")); | |||
language("java", "java"), | |||
language("php", "php4", "php5")); | |||
assertThat(languages.getSuffixes()).containsOnly("java", "php4", "php5"); | |||
assertThat(languages.getSuffixes("java")).containsOnly("java"); |
@@ -26,6 +26,7 @@ dependencies { | |||
compile 'com.google.protobuf:protobuf-java' | |||
compile 'com.squareup.okhttp3:okhttp' | |||
compile 'com.fasterxml.staxmate:staxmate' | |||
compile 'javax.annotation:javax.annotation-api' | |||
compile 'org.eclipse.jgit:org.eclipse.jgit' | |||
compile 'org.tmatesoft.svnkit:svnkit' | |||
compile 'org.picocontainer:picocontainer' | |||
@@ -34,6 +35,8 @@ dependencies { | |||
compile 'org.slf4j:log4j-over-slf4j' | |||
compile 'org.slf4j:slf4j-api' | |||
compile 'org.sonarsource.update-center:sonar-update-center-common' | |||
compile 'org.springframework:spring-context' | |||
compile project(':sonar-core') | |||
compile project(':sonar-scanner-protocol') |
@@ -27,7 +27,7 @@ import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.scanner.bootstrap.GlobalContainer; | |||
import org.sonar.scanner.bootstrap.SpringGlobalContainer; | |||
/** | |||
* Entry point for SonarQube Scanner API 2.1+. | |||
@@ -69,7 +69,7 @@ public final class Batch { | |||
public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) { | |||
configureLogging(); | |||
try { | |||
GlobalContainer.create(scannerProperties, components).execute(); | |||
SpringGlobalContainer.create(scannerProperties, components).execute(); | |||
} catch (RuntimeException e) { | |||
throw handleException(e); | |||
} |
@@ -24,8 +24,8 @@ import java.util.Date; | |||
import java.util.Optional; | |||
import java.util.function.Predicate; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.MessageException; | |||
@@ -41,7 +41,7 @@ import static org.sonar.api.CoreProperties.PROJECT_VERSION_PROPERTY; | |||
*/ | |||
public class ProjectInfo implements Startable { | |||
private final Clock clock; | |||
private Configuration settings; | |||
private final Configuration settings; | |||
private Date analysisDate; | |||
private String projectVersion; |
@@ -22,58 +22,25 @@ package org.sonar.scanner.analysis; | |||
import java.io.IOException; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import org.picocontainer.ComponentLifecycle; | |||
import org.picocontainer.PicoContainer; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.impl.utils.DefaultTempFolder; | |||
import org.sonar.api.utils.TempFolder; | |||
import org.springframework.context.annotation.Bean; | |||
public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> { | |||
public class AnalysisTempFolderProvider { | |||
static final String TMP_NAME = ".sonartmp"; | |||
private DefaultTempFolder projectTempFolder; | |||
private boolean started = false; | |||
@Bean("TempFolder") | |||
public TempFolder provide(DefaultInputProject project) { | |||
if (projectTempFolder == null) { | |||
Path workingDir = project.getWorkDir(); | |||
Path tempDir = workingDir.normalize().resolve(TMP_NAME); | |||
try { | |||
Files.deleteIfExists(tempDir); | |||
Files.createDirectories(tempDir); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Unable to create root temp directory " + tempDir, e); | |||
} | |||
projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true); | |||
} | |||
return projectTempFolder; | |||
} | |||
@Override | |||
public void start(PicoContainer container) { | |||
started = true; | |||
} | |||
@Override | |||
public void stop(PicoContainer container) { | |||
if (projectTempFolder != null) { | |||
projectTempFolder.stop(); | |||
Path workingDir = project.getWorkDir(); | |||
Path tempDir = workingDir.normalize().resolve(TMP_NAME); | |||
try { | |||
Files.deleteIfExists(tempDir); | |||
Files.createDirectories(tempDir); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Unable to create root temp directory " + tempDir, e); | |||
} | |||
} | |||
@Override | |||
public void dispose(PicoContainer container) { | |||
// nothing to do | |||
} | |||
@Override | |||
public boolean componentHasLifecycle() { | |||
return true; | |||
} | |||
@Override | |||
public boolean isStarted() { | |||
return started; | |||
return new DefaultTempFolder(tempDir.toFile(), true); | |||
} | |||
} |
@@ -35,13 +35,13 @@ import org.sonar.api.batch.DependsUpon; | |||
import org.sonar.api.batch.Phase; | |||
import org.sonar.api.utils.AnnotationUtils; | |||
import org.sonar.api.utils.dag.DirectAcyclicGraph; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.ExtensionContainer; | |||
public abstract class AbstractExtensionDictionary { | |||
private final ComponentContainer componentContainer; | |||
private final ExtensionContainer componentContainer; | |||
public AbstractExtensionDictionary(ComponentContainer componentContainer) { | |||
protected AbstractExtensionDictionary(ExtensionContainer componentContainer) { | |||
this.componentContainer = componentContainer; | |||
} | |||
@@ -78,9 +78,9 @@ public abstract class AbstractExtensionDictionary { | |||
return extensions; | |||
} | |||
private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) { | |||
private static <T> void completeScannerExtensions(ExtensionContainer container, List<T> extensions, Class<T> type) { | |||
extensions.addAll(container.getComponentsByType(type)); | |||
ComponentContainer parentContainer = container.getParent(); | |||
ExtensionContainer parentContainer = container.getParent(); | |||
if (parentContainer != null) { | |||
completeScannerExtensions(parentContainer, extensions, type); | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -24,7 +24,7 @@ import org.sonar.api.Plugin; | |||
import org.sonar.api.SonarRuntime; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.internal.PluginContextImpl; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.ExtensionContainer; | |||
import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.core.platform.PluginRepository; | |||
@@ -40,8 +40,7 @@ public class ExtensionInstaller { | |||
this.bootConfiguration = bootConfiguration; | |||
} | |||
public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) { | |||
public ExtensionInstaller install(ExtensionContainer container, ExtensionMatcher matcher) { | |||
// core components | |||
for (Object o : BatchComponents.all()) { | |||
doInstall(container, matcher, null, o); | |||
@@ -64,7 +63,7 @@ public class ExtensionInstaller { | |||
return this; | |||
} | |||
private static void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) { | |||
private static void doInstall(ExtensionContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) { | |||
if (matcher.accept(extension)) { | |||
container.addExtension(pluginInfo, extension); | |||
} else { |
@@ -21,15 +21,13 @@ package org.sonar.scanner.bootstrap; | |||
import java.util.Map; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.scanner.config.DefaultConfiguration; | |||
@Immutable | |||
public class GlobalConfiguration extends DefaultConfiguration { | |||
public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) { | |||
super(propertyDefinitions, encryption, settings); | |||
} | |||
} |
@@ -21,22 +21,15 @@ package org.sonar.scanner.bootstrap; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.springframework.context.annotation.Bean; | |||
public class GlobalConfigurationProvider extends ProviderAdapter { | |||
private GlobalConfiguration globalConfig; | |||
public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, | |||
PropertyDefinitions propertyDefinitions) { | |||
if (globalConfig == null) { | |||
Map<String, String> mergedSettings = new LinkedHashMap<>(); | |||
mergedSettings.putAll(globalServerSettings.properties()); | |||
mergedSettings.putAll(scannerProps.properties()); | |||
globalConfig = new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings); | |||
} | |||
return globalConfig; | |||
public class GlobalConfigurationProvider { | |||
@Bean("GlobalConfiguration") | |||
public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, PropertyDefinitions propertyDefinitions) { | |||
Map<String, String> mergedSettings = new LinkedHashMap<>(); | |||
mergedSettings.putAll(globalServerSettings.properties()); | |||
mergedSettings.putAll(scannerProps.properties()); | |||
return new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings); | |||
} | |||
} |
@@ -21,24 +21,19 @@ package org.sonar.scanner.bootstrap; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | |||
import org.springframework.context.annotation.Bean; | |||
public class GlobalServerSettingsProvider extends ProviderAdapter { | |||
public class GlobalServerSettingsProvider { | |||
private static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class); | |||
private GlobalServerSettings singleton; | |||
@Bean("GlobalServerSettings") | |||
public GlobalServerSettings provide(GlobalSettingsLoader loader) { | |||
if (singleton == null) { | |||
Map<String, String> serverSideSettings = loader.loadGlobalSettings(); | |||
singleton = new GlobalServerSettings(serverSideSettings); | |||
Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v)); | |||
} | |||
return singleton; | |||
Map<String, String> serverSideSettings = loader.loadGlobalSettings(); | |||
Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v)); | |||
return new GlobalServerSettings(serverSideSettings); | |||
} | |||
} |
@@ -27,23 +27,21 @@ import java.nio.file.Paths; | |||
import java.nio.file.attribute.BasicFileAttributes; | |||
import java.util.concurrent.TimeUnit; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.ComponentLifecycle; | |||
import org.picocontainer.PicoContainer; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.impl.utils.DefaultTempFolder; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.TempFolder; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.springframework.context.annotation.Bean; | |||
import static org.sonar.core.util.FileUtils.deleteQuietly; | |||
public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> { | |||
public class GlobalTempFolderProvider implements Startable { | |||
private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class); | |||
private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21); | |||
static final String TMP_NAME_PREFIX = ".sonartmp_"; | |||
private boolean started = false; | |||
private System2 system; | |||
private DefaultTempFolder tempFolder; | |||
@@ -56,6 +54,7 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone | |||
this.system = system; | |||
} | |||
@Bean("TempFolder") | |||
public TempFolder provide(ScannerProperties scannerProps) { | |||
if (tempFolder == null) { | |||
@@ -150,29 +149,14 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone | |||
} | |||
@Override | |||
public void start(PicoContainer container) { | |||
started = true; | |||
public void start() { | |||
// nothing to do | |||
} | |||
@Override | |||
public void stop(PicoContainer container) { | |||
public void stop() { | |||
if (tempFolder != null) { | |||
tempFolder.stop(); | |||
} | |||
} | |||
@Override | |||
public void dispose(PicoContainer container) { | |||
// nothing to do | |||
} | |||
@Override | |||
public boolean componentHasLifecycle() { | |||
return true; | |||
} | |||
@Override | |||
public boolean isStarted() { | |||
return started; | |||
} | |||
} |
@@ -0,0 +1,35 @@ | |||
/* | |||
* 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); | |||
} | |||
} | |||
} |
@@ -181,7 +181,7 @@ public class PluginFiles { | |||
LOGGER.debug("Unpacking plugin {}", pluginKey); | |||
File jar = newTempFile(); | |||
try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile))); | |||
JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) { | |||
JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) { | |||
Pack200.newUnpacker().unpack(input, output); | |||
} catch (IOException e) { | |||
throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e); |
@@ -23,7 +23,7 @@ import java.util.Collection; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.batch.postjob.PostJob; | |||
import org.sonar.api.batch.postjob.PostJobContext; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.ExtensionContainer; | |||
import org.sonar.scanner.postjob.PostJobOptimizer; | |||
import org.sonar.scanner.postjob.PostJobWrapper; | |||
@@ -32,8 +32,8 @@ public class PostJobExtensionDictionary extends AbstractExtensionDictionary { | |||
private final PostJobContext postJobContext; | |||
private final PostJobOptimizer postJobOptimizer; | |||
public PostJobExtensionDictionary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) { | |||
super(componentContainer); | |||
public PostJobExtensionDictionary(ExtensionContainer container, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) { | |||
super(container); | |||
this.postJobOptimizer = postJobOptimizer; | |||
this.postJobContext = postJobContext; | |||
} |
@@ -0,0 +1,123 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -24,8 +24,8 @@ import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.platform.ExplodedPlugin; |
@@ -19,49 +19,43 @@ | |||
*/ | |||
package org.sonar.scanner.bootstrap; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonarqube.ws.client.HttpConnector; | |||
import org.sonarqube.ws.client.WsClientFactories; | |||
import org.springframework.context.annotation.Bean; | |||
import static java.lang.Integer.parseInt; | |||
import static java.lang.String.valueOf; | |||
import static org.apache.commons.lang.StringUtils.defaultIfBlank; | |||
public class ScannerWsClientProvider extends ProviderAdapter { | |||
public class ScannerWsClientProvider { | |||
static final int CONNECT_TIMEOUT_MS = 5_000; | |||
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout"; | |||
static final int DEFAULT_READ_TIMEOUT_SEC = 60; | |||
private DefaultScannerWsClient wsClient; | |||
public synchronized DefaultScannerWsClient provide(final ScannerProperties scannerProps, | |||
final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) { | |||
if (wsClient == null) { | |||
String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000"); | |||
HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder(); | |||
String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC)); | |||
String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null); | |||
String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token); | |||
connectorBuilder | |||
.readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000) | |||
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS) | |||
.userAgent(env.toString()) | |||
.url(url) | |||
.credentials(login, scannerProps.property(CoreProperties.PASSWORD)); | |||
// OkHttp detect 'http.proxyHost' java property, but credentials should be filled | |||
final String proxyUser = System.getProperty("http.proxyUser", ""); | |||
if (!proxyUser.isEmpty()) { | |||
connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword")); | |||
} | |||
wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode); | |||
@Bean("DefaultScannerWsClient") | |||
public DefaultScannerWsClient provide(ScannerProperties scannerProps, EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) { | |||
String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000"); | |||
HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder(); | |||
String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC)); | |||
String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null); | |||
String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token); | |||
connectorBuilder | |||
.readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000) | |||
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS) | |||
.userAgent(env.toString()) | |||
.url(url) | |||
.credentials(login, scannerProps.property(CoreProperties.PASSWORD)); | |||
// OkHttp detect 'http.proxyHost' java property, but credentials should be filled | |||
final String proxyUser = System.getProperty("http.proxyUser", ""); | |||
if (!proxyUser.isEmpty()) { | |||
connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword")); | |||
} | |||
return wsClient; | |||
return new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode); | |||
} | |||
} |
@@ -0,0 +1,231 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -22,13 +22,13 @@ package org.sonar.scanner.bootstrap; | |||
import java.time.Clock; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.Priority; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.api.SonarEdition; | |||
import org.sonar.api.SonarQubeSide; | |||
import org.sonar.api.SonarQubeVersion; | |||
import org.sonar.api.SonarRuntime; | |||
import org.sonar.api.internal.MetadataLoader; | |||
import org.sonar.api.internal.SonarRuntimeImpl; | |||
import org.sonar.api.utils.MessageException; | |||
@@ -39,7 +39,6 @@ import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.extension.CoreExtensionRepositoryImpl; | |||
import org.sonar.core.extension.CoreExtensionsLoader; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.core.platform.PluginClassLoader; | |||
import org.sonar.core.platform.PluginClassloaderFactory; | |||
import org.sonar.core.platform.PluginInfo; | |||
@@ -51,30 +50,26 @@ import org.sonar.scanner.notifications.DefaultAnalysisWarnings; | |||
import org.sonar.scanner.platform.DefaultServer; | |||
import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader; | |||
import org.sonar.scanner.repository.DefaultNewCodePeriodLoader; | |||
import org.sonar.scanner.repository.MetricsRepositoryLoader; | |||
import org.sonar.scanner.repository.MetricsRepositoryProvider; | |||
import org.sonar.scanner.repository.NewCodePeriodLoader; | |||
import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader; | |||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | |||
import org.sonar.scanner.scan.ProjectScanContainer; | |||
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 GlobalContainer(Map<String, String> scannerProperties) { | |||
super(); | |||
private SpringGlobalContainer(Map<String, String> scannerProperties, List<?> addedExternally) { | |||
super(addedExternally); | |||
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 | |||
protected void doBeforeStart() { | |||
public void doBeforeStart() { | |||
ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties); | |||
GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties); | |||
add(rawScannerProperties); | |||
@@ -100,20 +95,22 @@ public class GlobalContainer extends ComponentContainer { | |||
new ScannerWsClientProvider(), | |||
DefaultServer.class, | |||
new GlobalTempFolderProvider(), | |||
DefaultHttpDownloader.class, | |||
analysisWarnings, | |||
UriReader.class, | |||
PluginFiles.class, | |||
System2.INSTANCE, | |||
Clock.systemDefaultZone(), | |||
new MetricsRepositoryProvider(), | |||
UuidFactoryImpl.INSTANCE); | |||
addIfMissing(SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), SonarRuntime.class); | |||
addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class); | |||
add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class); | |||
addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class); | |||
addIfMissing(DefaultNewCodePeriodLoader.class, NewCodePeriodLoader.class); | |||
addIfMissing(DefaultMetricsRepositoryLoader.class, MetricsRepositoryLoader.class); | |||
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 | |||
@@ -133,7 +130,7 @@ public class GlobalContainer extends ComponentContainer { | |||
if (!analysisMode.equals("publish")) { | |||
throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter."); | |||
} | |||
new ProjectScanContainer(this).execute(); | |||
new SpringProjectScanContainer(this).execute(); | |||
LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime)); | |||
} | |||
@@ -147,8 +144,7 @@ public class GlobalContainer extends ComponentContainer { | |||
} | |||
private void loadCoreExtensions() { | |||
CoreExtensionsLoader loader = getComponentByType(CoreExtensionsLoader.class); | |||
loader.load(); | |||
getComponentByType(CoreExtensionsLoader.class).load(); | |||
} | |||
static String formatTime(long time) { | |||
@@ -166,5 +162,4 @@ public class GlobalContainer extends ComponentContainer { | |||
} | |||
return String.format(format, h, m, s, ms); | |||
} | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
* 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); | |||
} | |||
} | |||
} |
@@ -23,17 +23,18 @@ import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import java.util.stream.Collectors; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.springframework.context.annotation.Bean; | |||
public class CiConfigurationProvider extends ProviderAdapter { | |||
public class CiConfigurationProvider { | |||
private static final Logger LOG = Loggers.get(CiConfigurationProvider.class); | |||
private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled"; | |||
@Bean("CiConfiguration") | |||
public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) { | |||
boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false); | |||
if (disabled) { |
@@ -32,6 +32,7 @@ import java.util.concurrent.TimeoutException; | |||
import java.util.function.Function; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Collectors; | |||
import javax.inject.Inject; | |||
import org.sonar.api.batch.fs.InputComponent; | |||
import org.sonar.api.batch.fs.internal.DefaultInputComponent; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
@@ -71,12 +72,12 @@ public class CpdExecutor { | |||
private int count = 0; | |||
private int total; | |||
@Inject | |||
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) { | |||
this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor()); | |||
} | |||
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, | |||
ExecutorService executorService) { | |||
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, ExecutorService executorService) { | |||
this.settings = settings; | |||
this.index = index; | |||
this.publisher = publisher; |
@@ -25,6 +25,7 @@ import org.sonar.api.scan.issue.filter.FilterableIssue; | |||
import org.sonar.api.scan.issue.filter.IssueFilter; | |||
import org.sonar.api.scan.issue.filter.IssueFilterChain; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
/** | |||
* @deprecated since 7.6, {@link IssueFilter} is deprecated | |||
@@ -34,11 +35,13 @@ public class IssueFilters { | |||
private final IssueFilterChain filterChain; | |||
private final DefaultInputProject project; | |||
@Autowired(required = false) | |||
public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) { | |||
this.project = project; | |||
this.filterChain = new DefaultIssueFilterChain(exclusionFilters); | |||
} | |||
@Autowired(required = false) | |||
public IssueFilters(DefaultInputProject project) { | |||
this(project, new IssueFilter[0]); | |||
} |
@@ -21,13 +21,13 @@ package org.sonar.scanner.mediumtest; | |||
import org.sonar.api.ExtensionPoint; | |||
import org.sonar.api.scanner.ScannerSide; | |||
import org.sonar.scanner.scan.ProjectScanContainer; | |||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||
@ScannerSide | |||
@ExtensionPoint | |||
@FunctionalInterface | |||
public interface AnalysisObserver { | |||
void analysisCompleted(ProjectScanContainer container); | |||
void analysisCompleted(SpringProjectScanContainer container); | |||
} |
@@ -19,22 +19,18 @@ | |||
*/ | |||
package org.sonar.scanner.mediumtest; | |||
import org.sonar.scanner.scan.ProjectScanContainer; | |||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||
public class AnalysisObservers { | |||
private AnalysisObserver[] observers; | |||
private ProjectScanContainer projectScanContainer; | |||
private final AnalysisObserver[] observers; | |||
private final SpringProjectScanContainer projectScanContainer; | |||
public AnalysisObservers(ProjectScanContainer projectScanContainer, AnalysisObserver... observers) { | |||
public AnalysisObservers(SpringProjectScanContainer projectScanContainer, AnalysisObserver... observers) { | |||
this.projectScanContainer = projectScanContainer; | |||
this.observers = observers; | |||
} | |||
public AnalysisObservers(ProjectScanContainer projectScanContainer) { | |||
this(projectScanContainer, new AnalysisObserver[0]); | |||
} | |||
public void notifyEndOfScanTask() { | |||
for (AnalysisObserver analysisObserver : observers) { | |||
analysisObserver.analysisCompleted(projectScanContainer); |
@@ -43,7 +43,7 @@ import org.sonar.scanner.protocol.output.ScannerReport.Symbol; | |||
import org.sonar.scanner.protocol.output.ScannerReportReader; | |||
import org.sonar.scanner.report.ReportPublisher; | |||
import org.sonar.scanner.report.ScannerReportUtils; | |||
import org.sonar.scanner.scan.ProjectScanContainer; | |||
import org.sonar.scanner.scan.SpringProjectScanContainer; | |||
import org.sonar.scanner.scan.filesystem.InputComponentStore; | |||
public class AnalysisResult implements AnalysisObserver { | |||
@@ -55,7 +55,7 @@ public class AnalysisResult implements AnalysisObserver { | |||
private ScannerReportReader reader; | |||
@Override | |||
public void analysisCompleted(ProjectScanContainer container) { | |||
public void analysisCompleted(SpringProjectScanContainer container) { | |||
LOG.info("Store analysis results in memory for later assertions in medium test"); | |||
ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class); | |||
reader = new ScannerReportReader(reportPublisher.getReportDir().toFile()); | |||
@@ -69,7 +69,7 @@ public class AnalysisResult implements AnalysisObserver { | |||
return reader; | |||
} | |||
private void storeFs(ProjectScanContainer container) { | |||
private void storeFs(SpringProjectScanContainer container) { | |||
InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class); | |||
for (InputFile inputPath : inputFileCache.inputFiles()) { | |||
inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath); |
@@ -24,11 +24,13 @@ import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.Priority; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.scanner.bootstrap.PluginInstaller; | |||
import org.sonar.scanner.bootstrap.ScannerPlugin; | |||
@Priority(1) | |||
public class FakePluginInstaller implements PluginInstaller { | |||
private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>(); |
@@ -23,7 +23,7 @@ import java.io.InputStream; | |||
import java.time.Duration; | |||
import java.time.temporal.ChronoUnit; | |||
import java.util.EnumSet; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; |
@@ -42,8 +42,7 @@ public class ContextPropertiesPublisher implements ReportPublisherStep { | |||
private final ScmConfiguration scmConfiguration; | |||
private final CiConfiguration ciConfiguration; | |||
public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration, | |||
CiConfiguration ciConfiguration) { | |||
public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration, CiConfiguration ciConfiguration) { | |||
this.cache = cache; | |||
this.config = config; | |||
this.scmConfiguration = scmConfiguration; |
@@ -33,7 +33,7 @@ import java.util.Map; | |||
import javax.annotation.Nullable; | |||
import okhttp3.HttpUrl; | |||
import org.apache.commons.io.FileUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.platform.Server; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.api.utils.TempFolder; | |||
@@ -97,13 +97,13 @@ public class ReportPublisher implements Startable { | |||
this.branchConfiguration = branchConfiguration; | |||
this.properties = properties; | |||
this.ceTaskReportDataHolder = ceTaskReportDataHolder; | |||
this.reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report"); | |||
this.writer = new ScannerReportWriter(reportDir.toFile()); | |||
this.reader = new ScannerReportReader(reportDir.toFile()); | |||
} | |||
@Override | |||
public void start() { | |||
reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report"); | |||
writer = new ScannerReportWriter(reportDir.toFile()); | |||
reader = new ScannerReportReader(reportDir.toFile()); | |||
contextPublisher.init(writer); | |||
if (!analysisMode.isMediumTest()) { |
@@ -19,23 +19,21 @@ | |||
*/ | |||
package org.sonar.scanner.repository; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.springframework.context.annotation.Bean; | |||
public class MetricsRepositoryProvider extends ProviderAdapter { | |||
public class MetricsRepositoryProvider { | |||
private static final Logger LOG = Loggers.get(MetricsRepositoryProvider.class); | |||
private static final String LOG_MSG = "Load metrics repository"; | |||
private MetricsRepository metricsRepository; | |||
@Bean("MetricsRepository") | |||
public MetricsRepository provide(MetricsRepositoryLoader loader) { | |||
if (metricsRepository == null) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
metricsRepository = loader.load(); | |||
profiler.stopInfo(); | |||
} | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
MetricsRepository metricsRepository = loader.load(); | |||
profiler.stopInfo(); | |||
return metricsRepository; | |||
} | |||
} |
@@ -19,25 +19,22 @@ | |||
*/ | |||
package org.sonar.scanner.repository; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.scanner.bootstrap.ScannerProperties; | |||
import org.sonar.scanner.rule.QualityProfiles; | |||
import org.springframework.context.annotation.Bean; | |||
public class QualityProfilesProvider extends ProviderAdapter { | |||
public class QualityProfilesProvider { | |||
private static final Logger LOG = Loggers.get(QualityProfilesProvider.class); | |||
private static final String LOG_MSG = "Load quality profiles"; | |||
private QualityProfiles profiles = null; | |||
@Bean("QualityProfiles") | |||
public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) { | |||
if (this.profiles == null) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
profiles = new QualityProfiles(loader.load(props.getProjectKey())); | |||
profiler.stopInfo(); | |||
} | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
QualityProfiles profiles = new QualityProfiles(loader.load(props.getProjectKey())); | |||
profiler.stopInfo(); | |||
return profiles; | |||
} | |||
@@ -24,7 +24,7 @@ import java.util.ArrayList; | |||
import java.util.Collection; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.resources.Languages; | |||
/** |
@@ -20,11 +20,13 @@ | |||
package org.sonar.scanner.repository.settings; | |||
import java.util.Map; | |||
import javax.inject.Inject; | |||
import org.sonar.scanner.bootstrap.DefaultScannerWsClient; | |||
public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader { | |||
public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) { | |||
@Inject | |||
public DefaultGlobalSettingsLoader(DefaultScannerWsClient wsClient) { | |||
super(wsClient); | |||
} | |||
@@ -25,7 +25,6 @@ import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.rule.LoadedActiveRule; | |||
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; | |||
import org.sonar.api.batch.rule.internal.DefaultActiveRules; | |||
@@ -34,23 +33,22 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.springframework.context.annotation.Bean; | |||
/** | |||
* Loads the rules that are activated on the Quality profiles | |||
* used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}. | |||
*/ | |||
public class ActiveRulesProvider extends ProviderAdapter { | |||
public class ActiveRulesProvider { | |||
private static final Logger LOG = Loggers.get(ActiveRulesProvider.class); | |||
private static final String LOG_MSG = "Load active rules"; | |||
private DefaultActiveRules singleton = null; | |||
@Bean("ActiveRules") | |||
public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) { | |||
if (singleton == null) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
singleton = load(loader, qProfiles); | |||
profiler.stopInfo(); | |||
} | |||
return singleton; | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
DefaultActiveRules activeRules = load(loader, qProfiles); | |||
profiler.stopInfo(); | |||
return activeRules; | |||
} | |||
private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) { |
@@ -20,29 +20,22 @@ | |||
package org.sonar.scanner.rule; | |||
import java.util.List; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.rule.internal.NewRule; | |||
import org.sonar.api.batch.rule.Rules; | |||
import org.sonar.api.batch.rule.internal.NewRule; | |||
import org.sonar.api.batch.rule.internal.RulesBuilder; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonarqube.ws.Rules.ListResponse.Rule; | |||
import org.springframework.context.annotation.Bean; | |||
public class RulesProvider extends ProviderAdapter { | |||
public class RulesProvider { | |||
private static final Logger LOG = Loggers.get(RulesProvider.class); | |||
private static final String LOG_MSG = "Load server rules"; | |||
private Rules singleton = null; | |||
@Bean("Rules") | |||
public Rules provide(RulesLoader ref) { | |||
if (singleton == null) { | |||
singleton = load(ref); | |||
} | |||
return singleton; | |||
} | |||
private static Rules load(RulesLoader ref) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
List<Rule> loadedRules = ref.load(); | |||
RulesBuilder builder = new RulesBuilder(); | |||
@@ -54,7 +47,6 @@ public class RulesProvider extends ProviderAdapter { | |||
} | |||
profiler.stopInfo(); | |||
return builder.build(); | |||
} | |||
} |
@@ -22,32 +22,31 @@ package org.sonar.scanner.scan; | |||
import java.util.HashMap; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; | |||
import org.springframework.context.annotation.Bean; | |||
public class InputModuleHierarchyProvider extends ProviderAdapter { | |||
public class InputModuleHierarchyProvider { | |||
private static final Logger LOG = Loggers.get(InputModuleHierarchyProvider.class); | |||
private DefaultInputModuleHierarchy hierarchy = null; | |||
public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, DefaultInputProject project) { | |||
if (hierarchy == null) { | |||
LOG.debug("Creating module hierarchy"); | |||
DefaultInputModule root = createModule(project.definition(), project.scannerId()); | |||
Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>()); | |||
if (parents.isEmpty()) { | |||
hierarchy = new DefaultInputModuleHierarchy(root); | |||
} else { | |||
hierarchy = new DefaultInputModuleHierarchy(root, parents); | |||
} | |||
@Bean("DefaultInputModuleHierarchy") | |||
public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, WorkDirectoriesInitializer workDirectoriesInit, DefaultInputProject project) { | |||
LOG.debug("Creating module hierarchy"); | |||
DefaultInputModule root = createModule(project.definition(), project.scannerId()); | |||
Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>()); | |||
DefaultInputModuleHierarchy inputModuleHierarchy; | |||
if (parents.isEmpty()) { | |||
inputModuleHierarchy = new DefaultInputModuleHierarchy(root); | |||
} else { | |||
inputModuleHierarchy = new DefaultInputModuleHierarchy(root, parents); | |||
} | |||
return hierarchy; | |||
workDirectoriesInit.execute(inputModuleHierarchy); | |||
return inputModuleHierarchy; | |||
} | |||
private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator, |
@@ -20,36 +20,32 @@ | |||
package org.sonar.scanner.scan; | |||
import java.util.Locale; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; | |||
import org.springframework.context.annotation.Bean; | |||
public class InputProjectProvider extends ProviderAdapter { | |||
public class InputProjectProvider { | |||
private static final Logger LOG = Loggers.get(InputProjectProvider.class); | |||
private DefaultInputProject project = null; | |||
@Bean("DefaultInputProject") | |||
public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator, | |||
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) { | |||
if (project == null) { | |||
// 1 Apply project builders | |||
projectBuildersExecutor.execute(projectReactor); | |||
// 1 Apply project builders | |||
projectBuildersExecutor.execute(projectReactor); | |||
// 2 Validate final reactor | |||
validator.validate(projectReactor); | |||
// 2 Validate final reactor | |||
validator.validate(projectReactor); | |||
// 3 Create project | |||
project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt()); | |||
// 3 Create project | |||
DefaultInputProject project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt()); | |||
LOG.info("Project key: {}", project.key()); | |||
LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString()); | |||
LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString()); | |||
LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault()); | |||
} | |||
LOG.info("Project key: {}", project.key()); | |||
LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString()); | |||
LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString()); | |||
LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault()); | |||
return project; | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
* 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])); | |||
} | |||
} |
@@ -20,14 +20,12 @@ | |||
package org.sonar.scanner.scan; | |||
import java.util.Map; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.scanner.config.DefaultConfiguration; | |||
public class ModuleConfiguration extends DefaultConfiguration { | |||
public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | |||
super(propertyDefinitions, encryption, props); | |||
} | |||
} |
@@ -23,28 +23,22 @@ import java.util.ArrayList; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | |||
import org.sonar.scanner.bootstrap.GlobalServerSettings; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
public class ModuleConfigurationProvider extends ProviderAdapter { | |||
private ModuleConfiguration moduleConfiguration; | |||
import org.springframework.context.annotation.Bean; | |||
public class ModuleConfigurationProvider { | |||
@Bean("ModuleConfiguration") | |||
public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings, | |||
ProjectServerSettings projectServerSettings) { | |||
if (moduleConfiguration == null) { | |||
Map<String, String> settings = new LinkedHashMap<>(); | |||
settings.putAll(globalServerSettings.properties()); | |||
settings.putAll(projectServerSettings.properties()); | |||
addScannerSideProperties(settings, module.definition()); | |||
Map<String, String> settings = new LinkedHashMap<>(); | |||
settings.putAll(globalServerSettings.properties()); | |||
settings.putAll(projectServerSettings.properties()); | |||
addScannerSideProperties(settings, module.definition()); | |||
moduleConfiguration = new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings); | |||
} | |||
return moduleConfiguration; | |||
return new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings); | |||
} | |||
private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) { |
@@ -19,7 +19,7 @@ | |||
*/ | |||
package org.sonar.scanner.scan; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.scanner.fs.InputModuleHierarchy; | |||
import org.sonar.scanner.scan.filesystem.InputComponentStore; |
@@ -22,6 +22,7 @@ package org.sonar.scanner.scan; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import javax.annotation.Priority; | |||
import org.sonar.api.config.internal.Settings; | |||
import static java.util.Objects.requireNonNull; | |||
@@ -30,6 +31,7 @@ import static java.util.Objects.requireNonNull; | |||
* @deprecated since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. | |||
*/ | |||
@Deprecated | |||
@Priority(1) | |||
public class MutableModuleSettings extends Settings { | |||
private final Map<String, String> properties = new HashMap<>(); |
@@ -19,16 +19,12 @@ | |||
*/ | |||
package org.sonar.scanner.scan; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.springframework.context.annotation.Bean; | |||
public class MutableProjectReactorProvider extends ProviderAdapter { | |||
private ProjectReactor reactor = null; | |||
public class MutableProjectReactorProvider { | |||
@Bean("ProjectReactor") | |||
public ProjectReactor provide(ProjectReactorBuilder builder) { | |||
if (reactor == null) { | |||
reactor = builder.execute(); | |||
} | |||
return reactor; | |||
return builder.execute(); | |||
} | |||
} |
@@ -25,12 +25,15 @@ import java.util.Optional; | |||
import org.sonar.api.config.internal.Settings; | |||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | |||
import javax.annotation.Priority; | |||
import static java.util.Objects.requireNonNull; | |||
/** | |||
* @deprecated since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. | |||
*/ | |||
@Deprecated | |||
@Priority(2) | |||
public class MutableProjectSettings extends Settings { | |||
private final Map<String, String> properties = new HashMap<>(); |
@@ -28,6 +28,7 @@ import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
public class ProjectBuildersExecutor { | |||
@@ -36,11 +37,13 @@ public class ProjectBuildersExecutor { | |||
private final GlobalConfiguration globalConfig; | |||
private final ProjectBuilder[] projectBuilders; | |||
@Autowired(required = false) | |||
public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) { | |||
this.globalConfig = globalConfig; | |||
this.projectBuilders = projectBuilders; | |||
} | |||
@Autowired(required = false) | |||
public ProjectBuildersExecutor(GlobalConfiguration globalConfig) { | |||
this(globalConfig, new ProjectBuilder[0]); | |||
} |
@@ -20,14 +20,12 @@ | |||
package org.sonar.scanner.scan; | |||
import java.util.Map; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.config.internal.Encryption; | |||
import org.sonar.scanner.config.DefaultConfiguration; | |||
public class ProjectConfiguration extends DefaultConfiguration { | |||
public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { | |||
super(propertyDefinitions, encryption, props); | |||
} | |||
} |
@@ -21,27 +21,22 @@ package org.sonar.scanner.scan; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | |||
import org.sonar.scanner.bootstrap.GlobalServerSettings; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
public class ProjectConfigurationProvider extends ProviderAdapter { | |||
private ProjectConfiguration projectConfig; | |||
import org.springframework.context.annotation.Bean; | |||
public class ProjectConfigurationProvider { | |||
@Bean("ProjectConfiguration") | |||
public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, | |||
ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) { | |||
if (projectConfig == null) { | |||
Map<String, String> settings = new LinkedHashMap<>(); | |||
settings.putAll(globalServerSettings.properties()); | |||
settings.putAll(projectServerSettings.properties()); | |||
settings.putAll(project.properties()); | |||
Map<String, String> settings = new LinkedHashMap<>(); | |||
settings.putAll(globalServerSettings.properties()); | |||
settings.putAll(projectServerSettings.properties()); | |||
settings.putAll(project.properties()); | |||
projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings); | |||
projectSettings.complete(projectConfig); | |||
} | |||
ProjectConfiguration projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings); | |||
projectSettings.complete(projectConfig); | |||
return projectConfig; | |||
} | |||
} |
@@ -23,7 +23,7 @@ import java.io.IOException; | |||
import java.nio.channels.OverlappingFileLockException; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule; | |||
public class ProjectLock implements Startable { |
@@ -29,6 +29,7 @@ import org.sonar.api.utils.MessageException; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.scanner.bootstrap.GlobalConfiguration; | |||
import org.sonar.scanner.scan.branch.BranchParamsValidator; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.nonNull; | |||
@@ -52,11 +53,13 @@ public class ProjectReactorValidator { | |||
@Nullable | |||
private final BranchParamsValidator branchParamsValidator; | |||
@Autowired(required = false) | |||
public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) { | |||
this.settings = settings; | |||
this.branchParamsValidator = branchParamsValidator; | |||
} | |||
@Autowired(required = false) | |||
public ProjectReactorValidator(GlobalConfiguration settings) { | |||
this(settings, null); | |||
} |
@@ -21,14 +21,14 @@ package org.sonar.scanner.scan; | |||
import java.util.Map; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.notifications.AnalysisWarnings; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.repository.settings.ProjectSettingsLoader; | |||
import org.springframework.context.annotation.Bean; | |||
public class ProjectServerSettingsProvider extends ProviderAdapter { | |||
public class ProjectServerSettingsProvider { | |||
private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class); | |||
@@ -37,17 +37,13 @@ public class ProjectServerSettingsProvider extends ProviderAdapter { | |||
"Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " + | |||
"displaying this warning."; | |||
private ProjectServerSettings singleton = null; | |||
@Bean("ProjectServerSettings") | |||
public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) { | |||
if (singleton == null) { | |||
Map<String, String> serverSideSettings = loader.loadProjectSettings(); | |||
if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) { | |||
LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); | |||
analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); | |||
} | |||
singleton = new ProjectServerSettings(serverSideSettings); | |||
Map<String, String> serverSideSettings = loader.loadProjectSettings(); | |||
if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) { | |||
LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); | |||
analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING); | |||
} | |||
return singleton; | |||
return new ProjectServerSettings(serverSideSettings); | |||
} | |||
} |
@@ -19,10 +19,11 @@ | |||
*/ | |||
package org.sonar.scanner.scan; | |||
import javax.annotation.Priority; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.scan.filesystem.FileExclusions; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.scanner.bootstrap.ExtensionInstaller; | |||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem; | |||
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore; | |||
import org.sonar.scanner.sensor.ModuleSensorContext; | |||
@@ -34,10 +35,11 @@ import static org.sonar.api.batch.InstantiationStrategy.PER_PROJECT; | |||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide; | |||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | |||
public class ModuleScanContainer extends ComponentContainer { | |||
@Priority(1) | |||
public class SpringModuleScanContainer extends SpringComponentContainer { | |||
private final DefaultInputModule module; | |||
public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) { | |||
public SpringModuleScanContainer(SpringComponentContainer parent, DefaultInputModule module) { | |||
super(parent); | |||
this.module = module; | |||
} | |||
@@ -70,7 +72,7 @@ public class ModuleScanContainer extends ComponentContainer { | |||
} | |||
private void addExtensions() { | |||
ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class); | |||
ExtensionInstaller pluginInstaller = parent.getComponentByType(ExtensionInstaller.class); | |||
pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT)); | |||
} | |||
@@ -78,5 +80,4 @@ public class ModuleScanContainer extends ComponentContainer { | |||
protected void doAfterStart() { | |||
getComponentByType(ModuleSensorsExecutor.class).execute(); | |||
} | |||
} |
@@ -20,12 +20,12 @@ | |||
package org.sonar.scanner.scan; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.Priority; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.batch.fs.internal.SensorStrategy; | |||
import org.sonar.api.batch.rule.CheckFactory; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.resources.ResourceTypes; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.api.utils.MessageException; | |||
@@ -34,7 +34,6 @@ import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.config.ScannerProperties; | |||
import org.sonar.core.extension.CoreExtensionsInstaller; | |||
import org.sonar.core.metric.ScannerMetrics; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.scanner.DefaultFileLinesContextFactory; | |||
import org.sonar.scanner.ProjectInfo; | |||
import org.sonar.scanner.analysis.AnalysisTempFolderProvider; | |||
@@ -42,6 +41,7 @@ import org.sonar.scanner.bootstrap.ExtensionInstaller; | |||
import org.sonar.scanner.bootstrap.ExtensionMatcher; | |||
import org.sonar.scanner.bootstrap.GlobalAnalysisMode; | |||
import org.sonar.scanner.bootstrap.PostJobExtensionDictionary; | |||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||
import org.sonar.scanner.ci.CiConfigurationProvider; | |||
import org.sonar.scanner.ci.vendors.AppVeyor; | |||
import org.sonar.scanner.ci.vendors.AwsCodeBuild; | |||
@@ -89,20 +89,15 @@ import org.sonar.scanner.report.TestExecutionPublisher; | |||
import org.sonar.scanner.repository.ContextPropertiesCache; | |||
import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader; | |||
import org.sonar.scanner.repository.DefaultQualityProfileLoader; | |||
import org.sonar.scanner.repository.ReferenceBranchSupplier; | |||
import org.sonar.scanner.repository.ProjectRepositoriesLoader; | |||
import org.sonar.scanner.repository.ProjectRepositoriesSupplier; | |||
import org.sonar.scanner.repository.QualityProfileLoader; | |||
import org.sonar.scanner.repository.QualityProfilesProvider; | |||
import org.sonar.scanner.repository.ReferenceBranchSupplier; | |||
import org.sonar.scanner.repository.language.DefaultLanguagesRepository; | |||
import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader; | |||
import org.sonar.scanner.repository.settings.ProjectSettingsLoader; | |||
import org.sonar.scanner.rule.ActiveRulesLoader; | |||
import org.sonar.scanner.rule.ActiveRulesProvider; | |||
import org.sonar.scanner.rule.DefaultActiveRulesLoader; | |||
import org.sonar.scanner.rule.DefaultRulesLoader; | |||
import org.sonar.scanner.rule.QProfileVerifier; | |||
import org.sonar.scanner.rule.RulesLoader; | |||
import org.sonar.scanner.rule.RulesProvider; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.scanner.scan.branch.BranchConfigurationProvider; | |||
@@ -138,11 +133,11 @@ import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide | |||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; | |||
import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; | |||
public class ProjectScanContainer extends ComponentContainer { | |||
private static final Logger LOG = Loggers.get(ProjectScanContainer.class); | |||
@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); | |||
} | |||
@@ -150,9 +145,6 @@ public class ProjectScanContainer extends ComponentContainer { | |||
protected void doBeforeStart() { | |||
addScannerExtensions(); | |||
addScannerComponents(); | |||
ProjectLock lock = getComponentByType(ProjectLock.class); | |||
lock.tryLock(); | |||
getComponentByType(WorkDirectoriesInitializer.class).execute(); | |||
} | |||
private void addScannerComponents() { | |||
@@ -207,7 +199,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
DefaultMetricFinder.class, | |||
// lang | |||
Languages.class, | |||
LanguagesProvider.class, | |||
DefaultLanguagesRepository.class, | |||
// issue exclusions | |||
@@ -298,17 +290,17 @@ public class ProjectScanContainer extends ComponentContainer { | |||
add(GitScmSupport.getObjects()); | |||
add(SvnScmSupport.getObjects()); | |||
addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); | |||
addIfMissing(DefaultRulesLoader.class, RulesLoader.class); | |||
addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class); | |||
addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class); | |||
addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); | |||
add(DefaultProjectSettingsLoader.class, | |||
DefaultRulesLoader.class, | |||
DefaultActiveRulesLoader.class, | |||
DefaultQualityProfileLoader.class, | |||
DefaultProjectRepositoriesLoader.class); | |||
} | |||
private void addScannerExtensions() { | |||
getComponentByType(CoreExtensionsInstaller.class) | |||
getParent().getComponentByType(CoreExtensionsInstaller.class) | |||
.install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension)); | |||
getComponentByType(ExtensionInstaller.class) | |||
getParent().getComponentByType(ExtensionInstaller.class) | |||
.install(this, getScannerProjectExtensionsFilter()); | |||
} | |||
@@ -323,6 +315,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
@Override | |||
protected void doAfterStart() { | |||
getComponentByType(ProjectLock.class).tryLock(); | |||
GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class); | |||
InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class); | |||
ScanProperties properties = getComponentByType(ScanProperties.class); | |||
@@ -381,7 +374,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
} | |||
void scan(DefaultInputModule module) { | |||
new ModuleScanContainer(this, module).execute(); | |||
new SpringModuleScanContainer(this, module).execute(); | |||
} | |||
} |
@@ -33,30 +33,23 @@ import org.sonar.scanner.fs.InputModuleHierarchy; | |||
* Be careful that sub module work dir might be nested in parent working directory. | |||
*/ | |||
public class WorkDirectoriesInitializer { | |||
private InputModuleHierarchy moduleHierarchy; | |||
public WorkDirectoriesInitializer(InputModuleHierarchy moduleHierarchy) { | |||
this.moduleHierarchy = moduleHierarchy; | |||
} | |||
public void execute() { | |||
cleanAllWorkingDirs(moduleHierarchy.root()); | |||
mkdirsAllWorkingDirs(moduleHierarchy.root()); | |||
public void execute(InputModuleHierarchy moduleHierarchy) { | |||
cleanAllWorkingDirs(moduleHierarchy, moduleHierarchy.root()); | |||
mkdirsAllWorkingDirs(moduleHierarchy, moduleHierarchy.root()); | |||
} | |||
private void cleanAllWorkingDirs(DefaultInputModule module) { | |||
private static void cleanAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) { | |||
for (DefaultInputModule sub : moduleHierarchy.children(module)) { | |||
cleanAllWorkingDirs(sub); | |||
cleanAllWorkingDirs(moduleHierarchy, sub); | |||
} | |||
if (Files.exists(module.getWorkDir())) { | |||
deleteAllRecursivelyExceptLockFile(module.getWorkDir()); | |||
} | |||
} | |||
private void mkdirsAllWorkingDirs(DefaultInputModule module) { | |||
private static void mkdirsAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) { | |||
for (DefaultInputModule sub : moduleHierarchy.children(module)) { | |||
mkdirsAllWorkingDirs(sub); | |||
mkdirsAllWorkingDirs(moduleHierarchy, sub); | |||
} | |||
try { | |||
Files.createDirectories(module.getWorkDir()); |
@@ -19,31 +19,28 @@ | |||
*/ | |||
package org.sonar.scanner.scan.branch; | |||
import org.picocontainer.annotations.Nullable; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.scanner.scan.ProjectConfiguration; | |||
import org.springframework.context.annotation.Bean; | |||
public class BranchConfigurationProvider extends ProviderAdapter { | |||
public class BranchConfigurationProvider { | |||
private static final Logger LOG = Loggers.get(BranchConfigurationProvider.class); | |||
private static final String LOG_MSG = "Load branch configuration"; | |||
private BranchConfiguration branchConfiguration = null; | |||
@Bean("BranchConfiguration") | |||
public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration, | |||
ProjectBranches branches, ProjectPullRequests pullRequests) { | |||
if (branchConfiguration == null) { | |||
if (loader == null) { | |||
branchConfiguration = new DefaultBranchConfiguration(); | |||
} else { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests); | |||
profiler.stopInfo(); | |||
} | |||
if (loader == null) { | |||
return new DefaultBranchConfiguration(); | |||
} else { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
BranchConfiguration branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests); | |||
profiler.stopInfo(); | |||
return branchConfiguration; | |||
} | |||
return branchConfiguration; | |||
} | |||
} |
@@ -20,33 +20,27 @@ | |||
package org.sonar.scanner.scan.branch; | |||
import java.util.Collections; | |||
import org.picocontainer.annotations.Nullable; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.scanner.bootstrap.ScannerProperties; | |||
import org.springframework.context.annotation.Bean; | |||
public class ProjectBranchesProvider extends ProviderAdapter { | |||
public class ProjectBranchesProvider { | |||
private static final Logger LOG = Loggers.get(ProjectBranchesProvider.class); | |||
private static final String LOG_MSG = "Load project branches"; | |||
private ProjectBranches branches = null; | |||
@Bean("ProjectBranches") | |||
public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) { | |||
if (this.branches != null) { | |||
return this.branches; | |||
} | |||
if (loader == null) { | |||
this.branches = new ProjectBranches(Collections.emptyList()); | |||
return this.branches; | |||
return new ProjectBranches(Collections.emptyList()); | |||
} | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
this.branches = loader.load(scannerProperties.getProjectKey()); | |||
ProjectBranches branches = loader.load(scannerProperties.getProjectKey()); | |||
profiler.stopInfo(); | |||
return this.branches; | |||
return branches; | |||
} | |||
} |
@@ -20,31 +20,26 @@ | |||
package org.sonar.scanner.scan.branch; | |||
import java.util.Collections; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.scanner.bootstrap.ScannerProperties; | |||
import org.springframework.context.annotation.Bean; | |||
public class ProjectPullRequestsProvider extends ProviderAdapter { | |||
public class ProjectPullRequestsProvider { | |||
private static final Logger LOG = Loggers.get(ProjectPullRequestsProvider.class); | |||
private static final String LOG_MSG = "Load project pull requests"; | |||
private ProjectPullRequests pullRequests = null; | |||
public ProjectPullRequests provide(@org.picocontainer.annotations.Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) { | |||
if (pullRequests != null) { | |||
return pullRequests; | |||
} | |||
@Bean("ProjectPullRequests") | |||
public ProjectPullRequests provide(@Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) { | |||
if (loader == null) { | |||
pullRequests = new ProjectPullRequests(Collections.emptyList()); | |||
return pullRequests; | |||
return new ProjectPullRequests(Collections.emptyList()); | |||
} | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
pullRequests = loader.load(scannerProperties.getProjectKey()); | |||
ProjectPullRequests pullRequests = loader.load(scannerProperties.getProjectKey()); | |||
profiler.stopInfo(); | |||
return pullRequests; | |||
} |
@@ -22,8 +22,13 @@ package org.sonar.scanner.scan.filesystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | |||
import javax.annotation.Priority; | |||
import javax.inject.Inject; | |||
@Priority(1) | |||
public class DefaultModuleFileSystem extends MutableFileSystem { | |||
@Inject | |||
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) { | |||
super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir())); | |||
initFields(module); |
@@ -22,8 +22,13 @@ package org.sonar.scanner.scan.filesystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; | |||
import javax.annotation.Priority; | |||
import javax.inject.Inject; | |||
@Priority(2) | |||
public class DefaultProjectFileSystem extends MutableFileSystem { | |||
@Inject | |||
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) { | |||
super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir())); | |||
setFields(project); |
@@ -90,14 +90,6 @@ public class FileIndexer { | |||
this.projectExclusionFilters = projectExclusionFilters; | |||
} | |||
public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, | |||
ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, | |||
IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, | |||
LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) { | |||
this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader, | |||
metadataGenerator, sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]); | |||
} | |||
void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, | |||
Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand) | |||
throws IOException { |
@@ -22,29 +22,25 @@ package org.sonar.scanner.scm; | |||
import java.nio.file.Path; | |||
import java.util.Collection; | |||
import javax.annotation.CheckForNull; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.batch.scm.ScmProvider; | |||
import org.sonar.api.impl.utils.ScannerUtils; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.api.impl.utils.ScannerUtils; | |||
import org.springframework.context.annotation.Bean; | |||
public class ScmChangedFilesProvider extends ProviderAdapter { | |||
public class ScmChangedFilesProvider { | |||
private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class); | |||
private static final String LOG_MSG = "SCM collecting changed files in the branch"; | |||
private ScmChangedFiles scmBranchChangedFiles; | |||
@Bean("ScmChangedFiles") | |||
public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) { | |||
if (scmBranchChangedFiles == null) { | |||
Path rootBaseDir = project.getBaseDir(); | |||
Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); | |||
validatePaths(changedFiles); | |||
scmBranchChangedFiles = new ScmChangedFiles(changedFiles); | |||
} | |||
return scmBranchChangedFiles; | |||
return new ScmChangedFiles(changedFiles); | |||
} | |||
private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) { |
@@ -24,11 +24,11 @@ import java.util.Map; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.Properties; | |||
import org.sonar.api.Property; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.batch.scm.ScmProvider; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.notifications.AnalysisWarnings; | |||
@@ -67,7 +67,8 @@ public class ScmConfiguration implements Startable { | |||
private ScmProvider provider; | |||
public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings, ScmProvider... providers) { | |||
public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings, | |||
ScmProvider... providers) { | |||
this.moduleHierarchy = moduleHierarchy; | |||
this.settings = settings; | |||
this.analysisWarnings = analysisWarnings; | |||
@@ -76,10 +77,6 @@ public class ScmConfiguration implements Startable { | |||
} | |||
} | |||
public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings) { | |||
this(moduleHierarchy, settings, analysisWarnings, new ScmProvider[0]); | |||
} | |||
@Override | |||
public void start() { | |||
if (isDisabled()) { |
@@ -34,9 +34,9 @@ public class ModuleSensorContext extends ProjectSensorContext { | |||
private final InputModule module; | |||
public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableSettings, FileSystem fs, ActiveRules activeRules, | |||
public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableModuleSettings, FileSystem fs, ActiveRules activeRules, | |||
SensorStorage sensorStorage, SonarRuntime sonarRuntime) { | |||
super(project, config, mutableSettings, fs, activeRules, sensorStorage, sonarRuntime); | |||
super(project, config, mutableModuleSettings, fs, activeRules, sensorStorage, sonarRuntime); | |||
this.module = module; | |||
} | |||
@@ -24,6 +24,7 @@ import java.util.stream.Collectors; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | |||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | |||
@@ -34,7 +35,7 @@ public class ModuleSensorExtensionDictionary extends AbstractExtensionDictionary | |||
private final MutableFileSystem fileSystem; | |||
private final BranchConfiguration branchConfiguration; | |||
public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer, | |||
public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer, | |||
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | |||
super(componentContainer); | |||
this.sensorContext = sensorContext; |
@@ -23,8 +23,8 @@ import java.util.Collection; | |||
import java.util.List; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.scanner.sensor.ProjectSensor; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; | |||
import org.sonar.scanner.bootstrap.SpringComponentContainer; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | |||
@@ -35,7 +35,7 @@ public class ProjectSensorExtensionDictionary extends AbstractExtensionDictionar | |||
private final MutableFileSystem fileSystem; | |||
private final BranchConfiguration branchConfiguration; | |||
public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer, | |||
public ProjectSensorExtensionDictionary(SpringComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer, | |||
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { | |||
super(componentContainer); | |||
this.sensorContext = sensorContext; |
@@ -28,6 +28,15 @@ | |||
<level value="INFO"/> | |||
</logger> | |||
<!-- Spring generates too many DEBUG logs when sonar.verbose is set --> | |||
<logger name="org.springframework"> | |||
<level value="INFO"/> | |||
</logger> | |||
<logger name="org.sonar.scanner.bootstrap.PriorityBeanFactory"> | |||
<level value="INFO"/> | |||
</logger> | |||
<!-- sonar.showSql --> | |||
<!-- see also org.sonar.db.MyBatis#configureLogback() --> | |||
<logger name="org.mybatis"> | |||
@@ -42,9 +51,6 @@ | |||
<logger name="java.sql.ResultSet"> | |||
<level value="WARN"/> | |||
</logger> | |||
<logger name="PERSISTIT"> | |||
<level value="WARN"/> | |||
</logger> | |||
<root> | |||
<!-- sonar.verbose --> |
@@ -19,10 +19,6 @@ | |||
<level value="WARN"/> | |||
</logger> | |||
<logger name="PERSISTIT"> | |||
<level value="WARN"/> | |||
</logger> | |||
<root> | |||
<!-- sonar.verbose --> | |||
<level value="${ROOT_LOGGER_LEVEL}"/> |
@@ -1,85 +0,0 @@ | |||
/* | |||
* 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 { | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* 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(); | |||
} | |||
} |
@@ -20,9 +20,6 @@ | |||
package org.sonar.scanner.bootstrap; | |||
import com.google.common.collect.Lists; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.picocontainer.behaviors.FieldDecorated; | |||
@@ -30,11 +27,13 @@ import org.sonar.api.batch.DependedUpon; | |||
import org.sonar.api.batch.DependsUpon; | |||
import org.sonar.api.batch.Phase; | |||
import org.sonar.api.batch.ScannerSide; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.sensor.Sensor; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; | |||
import org.sonar.core.platform.ComponentContainer; | |||
import org.sonar.scanner.scan.SpringModuleScanContainer; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
import org.sonar.scanner.scan.filesystem.MutableFileSystem; | |||
import org.sonar.scanner.sensor.ModuleSensorContext; | |||
@@ -42,6 +41,10 @@ import org.sonar.scanner.sensor.ModuleSensorExtensionDictionary; | |||
import org.sonar.scanner.sensor.ModuleSensorOptimizer; | |||
import org.sonar.scanner.sensor.ModuleSensorWrapper; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.mockito.ArgumentMatchers.any; | |||
@@ -59,10 +62,16 @@ public class ModuleSensorExtensionDictionaryTest { | |||
} | |||
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); | |||
} | |||
@@ -95,14 +104,17 @@ public class ModuleSensorExtensionDictionaryTest { | |||
Sensor b = new FakeSensor(); | |||
Sensor c = new FakeSensor(); | |||
ComponentContainer grandParent = new ComponentContainer(); | |||
grandParent.addSingleton(a); | |||
SpringComponentContainer grandParent = new SpringComponentContainer(); | |||
grandParent.add(a); | |||
grandParent.context.refresh(); | |||
ComponentContainer parent = grandParent.createChild(); | |||
parent.addSingleton(b); | |||
SpringComponentContainer parent = grandParent.createChild(); | |||
parent.add(b); | |||
parent.context.refresh(); | |||
ComponentContainer child = parent.createChild(); | |||
child.addSingleton(c); | |||
SpringComponentContainer child = parent.createChild(); | |||
child.add(c); | |||
child.context.refresh(); | |||
ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class), | |||
fileSystem, branchConfiguration); |
@@ -0,0 +1,103 @@ | |||
/* | |||
* 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 { | |||
} | |||
} |
@@ -66,14 +66,4 @@ public class ScannerWsClientProviderTest { | |||
assertThat(httpConnector.baseUrl()).isEqualTo("https://here/sonarqube/"); | |||
assertThat(httpConnector.okHttpClient().proxy()).isNull(); | |||
} | |||
@Test | |||
public void build_singleton() { | |||
System2 system = mock(System2.class); | |||
ScannerProperties settings = new ScannerProperties(new HashMap<>()); | |||
DefaultScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system); | |||
DefaultScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system); | |||
assertThat(first).isSameAs(second); | |||
} | |||
} |
@@ -0,0 +1,213 @@ | |||
/* | |||
* 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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* 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"); | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -36,6 +36,7 @@ import java.util.Map; | |||
import java.util.Properties; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.Priority; | |||
import org.apache.commons.io.FileUtils; | |||
import org.junit.rules.ExternalResource; | |||
import org.sonar.api.Plugin; | |||
@@ -100,7 +101,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader(); | |||
private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader(); | |||
private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime(); | |||
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder(); | |||
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt(); | |||
private LogOutput logOutput = null; | |||
private static void createWorkingDirs() throws IOException { | |||
@@ -280,7 +281,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
public static class AnalysisBuilder { | |||
private final Map<String, String> taskProperties = new HashMap<>(); | |||
private ScannerMediumTester tester; | |||
private final ScannerMediumTester tester; | |||
public AnalysisBuilder(ScannerMediumTester tester) { | |||
this.tester = tester; | |||
@@ -327,6 +328,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
@Priority(1) | |||
private static class FakeRulesLoader implements RulesLoader { | |||
private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>(); | |||
@@ -341,6 +343,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeActiveRulesLoader implements ActiveRulesLoader { | |||
private List<LoadedActiveRule> activeRules = new LinkedList<>(); | |||
@@ -354,6 +357,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader { | |||
private int metricId = 1; | |||
@@ -374,6 +378,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
@Priority(1) | |||
private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { | |||
private Map<String, FileData> fileDataMap = new HashMap<>(); | |||
@@ -389,6 +394,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
@Priority(1) | |||
private static class FakeBranchConfiguration implements BranchConfiguration { | |||
private BranchType branchType = BranchType.BRANCH; | |||
@@ -425,6 +431,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeSonarRuntime implements SonarRuntime { | |||
private SonarEdition edition; | |||
@@ -483,6 +490,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
return this; | |||
} | |||
@Priority(1) | |||
private class FakeBranchConfigurationLoader implements BranchConfigurationLoader { | |||
@Override | |||
public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) { | |||
@@ -490,6 +498,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeQualityProfileLoader implements QualityProfileLoader { | |||
private List<QualityProfile> qualityProfiles = new LinkedList<>(); | |||
@@ -509,6 +518,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader { | |||
private Map<String, String> globalSettings = new HashMap<>(); | |||
@@ -523,6 +533,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader { | |||
private NewCodePeriods.ShowWSResponse response; | |||
@@ -536,6 +547,7 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class FakeProjectSettingsLoader implements ProjectSettingsLoader { | |||
private Map<String, String> projectSettings = new HashMap<>(); | |||
@@ -550,4 +562,9 @@ public class ScannerMediumTester extends ExternalResource { | |||
} | |||
} | |||
@Priority(1) | |||
private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder { | |||
} | |||
} |
@@ -26,6 +26,7 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.scanner.mediumtest.ScannerMediumTester; | |||
import org.springframework.beans.factory.UnsatisfiedDependencyException; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
@@ -43,8 +44,8 @@ public class NoLanguagesPluginsMediumTest { | |||
assertThatThrownBy(() -> tester | |||
.newAnalysis(new File(projectDir, "sonar-project.properties")) | |||
.execute()) | |||
.isInstanceOf(IllegalStateException.class) | |||
.hasMessage("No language plugins are installed."); | |||
.isInstanceOf(UnsatisfiedDependencyException.class) | |||
.hasRootCauseMessage("No language plugins are installed."); | |||
} | |||
private File copyProject(String path) throws Exception { |
@@ -73,11 +73,11 @@ public class IssuesMediumTest { | |||
List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | |||
assertThat(issues).hasSize(8 /* lines */); | |||
List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo")); | |||
assertThat(externalIssues).isEmpty(); | |||
} | |||
@Test | |||
public void testOneExternalIssuePerLine() throws Exception { | |||
File projectDir = new File("test-resources/mediumtest/xoo/sample"); | |||
@@ -243,7 +243,8 @@ public class IssuesMediumTest { | |||
.build()) | |||
.execute(); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).contains( | |||
"Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); | |||
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | |||
assertThat(issues).isEmpty(); | |||
@@ -295,7 +296,8 @@ public class IssuesMediumTest { | |||
.build()) | |||
.execute(); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level."); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly( | |||
"Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level."); | |||
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | |||
assertThat(issues).hasSize(10); | |||
@@ -303,7 +305,6 @@ public class IssuesMediumTest { | |||
issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo")); | |||
assertThat(issues).hasSize(10); | |||
// SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules | |||
logTester.clear(); | |||
result = tester.newAnalysis() | |||
@@ -387,7 +388,8 @@ public class IssuesMediumTest { | |||
.build()) | |||
.execute(); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).contains( | |||
"Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths."); | |||
List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); | |||
assertThat(issues).hasSize(10); |
@@ -21,12 +21,14 @@ package org.sonar.scanner.mediumtest.log; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import javax.annotation.Priority; | |||
import org.junit.BeforeClass; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrapper.Batch; | |||
import org.sonar.batch.bootstrapper.EnvironmentInformation; | |||
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; | |||
import org.springframework.beans.factory.UnsatisfiedDependencyException; | |||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | |||
@@ -78,12 +80,12 @@ public class ExceptionHandlingMediumTest { | |||
@Test | |||
public void testWithVerbose() { | |||
setUp(true); | |||
assertThatThrownBy(() -> batch.execute()) | |||
.isInstanceOf(IllegalStateException.class) | |||
.hasMessageContaining("Unable to load component class"); | |||
.isInstanceOf(UnsatisfiedDependencyException.class) | |||
.hasMessageContaining("Error loading settings"); | |||
} | |||
@Priority(1) | |||
private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader { | |||
boolean withCause = false; | |||
@@ -25,6 +25,7 @@ import java.io.PipedOutputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -77,8 +78,7 @@ public class ReportPublisherTest { | |||
private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class); | |||
private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); | |||
private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class); | |||
private ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder, | |||
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder); | |||
private ReportPublisher underTest; | |||
@Before | |||
public void setUp() { | |||
@@ -90,6 +90,8 @@ public class ReportPublisherTest { | |||
when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath() | |||
.resolve("folder") | |||
.resolve("report-task.txt")); | |||
underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder, | |||
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder); | |||
} | |||
@Test | |||
@@ -109,7 +111,7 @@ public class ReportPublisherTest { | |||
underTest.prepareAndDumpMetadata("TASK-123"); | |||
assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo( | |||
"projectKey=org.sonarsource.sonarqube:sonarqube\n" + | |||
"projectKey=org.sonarsource.sonarqube:sonarqube\n" + | |||
"serverUrl=https://localhost\n" + | |||
"serverVersion=6.4\n" + | |||
"dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" + | |||
@@ -249,7 +251,6 @@ public class ReportPublisherTest { | |||
public void should_not_delete_report_if_property_is_set() throws IOException { | |||
when(properties.shouldKeepReport()).thenReturn(true); | |||
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | |||
Files.createDirectory(reportDir); | |||
underTest.start(); | |||
underTest.stop(); | |||
@@ -259,7 +260,6 @@ public class ReportPublisherTest { | |||
@Test | |||
public void should_delete_report_by_default() throws IOException { | |||
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); | |||
Files.createDirectory(reportDir); | |||
underTest.start(); | |||
underTest.stop(); |
@@ -27,11 +27,11 @@ import org.sonar.scanner.bootstrap.ExtensionMatcher; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ProjectScanContainerTest { | |||
public class SpringProjectScanContainerTest { | |||
@Test | |||
public void should_add_only_batch_extensions() { | |||
ExtensionMatcher filter = ProjectScanContainer.getScannerProjectExtensionsFilter(); | |||
ExtensionMatcher filter = SpringProjectScanContainer.getScannerProjectExtensionsFilter(); | |||
assertThat(filter.accept(new MyBatchExtension())).isTrue(); | |||
assertThat(filter.accept(MyBatchExtension.class)).isTrue(); |