@@ -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(); | |||
} | |||
} | |||
} |
@@ -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() |
@@ -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 |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
@@ -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); | |||
} |
@@ -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(); | |||
} |
@@ -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(); | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -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)); | |||
} | |||
} | |||
} |
@@ -136,6 +136,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
DefaultIndex.class, | |||
Storages.class, | |||
new RulesProvider(), | |||
new BranchConfigurationProvider(), | |||
// temp | |||
new AnalysisTempFolderProvider(), |
@@ -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<>(); |
@@ -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); | |||
} | |||
} |
@@ -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"); | |||
@@ -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); | |||
} | |||
} |
@@ -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); |