Browse Source

SONAR-9616 Handle branch in scanner

tags/6.6-RC1
Janos Gyerik 6 years ago
parent
commit
d6e6f92aef
20 changed files with 401 additions and 115 deletions
  1. 46
    52
      server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
  2. 7
    1
      sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java
  3. 1
    1
      sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java
  4. 21
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
  5. 7
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java
  6. 2
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesLoader.java
  7. 5
    4
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java
  8. 48
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java
  9. 30
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationLoader.java
  10. 49
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java
  11. 31
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationValidator.java
  12. 35
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java
  13. 30
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfigurationValidator.java
  14. 11
    14
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
  15. 1
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
  16. 15
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
  17. 40
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
  18. 9
    9
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoaderTest.java
  19. 9
    5
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java
  20. 4
    20
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java

+ 46
- 52
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java View File

@@ -96,16 +96,13 @@ public class ComputeEngineContainerImplTest {
underTest
.start(new Props(properties));

try {
MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();
assertThat(
picoContainer.getComponentAdapters().stream()
.map(ComponentAdapter::getComponentImplementation)
.collect(Collectors.toList())).contains((Class) HazelcastClientWrapperImpl.class,
(Class) CeDistributedInformationImpl.class);
} finally {
underTest.stop();
}
MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();
assertThat(
picoContainer.getComponentAdapters().stream()
.map(ComponentAdapter::getComponentImplementation)
.collect(Collectors.toList())).contains((Class) HazelcastClientWrapperImpl.class,
(Class) CeDistributedInformationImpl.class);
underTest.stop();
}

@Test
@@ -118,49 +115,46 @@ public class ComputeEngineContainerImplTest {

underTest
.start(new Props(properties));
MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();

try {
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CONTAINER_ITSELF
+ 72 // level 4
+ 4 // content of CeConfigurationModule
+ 4 // content of CeQueueModule
+ 4 // content of CeHttpModule
+ 3 // content of CeTaskCommonsModule
+ 4 // content of ProjectAnalysisTaskModule
+ 5 // content of CeTaskProcessorModule
+ 3 // CeCleaningModule + its content
+ 1 // CeDistributedInformation
);
assertThat(picoContainer.getParent().getComponentAdapters()).hasSize(
CONTAINER_ITSELF
+ 5 // level 3
);
assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize(
MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer();
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CONTAINER_ITSELF
+ 12 // MigrationConfigurationModule
+ 17 // level 2
);
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 25 // level 1
+ 49 // content of DaoModule
+ 3 // content of EsSearchModule
+ 63 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
);
assertThat(
picoContainer.getComponentAdapters().stream()
.map(ComponentAdapter::getComponentImplementation)
.collect(Collectors.toList())).doesNotContain((Class) HazelcastClientWrapperImpl.class,
(Class) CeDistributedInformationImpl.class).contains(
(Class) StandaloneCeDistributedInformation.class);
assertThat(picoContainer.getParent().getParent().getParent().getParent()).isNull();
} finally {
underTest.stop();
}
+ 72 // level 4
+ 4 // content of CeConfigurationModule
+ 4 // content of CeQueueModule
+ 4 // content of CeHttpModule
+ 3 // content of CeTaskCommonsModule
+ 4 // content of ProjectAnalysisTaskModule
+ 5 // content of CeTaskProcessorModule
+ 3 // CeCleaningModule + its content
+ 1 // CeDistributedInformation
);
assertThat(picoContainer.getParent().getComponentAdapters()).hasSize(
CONTAINER_ITSELF
+ 5 // level 3
);
assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize(
CONTAINER_ITSELF
+ 12 // MigrationConfigurationModule
+ 17 // level 2
);
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
+ 25 // level 1
+ 49 // content of DaoModule
+ 3 // content of EsSearchModule
+ 64 // content of CorePropertyDefinitions
+ 1 // StopFlagContainer
);
assertThat(
picoContainer.getComponentAdapters().stream()
.map(ComponentAdapter::getComponentImplementation)
.collect(Collectors.toList())).doesNotContain((Class) HazelcastClientWrapperImpl.class,
(Class) CeDistributedInformationImpl.class).contains(
(Class) StandaloneCeDistributedInformation.class);
assertThat(picoContainer.getParent().getParent().getParent().getParent()).isNull();
underTest.stop();

assertThat(picoContainer.getLifecycleState().isStarted()).isFalse();
assertThat(picoContainer.getLifecycleState().isStopped()).isFalse();
@@ -188,4 +182,4 @@ public class ComputeEngineContainerImplTest {
dbTester.getDbClient().propertiesDao().saveProperty(dbTester.getSession(), dto);
dbTester.commit();
}
}
}

+ 7
- 1
sonar-core/src/main/java/org/sonar/core/config/ScannerProperties.java View File

@@ -31,6 +31,7 @@ import static org.sonar.api.PropertyType.BOOLEAN;
public class ScannerProperties {

public static final String BRANCH_NAME = "sonar.branch.name";
public static final String BRANCH_TARGET = "sonar.branch.target";
public static final String ORGANIZATION = "sonar.organization";

private ScannerProperties() {
@@ -67,7 +68,12 @@ public class ScannerProperties {
.hidden()
.build(),
PropertyDefinition.builder(BRANCH_NAME)
.name("Optional name of SCM branch")
.name("Optional name of SonarQube/SCM branch")
.description("TODO")
.hidden()
.build(),
PropertyDefinition.builder(BRANCH_TARGET)
.name("Optional name of target branch to merge into, and the base to determine changed files")
.description("TODO")
.hidden()
.build()

+ 1
- 1
sonar-core/src/test/java/org/sonar/core/config/CorePropertyDefinitionsTest.java View File

@@ -33,7 +33,7 @@ public class CorePropertyDefinitionsTest {
@Test
public void all() {
List<PropertyDefinition> defs = CorePropertyDefinitions.all();
assertThat(defs).hasSize(63);
assertThat(defs).hasSize(64);
}

@Test

+ 21
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java View File

@@ -20,8 +20,8 @@
package org.sonar.scanner.report;

import java.util.Map.Entry;
import org.sonar.api.batch.AnalysisMode;
import java.util.Optional;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
@@ -31,9 +31,11 @@ import org.sonar.scanner.bootstrap.ScannerPlugin;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.cpd.CpdSettings;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Metadata.BranchType;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
import org.sonar.scanner.rule.QProfile;
import org.sonar.scanner.scan.BranchConfiguration;

import static org.sonar.core.config.ScannerProperties.BRANCH_NAME;
import static org.sonar.core.config.ScannerProperties.ORGANIZATION;
@@ -47,9 +49,10 @@ public class MetadataPublisher implements ReportPublisherStep {
private final CpdSettings cpdSettings;
private final AnalysisMode mode;
private final ScannerPluginRepository pluginRepository;
private final BranchConfiguration branchConfiguration;

public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, Configuration settings,
ModuleQProfiles qProfiles, CpdSettings cpdSettings, AnalysisMode mode, ScannerPluginRepository pluginRepository) {
ModuleQProfiles qProfiles, CpdSettings cpdSettings, AnalysisMode mode, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration) {
this.projectAnalysisInfo = projectAnalysisInfo;
this.moduleHierarchy = moduleHierarchy;
this.settings = settings;
@@ -57,6 +60,7 @@ public class MetadataPublisher implements ReportPublisherStep {
this.cpdSettings = cpdSettings;
this.mode = mode;
this.pluginRepository = pluginRepository;
this.branchConfiguration = branchConfiguration;
}

@Override
@@ -72,7 +76,14 @@ public class MetadataPublisher implements ReportPublisherStep {
.setIncremental(mode.isIncremental());

settings.get(ORGANIZATION).ifPresent(builder::setOrganizationKey);
settings.get(BRANCH_NAME).ifPresent(builder::setBranchName);
settings.get(BRANCH_NAME).ifPresent(branch -> {
builder.setBranchName(branch);
builder.setBranchType(toProtobufBranchType(branchConfiguration.branchType()));
String branchTarget = branchConfiguration.branchTarget();
if (branchTarget != null) {
builder.setMergeBranchName(branchTarget);
}
});
Optional.ofNullable(rootDef.getBranch()).ifPresent(builder::setDeprecatedBranch);

for (QProfile qp : qProfiles.findAll()) {
@@ -89,4 +100,11 @@ public class MetadataPublisher implements ReportPublisherStep {
}
writer.writeMetadata(builder.build());
}

private static BranchType toProtobufBranchType(BranchConfiguration.BranchType branchType) {
if (branchType == BranchConfiguration.BranchType.LONG) {
return BranchType.LONG;
}
return BranchType.SHORT;
}
}

+ 7
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java View File

@@ -27,6 +27,7 @@ import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Date;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,8 +52,8 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
}

@Override
public ProjectRepositories load(String projectKey, boolean issuesMode) {
GetRequest request = new GetRequest(getUrl(projectKey, issuesMode));
public ProjectRepositories load(String projectKey, boolean issuesMode, @Nullable String branchTarget) {
GetRequest request = new GetRequest(getUrl(projectKey, issuesMode, branchTarget));
try (WsResponse response = wsClient.call(request)) {
InputStream is = response.contentStream();
return processStream(is, projectKey);
@@ -66,7 +67,7 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
}
}

private static String getUrl(String projectKey, boolean issuesMode) {
private static String getUrl(String projectKey, boolean issuesMode, @Nullable String branchTarget) {
StringBuilder builder = new StringBuilder();

builder.append(BATCH_PROJECT_URL)
@@ -74,6 +75,9 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
if (issuesMode) {
builder.append("&issues_mode=true");
}
if (branchTarget != null) {
builder.append("&branch=").append(branchTarget);
}
return builder.toString();
}


+ 2
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesLoader.java View File

@@ -19,7 +19,8 @@
*/
package org.sonar.scanner.repository;

import javax.annotation.Nullable;

public interface ProjectRepositoriesLoader {
ProjectRepositories load(String projectKeyWithBranch, boolean issuesMode);
ProjectRepositories load(String projectKeyWithBranch, boolean issuesMode, @Nullable String branchTarget);
}

+ 5
- 4
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositoriesProvider.java View File

@@ -25,20 +25,21 @@ import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
import org.sonar.scanner.scan.BranchConfiguration;

public class ProjectRepositoriesProvider extends ProviderAdapter {
private static final Logger LOG = Loggers.get(ProjectRepositoriesProvider.class);
private static final String LOG_MSG = "Load project repositories";
private ProjectRepositories project = null;

public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProjectKey projectKey, DefaultAnalysisMode mode) {
return provideInternal(loader, projectKey, mode.isIssues());
public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProjectKey projectKey, DefaultAnalysisMode mode, BranchConfiguration branchConfig) {
return provideInternal(loader, projectKey, mode.isIssues(), branchConfig);
}

protected ProjectRepositories provideInternal(ProjectRepositoriesLoader loader, ProjectKey projectKey, boolean isIssueMode) {
protected ProjectRepositories provideInternal(ProjectRepositoriesLoader loader, ProjectKey projectKey, boolean isIssueMode, BranchConfiguration branchConfig) {
if (project == null) {
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
project = loader.load(projectKey.get(), isIssueMode);
project = loader.load(projectKey.get(), isIssueMode, branchConfig.branchTarget());
checkProject(isIssueMode);
profiler.stopInfo();
}

+ 48
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfiguration.java View File

@@ -0,0 +1,48 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.scan;

import javax.annotation.CheckForNull;

public interface BranchConfiguration {

enum BranchType {
SHORT, LONG
}

/**
* The type of the branch we're on, determined by:
*
* - If the specified branch exists on the server, then its type
* - If the branch name matches the pattern of long-lived branches, then it's long-lived
* - Otherwise it's short-lived
*
* @return type of the current branch
*/
BranchType branchType();

/**
* The name of the target branch to merge into, and the base to determine changed files.
*
* @return name of the target branch
*/
@CheckForNull
String branchTarget();
}

+ 30
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationLoader.java View File

@@ -0,0 +1,30 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.scan;

import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;
import org.sonar.scanner.bootstrap.GlobalConfiguration;

@ScannerSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
public interface BranchConfigurationLoader {
BranchConfiguration load(String projectKey, GlobalConfiguration settings);
}

+ 49
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationProvider.java View File

@@ -0,0 +1,49 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.scan;

import org.picocontainer.annotations.Nullable;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.bootstrap.ProjectKey;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
import org.sonar.scanner.bootstrap.GlobalConfiguration;

public class BranchConfigurationProvider extends ProviderAdapter {

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

private BranchConfiguration branchConfiguration = null;

public BranchConfiguration provide(@Nullable BranchConfigurationLoader loader, ProjectKey projectKey, GlobalConfiguration globalConfiguration) {
if (branchConfiguration == null) {
if (loader == null) {
return new DefaultBranchConfiguration();
}
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG);
branchConfiguration = loader.load(projectKey.get(), globalConfiguration);
profiler.stopInfo();
}
return branchConfiguration;
}

}

+ 31
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/BranchConfigurationValidator.java View File

@@ -0,0 +1,31 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 javax.annotation.Nullable;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;

@ScannerSide
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
public interface BranchConfigurationValidator {
void validate(List<String> validationMessages, @Nullable String deprecatedBranchName);
}

+ 35
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfiguration.java View File

@@ -0,0 +1,35 @@
/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.scan;

import javax.annotation.CheckForNull;

public class DefaultBranchConfiguration implements BranchConfiguration {
@Override
public BranchType branchType() {
return BranchType.LONG;
}

@CheckForNull
@Override
public String branchTarget() {
return null;
}
}

+ 30
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/DefaultBranchConfigurationValidator.java View File

@@ -0,0 +1,30 @@
/*
* SonarQube
* Copyright (C) 2009-2017 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 javax.annotation.Nullable;

public class DefaultBranchConfigurationValidator implements BranchConfigurationValidator {
@Override
public void validate(List<String> validationMessages, @Nullable String deprecatedBranchName) {
// no-op
}
}

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

@@ -28,7 +28,6 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.utils.MessageException;
import org.sonar.core.component.ComponentKeys;
import org.sonar.core.config.ScannerProperties;
import org.sonar.scanner.analysis.DefaultAnalysisMode;

/**
@@ -37,16 +36,19 @@ import org.sonar.scanner.analysis.DefaultAnalysisMode;
*/
public class ProjectReactorValidator {
private final DefaultAnalysisMode mode;
private final ProjectSettings settings;

public ProjectReactorValidator(DefaultAnalysisMode mode, ProjectSettings settings) {
private final BranchConfigurationValidator branchConfigurationValidator;

public ProjectReactorValidator(DefaultAnalysisMode mode, BranchConfigurationValidator branchConfigurationValidator) {
this.mode = mode;
this.settings = settings;
this.branchConfigurationValidator = branchConfigurationValidator;
}

public void validate(ProjectReactor reactor) {
String branch = reactor.getRoot().getBranch();
public ProjectReactorValidator(DefaultAnalysisMode mode) {
this(mode, new DefaultBranchConfigurationValidator());
}

public void validate(ProjectReactor reactor) {
List<String> validationMessages = new ArrayList<>();

for (ProjectDefinition moduleDef : reactor.getProjects()) {
@@ -57,9 +59,10 @@ public class ProjectReactorValidator {
}
}

validateBranchParams(validationMessages, branch, settings.get(ScannerProperties.BRANCH_NAME).orElse(null));
String deprecatedBranchName = reactor.getRoot().getBranch();

validateBranch(validationMessages, branch);
branchConfigurationValidator.validate(validationMessages, deprecatedBranchName);
validateBranch(validationMessages, deprecatedBranchName);

if (!validationMessages.isEmpty()) {
throw MessageException.of("Validation of project reactor failed:\n o " + Joiner.on("\n o ").join(validationMessages));
@@ -87,10 +90,4 @@ public class ProjectReactorValidator {
}
}

private static void validateBranchParams(List<String> validationMessages, @Nullable String deprecatedBranch, @Nullable String branchName) {
if (StringUtils.isNotEmpty(deprecatedBranch) && StringUtils.isNotEmpty(branchName)) {
validationMessages.add(String.format("The %s parameter must not be used together with the deprecated sonar.branch parameter", ScannerProperties.BRANCH_NAME));
}
}

}

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

@@ -136,6 +136,7 @@ public class ProjectScanContainer extends ComponentContainer {
DefaultIndex.class,
Storages.class,
new RulesProvider(),
new BranchConfigurationProvider(),

// temp
new AnalysisTempFolderProvider(),

+ 15
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java View File

@@ -51,6 +51,7 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.bootstrapper.LogOutput;
import org.sonar.scanner.bootstrap.GlobalConfiguration;
import org.sonar.scanner.bootstrap.GlobalMode;
import org.sonar.scanner.issue.tracking.ServerLineHashesLoader;
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
@@ -66,9 +67,13 @@ import org.sonar.scanner.repository.settings.SettingsLoader;
import org.sonar.scanner.rule.ActiveRulesLoader;
import org.sonar.scanner.rule.LoadedActiveRule;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.scan.BranchConfiguration;
import org.sonar.scanner.scan.BranchConfigurationLoader;
import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile;
import org.sonarqube.ws.Rules.ListResponse.Rule;

import static org.mockito.Mockito.mock;

/**
* Main utility class for writing scanner medium tests.
*
@@ -78,6 +83,7 @@ public class ScannerMediumTester extends ExternalResource {
private static Path userHome = null;
private Map<String, String> globalProperties = new HashMap<>();
private final FakeMetricsRepositoryLoader globalRefProvider = new FakeMetricsRepositoryLoader();
private final FakeBranchConfigurationLoader projectBranchesProvider = new FakeBranchConfigurationLoader();
private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader();
@@ -288,6 +294,7 @@ public class ScannerMediumTester extends ExternalResource {
tester.globalRefProvider,
tester.qualityProfiles,
tester.rulesLoader,
tester.projectBranchesProvider,
tester.projectRefProvider,
tester.activeRules,
tester.serverIssues,
@@ -365,7 +372,7 @@ public class ScannerMediumTester extends ExternalResource {
private Date lastAnalysisDate;

@Override
public ProjectRepositories load(String projectKey, boolean isIssuesMode) {
public ProjectRepositories load(String projectKey, boolean isIssuesMode, @Nullable String branchTarget) {
Table<String, String, String> settings = HashBasedTable.create();
return new ProjectRepositories(settings, fileDataTable, lastAnalysisDate);
}
@@ -382,6 +389,13 @@ public class ScannerMediumTester extends ExternalResource {

}

private static class FakeBranchConfigurationLoader implements BranchConfigurationLoader {
@Override
public BranchConfiguration load(String projectKey, GlobalConfiguration settings) {
return mock(BranchConfiguration.class);
}
}

private static class FakeQualityProfileLoader implements QualityProfileLoader {

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

+ 40
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java View File

@@ -44,6 +44,7 @@ import org.sonar.scanner.protocol.output.ScannerReportReader;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.rule.ModuleQProfiles;
import org.sonar.scanner.rule.QProfile;
import org.sonar.scanner.scan.BranchConfiguration;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
@@ -66,6 +67,7 @@ public class MetadataPublisherTest {
private InputModuleHierarchy inputModuleHierarchy;
private AnalysisMode analysisMode;
private ScannerPluginRepository pluginRepository;
private BranchConfiguration branches;

@Before
public void prepare() throws IOException {
@@ -84,7 +86,9 @@ public class MetadataPublisherTest {
inputModuleHierarchy = mock(InputModuleHierarchy.class);
when(inputModuleHierarchy.root()).thenReturn(rootModule);
analysisMode = mock(AnalysisMode.class);
underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, settings.asConfig(), qProfiles, cpdSettings, analysisMode, pluginRepository);
branches = mock(BranchConfiguration.class);
underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, settings.asConfig(), qProfiles, cpdSettings, analysisMode,
pluginRepository, branches);
}

@Test
@@ -160,4 +164,39 @@ public class MetadataPublisherTest {
assertThat(metadata.getOrganizationKey()).isEqualTo("SonarSource");
}

@Test
public void write_long_lived_branch_info() throws Exception {
String branchName = "long-lived";
settings.setProperty(ScannerProperties.BRANCH_NAME, branchName);

when(branches.branchType()).thenReturn(BranchConfiguration.BranchType.LONG);

File outputDir = temp.newFolder();
underTest.publish(new ScannerReportWriter(outputDir));

ScannerReportReader reader = new ScannerReportReader(outputDir);
ScannerReport.Metadata metadata = reader.readMetadata();
assertThat(metadata.getBranchName()).isEqualTo(branchName);
assertThat(metadata.getBranchType()).isEqualTo(ScannerReport.Metadata.BranchType.LONG);
}

@Test
public void write_short_lived_branch_info() throws Exception {
String branchName = "feature";
String branchTarget = "short-lived";
settings.setProperty(ScannerProperties.BRANCH_NAME, branchName);
settings.setProperty(ScannerProperties.BRANCH_TARGET, branchTarget);

when(branches.branchTarget()).thenReturn(branchTarget);

File outputDir = temp.newFolder();
underTest.publish(new ScannerReportWriter(outputDir));

ScannerReportReader reader = new ScannerReportReader(outputDir);
ScannerReport.Metadata metadata = reader.readMetadata();
assertThat(metadata.getBranchName()).isEqualTo(branchName);
assertThat(metadata.getBranchType()).isEqualTo(ScannerReport.Metadata.BranchType.SHORT);
assertThat(metadata.getMergeBranchName()).isEqualTo(branchTarget);
}

}

+ 9
- 9
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoaderTest.java View File

@@ -59,7 +59,7 @@ public class DefaultProjectRepositoriesLoaderTest {
@Test
public void continueOnError() {
when(wsClient.call(any(WsRequest.class))).thenThrow(IllegalStateException.class);
ProjectRepositories proj = loader.load(PROJECT_KEY, false);
ProjectRepositories proj = loader.load(PROJECT_KEY, false, null);
assertThat(proj.exists()).isEqualTo(false);
}

@@ -68,7 +68,7 @@ public class DefaultProjectRepositoriesLoaderTest {
InputStream is = mock(InputStream.class);
when(is.read()).thenThrow(IOException.class);
WsTestUtil.mockStream(wsClient, "/batch/project.protobuf?key=foo%3F", is);
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
}

@Test(expected = IllegalStateException.class)
@@ -76,7 +76,7 @@ public class DefaultProjectRepositoriesLoaderTest {
HttpException http = new HttpException("url", 403, null);
IllegalStateException e = new IllegalStateException("http error", http);
WsTestUtil.mockException(wsClient, e);
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
}

@Test
@@ -87,26 +87,26 @@ public class DefaultProjectRepositoriesLoaderTest {
HttpException http = new HttpException("uri", 403, null);
MessageException e = MessageException.of("http error", http);
WsTestUtil.mockException(wsClient, e);
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
}

@Test
public void passIssuesModeParameter() {
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
WsTestUtil.verifyCall(wsClient, "/batch/project.protobuf?key=foo%3F");

loader.load(PROJECT_KEY, true);
loader.load(PROJECT_KEY, true, null);
WsTestUtil.verifyCall(wsClient, "/batch/project.protobuf?key=foo%3F&issues_mode=true");
}

@Test
public void deserializeResponse() throws IOException {
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
}

@Test
public void passAndEncodeProjectKeyParameter() {
loader.load(PROJECT_KEY, false);
loader.load(PROJECT_KEY, false, null);
WsTestUtil.verifyCall(wsClient, "/batch/project.protobuf?key=foo%3F");
}

@@ -124,7 +124,7 @@ public class DefaultProjectRepositoriesLoaderTest {
InputStream is = getTestResource("project.protobuf");
WsTestUtil.mockStream(wsClient, "/batch/project.protobuf?key=org.sonarsource.github%3Asonar-github-plugin&issues_mode=true", is);

ProjectRepositories proj = loader.load("org.sonarsource.github:sonar-github-plugin", true);
ProjectRepositories proj = loader.load("org.sonarsource.github:sonar-github-plugin", true, null);
FileData fd = proj.fileData("org.sonarsource.github:sonar-github-plugin",
"src/test/java/org/sonar/plugins/github/PullRequestIssuePostJobTest.java");


+ 9
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java View File

@@ -28,8 +28,10 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.bootstrap.ProjectKey;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
import org.sonar.scanner.scan.BranchConfiguration;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -46,6 +48,8 @@ public class ProjectRepositoriesProviderTest {
private ProjectKey projectKey;
@Mock
private DefaultAnalysisMode mode;
@Mock
private BranchConfiguration branchConfiguration;

@Before
public void setUp() {
@@ -63,24 +67,24 @@ public class ProjectRepositoriesProviderTest {
@Test
public void testValidation() {
when(mode.isIssues()).thenReturn(true);
when(loader.load(eq("key"), eq(true))).thenReturn(project);
when(loader.load(eq("key"), eq(true), any())).thenReturn(project);

provider.provide(loader, projectKey, mode);
provider.provide(loader, projectKey, mode, branchConfiguration);
}

@Test
public void testAssociated() {
when(mode.isIssues()).thenReturn(false);
when(loader.load(eq("key"), eq(false))).thenReturn(project);
when(loader.load(eq("key"), eq(false), any())).thenReturn(project);

ProjectRepositories repo = provider.provide(loader, projectKey, mode);
ProjectRepositories repo = provider.provide(loader, projectKey, mode, branchConfiguration);

assertThat(repo.exists()).isEqualTo(true);
assertThat(repo.lastAnalysisDate()).isNotNull();

verify(mode, times(1)).isIssues();
verify(projectKey).get();
verify(loader).load(eq("key"), eq(false));
verify(loader).load(eq("key"), eq(false), eq(null));
verifyNoMoreInteractions(loader, projectKey, mode);
}
}

+ 4
- 20
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java View File

@@ -19,11 +19,6 @@
*/
package org.sonar.scanner.scan;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Optional;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -32,26 +27,23 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.utils.MessageException;
import org.sonar.core.config.ScannerProperties;
import org.sonar.scanner.analysis.DefaultAnalysisMode;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ProjectReactorValidatorTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

private DefaultAnalysisMode mode;
private ProjectSettings settings;
private ProjectReactorValidator validator;

@Before
public void prepare() {
mode = mock(DefaultAnalysisMode.class);

settings = mock(ProjectSettings.class);
when(settings.get(ScannerProperties.BRANCH_NAME)).thenReturn(Optional.empty());

validator = new ProjectReactorValidator(mode, settings);
validator = new ProjectReactorValidator(mode);
}

@Test
@@ -161,14 +153,6 @@ public class ProjectReactorValidatorTest {
validator.validate(reactor);
}

@Test
public void should_fail_when_both_old_and_new_branch_property_present() {
thrown.expect(MessageException.class);
thrown.expectMessage("The sonar.branch.name parameter must not be used together with the deprecated sonar.branch parameter");
when(settings.get(ScannerProperties.BRANCH_NAME)).thenReturn(Optional.of("feature"));
validator.validate(createProjectReactor("foo", "branch1"));
}

private ProjectReactor createProjectReactor(String projectKey) {
ProjectDefinition def = ProjectDefinition.create().setProperty(CoreProperties.PROJECT_KEY_PROPERTY, projectKey);
ProjectReactor reactor = new ProjectReactor(def);

Loading…
Cancel
Save