Browse Source

SONAR-15966 Use Spring instead of Pico as dependency injection framework in the scanner-engine

Co-authored-by: Zipeng WU <zipeng.wu@sonarsource.com>
tags/9.4.0.54424
Duarte Meneses 2 years ago
parent
commit
a53007e824
100 changed files with 1531 additions and 627 deletions
  1. 4
    0
      build.gradle
  2. 4
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/AbstractComputationSteps.java
  3. 2
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessor.java
  4. 2
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/IssueSyncTaskProcessor.java
  5. 2
    2
      server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/TaskContainer.java
  6. 2
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationContainer.java
  7. 2
    0
      sonar-core/build.gradle
  8. 16
    18
      sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java
  9. 2
    0
      sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsLoader.java
  10. 3
    0
      sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java
  11. 9
    3
      sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
  12. 12
    4
      sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java
  13. 34
    0
      sonar-core/src/main/java/org/sonar/core/platform/Container.java
  14. 1
    13
      sonar-core/src/main/java/org/sonar/core/platform/ContainerPopulator.java
  15. 36
    0
      sonar-core/src/main/java/org/sonar/core/platform/ExtensionContainer.java
  16. 2
    0
      sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java
  17. 8
    1
      sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/utils/DefaultTempFolder.java
  18. 4
    4
      sonar-plugin-api/src/test/java/org/sonar/api/resources/LanguagesTest.java
  19. 3
    0
      sonar-scanner-engine/build.gradle
  20. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java
  21. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectInfo.java
  22. 11
    44
      sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java
  23. 5
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java
  24. 62
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java
  25. 3
    4
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java
  26. 1
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfiguration.java
  27. 8
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfigurationProvider.java
  28. 6
    11
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalServerSettingsProvider.java
  29. 7
    23
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalTempFolderProvider.java
  30. 35
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java
  31. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PluginFiles.java
  32. 3
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java
  33. 123
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java
  34. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerPluginRepository.java
  35. 23
    29
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerWsClientProvider.java
  36. 231
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java
  37. 22
    27
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java
  38. 60
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java
  39. 3
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java
  40. 3
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java
  41. 3
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
  42. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObserver.java
  43. 4
    8
      sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObservers.java
  44. 3
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisResult.java
  45. 2
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/FakePluginInstaller.java
  46. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java
  47. 1
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java
  48. 4
    4
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java
  49. 6
    8
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/MetricsRepositoryProvider.java
  50. 6
    9
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java
  51. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java
  52. 3
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java
  53. 7
    9
      sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java
  54. 4
    12
      sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RulesProvider.java
  55. 16
    17
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java
  56. 14
    18
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java
  57. 36
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java
  58. 1
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfiguration.java
  59. 9
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfigurationProvider.java
  60. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java
  61. 2
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableModuleSettings.java
  62. 4
    8
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectReactorProvider.java
  63. 3
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectSettings.java
  64. 3
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectBuildersExecutor.java
  65. 1
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfiguration.java
  66. 10
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfigurationProvider.java
  67. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java
  68. 3
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
  69. 8
    12
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java
  70. 6
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java
  71. 17
    24
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java
  72. 7
    14
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoriesInitializer.java
  73. 11
    14
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfigurationProvider.java
  74. 7
    13
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectBranchesProvider.java
  75. 7
    12
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectPullRequestsProvider.java
  76. 5
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java
  77. 5
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java
  78. 0
    8
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
  79. 6
    10
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java
  80. 3
    6
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java
  81. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorContext.java
  82. 2
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java
  83. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java
  84. 9
    3
      sonar-scanner-engine/src/main/resources/org/sonar/batch/bootstrapper/logback.xml
  85. 0
    4
      sonar-scanner-engine/src/main/resources/org/sonar/batch/logback.xml
  86. 0
    85
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java
  87. 41
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java
  88. 26
    14
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java
  89. 103
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java
  90. 0
    10
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerWsClientProviderTest.java
  91. 213
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java
  92. 34
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringGlobalContainerTest.java
  93. 64
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java
  94. 19
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
  95. 3
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/NoLanguagesPluginsMediumTest.java
  96. 8
    6
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java
  97. 5
    3
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/log/ExceptionHandlingMediumTest.java
  98. 5
    5
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java
  99. 2
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/SpringProjectScanContainerTest.java
  100. 0
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoriesInitializerTest.java

+ 4
- 0
build.gradle View File

dependency 'io.netty:netty-all:4.1.70.Final' dependency 'io.netty:netty-all:4.1.70.Final'
dependency 'com.sun.mail:javax.mail:1.5.6' dependency 'com.sun.mail:javax.mail:1.5.6'
dependency 'javax.annotation:javax.annotation-api:1.3.2' dependency 'javax.annotation:javax.annotation-api:1.3.2'
dependency 'javax.inject:javax.inject:1'
dependency 'javax.servlet:javax.servlet-api:3.1.0' dependency 'javax.servlet:javax.servlet-api:3.1.0'
dependency 'javax.xml.bind:jaxb-api:2.3.0' dependency 'javax.xml.bind:jaxb-api:2.3.0'
dependency 'junit:junit:4.13.2' dependency 'junit:junit:4.13.2'
dependency 'org.simpleframework:simple:4.1.21' dependency 'org.simpleframework:simple:4.1.21'
dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63' dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.36.0.63'
dependency 'org.sonarsource.update-center:sonar-update-center-common:1.23.0.723' dependency 'org.sonarsource.update-center:sonar-update-center-common:1.23.0.723'
dependency('org.springframework:spring-context:5.3.14') {
exclude 'commons-logging:commons-logging'
}
dependency 'org.subethamail:subethasmtp:3.1.7' dependency 'org.subethamail:subethasmtp:3.1.7'
dependency 'org.yaml:snakeyaml:1.26' dependency 'org.yaml:snakeyaml:1.26'
dependency 'xml-apis:xml-apis:1.4.01' dependency 'xml-apis:xml-apis:1.4.01'

+ 4
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/AbstractComputationSteps.java View File

import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import org.sonar.ce.task.step.ComputationStep; import org.sonar.ce.task.step.ComputationStep;
import org.sonar.ce.task.step.ComputationSteps; import org.sonar.ce.task.step.ComputationSteps;
import org.sonar.core.platform.ContainerPopulator;
import org.sonar.core.platform.Container;


/** /**
* Abstract implementation of {@link ComputationStep} which provides the implementation of {@link ComputationSteps#instances()} * Abstract implementation of {@link ComputationStep} which provides the implementation of {@link ComputationSteps#instances()}
* based on a {@link org.sonar.core.platform.ContainerPopulator.Container}.
* based on a {@link org.sonar.core.platform.Container}.
*/ */
public abstract class AbstractComputationSteps implements ComputationSteps { public abstract class AbstractComputationSteps implements ComputationSteps {
private final ContainerPopulator.Container container;
private final Container container;


protected AbstractComputationSteps(ContainerPopulator.Container container) {
protected AbstractComputationSteps(Container container) {
this.container = container; this.container = container;
} }



+ 2
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/AuditPurgeTaskProcessor.java View File

import org.sonar.ce.task.step.ComputationStepExecutor; import org.sonar.ce.task.step.ComputationStepExecutor;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.Container;
import org.sonar.core.platform.ContainerPopulator; import org.sonar.core.platform.ContainerPopulator;


import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE; import static org.sonar.db.ce.CeTaskTypes.AUDIT_PURGE;


public static final class AuditPurgeComputationSteps extends AbstractComputationSteps { public static final class AuditPurgeComputationSteps extends AbstractComputationSteps {


public AuditPurgeComputationSteps(ContainerPopulator.Container container) {
public AuditPurgeComputationSteps(Container container) {
super(container); super(container);
} }



+ 2
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/taskprocessor/IssueSyncTaskProcessor.java View File

import org.sonar.ce.task.step.ComputationStepExecutor; import org.sonar.ce.task.step.ComputationStepExecutor;
import org.sonar.ce.task.taskprocessor.CeTaskProcessor; import org.sonar.ce.task.taskprocessor.CeTaskProcessor;
import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.Container;
import org.sonar.core.platform.ContainerPopulator; import org.sonar.core.platform.ContainerPopulator;


import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC; import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;


public static final class SyncComputationSteps extends AbstractComputationSteps { public static final class SyncComputationSteps extends AbstractComputationSteps {


public SyncComputationSteps(ContainerPopulator.Container container) {
public SyncComputationSteps(Container container) {
super(container); super(container);
} }



+ 2
- 2
server/sonar-ce-task/src/main/java/org/sonar/ce/task/container/TaskContainer.java View File

import org.picocontainer.PicoContainer; import org.picocontainer.PicoContainer;
import org.sonar.ce.task.CeTask; import org.sonar.ce.task.CeTask;
import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ContainerPopulator;
import org.sonar.core.platform.Container;


/** /**
* The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}. * The Compute Engine task container. Created for a specific parent {@link ComponentContainer} and a specific {@link CeTask}.
*/ */
public interface TaskContainer extends ContainerPopulator.Container, AutoCloseable {
public interface TaskContainer extends Container, AutoCloseable {


ComponentContainer getParent(); ComponentContainer getParent();



+ 2
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/engine/MigrationContainer.java View File

*/ */
package org.sonar.server.platform.db.migration.engine; package org.sonar.server.platform.db.migration.engine;


import org.sonar.core.platform.ContainerPopulator;
import org.sonar.core.platform.Container;


/** /**
* A dedicated container used to run DB migrations where all components are lazily instantiated. * A dedicated container used to run DB migrations where all components are lazily instantiated.
* classes only they really are to be executed. * classes only they really are to be executed.
* </p> * </p>
*/ */
public interface MigrationContainer extends ContainerPopulator.Container {
public interface MigrationContainer extends Container {


/** /**
* Cleans up resources after migration has run. * Cleans up resources after migration has run.

+ 2
- 0
sonar-core/build.gradle View File

compile 'commons-codec:commons-codec' compile 'commons-codec:commons-codec'
compile 'commons-io:commons-io' compile 'commons-io:commons-io'
compile 'commons-lang:commons-lang' compile 'commons-lang:commons-lang'
compile 'javax.inject:javax.inject'
compile 'org.codehaus.sonar:sonar-classloader' compile 'org.codehaus.sonar:sonar-classloader'
compile 'org.picocontainer:picocontainer' compile 'org.picocontainer:picocontainer'
compile 'org.slf4j:slf4j-api' compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.update-center:sonar-update-center-common' compile 'org.sonarsource.update-center:sonar-update-center-common'
compile 'org.springframework:spring-context'
compile project(path: ':sonar-plugin-api', configuration: 'shadow') compile project(path: ':sonar-plugin-api', configuration: 'shadow')
compile project(':sonar-plugin-api-impl') compile project(':sonar-plugin-api-impl')



+ 16
- 18
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsInstaller.java View File

import org.sonar.api.utils.AnnotationUtils; import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ExtensionContainer;


import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;


private final CoreExtensionRepository coreExtensionRepository; private final CoreExtensionRepository coreExtensionRepository;
private final Class<? extends Annotation> supportedAnnotationType; private final Class<? extends Annotation> supportedAnnotationType;


protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository,
Class<? extends Annotation> supportedAnnotationType) {
protected CoreExtensionsInstaller(SonarRuntime sonarRuntime, CoreExtensionRepository coreExtensionRepository, Class<? extends Annotation> supportedAnnotationType) {
this.sonarRuntime = sonarRuntime; this.sonarRuntime = sonarRuntime;
this.coreExtensionRepository = coreExtensionRepository; this.coreExtensionRepository = coreExtensionRepository;
this.supportedAnnotationType = supportedAnnotationType; this.supportedAnnotationType = supportedAnnotationType;
* @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether * @param additionalSideFilter applied on top of filtering on {@link #supportedAnnotationType} to decide whether
* extension should be added to container as an object or only as a PropertyDefinition. * extension should be added to container as an object or only as a PropertyDefinition.
*/ */
public void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) {
public void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter) {
coreExtensionRepository.loadedCoreExtensions() coreExtensionRepository.loadedCoreExtensions()
.forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension)); .forEach(coreExtension -> install(container, extensionFilter, additionalSideFilter, coreExtension));
} }


private void install(ComponentContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
private void install(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
String coreExtensionName = coreExtension.getName(); String coreExtensionName = coreExtension.getName();
try { try {
addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension); addDeclaredExtensions(container, extensionFilter, additionalSideFilter, coreExtension);
} }
} }


private void addDeclaredExtensions(ComponentContainer container, Predicate<Object> extensionFilter,
private void addDeclaredExtensions(ExtensionContainer container, Predicate<Object> extensionFilter,
Predicate<Object> additionalSideFilter, CoreExtension coreExtension) { Predicate<Object> additionalSideFilter, CoreExtension coreExtension) {
ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName()); ContextImpl context = new ContextImpl(container, extensionFilter, additionalSideFilter, coreExtension.getName());
coreExtension.load(context); coreExtension.load(context);
} }


private <T> boolean addSupportedExtension(ComponentContainer container, Predicate<Object> additionalSideFilter,
String extensionCategory, T component) {
if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
container.addExtension(extensionCategory, component);
return true;
}
return false;
}

private <T> boolean hasSupportedAnnotation(T component) { private <T> boolean hasSupportedAnnotation(T component) {
return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null; return AnnotationUtils.getAnnotation(component, supportedAnnotationType) != null;
} }


private class ContextImpl implements CoreExtension.Context { private class ContextImpl implements CoreExtension.Context {
private final ComponentContainer container;
private final ExtensionContainer container;
private final Predicate<Object> extensionFilter; private final Predicate<Object> extensionFilter;
private final Predicate<Object> additionalSideFilter; private final Predicate<Object> additionalSideFilter;
private final String extensionCategory; private final String extensionCategory;


public ContextImpl(ComponentContainer container, Predicate<Object> extensionFilter,
Predicate<Object> additionalSideFilter, String extensionCategory) {
public ContextImpl(ExtensionContainer container, Predicate<Object> extensionFilter, Predicate<Object> additionalSideFilter, String extensionCategory) {
this.container = container; this.container = container;
this.extensionFilter = extensionFilter; this.extensionFilter = extensionFilter;
this.additionalSideFilter = additionalSideFilter; this.additionalSideFilter = additionalSideFilter;
components.forEach(this::addExtension); components.forEach(this::addExtension);
return this; return this;
} }

private <T> boolean addSupportedExtension(ExtensionContainer container, Predicate<Object> additionalSideFilter,
String extensionCategory, T component) {
if (hasSupportedAnnotation(component) && additionalSideFilter.test(component)) {
container.addExtension(extensionCategory, component);
return true;
}
return false;
}
} }
} }

+ 2
- 0
sonar-core/src/main/java/org/sonar/core/extension/CoreExtensionsLoader.java View File

import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.stream.MoreCollectors; import org.sonar.core.util.stream.MoreCollectors;
private final CoreExtensionRepository coreExtensionRepository; private final CoreExtensionRepository coreExtensionRepository;
private final ServiceLoaderWrapper serviceLoaderWrapper; private final ServiceLoaderWrapper serviceLoaderWrapper;


@Inject
public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) { public CoreExtensionsLoader(CoreExtensionRepository coreExtensionRepository) {
this(coreExtensionRepository, new ServiceLoaderWrapper()); this(coreExtensionRepository, new ServiceLoaderWrapper());
} }

+ 3
- 0
sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java View File

import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metrics; import org.sonar.api.measures.Metrics;
import org.sonar.api.scanner.ScannerSide; import org.sonar.api.scanner.ScannerSide;
import org.springframework.beans.factory.annotation.Autowired;


import static org.sonar.api.measures.CoreMetrics.CLASSES; import static org.sonar.api.measures.CoreMetrics.CLASSES;
import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY; import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY;


private final Set<Metric> metrics; private final Set<Metric> metrics;


@Autowired(required = false)
public ScannerMetrics() { public ScannerMetrics() {
this.metrics = ALLOWED_CORE_METRICS; this.metrics = ALLOWED_CORE_METRICS;
} }


@Autowired(required = false)
public ScannerMetrics(Metrics[] metricsRepositories) { public ScannerMetrics(Metrics[] metricsRepositories) {
this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet()); this.metrics = Stream.concat(getPluginMetrics(metricsRepositories), ALLOWED_CORE_METRICS.stream()).collect(toSet());
} }

+ 9
- 3
sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java View File

@ScannerSide @ScannerSide
@ServerSide @ServerSide
@ComputeEngineSide @ComputeEngineSide
public class ComponentContainer implements ContainerPopulator.Container {
public class ComponentContainer implements ExtensionContainer {
public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2; public static final int COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER = 2;


private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer { private static final class ExtendedDefaultPicoContainer extends DefaultPicoContainer {
return this; return this;
} }


@Override
public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) { public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
Object key = componentKeys.of(extension); Object key = componentKeys.of(extension);
try { try {
return this; return this;
} }


@Override
public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) { public ComponentContainer addExtension(@Nullable String defaultCategory, Object extension) {
Object key = componentKeys.of(extension); Object key = componentKeys.of(extension);
try { try {
return getName(extension.getClass()); return getName(extension.getClass());
} }


public void declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
@Override
public ComponentContainer declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension); declareExtension(pluginInfo != null ? pluginInfo.getName() : "", extension);
return this;
} }


public void declareExtension(@Nullable String defaultCategory, Object extension) {
@Override
public ComponentContainer declareExtension(@Nullable String defaultCategory, Object extension) {
propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse("")); propertyDefinitions.addComponent(extension, ofNullable(defaultCategory).orElse(""));
return this;
} }


public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) { public ComponentContainer addPicoAdapter(ComponentAdapter<?> adapter) {

+ 12
- 4
sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java View File

import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;


class ComponentKeys {
public class ComponentKeys {
private static final Logger LOG = Loggers.get(ComponentKeys.class);
private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+"); private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+");
private final Set<Class> objectsWithoutToString = new HashSet<>(); private final Set<Class> objectsWithoutToString = new HashSet<>();


Object of(Object component) { Object of(Object component) {
return of(component, Loggers.get(ComponentKeys.class));
return of(component, LOG);
} }


Object of(Object component, Logger log) { Object of(Object component, Logger log) {
if (component instanceof Class) { if (component instanceof Class) {
return component; return component;
} }
return ofInstance(component, log);
}

public String ofInstance(Object component) {
return ofInstance(component, LOG);
}

String ofInstance(Object component, Logger log) {
String key = component.toString(); String key = component.toString();
if (IDENTITY_HASH_PATTERN.matcher(key).matches()) { if (IDENTITY_HASH_PATTERN.matcher(key).matches()) {
if (!objectsWithoutToString.add(component.getClass())) { if (!objectsWithoutToString.add(component.getClass())) {
} }
key += Uuids.create(); key += Uuids.create();
} }
return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString();
return component.getClass().getCanonicalName() + "-" + key;
} }
} }

+ 34
- 0
sonar-core/src/main/java/org/sonar/core/platform/Container.java View File

/*
* 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();
}

+ 1
- 13
sonar-core/src/main/java/org/sonar/core/platform/ContainerPopulator.java View File

*/ */
package org.sonar.core.platform; package org.sonar.core.platform;


import java.util.List;

@FunctionalInterface @FunctionalInterface
public interface ContainerPopulator<T extends ContainerPopulator.Container> {
public interface ContainerPopulator<T extends Container> {
void populateContainer(T container); void populateContainer(T container);

interface Container {
Container add(Object... objects);

Container addSingletons(Iterable<?> components);

<T> T getComponentByType(Class<T> type);

<T> List<T> getComponentsByType(Class<T> type);
}
} }

+ 36
- 0
sonar-core/src/main/java/org/sonar/core/platform/ExtensionContainer.java View File

/*
* 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();
}

+ 2
- 0
sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java View File

import java.util.Optional; import java.util.Optional;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
private final Integer readTimeout; private final Integer readTimeout;
private final Integer connectTimeout; private final Integer connectTimeout;


@Inject
public DefaultHttpDownloader(Server server, Configuration config) { public DefaultHttpDownloader(Server server, Configuration config) {
this(server, config, null); this(server, config, null);
} }

+ 8
- 1
sonar-plugin-api-impl/src/main/java/org/sonar/api/impl/utils/DefaultTempFolder.java View File

import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.sonar.api.Startable;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;


import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;


public class DefaultTempFolder implements TempFolder {
public class DefaultTempFolder implements TempFolder, Startable {
private static final Logger LOG = Loggers.get(DefaultTempFolder.class); private static final Logger LOG = Loggers.get(DefaultTempFolder.class);


private final File tempDir; private final File tempDir;
} }
} }


@Override
public void start() {
// nothing to do
}

@Override
public void stop() { public void stop() {
if (deleteOnExit) { if (deleteOnExit) {
clean(); clean();

+ 4
- 4
sonar-plugin-api/src/test/java/org/sonar/api/resources/LanguagesTest.java View File

@Test @Test
public void should_add_several_times_the_same_language() { public void should_add_several_times_the_same_language() {
Languages languages = new Languages( Languages languages = new Languages(
language("fake"),
language("fake"));
language("fake"),
language("fake"));


assertThat(languages.get("fake").getKey()).isEqualTo("fake"); assertThat(languages.get("fake").getKey()).isEqualTo("fake");
} }
@Test @Test
public void should_get_suffixes() { public void should_get_suffixes() {
Languages languages = new Languages( Languages languages = new Languages(
language("java", "java"),
language("php", "php4", "php5"));
language("java", "java"),
language("php", "php4", "php5"));


assertThat(languages.getSuffixes()).containsOnly("java", "php4", "php5"); assertThat(languages.getSuffixes()).containsOnly("java", "php4", "php5");
assertThat(languages.getSuffixes("java")).containsOnly("java"); assertThat(languages.getSuffixes("java")).containsOnly("java");

+ 3
- 0
sonar-scanner-engine/build.gradle View File

compile 'com.google.protobuf:protobuf-java' compile 'com.google.protobuf:protobuf-java'
compile 'com.squareup.okhttp3:okhttp' compile 'com.squareup.okhttp3:okhttp'
compile 'com.fasterxml.staxmate:staxmate' compile 'com.fasterxml.staxmate:staxmate'
compile 'javax.annotation:javax.annotation-api'
compile 'org.eclipse.jgit:org.eclipse.jgit' compile 'org.eclipse.jgit:org.eclipse.jgit'
compile 'org.tmatesoft.svnkit:svnkit' compile 'org.tmatesoft.svnkit:svnkit'
compile 'org.picocontainer:picocontainer' compile 'org.picocontainer:picocontainer'
compile 'org.slf4j:log4j-over-slf4j' compile 'org.slf4j:log4j-over-slf4j'
compile 'org.slf4j:slf4j-api' compile 'org.slf4j:slf4j-api'
compile 'org.sonarsource.update-center:sonar-update-center-common' compile 'org.sonarsource.update-center:sonar-update-center-common'
compile 'org.springframework:spring-context'



compile project(':sonar-core') compile project(':sonar-core')
compile project(':sonar-scanner-protocol') compile project(':sonar-scanner-protocol')

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/batch/bootstrapper/Batch.java View File

import java.util.Map; import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.scanner.bootstrap.GlobalContainer;
import org.sonar.scanner.bootstrap.SpringGlobalContainer;


/** /**
* Entry point for SonarQube Scanner API 2.1+. * Entry point for SonarQube Scanner API 2.1+.
public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) { public synchronized Batch doExecute(Map<String, String> scannerProperties, List<Object> components) {
configureLogging(); configureLogging();
try { try {
GlobalContainer.create(scannerProperties, components).execute();
SpringGlobalContainer.create(scannerProperties, components).execute();
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw handleException(e); throw handleException(e);
} }

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectInfo.java View File

import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.Startable;
import org.sonar.api.config.Configuration; import org.sonar.api.config.Configuration;
import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
*/ */
public class ProjectInfo implements Startable { public class ProjectInfo implements Startable {
private final Clock clock; private final Clock clock;
private Configuration settings;
private final Configuration settings;


private Date analysisDate; private Date analysisDate;
private String projectVersion; private String projectVersion;

+ 11
- 44
sonar-scanner-engine/src/main/java/org/sonar/scanner/analysis/AnalysisTempFolderProvider.java View File

import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.impl.utils.DefaultTempFolder; import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;
import org.springframework.context.annotation.Bean;


public class AnalysisTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
public class AnalysisTempFolderProvider {
static final String TMP_NAME = ".sonartmp"; static final String TMP_NAME = ".sonartmp";
private DefaultTempFolder projectTempFolder;
private boolean started = false;


@Bean("TempFolder")
public TempFolder provide(DefaultInputProject project) { public TempFolder provide(DefaultInputProject project) {
if (projectTempFolder == null) {
Path workingDir = project.getWorkDir();
Path tempDir = workingDir.normalize().resolve(TMP_NAME);
try {
Files.deleteIfExists(tempDir);
Files.createDirectories(tempDir);
} catch (IOException e) {
throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
}

projectTempFolder = new DefaultTempFolder(tempDir.toFile(), true);
}
return projectTempFolder;
}

@Override
public void start(PicoContainer container) {
started = true;
}

@Override
public void stop(PicoContainer container) {
if (projectTempFolder != null) {
projectTempFolder.stop();
Path workingDir = project.getWorkDir();
Path tempDir = workingDir.normalize().resolve(TMP_NAME);
try {
Files.deleteIfExists(tempDir);
Files.createDirectories(tempDir);
} catch (IOException e) {
throw new IllegalStateException("Unable to create root temp directory " + tempDir, e);
} }
}

@Override
public void dispose(PicoContainer container) {
// nothing to do
}

@Override
public boolean componentHasLifecycle() {
return true;
}


@Override
public boolean isStarted() {
return started;
return new DefaultTempFolder(tempDir.toFile(), true);
} }
} }

+ 5
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/AbstractExtensionDictionary.java View File

import org.sonar.api.batch.Phase; import org.sonar.api.batch.Phase;
import org.sonar.api.utils.AnnotationUtils; import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.dag.DirectAcyclicGraph; import org.sonar.api.utils.dag.DirectAcyclicGraph;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ExtensionContainer;


public abstract class AbstractExtensionDictionary { public abstract class AbstractExtensionDictionary {


private final ComponentContainer componentContainer;
private final ExtensionContainer componentContainer;


public AbstractExtensionDictionary(ComponentContainer componentContainer) {
protected AbstractExtensionDictionary(ExtensionContainer componentContainer) {
this.componentContainer = componentContainer; this.componentContainer = componentContainer;
} }


return extensions; return extensions;
} }


private static <T> void completeScannerExtensions(ComponentContainer container, List<T> extensions, Class<T> type) {
private static <T> void completeScannerExtensions(ExtensionContainer container, List<T> extensions, Class<T> type) {
extensions.addAll(container.getComponentsByType(type)); extensions.addAll(container.getComponentsByType(type));
ComponentContainer parentContainer = container.getParent();
ExtensionContainer parentContainer = container.getParent();
if (parentContainer != null) { if (parentContainer != null) {
completeScannerExtensions(parentContainer, extensions, type); completeScannerExtensions(parentContainer, extensions, type);
} }

+ 62
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ClassDerivedBeanDefinition.java View File

/*
* 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);
}
}

+ 3
- 4
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ExtensionInstaller.java View File

import org.sonar.api.SonarRuntime; import org.sonar.api.SonarRuntime;
import org.sonar.api.config.Configuration; import org.sonar.api.config.Configuration;
import org.sonar.api.internal.PluginContextImpl; import org.sonar.api.internal.PluginContextImpl;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ExtensionContainer;
import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository; import org.sonar.core.platform.PluginRepository;


this.bootConfiguration = bootConfiguration; this.bootConfiguration = bootConfiguration;
} }


public ExtensionInstaller install(ComponentContainer container, ExtensionMatcher matcher) {

public ExtensionInstaller install(ExtensionContainer container, ExtensionMatcher matcher) {
// core components // core components
for (Object o : BatchComponents.all()) { for (Object o : BatchComponents.all()) {
doInstall(container, matcher, null, o); doInstall(container, matcher, null, o);
return this; return this;
} }


private static void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
private static void doInstall(ExtensionContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
if (matcher.accept(extension)) { if (matcher.accept(extension)) {
container.addExtension(pluginInfo, extension); container.addExtension(pluginInfo, extension);
} else { } else {

+ 1
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfiguration.java View File



import java.util.Map; import java.util.Map;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration; import org.sonar.scanner.config.DefaultConfiguration;


@Immutable @Immutable
public class GlobalConfiguration extends DefaultConfiguration { public class GlobalConfiguration extends DefaultConfiguration {

public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) { public GlobalConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> settings) {
super(propertyDefinitions, encryption, settings); super(propertyDefinitions, encryption, settings);
} }

} }

+ 8
- 15
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalConfigurationProvider.java View File



import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.PropertyDefinitions;
import org.springframework.context.annotation.Bean;


public class GlobalConfigurationProvider extends ProviderAdapter {

private GlobalConfiguration globalConfig;

public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps,
PropertyDefinitions propertyDefinitions) {
if (globalConfig == null) {
Map<String, String> mergedSettings = new LinkedHashMap<>();
mergedSettings.putAll(globalServerSettings.properties());
mergedSettings.putAll(scannerProps.properties());

globalConfig = new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
}
return globalConfig;
public class GlobalConfigurationProvider {
@Bean("GlobalConfiguration")
public GlobalConfiguration provide(GlobalServerSettings globalServerSettings, ScannerProperties scannerProps, PropertyDefinitions propertyDefinitions) {
Map<String, String> mergedSettings = new LinkedHashMap<>();
mergedSettings.putAll(globalServerSettings.properties());
mergedSettings.putAll(scannerProps.properties());
return new GlobalConfiguration(propertyDefinitions, scannerProps.getEncryption(), mergedSettings);
} }
} }

+ 6
- 11
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalServerSettingsProvider.java View File



import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
import org.springframework.context.annotation.Bean;


public class GlobalServerSettingsProvider extends ProviderAdapter {

public class GlobalServerSettingsProvider {
private static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class); private static final Logger LOG = Loggers.get(GlobalServerSettingsProvider.class);


private GlobalServerSettings singleton;

@Bean("GlobalServerSettings")
public GlobalServerSettings provide(GlobalSettingsLoader loader) { public GlobalServerSettings provide(GlobalSettingsLoader loader) {
if (singleton == null) {
Map<String, String> serverSideSettings = loader.loadGlobalSettings();
singleton = new GlobalServerSettings(serverSideSettings);
Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
}
return singleton;
Map<String, String> serverSideSettings = loader.loadGlobalSettings();
Optional.ofNullable(serverSideSettings.get(CoreProperties.SERVER_ID)).ifPresent(v -> LOG.info("Server id: {}", v));
return new GlobalServerSettings(serverSideSettings);
} }
} }

+ 7
- 23
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalTempFolderProvider.java View File

import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.picocontainer.ComponentLifecycle;
import org.picocontainer.PicoContainer;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.Startable;
import org.sonar.api.impl.utils.DefaultTempFolder; import org.sonar.api.impl.utils.DefaultTempFolder;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.springframework.context.annotation.Bean;


import static org.sonar.core.util.FileUtils.deleteQuietly; import static org.sonar.core.util.FileUtils.deleteQuietly;


public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle<TempFolder> {
public class GlobalTempFolderProvider implements Startable {
private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class); private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class);
private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21); private static final long CLEAN_MAX_AGE = TimeUnit.DAYS.toMillis(21);
static final String TMP_NAME_PREFIX = ".sonartmp_"; static final String TMP_NAME_PREFIX = ".sonartmp_";
private boolean started = false;


private System2 system; private System2 system;
private DefaultTempFolder tempFolder; private DefaultTempFolder tempFolder;
this.system = system; this.system = system;
} }


@Bean("TempFolder")
public TempFolder provide(ScannerProperties scannerProps) { public TempFolder provide(ScannerProperties scannerProps) {
if (tempFolder == null) { if (tempFolder == null) {


} }


@Override @Override
public void start(PicoContainer container) {
started = true;
public void start() {
// nothing to do
} }


@Override @Override
public void stop(PicoContainer container) {
public void stop() {
if (tempFolder != null) { if (tempFolder != null) {
tempFolder.stop(); tempFolder.stop();
} }
} }

@Override
public void dispose(PicoContainer container) {
// nothing to do
}

@Override
public boolean componentHasLifecycle() {
return true;
}

@Override
public boolean isStarted() {
return started;
}
} }

+ 35
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessor.java View File

/*
* 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);
}
}
}

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PluginFiles.java View File

LOGGER.debug("Unpacking plugin {}", pluginKey); LOGGER.debug("Unpacking plugin {}", pluginKey);
File jar = newTempFile(); File jar = newTempFile();
try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile))); try (InputStream input = new GZIPInputStream(new BufferedInputStream(FileUtils.openInputStream(compressedFile)));
JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
JarOutputStream output = new JarOutputStream(new BufferedOutputStream(FileUtils.openOutputStream(jar)))) {
Pack200.newUnpacker().unpack(input, output); Pack200.newUnpacker().unpack(input, output);
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e); throw new IllegalStateException(format("Fail to download plugin [%s]. Pack200 error.", pluginKey), e);

+ 3
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PostJobExtensionDictionary.java View File

import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.sonar.api.batch.postjob.PostJob; import org.sonar.api.batch.postjob.PostJob;
import org.sonar.api.batch.postjob.PostJobContext; import org.sonar.api.batch.postjob.PostJobContext;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.ExtensionContainer;
import org.sonar.scanner.postjob.PostJobOptimizer; import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.postjob.PostJobWrapper; import org.sonar.scanner.postjob.PostJobWrapper;


private final PostJobContext postJobContext; private final PostJobContext postJobContext;
private final PostJobOptimizer postJobOptimizer; private final PostJobOptimizer postJobOptimizer;


public PostJobExtensionDictionary(ComponentContainer componentContainer, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
super(componentContainer);
public PostJobExtensionDictionary(ExtensionContainer container, PostJobOptimizer postJobOptimizer, PostJobContext postJobContext) {
super(container);
this.postJobOptimizer = postJobOptimizer; this.postJobOptimizer = postJobOptimizer;
this.postJobContext = postJobContext; this.postJobContext = postJobContext;
} }

+ 123
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/PriorityBeanFactory.java View File

/*
* 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);
}
}

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerPluginRepository.java View File

import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import org.picocontainer.Startable;
import org.sonar.api.Plugin; import org.sonar.api.Plugin;
import org.sonar.api.Startable;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.core.platform.ExplodedPlugin; import org.sonar.core.platform.ExplodedPlugin;

+ 23
- 29
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/ScannerWsClientProvider.java View File

*/ */
package org.sonar.scanner.bootstrap; package org.sonar.scanner.bootstrap;


import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.batch.bootstrapper.EnvironmentInformation; import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonarqube.ws.client.HttpConnector; import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.WsClientFactories; import org.sonarqube.ws.client.WsClientFactories;
import org.springframework.context.annotation.Bean;


import static java.lang.Integer.parseInt; import static java.lang.Integer.parseInt;
import static java.lang.String.valueOf; import static java.lang.String.valueOf;
import static org.apache.commons.lang.StringUtils.defaultIfBlank; import static org.apache.commons.lang.StringUtils.defaultIfBlank;


public class ScannerWsClientProvider extends ProviderAdapter {

public class ScannerWsClientProvider {
static final int CONNECT_TIMEOUT_MS = 5_000; static final int CONNECT_TIMEOUT_MS = 5_000;
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout"; static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout";
static final int DEFAULT_READ_TIMEOUT_SEC = 60; static final int DEFAULT_READ_TIMEOUT_SEC = 60;


private DefaultScannerWsClient wsClient;

public synchronized DefaultScannerWsClient provide(final ScannerProperties scannerProps,
final EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
if (wsClient == null) {
String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();

String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
connectorBuilder
.readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
.userAgent(env.toString())
.url(url)
.credentials(login, scannerProps.property(CoreProperties.PASSWORD));

// OkHttp detect 'http.proxyHost' java property, but credentials should be filled
final String proxyUser = System.getProperty("http.proxyUser", "");
if (!proxyUser.isEmpty()) {
connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
}

wsClient = new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
@Bean("DefaultScannerWsClient")
public DefaultScannerWsClient provide(ScannerProperties scannerProps, EnvironmentInformation env, GlobalAnalysisMode globalMode, System2 system) {
String url = defaultIfBlank(scannerProps.property("sonar.host.url"), "http://localhost:9000");
HttpConnector.Builder connectorBuilder = HttpConnector.newBuilder();

String timeoutSec = defaultIfBlank(scannerProps.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
String token = defaultIfBlank(system.envVariable("SONAR_TOKEN"), null);
String login = defaultIfBlank(scannerProps.property(CoreProperties.LOGIN), token);
connectorBuilder
.readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
.userAgent(env.toString())
.url(url)
.credentials(login, scannerProps.property(CoreProperties.PASSWORD));

// OkHttp detect 'http.proxyHost' java property, but credentials should be filled
final String proxyUser = System.getProperty("http.proxyUser", "");
if (!proxyUser.isEmpty()) {
connectorBuilder.proxyCredentials(proxyUser, System.getProperty("http.proxyPassword"));
} }
return wsClient;

return new DefaultScannerWsClient(WsClientFactories.getDefault().newClient(connectorBuilder.build()), login != null, globalMode);
} }
} }

+ 231
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringComponentContainer.java View File

/*
* 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
}
}

sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java → sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/SpringGlobalContainer.java View File

import java.time.Clock; import java.time.Clock;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Priority;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.Plugin; import org.sonar.api.Plugin;
import org.sonar.api.SonarEdition; import org.sonar.api.SonarEdition;
import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarQubeVersion; import org.sonar.api.SonarQubeVersion;
import org.sonar.api.SonarRuntime;
import org.sonar.api.internal.MetadataLoader; import org.sonar.api.internal.MetadataLoader;
import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.internal.SonarRuntimeImpl;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.core.extension.CoreExtensionRepositoryImpl; import org.sonar.core.extension.CoreExtensionRepositoryImpl;
import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.extension.CoreExtensionsLoader;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.platform.PluginClassLoader; import org.sonar.core.platform.PluginClassLoader;
import org.sonar.core.platform.PluginClassloaderFactory; import org.sonar.core.platform.PluginClassloaderFactory;
import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginInfo;
import org.sonar.scanner.platform.DefaultServer; import org.sonar.scanner.platform.DefaultServer;
import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader; import org.sonar.scanner.repository.DefaultMetricsRepositoryLoader;
import org.sonar.scanner.repository.DefaultNewCodePeriodLoader; import org.sonar.scanner.repository.DefaultNewCodePeriodLoader;
import org.sonar.scanner.repository.MetricsRepositoryLoader;
import org.sonar.scanner.repository.MetricsRepositoryProvider; import org.sonar.scanner.repository.MetricsRepositoryProvider;
import org.sonar.scanner.repository.NewCodePeriodLoader;
import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader; import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
import org.sonar.scanner.scan.ProjectScanContainer;
import org.sonar.scanner.scan.SpringProjectScanContainer;


public class GlobalContainer extends ComponentContainer {
private static final Logger LOG = Loggers.get(GlobalContainer.class);
@Priority(3)
public class SpringGlobalContainer extends SpringComponentContainer {
private static final Logger LOG = Loggers.get(SpringGlobalContainer.class);
private final Map<String, String> scannerProperties; private final Map<String, String> scannerProperties;


private GlobalContainer(Map<String, String> scannerProperties) {
super();
private SpringGlobalContainer(Map<String, String> scannerProperties, List<?> addedExternally) {
super(addedExternally);
this.scannerProperties = scannerProperties; this.scannerProperties = scannerProperties;
} }


public static GlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
GlobalContainer container = new GlobalContainer(scannerProperties);
container.add(extensions);
return container;
public static SpringGlobalContainer create(Map<String, String> scannerProperties, List<?> extensions) {
return new SpringGlobalContainer(scannerProperties, extensions);
} }


@Override @Override
protected void doBeforeStart() {
public void doBeforeStart() {
ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties); ScannerProperties rawScannerProperties = new ScannerProperties(scannerProperties);
GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties); GlobalAnalysisMode globalMode = new GlobalAnalysisMode(rawScannerProperties);
add(rawScannerProperties); add(rawScannerProperties);
new ScannerWsClientProvider(), new ScannerWsClientProvider(),
DefaultServer.class, DefaultServer.class,
new GlobalTempFolderProvider(), new GlobalTempFolderProvider(),
DefaultHttpDownloader.class,
analysisWarnings, analysisWarnings,
UriReader.class, UriReader.class,
PluginFiles.class, PluginFiles.class,
System2.INSTANCE, System2.INSTANCE,
Clock.systemDefaultZone(), Clock.systemDefaultZone(),
new MetricsRepositoryProvider(), new MetricsRepositoryProvider(),
UuidFactoryImpl.INSTANCE);
addIfMissing(SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition), SonarRuntime.class);
addIfMissing(ScannerPluginInstaller.class, PluginInstaller.class);
add(CoreExtensionRepositoryImpl.class, CoreExtensionsLoader.class, ScannerCoreExtensionsInstaller.class);
addIfMissing(DefaultGlobalSettingsLoader.class, GlobalSettingsLoader.class);
addIfMissing(DefaultNewCodePeriodLoader.class, NewCodePeriodLoader.class);
addIfMissing(DefaultMetricsRepositoryLoader.class, MetricsRepositoryLoader.class);
UuidFactoryImpl.INSTANCE,
DefaultHttpDownloader.class,
SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER, edition),
ScannerPluginInstaller.class,
CoreExtensionRepositoryImpl.class,
CoreExtensionsLoader.class,
ScannerCoreExtensionsInstaller.class,
DefaultGlobalSettingsLoader.class,
DefaultNewCodePeriodLoader.class,
DefaultMetricsRepositoryLoader.class);
} }


@Override @Override
if (!analysisMode.equals("publish")) { if (!analysisMode.equals("publish")) {
throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter."); throw MessageException.of("The preview mode, along with the 'sonar.analysis.mode' parameter, is no more supported. You should stop using this parameter.");
} }
new ProjectScanContainer(this).execute();
new SpringProjectScanContainer(this).execute();


LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime)); LOG.info("Analysis total time: {}", formatTime(System.currentTimeMillis() - startTime));
} }
} }


private void loadCoreExtensions() { private void loadCoreExtensions() {
CoreExtensionsLoader loader = getComponentByType(CoreExtensionsLoader.class);
loader.load();
getComponentByType(CoreExtensionsLoader.class).load();
} }


static String formatTime(long time) { static String formatTime(long time) {
} }
return String.format(format, h, m, s, ms); return String.format(format, h, m, s, ms);
} }

} }

+ 60
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessor.java View File

/*
* 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);
}
}
}

+ 3
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/ci/CiConfigurationProvider.java View File

import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.config.Configuration; import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.springframework.context.annotation.Bean;


public class CiConfigurationProvider extends ProviderAdapter {
public class CiConfigurationProvider {


private static final Logger LOG = Loggers.get(CiConfigurationProvider.class); private static final Logger LOG = Loggers.get(CiConfigurationProvider.class);
private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled"; private static final String PROP_DISABLED = "sonar.ci.autoconfig.disabled";


@Bean("CiConfiguration")
public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) { public CiConfiguration provide(Configuration configuration, CiVendor[] ciVendors) {
boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false); boolean disabled = configuration.getBoolean(PROP_DISABLED).orElse(false);
if (disabled) { if (disabled) {

+ 3
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/cpd/CpdExecutor.java View File

import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject;
import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputComponent; import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile;
private int count = 0; private int count = 0;
private int total; private int total;


@Inject
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) { public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache) {
this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor()); this(settings, index, publisher, inputComponentCache, Executors.newSingleThreadExecutor());
} }


public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache,
ExecutorService executorService) {
public CpdExecutor(CpdSettings settings, SonarCpdBlockIndex index, ReportPublisher publisher, InputComponentStore inputComponentCache, ExecutorService executorService) {
this.settings = settings; this.settings = settings;
this.index = index; this.index = index;
this.publisher = publisher; this.publisher = publisher;

+ 3
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java View File

import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain; import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport;
import org.springframework.beans.factory.annotation.Autowired;


/** /**
* @deprecated since 7.6, {@link IssueFilter} is deprecated * @deprecated since 7.6, {@link IssueFilter} is deprecated
private final IssueFilterChain filterChain; private final IssueFilterChain filterChain;
private final DefaultInputProject project; private final DefaultInputProject project;


@Autowired(required = false)
public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) { public IssueFilters(DefaultInputProject project, IssueFilter[] exclusionFilters) {
this.project = project; this.project = project;
this.filterChain = new DefaultIssueFilterChain(exclusionFilters); this.filterChain = new DefaultIssueFilterChain(exclusionFilters);
} }


@Autowired(required = false)
public IssueFilters(DefaultInputProject project) { public IssueFilters(DefaultInputProject project) {
this(project, new IssueFilter[0]); this(project, new IssueFilter[0]);
} }

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObserver.java View File



import org.sonar.api.ExtensionPoint; import org.sonar.api.ExtensionPoint;
import org.sonar.api.scanner.ScannerSide; import org.sonar.api.scanner.ScannerSide;
import org.sonar.scanner.scan.ProjectScanContainer;
import org.sonar.scanner.scan.SpringProjectScanContainer;


@ScannerSide @ScannerSide
@ExtensionPoint @ExtensionPoint
@FunctionalInterface @FunctionalInterface
public interface AnalysisObserver { public interface AnalysisObserver {


void analysisCompleted(ProjectScanContainer container);
void analysisCompleted(SpringProjectScanContainer container);


} }

+ 4
- 8
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisObservers.java View File

*/ */
package org.sonar.scanner.mediumtest; package org.sonar.scanner.mediumtest;


import org.sonar.scanner.scan.ProjectScanContainer;
import org.sonar.scanner.scan.SpringProjectScanContainer;


public class AnalysisObservers { public class AnalysisObservers {


private AnalysisObserver[] observers;
private ProjectScanContainer projectScanContainer;
private final AnalysisObserver[] observers;
private final SpringProjectScanContainer projectScanContainer;


public AnalysisObservers(ProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
public AnalysisObservers(SpringProjectScanContainer projectScanContainer, AnalysisObserver... observers) {
this.projectScanContainer = projectScanContainer; this.projectScanContainer = projectScanContainer;
this.observers = observers; this.observers = observers;
} }


public AnalysisObservers(ProjectScanContainer projectScanContainer) {
this(projectScanContainer, new AnalysisObserver[0]);
}

public void notifyEndOfScanTask() { public void notifyEndOfScanTask() {
for (AnalysisObserver analysisObserver : observers) { for (AnalysisObserver analysisObserver : observers) {
analysisObserver.analysisCompleted(projectScanContainer); analysisObserver.analysisCompleted(projectScanContainer);

+ 3
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisResult.java View File

import org.sonar.scanner.protocol.output.ScannerReportReader; import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.report.ReportPublisher; import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.report.ScannerReportUtils; import org.sonar.scanner.report.ScannerReportUtils;
import org.sonar.scanner.scan.ProjectScanContainer;
import org.sonar.scanner.scan.SpringProjectScanContainer;
import org.sonar.scanner.scan.filesystem.InputComponentStore; import org.sonar.scanner.scan.filesystem.InputComponentStore;


public class AnalysisResult implements AnalysisObserver { public class AnalysisResult implements AnalysisObserver {
private ScannerReportReader reader; private ScannerReportReader reader;


@Override @Override
public void analysisCompleted(ProjectScanContainer container) {
public void analysisCompleted(SpringProjectScanContainer container) {
LOG.info("Store analysis results in memory for later assertions in medium test"); LOG.info("Store analysis results in memory for later assertions in medium test");
ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class); ReportPublisher reportPublisher = container.getComponentByType(ReportPublisher.class);
reader = new ScannerReportReader(reportPublisher.getReportDir().toFile()); reader = new ScannerReportReader(reportPublisher.getReportDir().toFile());
return reader; return reader;
} }


private void storeFs(ProjectScanContainer container) {
private void storeFs(SpringProjectScanContainer container) {
InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class); InputComponentStore inputFileCache = container.getComponentByType(InputComponentStore.class);
for (InputFile inputPath : inputFileCache.inputFiles()) { for (InputFile inputPath : inputFileCache.inputFiles()) {
inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath); inputFilesByKeys.put(((DefaultInputFile) inputPath).getProjectRelativePath(), inputPath);

+ 2
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/FakePluginInstaller.java View File

import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Priority;
import org.sonar.api.Plugin; import org.sonar.api.Plugin;
import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginInfo;
import org.sonar.scanner.bootstrap.PluginInstaller; import org.sonar.scanner.bootstrap.PluginInstaller;
import org.sonar.scanner.bootstrap.ScannerPlugin; import org.sonar.scanner.bootstrap.ScannerPlugin;


@Priority(1)
public class FakePluginInstaller implements PluginInstaller { public class FakePluginInstaller implements PluginInstaller {


private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>(); private final Map<String, ScannerPlugin> pluginsByKeys = new HashMap<>();

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/qualitygate/QualityGateCheck.java View File

import java.time.Duration; import java.time.Duration;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.EnumSet; import java.util.EnumSet;
import org.picocontainer.Startable;
import org.sonar.api.Startable;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;

+ 1
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ContextPropertiesPublisher.java View File

private final ScmConfiguration scmConfiguration; private final ScmConfiguration scmConfiguration;
private final CiConfiguration ciConfiguration; private final CiConfiguration ciConfiguration;


public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration,
CiConfiguration ciConfiguration) {
public ContextPropertiesPublisher(ContextPropertiesCache cache, DefaultConfiguration config, ScmConfiguration scmConfiguration, CiConfiguration ciConfiguration) {
this.cache = cache; this.cache = cache;
this.config = config; this.config = config;
this.scmConfiguration = scmConfiguration; this.scmConfiguration = scmConfiguration;

+ 4
- 4
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java View File

import javax.annotation.Nullable; import javax.annotation.Nullable;
import okhttp3.HttpUrl; import okhttp3.HttpUrl;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
import org.sonar.api.Startable;
import org.sonar.api.platform.Server; import org.sonar.api.platform.Server;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.TempFolder; import org.sonar.api.utils.TempFolder;
this.branchConfiguration = branchConfiguration; this.branchConfiguration = branchConfiguration;
this.properties = properties; this.properties = properties;
this.ceTaskReportDataHolder = ceTaskReportDataHolder; this.ceTaskReportDataHolder = ceTaskReportDataHolder;
this.reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
this.writer = new ScannerReportWriter(reportDir.toFile());
this.reader = new ScannerReportReader(reportDir.toFile());
} }


@Override @Override
public void start() { public void start() {
reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report");
writer = new ScannerReportWriter(reportDir.toFile());
reader = new ScannerReportReader(reportDir.toFile());
contextPublisher.init(writer); contextPublisher.init(writer);


if (!analysisMode.isMediumTest()) { if (!analysisMode.isMediumTest()) {

+ 6
- 8
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/MetricsRepositoryProvider.java View File

*/ */
package org.sonar.scanner.repository; package org.sonar.scanner.repository;


import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.springframework.context.annotation.Bean;


public class MetricsRepositoryProvider extends ProviderAdapter {
public class MetricsRepositoryProvider {


private static final Logger LOG = Loggers.get(MetricsRepositoryProvider.class); private static final Logger LOG = Loggers.get(MetricsRepositoryProvider.class);
private static final String LOG_MSG = "Load metrics repository"; private static final String LOG_MSG = "Load metrics repository";
private MetricsRepository metricsRepository;


@Bean("MetricsRepository")
public MetricsRepository provide(MetricsRepositoryLoader loader) { public MetricsRepository provide(MetricsRepositoryLoader loader) {
if (metricsRepository == null) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
metricsRepository = loader.load();
profiler.stopInfo();
}
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
MetricsRepository metricsRepository = loader.load();
profiler.stopInfo();
return metricsRepository; return metricsRepository;
} }
} }

+ 6
- 9
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/QualityProfilesProvider.java View File

*/ */
package org.sonar.scanner.repository; package org.sonar.scanner.repository;


import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties; import org.sonar.scanner.bootstrap.ScannerProperties;
import org.sonar.scanner.rule.QualityProfiles; import org.sonar.scanner.rule.QualityProfiles;
import org.springframework.context.annotation.Bean;


public class QualityProfilesProvider extends ProviderAdapter {
public class QualityProfilesProvider {
private static final Logger LOG = Loggers.get(QualityProfilesProvider.class); private static final Logger LOG = Loggers.get(QualityProfilesProvider.class);
private static final String LOG_MSG = "Load quality profiles"; private static final String LOG_MSG = "Load quality profiles";
private QualityProfiles profiles = null;


@Bean("QualityProfiles")
public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) { public QualityProfiles provide(QualityProfileLoader loader, ScannerProperties props) {
if (this.profiles == null) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
profiles = new QualityProfiles(loader.load(props.getProjectKey()));
profiler.stopInfo();
}

Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
QualityProfiles profiles = new QualityProfiles(loader.load(props.getProjectKey()));
profiler.stopInfo();
return profiles; return profiles;
} }



+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/language/DefaultLanguagesRepository.java View File

import java.util.Collection; import java.util.Collection;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.picocontainer.Startable;
import org.sonar.api.Startable;
import org.sonar.api.resources.Languages; import org.sonar.api.resources.Languages;


/** /**

+ 3
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/settings/DefaultGlobalSettingsLoader.java View File

package org.sonar.scanner.repository.settings; package org.sonar.scanner.repository.settings;


import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import org.sonar.scanner.bootstrap.DefaultScannerWsClient; import org.sonar.scanner.bootstrap.DefaultScannerWsClient;


public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader { public class DefaultGlobalSettingsLoader extends AbstractSettingsLoader implements GlobalSettingsLoader {


public DefaultGlobalSettingsLoader(final DefaultScannerWsClient wsClient) {
@Inject
public DefaultGlobalSettingsLoader(DefaultScannerWsClient wsClient) {
super(wsClient); super(wsClient);
} }



+ 7
- 9
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java View File

import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.rule.LoadedActiveRule; import org.sonar.api.batch.rule.LoadedActiveRule;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.internal.DefaultActiveRules; import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.springframework.context.annotation.Bean;


/** /**
* Loads the rules that are activated on the Quality profiles * Loads the rules that are activated on the Quality profiles
* used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}. * used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}.
*/ */
public class ActiveRulesProvider extends ProviderAdapter {
public class ActiveRulesProvider {
private static final Logger LOG = Loggers.get(ActiveRulesProvider.class); private static final Logger LOG = Loggers.get(ActiveRulesProvider.class);
private static final String LOG_MSG = "Load active rules"; private static final String LOG_MSG = "Load active rules";
private DefaultActiveRules singleton = null;


@Bean("ActiveRules")
public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) { public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) {
if (singleton == null) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
singleton = load(loader, qProfiles);
profiler.stopInfo();
}
return singleton;
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
DefaultActiveRules activeRules = load(loader, qProfiles);
profiler.stopInfo();
return activeRules;
} }


private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) { private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) {

+ 4
- 12
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/RulesProvider.java View File

package org.sonar.scanner.rule; package org.sonar.scanner.rule;


import java.util.List; import java.util.List;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.Rules; import org.sonar.api.batch.rule.Rules;
import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.internal.RulesBuilder; import org.sonar.api.batch.rule.internal.RulesBuilder;
import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonarqube.ws.Rules.ListResponse.Rule; import org.sonarqube.ws.Rules.ListResponse.Rule;
import org.springframework.context.annotation.Bean;


public class RulesProvider extends ProviderAdapter {
public class RulesProvider {
private static final Logger LOG = Loggers.get(RulesProvider.class); private static final Logger LOG = Loggers.get(RulesProvider.class);
private static final String LOG_MSG = "Load server rules"; private static final String LOG_MSG = "Load server rules";
private Rules singleton = null;


@Bean("Rules")
public Rules provide(RulesLoader ref) { public Rules provide(RulesLoader ref) {
if (singleton == null) {
singleton = load(ref);
}
return singleton;
}

private static Rules load(RulesLoader ref) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
List<Rule> loadedRules = ref.load(); List<Rule> loadedRules = ref.load();
RulesBuilder builder = new RulesBuilder(); RulesBuilder builder = new RulesBuilder();
} }


profiler.stopInfo(); profiler.stopInfo();

return builder.build(); return builder.build();
} }
} }

+ 16
- 17
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputModuleHierarchyProvider.java View File

import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
import org.springframework.context.annotation.Bean;


public class InputModuleHierarchyProvider extends ProviderAdapter {
public class InputModuleHierarchyProvider {


private static final Logger LOG = Loggers.get(InputModuleHierarchyProvider.class); private static final Logger LOG = Loggers.get(InputModuleHierarchyProvider.class);


private DefaultInputModuleHierarchy hierarchy = null;

public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, DefaultInputProject project) {
if (hierarchy == null) {
LOG.debug("Creating module hierarchy");
DefaultInputModule root = createModule(project.definition(), project.scannerId());
Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
if (parents.isEmpty()) {
hierarchy = new DefaultInputModuleHierarchy(root);
} else {
hierarchy = new DefaultInputModuleHierarchy(root, parents);
}
@Bean("DefaultInputModuleHierarchy")
public DefaultInputModuleHierarchy provide(ScannerComponentIdGenerator scannerComponentIdGenerator, WorkDirectoriesInitializer workDirectoriesInit, DefaultInputProject project) {
LOG.debug("Creating module hierarchy");
DefaultInputModule root = createModule(project.definition(), project.scannerId());
Map<DefaultInputModule, DefaultInputModule> parents = createChildren(root, scannerComponentIdGenerator, new HashMap<>());
DefaultInputModuleHierarchy inputModuleHierarchy;
if (parents.isEmpty()) {
inputModuleHierarchy = new DefaultInputModuleHierarchy(root);
} else {
inputModuleHierarchy = new DefaultInputModuleHierarchy(root, parents);
} }
return hierarchy;
workDirectoriesInit.execute(inputModuleHierarchy);
return inputModuleHierarchy;
} }


private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator, private static Map<DefaultInputModule, DefaultInputModule> createChildren(DefaultInputModule parent, ScannerComponentIdGenerator scannerComponentIdGenerator,

+ 14
- 18
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java View File

package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import java.util.Locale; import java.util.Locale;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
import org.springframework.context.annotation.Bean;


public class InputProjectProvider extends ProviderAdapter {

public class InputProjectProvider {
private static final Logger LOG = Loggers.get(InputProjectProvider.class); private static final Logger LOG = Loggers.get(InputProjectProvider.class);


private DefaultInputProject project = null;

@Bean("DefaultInputProject")
public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator, public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) { ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
if (project == null) {
// 1 Apply project builders
projectBuildersExecutor.execute(projectReactor);
// 1 Apply project builders
projectBuildersExecutor.execute(projectReactor);


// 2 Validate final reactor
validator.validate(projectReactor);
// 2 Validate final reactor
validator.validate(projectReactor);


// 3 Create project
project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());
// 3 Create project
DefaultInputProject project = new DefaultInputProject(projectReactor.getRoot(), scannerComponentIdGenerator.getAsInt());


LOG.info("Project key: {}", project.key());
LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
}
LOG.info("Project key: {}", project.key());
LOG.info("Base dir: {}", project.getBaseDir().toAbsolutePath().toString());
LOG.info("Working dir: {}", project.getWorkDir().toAbsolutePath().toString());
LOG.debug("Project global encoding: {}, default locale: {}", project.getEncoding().displayName(), Locale.getDefault());
return project; return project;
} }
} }

+ 36
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/LanguagesProvider.java View File

/*
* 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]));
}
}

+ 1
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfiguration.java View File

package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import java.util.Map; import java.util.Map;
import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration; import org.sonar.scanner.config.DefaultConfiguration;


public class ModuleConfiguration extends DefaultConfiguration { public class ModuleConfiguration extends DefaultConfiguration {

public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { public ModuleConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
super(propertyDefinitions, encryption, props); super(propertyDefinitions, encryption, props);
} }

} }

+ 9
- 15
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleConfigurationProvider.java View File

import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.bootstrap.GlobalConfiguration; import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings; import org.sonar.scanner.bootstrap.GlobalServerSettings;
import org.sonar.api.batch.fs.internal.DefaultInputModule;

public class ModuleConfigurationProvider extends ProviderAdapter {

private ModuleConfiguration moduleConfiguration;
import org.springframework.context.annotation.Bean;


public class ModuleConfigurationProvider {
@Bean("ModuleConfiguration")
public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings, public ModuleConfiguration provide(GlobalConfiguration globalConfig, DefaultInputModule module, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings) { ProjectServerSettings projectServerSettings) {
if (moduleConfiguration == null) {

Map<String, String> settings = new LinkedHashMap<>();
settings.putAll(globalServerSettings.properties());
settings.putAll(projectServerSettings.properties());
addScannerSideProperties(settings, module.definition());
Map<String, String> settings = new LinkedHashMap<>();
settings.putAll(globalServerSettings.properties());
settings.putAll(projectServerSettings.properties());
addScannerSideProperties(settings, module.definition());


moduleConfiguration = new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
}
return moduleConfiguration;
return new ModuleConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
} }


private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) { private static void addScannerSideProperties(Map<String, String> settings, ProjectDefinition project) {

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleIndexer.java View File

*/ */
package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import org.picocontainer.Startable;
import org.sonar.api.Startable;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.scanner.fs.InputModuleHierarchy; import org.sonar.scanner.fs.InputModuleHierarchy;
import org.sonar.scanner.scan.filesystem.InputComponentStore; import org.sonar.scanner.scan.filesystem.InputComponentStore;

+ 2
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableModuleSettings.java View File

import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import javax.annotation.Priority;
import org.sonar.api.config.internal.Settings; import org.sonar.api.config.internal.Settings;


import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
* @deprecated since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. * @deprecated since 6.5 {@link ModuleConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
*/ */
@Deprecated @Deprecated
@Priority(1)
public class MutableModuleSettings extends Settings { public class MutableModuleSettings extends Settings {


private final Map<String, String> properties = new HashMap<>(); private final Map<String, String> properties = new HashMap<>();

+ 4
- 8
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectReactorProvider.java View File

*/ */
package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.springframework.context.annotation.Bean;


public class MutableProjectReactorProvider extends ProviderAdapter {
private ProjectReactor reactor = null;

public class MutableProjectReactorProvider {
@Bean("ProjectReactor")
public ProjectReactor provide(ProjectReactorBuilder builder) { public ProjectReactor provide(ProjectReactorBuilder builder) {
if (reactor == null) {
reactor = builder.execute();
}
return reactor;
return builder.execute();
} }
} }

+ 3
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/MutableProjectSettings.java View File

import org.sonar.api.config.internal.Settings; import org.sonar.api.config.internal.Settings;
import org.sonar.scanner.bootstrap.GlobalConfiguration; import org.sonar.scanner.bootstrap.GlobalConfiguration;


import javax.annotation.Priority;

import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;


/** /**
* @deprecated since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility. * @deprecated since 6.5 {@link ProjectConfiguration} used to be mutable, so keep a mutable copy for backward compatibility.
*/ */
@Deprecated @Deprecated
@Priority(2)
public class MutableProjectSettings extends Settings { public class MutableProjectSettings extends Settings {


private final Map<String, String> properties = new HashMap<>(); private final Map<String, String> properties = new HashMap<>();

+ 3
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectBuildersExecutor.java View File

import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.GlobalConfiguration; import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.springframework.beans.factory.annotation.Autowired;


public class ProjectBuildersExecutor { public class ProjectBuildersExecutor {


private final GlobalConfiguration globalConfig; private final GlobalConfiguration globalConfig;
private final ProjectBuilder[] projectBuilders; private final ProjectBuilder[] projectBuilders;


@Autowired(required = false)
public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) { public ProjectBuildersExecutor(GlobalConfiguration globalConfig, ProjectBuilder... projectBuilders) {
this.globalConfig = globalConfig; this.globalConfig = globalConfig;
this.projectBuilders = projectBuilders; this.projectBuilders = projectBuilders;
} }


@Autowired(required = false)
public ProjectBuildersExecutor(GlobalConfiguration globalConfig) { public ProjectBuildersExecutor(GlobalConfiguration globalConfig) {
this(globalConfig, new ProjectBuilder[0]); this(globalConfig, new ProjectBuilder[0]);
} }

+ 1
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfiguration.java View File

package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import java.util.Map; import java.util.Map;
import org.sonar.api.config.internal.Encryption;
import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.internal.Encryption;
import org.sonar.scanner.config.DefaultConfiguration; import org.sonar.scanner.config.DefaultConfiguration;


public class ProjectConfiguration extends DefaultConfiguration { public class ProjectConfiguration extends DefaultConfiguration {

public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) { public ProjectConfiguration(PropertyDefinitions propertyDefinitions, Encryption encryption, Map<String, String> props) {
super(propertyDefinitions, encryption, props); super(propertyDefinitions, encryption, props);
} }

} }

+ 10
- 15
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectConfigurationProvider.java View File



import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.bootstrap.GlobalConfiguration; import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalServerSettings; import org.sonar.scanner.bootstrap.GlobalServerSettings;
import org.sonar.api.batch.fs.internal.DefaultInputProject;

public class ProjectConfigurationProvider extends ProviderAdapter {

private ProjectConfiguration projectConfig;
import org.springframework.context.annotation.Bean;


public class ProjectConfigurationProvider {
@Bean("ProjectConfiguration")
public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings, public ProjectConfiguration provide(DefaultInputProject project, GlobalConfiguration globalConfig, GlobalServerSettings globalServerSettings,
ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) { ProjectServerSettings projectServerSettings, MutableProjectSettings projectSettings) {
if (projectConfig == null) {

Map<String, String> settings = new LinkedHashMap<>();
settings.putAll(globalServerSettings.properties());
settings.putAll(projectServerSettings.properties());
settings.putAll(project.properties());
Map<String, String> settings = new LinkedHashMap<>();
settings.putAll(globalServerSettings.properties());
settings.putAll(projectServerSettings.properties());
settings.putAll(project.properties());


projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
projectSettings.complete(projectConfig);
}
ProjectConfiguration projectConfig = new ProjectConfiguration(globalConfig.getDefinitions(), globalConfig.getEncryption(), settings);
projectSettings.complete(projectConfig);
return projectConfig; return projectConfig;
} }
} }

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectLock.java View File

import java.nio.channels.OverlappingFileLockException; import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import org.picocontainer.Startable;
import org.sonar.api.Startable;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule; import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;


public class ProjectLock implements Startable { public class ProjectLock implements Startable {

+ 3
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java View File

import org.sonar.core.component.ComponentKeys; import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.bootstrap.GlobalConfiguration; import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.scan.branch.BranchParamsValidator; import org.sonar.scanner.scan.branch.BranchParamsValidator;
import org.springframework.beans.factory.annotation.Autowired;


import static java.lang.String.format; import static java.lang.String.format;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
@Nullable @Nullable
private final BranchParamsValidator branchParamsValidator; private final BranchParamsValidator branchParamsValidator;


@Autowired(required = false)
public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) { public ProjectReactorValidator(GlobalConfiguration settings, @Nullable BranchParamsValidator branchParamsValidator) {
this.settings = settings; this.settings = settings;
this.branchParamsValidator = branchParamsValidator; this.branchParamsValidator = branchParamsValidator;
} }


@Autowired(required = false)
public ProjectReactorValidator(GlobalConfiguration settings) { public ProjectReactorValidator(GlobalConfiguration settings) {
this(settings, null); this(settings, null);
} }

+ 8
- 12
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectServerSettingsProvider.java View File



import java.util.Map; import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.repository.settings.ProjectSettingsLoader; import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
import org.springframework.context.annotation.Bean;


public class ProjectServerSettingsProvider extends ProviderAdapter {
public class ProjectServerSettingsProvider {


private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class); private static final Logger LOG = Loggers.get(ProjectConfigurationProvider.class);


"Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " + "Archived Sub-Projects Settings' at project level, and clear the property to prevent the analysis from " +
"displaying this warning."; "displaying this warning.";


private ProjectServerSettings singleton = null;

@Bean("ProjectServerSettings")
public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) { public ProjectServerSettings provide(ProjectSettingsLoader loader, AnalysisWarnings analysisWarnings) {
if (singleton == null) {
Map<String, String> serverSideSettings = loader.loadProjectSettings();
if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
}
singleton = new ProjectServerSettings(serverSideSettings);
Map<String, String> serverSideSettings = loader.loadProjectSettings();
if (StringUtils.isNotBlank(serverSideSettings.get(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS))) {
LOG.warn(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
analysisWarnings.addUnique(MODULE_LEVEL_ARCHIVED_SETTINGS_WARNING);
} }
return singleton;
return new ProjectServerSettings(serverSideSettings);
} }
} }

sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java → sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringModuleScanContainer.java View File

*/ */
package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import javax.annotation.Priority;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.scan.filesystem.FileExclusions; import org.sonar.api.scan.filesystem.FileExclusions;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.ExtensionInstaller; import org.sonar.scanner.bootstrap.ExtensionInstaller;
import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem; import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore; import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.sensor.ModuleSensorContext; import org.sonar.scanner.sensor.ModuleSensorContext;
import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide; import static org.sonar.scanner.bootstrap.ExtensionUtils.isDeprecatedScannerSide;
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;


public class ModuleScanContainer extends ComponentContainer {
@Priority(1)
public class SpringModuleScanContainer extends SpringComponentContainer {
private final DefaultInputModule module; private final DefaultInputModule module;


public ModuleScanContainer(ProjectScanContainer parent, DefaultInputModule module) {
public SpringModuleScanContainer(SpringComponentContainer parent, DefaultInputModule module) {
super(parent); super(parent);
this.module = module; this.module = module;
} }
} }


private void addExtensions() { private void addExtensions() {
ExtensionInstaller pluginInstaller = getComponentByType(ExtensionInstaller.class);
ExtensionInstaller pluginInstaller = parent.getComponentByType(ExtensionInstaller.class);
pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT)); pluginInstaller.install(this, e -> isDeprecatedScannerSide(e) && isInstantiationStrategy(e, PER_PROJECT));
} }


protected void doAfterStart() { protected void doAfterStart() {
getComponentByType(ModuleSensorsExecutor.class).execute(); getComponentByType(ModuleSensorsExecutor.class).execute();
} }

} }

sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java → sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/SpringProjectScanContainer.java View File

package org.sonar.scanner.scan; package org.sonar.scanner.scan;


import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.Priority;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.SensorStrategy; import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.batch.rule.CheckFactory; import org.sonar.api.batch.rule.CheckFactory;
import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter; import org.sonar.api.batch.sensor.issue.internal.DefaultNoSonarFilter;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.ResourceTypes; import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.scan.filesystem.PathResolver; import org.sonar.api.scan.filesystem.PathResolver;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.core.config.ScannerProperties; import org.sonar.core.config.ScannerProperties;
import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.extension.CoreExtensionsInstaller;
import org.sonar.core.metric.ScannerMetrics; import org.sonar.core.metric.ScannerMetrics;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.DefaultFileLinesContextFactory; import org.sonar.scanner.DefaultFileLinesContextFactory;
import org.sonar.scanner.ProjectInfo; import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.analysis.AnalysisTempFolderProvider; import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
import org.sonar.scanner.bootstrap.ExtensionMatcher; import org.sonar.scanner.bootstrap.ExtensionMatcher;
import org.sonar.scanner.bootstrap.GlobalAnalysisMode; import org.sonar.scanner.bootstrap.GlobalAnalysisMode;
import org.sonar.scanner.bootstrap.PostJobExtensionDictionary; import org.sonar.scanner.bootstrap.PostJobExtensionDictionary;
import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.ci.CiConfigurationProvider; import org.sonar.scanner.ci.CiConfigurationProvider;
import org.sonar.scanner.ci.vendors.AppVeyor; import org.sonar.scanner.ci.vendors.AppVeyor;
import org.sonar.scanner.ci.vendors.AwsCodeBuild; import org.sonar.scanner.ci.vendors.AwsCodeBuild;
import org.sonar.scanner.repository.ContextPropertiesCache; import org.sonar.scanner.repository.ContextPropertiesCache;
import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader; import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
import org.sonar.scanner.repository.DefaultQualityProfileLoader; import org.sonar.scanner.repository.DefaultQualityProfileLoader;
import org.sonar.scanner.repository.ReferenceBranchSupplier;
import org.sonar.scanner.repository.ProjectRepositoriesLoader;
import org.sonar.scanner.repository.ProjectRepositoriesSupplier; import org.sonar.scanner.repository.ProjectRepositoriesSupplier;
import org.sonar.scanner.repository.QualityProfileLoader;
import org.sonar.scanner.repository.QualityProfilesProvider; import org.sonar.scanner.repository.QualityProfilesProvider;
import org.sonar.scanner.repository.ReferenceBranchSupplier;
import org.sonar.scanner.repository.language.DefaultLanguagesRepository; import org.sonar.scanner.repository.language.DefaultLanguagesRepository;
import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader; import org.sonar.scanner.repository.settings.DefaultProjectSettingsLoader;
import org.sonar.scanner.repository.settings.ProjectSettingsLoader;
import org.sonar.scanner.rule.ActiveRulesLoader;
import org.sonar.scanner.rule.ActiveRulesProvider; import org.sonar.scanner.rule.ActiveRulesProvider;
import org.sonar.scanner.rule.DefaultActiveRulesLoader; import org.sonar.scanner.rule.DefaultActiveRulesLoader;
import org.sonar.scanner.rule.DefaultRulesLoader; import org.sonar.scanner.rule.DefaultRulesLoader;
import org.sonar.scanner.rule.QProfileVerifier; import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.rule.RulesProvider; import org.sonar.scanner.rule.RulesProvider;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchConfigurationProvider; import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy; import static org.sonar.scanner.bootstrap.ExtensionUtils.isInstantiationStrategy;
import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide; import static org.sonar.scanner.bootstrap.ExtensionUtils.isScannerSide;


public class ProjectScanContainer extends ComponentContainer {
private static final Logger LOG = Loggers.get(ProjectScanContainer.class);
@Priority(2)
public class SpringProjectScanContainer extends SpringComponentContainer {
private static final Logger LOG = Loggers.get(SpringProjectScanContainer.class);


public ProjectScanContainer(ComponentContainer globalContainer) {
public SpringProjectScanContainer(SpringComponentContainer globalContainer) {
super(globalContainer); super(globalContainer);
} }


protected void doBeforeStart() { protected void doBeforeStart() {
addScannerExtensions(); addScannerExtensions();
addScannerComponents(); addScannerComponents();
ProjectLock lock = getComponentByType(ProjectLock.class);
lock.tryLock();
getComponentByType(WorkDirectoriesInitializer.class).execute();
} }


private void addScannerComponents() { private void addScannerComponents() {
DefaultMetricFinder.class, DefaultMetricFinder.class,


// lang // lang
Languages.class,
LanguagesProvider.class,
DefaultLanguagesRepository.class, DefaultLanguagesRepository.class,


// issue exclusions // issue exclusions
add(GitScmSupport.getObjects()); add(GitScmSupport.getObjects());
add(SvnScmSupport.getObjects()); add(SvnScmSupport.getObjects());


addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class);
addIfMissing(DefaultRulesLoader.class, RulesLoader.class);
addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class);
addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class);
addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class);
add(DefaultProjectSettingsLoader.class,
DefaultRulesLoader.class,
DefaultActiveRulesLoader.class,
DefaultQualityProfileLoader.class,
DefaultProjectRepositoriesLoader.class);
} }


private void addScannerExtensions() { private void addScannerExtensions() {
getComponentByType(CoreExtensionsInstaller.class)
getParent().getComponentByType(CoreExtensionsInstaller.class)
.install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension)); .install(this, noExtensionFilter(), extension -> getScannerProjectExtensionsFilter().accept(extension));
getComponentByType(ExtensionInstaller.class)
getParent().getComponentByType(ExtensionInstaller.class)
.install(this, getScannerProjectExtensionsFilter()); .install(this, getScannerProjectExtensionsFilter());
} }




@Override @Override
protected void doAfterStart() { protected void doAfterStart() {
getComponentByType(ProjectLock.class).tryLock();
GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class); GlobalAnalysisMode analysisMode = getComponentByType(GlobalAnalysisMode.class);
InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class); InputModuleHierarchy tree = getComponentByType(InputModuleHierarchy.class);
ScanProperties properties = getComponentByType(ScanProperties.class); ScanProperties properties = getComponentByType(ScanProperties.class);
} }


void scan(DefaultInputModule module) { void scan(DefaultInputModule module) {
new ModuleScanContainer(this, module).execute();
new SpringModuleScanContainer(this, module).execute();
} }


} }

+ 7
- 14
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/WorkDirectoriesInitializer.java View File

* Be careful that sub module work dir might be nested in parent working directory. * Be careful that sub module work dir might be nested in parent working directory.
*/ */
public class WorkDirectoriesInitializer { public class WorkDirectoriesInitializer {

private InputModuleHierarchy moduleHierarchy;

public WorkDirectoriesInitializer(InputModuleHierarchy moduleHierarchy) {
this.moduleHierarchy = moduleHierarchy;
}

public void execute() {
cleanAllWorkingDirs(moduleHierarchy.root());
mkdirsAllWorkingDirs(moduleHierarchy.root());
public void execute(InputModuleHierarchy moduleHierarchy) {
cleanAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
mkdirsAllWorkingDirs(moduleHierarchy, moduleHierarchy.root());
} }


private void cleanAllWorkingDirs(DefaultInputModule module) {
private static void cleanAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
for (DefaultInputModule sub : moduleHierarchy.children(module)) { for (DefaultInputModule sub : moduleHierarchy.children(module)) {
cleanAllWorkingDirs(sub);
cleanAllWorkingDirs(moduleHierarchy, sub);
} }
if (Files.exists(module.getWorkDir())) { if (Files.exists(module.getWorkDir())) {
deleteAllRecursivelyExceptLockFile(module.getWorkDir()); deleteAllRecursivelyExceptLockFile(module.getWorkDir());
} }
} }


private void mkdirsAllWorkingDirs(DefaultInputModule module) {
private static void mkdirsAllWorkingDirs(InputModuleHierarchy moduleHierarchy, DefaultInputModule module) {
for (DefaultInputModule sub : moduleHierarchy.children(module)) { for (DefaultInputModule sub : moduleHierarchy.children(module)) {
mkdirsAllWorkingDirs(sub);
mkdirsAllWorkingDirs(moduleHierarchy, sub);
} }
try { try {
Files.createDirectories(module.getWorkDir()); Files.createDirectories(module.getWorkDir());

+ 11
- 14
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/BranchConfigurationProvider.java View File

*/ */
package org.sonar.scanner.scan.branch; package org.sonar.scanner.scan.branch;


import org.picocontainer.annotations.Nullable;
import org.picocontainer.injectors.ProviderAdapter;
import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.scan.ProjectConfiguration; import org.sonar.scanner.scan.ProjectConfiguration;
import org.springframework.context.annotation.Bean;


public class BranchConfigurationProvider extends ProviderAdapter {
public class BranchConfigurationProvider {


private static final Logger LOG = Loggers.get(BranchConfigurationProvider.class); private static final Logger LOG = Loggers.get(BranchConfigurationProvider.class);
private static final String LOG_MSG = "Load branch configuration"; private static final String LOG_MSG = "Load branch configuration";


private BranchConfiguration branchConfiguration = null;

@Bean("BranchConfiguration")
public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration, public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectConfiguration projectConfiguration,
ProjectBranches branches, ProjectPullRequests pullRequests) { ProjectBranches branches, ProjectPullRequests pullRequests) {
if (branchConfiguration == null) {
if (loader == null) {
branchConfiguration = new DefaultBranchConfiguration();
} else {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
profiler.stopInfo();
}
if (loader == null) {
return new DefaultBranchConfiguration();
} else {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
BranchConfiguration branchConfiguration = loader.load(projectConfiguration.getProperties(), branches, pullRequests);
profiler.stopInfo();
return branchConfiguration;
} }
return branchConfiguration;
} }
} }

+ 7
- 13
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectBranchesProvider.java View File

package org.sonar.scanner.scan.branch; package org.sonar.scanner.scan.branch;


import java.util.Collections; import java.util.Collections;
import org.picocontainer.annotations.Nullable;
import org.picocontainer.injectors.ProviderAdapter;
import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties; import org.sonar.scanner.bootstrap.ScannerProperties;
import org.springframework.context.annotation.Bean;


public class ProjectBranchesProvider extends ProviderAdapter {
public class ProjectBranchesProvider {


private static final Logger LOG = Loggers.get(ProjectBranchesProvider.class); private static final Logger LOG = Loggers.get(ProjectBranchesProvider.class);
private static final String LOG_MSG = "Load project branches"; private static final String LOG_MSG = "Load project branches";


private ProjectBranches branches = null;

@Bean("ProjectBranches")
public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) { public ProjectBranches provide(@Nullable ProjectBranchesLoader loader, ScannerProperties scannerProperties) {
if (this.branches != null) {
return this.branches;
}

if (loader == null) { if (loader == null) {
this.branches = new ProjectBranches(Collections.emptyList());
return this.branches;
return new ProjectBranches(Collections.emptyList());
} }


Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
this.branches = loader.load(scannerProperties.getProjectKey());
ProjectBranches branches = loader.load(scannerProperties.getProjectKey());
profiler.stopInfo(); profiler.stopInfo();
return this.branches;
return branches;
} }
} }

+ 7
- 12
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/branch/ProjectPullRequestsProvider.java View File

package org.sonar.scanner.scan.branch; package org.sonar.scanner.scan.branch;


import java.util.Collections; import java.util.Collections;
import org.picocontainer.injectors.ProviderAdapter;
import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.ScannerProperties; import org.sonar.scanner.bootstrap.ScannerProperties;
import org.springframework.context.annotation.Bean;


public class ProjectPullRequestsProvider extends ProviderAdapter {
public class ProjectPullRequestsProvider {


private static final Logger LOG = Loggers.get(ProjectPullRequestsProvider.class); private static final Logger LOG = Loggers.get(ProjectPullRequestsProvider.class);
private static final String LOG_MSG = "Load project pull requests"; private static final String LOG_MSG = "Load project pull requests";


private ProjectPullRequests pullRequests = null;

public ProjectPullRequests provide(@org.picocontainer.annotations.Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
if (pullRequests != null) {
return pullRequests;
}

@Bean("ProjectPullRequests")
public ProjectPullRequests provide(@Nullable ProjectPullRequestsLoader loader, ScannerProperties scannerProperties) {
if (loader == null) { if (loader == null) {
pullRequests = new ProjectPullRequests(Collections.emptyList());
return pullRequests;
return new ProjectPullRequests(Collections.emptyList());
} }


Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
pullRequests = loader.load(scannerProperties.getProjectKey());
ProjectPullRequests pullRequests = loader.load(scannerProperties.getProjectKey());
profiler.stopInfo(); profiler.stopInfo();
return pullRequests; return pullRequests;
} }

+ 5
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultModuleFileSystem.java View File

import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;


import javax.annotation.Priority;
import javax.inject.Inject;

@Priority(1)
public class DefaultModuleFileSystem extends MutableFileSystem { public class DefaultModuleFileSystem extends MutableFileSystem {


@Inject
public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) { public DefaultModuleFileSystem(ModuleInputComponentStore moduleInputFileCache, DefaultInputModule module) {
super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir())); super(module.getBaseDir(), moduleInputFileCache, new DefaultFilePredicates(module.getBaseDir()));
initFields(module); initFields(module);

+ 5
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/DefaultProjectFileSystem.java View File

import org.sonar.api.batch.fs.internal.DefaultInputProject; import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates; import org.sonar.api.batch.fs.internal.predicates.DefaultFilePredicates;


import javax.annotation.Priority;
import javax.inject.Inject;

@Priority(2)
public class DefaultProjectFileSystem extends MutableFileSystem { public class DefaultProjectFileSystem extends MutableFileSystem {


@Inject
public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) { public DefaultProjectFileSystem(InputComponentStore inputComponentStore, DefaultInputProject project) {
super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir())); super(project.getBaseDir(), inputComponentStore, new DefaultFilePredicates(project.getBaseDir()));
setFields(project); setFields(project);

+ 0
- 8
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java View File

this.projectExclusionFilters = projectExclusionFilters; this.projectExclusionFilters = projectExclusionFilters;
} }


public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions,
IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader,
metadataGenerator, sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]);
}

void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions,
Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand) Path sourceFile, Type type, ProgressReport progressReport, ProjectFileIndexer.ExclusionCounter exclusionCounter, @Nullable IgnoreCommand ignoreCommand)
throws IOException { throws IOException {

+ 6
- 10
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmChangedFilesProvider.java View File

import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection; import java.util.Collection;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.scm.ScmProvider; import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.impl.utils.ScannerUtils;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler; import org.sonar.api.utils.log.Profiler;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.api.impl.utils.ScannerUtils;
import org.springframework.context.annotation.Bean;


public class ScmChangedFilesProvider extends ProviderAdapter {
public class ScmChangedFilesProvider {
private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class); private static final Logger LOG = Loggers.get(ScmChangedFilesProvider.class);
private static final String LOG_MSG = "SCM collecting changed files in the branch"; private static final String LOG_MSG = "SCM collecting changed files in the branch";


private ScmChangedFiles scmBranchChangedFiles;

@Bean("ScmChangedFiles")
public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) { public ScmChangedFiles provide(ScmConfiguration scmConfiguration, BranchConfiguration branchConfiguration, DefaultInputProject project) {
if (scmBranchChangedFiles == null) {
Path rootBaseDir = project.getBaseDir(); Path rootBaseDir = project.getBaseDir();
Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir); Collection<Path> changedFiles = loadChangedFilesIfNeeded(scmConfiguration, branchConfiguration, rootBaseDir);
validatePaths(changedFiles); validatePaths(changedFiles);
scmBranchChangedFiles = new ScmChangedFiles(changedFiles);
}
return scmBranchChangedFiles;
return new ScmChangedFiles(changedFiles);
} }


private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) { private static void validatePaths(@javax.annotation.Nullable Collection<Path> paths) {

+ 3
- 6
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmConfiguration.java View File

import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.Properties; import org.sonar.api.Properties;
import org.sonar.api.Property; import org.sonar.api.Property;
import org.sonar.api.PropertyType; import org.sonar.api.PropertyType;
import org.sonar.api.Startable;
import org.sonar.api.batch.scm.ScmProvider; import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.config.Configuration; import org.sonar.api.config.Configuration;
import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.notifications.AnalysisWarnings;


private ScmProvider provider; private ScmProvider provider;


public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings, ScmProvider... providers) {
public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings,
ScmProvider... providers) {
this.moduleHierarchy = moduleHierarchy; this.moduleHierarchy = moduleHierarchy;
this.settings = settings; this.settings = settings;
this.analysisWarnings = analysisWarnings; this.analysisWarnings = analysisWarnings;
} }
} }


public ScmConfiguration(InputModuleHierarchy moduleHierarchy, Configuration settings, AnalysisWarnings analysisWarnings) {
this(moduleHierarchy, settings, analysisWarnings, new ScmProvider[0]);
}

@Override @Override
public void start() { public void start() {
if (isDisabled()) { if (isDisabled()) {

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorContext.java View File



private final InputModule module; private final InputModule module;


public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableSettings, FileSystem fs, ActiveRules activeRules,
public ModuleSensorContext(DefaultInputProject project, InputModule module, Configuration config, Settings mutableModuleSettings, FileSystem fs, ActiveRules activeRules,
SensorStorage sensorStorage, SonarRuntime sonarRuntime) { SensorStorage sensorStorage, SonarRuntime sonarRuntime) {
super(project, config, mutableSettings, fs, activeRules, sensorStorage, sonarRuntime);
super(project, config, mutableModuleSettings, fs, activeRules, sensorStorage, sonarRuntime);
this.module = module; this.module = module;
} }



+ 2
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ModuleSensorExtensionDictionary.java View File

import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.Sensor;
import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem; import org.sonar.scanner.scan.filesystem.MutableFileSystem;


private final MutableFileSystem fileSystem; private final MutableFileSystem fileSystem;
private final BranchConfiguration branchConfiguration; private final BranchConfiguration branchConfiguration;


public ModuleSensorExtensionDictionary(ComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
public ModuleSensorExtensionDictionary(SpringComponentContainer componentContainer, ModuleSensorContext sensorContext, ModuleSensorOptimizer sensorOptimizer,
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer); super(componentContainer);
this.sensorContext = sensorContext; this.sensorContext = sensorContext;

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/ProjectSensorExtensionDictionary.java View File

import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.sonar.api.scanner.sensor.ProjectSensor; import org.sonar.api.scanner.sensor.ProjectSensor;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.bootstrap.AbstractExtensionDictionary; import org.sonar.scanner.bootstrap.AbstractExtensionDictionary;
import org.sonar.scanner.bootstrap.SpringComponentContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem; import org.sonar.scanner.scan.filesystem.MutableFileSystem;


private final MutableFileSystem fileSystem; private final MutableFileSystem fileSystem;
private final BranchConfiguration branchConfiguration; private final BranchConfiguration branchConfiguration;


public ProjectSensorExtensionDictionary(ComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
public ProjectSensorExtensionDictionary(SpringComponentContainer componentContainer, ProjectSensorContext sensorContext, ProjectSensorOptimizer sensorOptimizer,
MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) { MutableFileSystem fileSystem, BranchConfiguration branchConfiguration) {
super(componentContainer); super(componentContainer);
this.sensorContext = sensorContext; this.sensorContext = sensorContext;

+ 9
- 3
sonar-scanner-engine/src/main/resources/org/sonar/batch/bootstrapper/logback.xml View File

<level value="INFO"/> <level value="INFO"/>
</logger> </logger>


<!-- Spring generates too many DEBUG logs when sonar.verbose is set -->
<logger name="org.springframework">
<level value="INFO"/>
</logger>

<logger name="org.sonar.scanner.bootstrap.PriorityBeanFactory">
<level value="INFO"/>
</logger>

<!-- sonar.showSql --> <!-- sonar.showSql -->
<!-- see also org.sonar.db.MyBatis#configureLogback() --> <!-- see also org.sonar.db.MyBatis#configureLogback() -->
<logger name="org.mybatis"> <logger name="org.mybatis">
<logger name="java.sql.ResultSet"> <logger name="java.sql.ResultSet">
<level value="WARN"/> <level value="WARN"/>
</logger> </logger>
<logger name="PERSISTIT">
<level value="WARN"/>
</logger>


<root> <root>
<!-- sonar.verbose --> <!-- sonar.verbose -->

+ 0
- 4
sonar-scanner-engine/src/main/resources/org/sonar/batch/logback.xml View File

<level value="WARN"/> <level value="WARN"/>
</logger> </logger>


<logger name="PERSISTIT">
<level value="WARN"/>
</logger>

<root> <root>
<!-- sonar.verbose --> <!-- sonar.verbose -->
<level value="${ROOT_LOGGER_LEVEL}"/> <level value="${ROOT_LOGGER_LEVEL}"/>

+ 0
- 85
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/GlobalContainerTest.java View File

/*
* 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 {

}

}

+ 41
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/LazyBeanFactoryPostProcessorTest.java View File

/*
* 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();
}

}

+ 26
- 14
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ModuleSensorExtensionDictionaryTest.java View File

package org.sonar.scanner.bootstrap; package org.sonar.scanner.bootstrap;


import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.picocontainer.behaviors.FieldDecorated; import org.picocontainer.behaviors.FieldDecorated;
import org.sonar.api.batch.DependsUpon; import org.sonar.api.batch.DependsUpon;
import org.sonar.api.batch.Phase; import org.sonar.api.batch.Phase;
import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor; import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.scan.SpringModuleScanContainer;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.MutableFileSystem; import org.sonar.scanner.scan.filesystem.MutableFileSystem;
import org.sonar.scanner.sensor.ModuleSensorContext; import org.sonar.scanner.sensor.ModuleSensorContext;
import org.sonar.scanner.sensor.ModuleSensorOptimizer; import org.sonar.scanner.sensor.ModuleSensorOptimizer;
import org.sonar.scanner.sensor.ModuleSensorWrapper; import org.sonar.scanner.sensor.ModuleSensorWrapper;


import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
} }


private ModuleSensorExtensionDictionary newSelector(Object... extensions) { private ModuleSensorExtensionDictionary newSelector(Object... extensions) {
ComponentContainer iocContainer = new ComponentContainer();
for (Object extension : extensions) {
iocContainer.addSingleton(extension);
}
DefaultInputModule inputModule = mock(DefaultInputModule.class);
when(inputModule.definition()).thenReturn(mock(ProjectDefinition.class));

SpringComponentContainer parent = new SpringComponentContainer();
parent.context.refresh();

SpringComponentContainer iocContainer = new SpringModuleScanContainer(parent, inputModule);
iocContainer.add(Arrays.asList(extensions));
iocContainer.context.refresh();

return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration); return new ModuleSensorExtensionDictionary(iocContainer, mock(ModuleSensorContext.class), sensorOptimizer, fileSystem, branchConfiguration);
} }


Sensor b = new FakeSensor(); Sensor b = new FakeSensor();
Sensor c = new FakeSensor(); Sensor c = new FakeSensor();


ComponentContainer grandParent = new ComponentContainer();
grandParent.addSingleton(a);
SpringComponentContainer grandParent = new SpringComponentContainer();
grandParent.add(a);
grandParent.context.refresh();


ComponentContainer parent = grandParent.createChild();
parent.addSingleton(b);
SpringComponentContainer parent = grandParent.createChild();
parent.add(b);
parent.context.refresh();


ComponentContainer child = parent.createChild();
child.addSingleton(c);
SpringComponentContainer child = parent.createChild();
child.add(c);
child.context.refresh();


ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class), ModuleSensorExtensionDictionary dictionnary = new ModuleSensorExtensionDictionary(child, mock(ModuleSensorContext.class), mock(ModuleSensorOptimizer.class),
fileSystem, branchConfiguration); fileSystem, branchConfiguration);

+ 103
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/PriorityBeanFactoryTest.java View File

/*
* 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 {

}

}

+ 0
- 10
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/ScannerWsClientProviderTest.java View File

assertThat(httpConnector.baseUrl()).isEqualTo("https://here/sonarqube/"); assertThat(httpConnector.baseUrl()).isEqualTo("https://here/sonarqube/");
assertThat(httpConnector.okHttpClient().proxy()).isNull(); assertThat(httpConnector.okHttpClient().proxy()).isNull();
} }

@Test
public void build_singleton() {
System2 system = mock(System2.class);

ScannerProperties settings = new ScannerProperties(new HashMap<>());
DefaultScannerWsClient first = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
DefaultScannerWsClient second = underTest.provide(settings, env, new GlobalAnalysisMode(new ScannerProperties(Collections.emptyMap())), system);
assertThat(first).isSameAs(second);
}
} }

+ 213
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringComponentContainerTest.java View File

/*
* 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);
}
}
}

+ 34
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/SpringGlobalContainerTest.java View File

/*
* 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");
}
}

+ 64
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/bootstrap/StartableBeanPostProcessorTest.java View File

/*
* 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);
}

}

+ 19
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java View File

import java.util.Properties; import java.util.Properties;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.Priority;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;
import org.sonar.api.Plugin; import org.sonar.api.Plugin;
private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader(); private final FakeQualityProfileLoader qualityProfiles = new FakeQualityProfileLoader();
private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader(); private final FakeActiveRulesLoader activeRules = new FakeActiveRulesLoader();
private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime(); private final FakeSonarRuntime sonarRuntime = new FakeSonarRuntime();
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolder();
private final CeTaskReportDataHolder reportMetadataHolder = new CeTaskReportDataHolderExt();
private LogOutput logOutput = null; private LogOutput logOutput = null;


private static void createWorkingDirs() throws IOException { private static void createWorkingDirs() throws IOException {


public static class AnalysisBuilder { public static class AnalysisBuilder {
private final Map<String, String> taskProperties = new HashMap<>(); private final Map<String, String> taskProperties = new HashMap<>();
private ScannerMediumTester tester;
private final ScannerMediumTester tester;


public AnalysisBuilder(ScannerMediumTester tester) { public AnalysisBuilder(ScannerMediumTester tester) {
this.tester = tester; this.tester = tester;


} }


@Priority(1)
private static class FakeRulesLoader implements RulesLoader { private static class FakeRulesLoader implements RulesLoader {
private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>(); private List<org.sonarqube.ws.Rules.ListResponse.Rule> rules = new LinkedList<>();


} }
} }


@Priority(1)
private static class FakeActiveRulesLoader implements ActiveRulesLoader { private static class FakeActiveRulesLoader implements ActiveRulesLoader {
private List<LoadedActiveRule> activeRules = new LinkedList<>(); private List<LoadedActiveRule> activeRules = new LinkedList<>();


} }
} }


@Priority(1)
private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader { private static class FakeMetricsRepositoryLoader implements MetricsRepositoryLoader {


private int metricId = 1; private int metricId = 1;


} }


@Priority(1)
private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader { private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {
private Map<String, FileData> fileDataMap = new HashMap<>(); private Map<String, FileData> fileDataMap = new HashMap<>();




} }


@Priority(1)
private static class FakeBranchConfiguration implements BranchConfiguration { private static class FakeBranchConfiguration implements BranchConfiguration {


private BranchType branchType = BranchType.BRANCH; private BranchType branchType = BranchType.BRANCH;
} }
} }


@Priority(1)
private static class FakeSonarRuntime implements SonarRuntime { private static class FakeSonarRuntime implements SonarRuntime {


private SonarEdition edition; private SonarEdition edition;
return this; return this;
} }


@Priority(1)
private class FakeBranchConfigurationLoader implements BranchConfigurationLoader { private class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
@Override @Override
public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) { public BranchConfiguration load(Map<String, String> projectSettings, ProjectBranches branches, ProjectPullRequests pullRequests) {
} }
} }


@Priority(1)
private static class FakeQualityProfileLoader implements QualityProfileLoader { private static class FakeQualityProfileLoader implements QualityProfileLoader {


private List<QualityProfile> qualityProfiles = new LinkedList<>(); private List<QualityProfile> qualityProfiles = new LinkedList<>();
} }
} }


@Priority(1)
private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader { private static class FakeGlobalSettingsLoader implements GlobalSettingsLoader {


private Map<String, String> globalSettings = new HashMap<>(); private Map<String, String> globalSettings = new HashMap<>();
} }
} }


@Priority(1)
private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader { private static class FakeNewCodePeriodLoader implements NewCodePeriodLoader {
private NewCodePeriods.ShowWSResponse response; private NewCodePeriods.ShowWSResponse response;


} }
} }


@Priority(1)
private static class FakeProjectSettingsLoader implements ProjectSettingsLoader { private static class FakeProjectSettingsLoader implements ProjectSettingsLoader {


private Map<String, String> projectSettings = new HashMap<>(); private Map<String, String> projectSettings = new HashMap<>();
} }
} }


@Priority(1)
private static class CeTaskReportDataHolderExt extends CeTaskReportDataHolder {

}

} }

+ 3
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/NoLanguagesPluginsMediumTest.java View File

import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.springframework.beans.factory.UnsatisfiedDependencyException;


import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;


assertThatThrownBy(() -> tester assertThatThrownBy(() -> tester
.newAnalysis(new File(projectDir, "sonar-project.properties")) .newAnalysis(new File(projectDir, "sonar-project.properties"))
.execute()) .execute())
.isInstanceOf(IllegalStateException.class)
.hasMessage("No language plugins are installed.");
.isInstanceOf(UnsatisfiedDependencyException.class)
.hasRootCauseMessage("No language plugins are installed.");
} }


private File copyProject(String path) throws Exception { private File copyProject(String path) throws Exception {

+ 8
- 6
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java View File



List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); List<Issue> issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
assertThat(issues).hasSize(8 /* lines */); assertThat(issues).hasSize(8 /* lines */);
List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo")); List<ExternalIssue> externalIssues = result.externalIssuesFor(result.inputFile("xources/hello/HelloJava.xoo"));
assertThat(externalIssues).isEmpty(); assertThat(externalIssues).isEmpty();
} }
@Test @Test
public void testOneExternalIssuePerLine() throws Exception { public void testOneExternalIssuePerLine() throws Exception {
File projectDir = new File("test-resources/mediumtest/xoo/sample"); File projectDir = new File("test-resources/mediumtest/xoo/sample");
.build()) .build())
.execute(); .execute();


assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
assertThat(logTester.logs(LoggerLevel.WARN)).contains(
"Specifying module-relative paths at project level in property 'sonar.issue.ignore.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");


List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).isEmpty(); assertThat(issues).isEmpty();
.build()) .build())
.execute(); .execute();


assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");
assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly(
"Specifying issue exclusions at module level is not supported anymore. Configure the property 'sonar.issue.ignore.multicriteria' and any other issue exclusions at project level.");


List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).hasSize(10); assertThat(issues).hasSize(10);
issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo")); issues = result.issuesFor(result.inputFile("moduleB/src/sampleB.xoo"));
assertThat(issues).hasSize(10); assertThat(issues).hasSize(10);



// SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules // SONAR-11850 The Maven scanner replicates properties defined on the root module to all modules
logTester.clear(); logTester.clear();
result = tester.newAnalysis() result = tester.newAnalysis()
.build()) .build())
.execute(); .execute();


assertThat(logTester.logs(LoggerLevel.WARN)).contains("Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");
assertThat(logTester.logs(LoggerLevel.WARN)).contains(
"Specifying module-relative paths at project level in property 'sonar.issue.enforce.multicriteria' is deprecated. To continue matching files like 'moduleA/src/sampleA.xoo', update this property so that patterns refer to project-relative paths.");


List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo")); List<Issue> issues = result.issuesFor(result.inputFile("moduleA/src/sampleA.xoo"));
assertThat(issues).hasSize(10); assertThat(issues).hasSize(10);

+ 5
- 3
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/log/ExceptionHandlingMediumTest.java View File



import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import javax.annotation.Priority;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.batch.bootstrapper.Batch; import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation; import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.scanner.repository.settings.GlobalSettingsLoader; import org.sonar.scanner.repository.settings.GlobalSettingsLoader;
import org.springframework.beans.factory.UnsatisfiedDependencyException;


import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;


@Test @Test
public void testWithVerbose() { public void testWithVerbose() {
setUp(true); setUp(true);

assertThatThrownBy(() -> batch.execute()) assertThatThrownBy(() -> batch.execute())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Unable to load component class");
.isInstanceOf(UnsatisfiedDependencyException.class)
.hasMessageContaining("Error loading settings");
} }


@Priority(1)
private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader { private static class ErrorGlobalSettingsLoader implements GlobalSettingsLoader {
boolean withCause = false; boolean withCause = false;



+ 5
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ReportPublisherTest.java View File

import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;

import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class); private AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class); private BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class); private CeTaskReportDataHolder reportMetadataHolder = mock(CeTaskReportDataHolder.class);
private ReportPublisher underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
private ReportPublisher underTest;


@Before @Before
public void setUp() { public void setUp() {
when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath() when(properties.metadataFilePath()).thenReturn(reportTempFolder.newDir().toPath()
.resolve("folder") .resolve("folder")
.resolve("report-task.txt")); .resolve("report-task.txt"));
underTest = new ReportPublisher(properties, wsClient, server, contextPublisher, moduleHierarchy, mode, reportTempFolder,
new ReportPublisherStep[0], branchConfiguration, reportMetadataHolder);
} }


@Test @Test
underTest.prepareAndDumpMetadata("TASK-123"); underTest.prepareAndDumpMetadata("TASK-123");


assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo( assertThat(readFileToString(properties.metadataFilePath().toFile(), StandardCharsets.UTF_8)).isEqualTo(
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"projectKey=org.sonarsource.sonarqube:sonarqube\n" +
"serverUrl=https://localhost\n" + "serverUrl=https://localhost\n" +
"serverVersion=6.4\n" + "serverVersion=6.4\n" +
"dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" + "dashboardUrl=https://localhost/dashboard?id=org.sonarsource.sonarqube%3Asonarqube\n" +
public void should_not_delete_report_if_property_is_set() throws IOException { public void should_not_delete_report_if_property_is_set() throws IOException {
when(properties.shouldKeepReport()).thenReturn(true); when(properties.shouldKeepReport()).thenReturn(true);
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
Files.createDirectory(reportDir);


underTest.start(); underTest.start();
underTest.stop(); underTest.stop();
@Test @Test
public void should_delete_report_by_default() throws IOException { public void should_delete_report_by_default() throws IOException {
Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report"); Path reportDir = reportTempFolder.getRoot().toPath().resolve("scanner-report");
Files.createDirectory(reportDir);


underTest.start(); underTest.start();
underTest.stop(); underTest.stop();

sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectScanContainerTest.java → sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/SpringProjectScanContainerTest.java View File



import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;


public class ProjectScanContainerTest {
public class SpringProjectScanContainerTest {


@Test @Test
public void should_add_only_batch_extensions() { public void should_add_only_batch_extensions() {
ExtensionMatcher filter = ProjectScanContainer.getScannerProjectExtensionsFilter();
ExtensionMatcher filter = SpringProjectScanContainer.getScannerProjectExtensionsFilter();


assertThat(filter.accept(new MyBatchExtension())).isTrue(); assertThat(filter.accept(new MyBatchExtension())).isTrue();
assertThat(filter.accept(MyBatchExtension.class)).isTrue(); assertThat(filter.accept(MyBatchExtension.class)).isTrue();

+ 0
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/WorkDirectoriesInitializerTest.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save