@@ -0,0 +1,5 @@ | |||
#sonar.projectKey=sample | |||
sonar.projectName=Sample | |||
sonar.projectVersion=1.0-SNAPSHOT | |||
sonar.sources=src/main/xoo | |||
sonar.language=xoo |
@@ -0,0 +1,16 @@ | |||
package sample; | |||
public class Sample { | |||
public Sample(int i) { | |||
int j = i++; | |||
} | |||
private String myMethod() { | |||
if (foo == bar) { | |||
return "hello"; | |||
} else { | |||
throw new IllegalStateException(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
ncloc:13 | |||
#Used by dashboard/widgets tests | |||
complexity:3 | |||
complexity_in_classes:3 | |||
classes:1 | |||
comment_lines:3 | |||
public_api:5 | |||
public_undocumented_api:2 | |||
duplicated_files:1 | |||
duplicated_blocks:2 | |||
duplicated_lines:3 |
@@ -69,28 +69,45 @@ public class IssuesModeTest { | |||
} | |||
@Test | |||
public void issuesAnalysisOnNewProject() throws IOException { | |||
public void issues_analysis_on_new_project() throws IOException { | |||
restoreProfile("one-issue-per-line.xml"); | |||
orchestrator.getServer().provisionProject("sample", "xoo-sample"); | |||
orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); | |||
SonarRunner runner = configureRunnerIssues("shared/xoo-sample"); | |||
orchestrator.executeBuild(runner); | |||
BuildResult result = orchestrator.executeBuild(runner); | |||
assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); | |||
} | |||
@Test | |||
public void invalidIncrementalMode() throws IOException { | |||
public void invalid_incremental_mode() throws IOException { | |||
restoreProfile("one-issue-per-line.xml"); | |||
orchestrator.getServer().provisionProject("sample", "xoo-sample"); | |||
orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-line"); | |||
SonarRunner runner = configureRunner("shared/xoo-sample"); | |||
runner.setProperty("sonar.analysis.mode", "incremental"); | |||
thrown.expect(BuildFailureException.class); | |||
BuildResult res = orchestrator.executeBuild(runner); | |||
assertThat(res.getLogs()).contains("Invalid analysis mode: incremental. This mode was removed in SonarQube 5.2"); | |||
} | |||
@Test | |||
public void non_associated_mode() throws IOException { | |||
restoreProfile("one-issue-per-line.xml"); | |||
setDefaultQualityProfile("xoo", "one-issue-per-line"); | |||
SonarRunner runner = configureRunnerIssues("shared/xoo-sample-non-associated"); | |||
BuildResult result = orchestrator.executeBuild(runner); | |||
assertThat(result.getLogs()).contains("is not associated"); | |||
assertThat(result.getLogs()).contains("Cache not found, synchronizing data"); | |||
assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); | |||
result = orchestrator.executeBuild(runner); | |||
assertThat(ItUtils.countIssuesInJsonReport(result, true)).isEqualTo(17); | |||
assertThat(result.getLogs()).contains("Found cache"); | |||
} | |||
// SONAR-5715 | |||
@Test | |||
public void test_issues_mode_on_project_with_space_in_filename() throws IOException { | |||
@@ -329,16 +346,16 @@ public class IssuesModeTest { | |||
boolean expectedError = false; | |||
for (Future<BuildResult> result : executorService.invokeAll(tasks)) { | |||
try { | |||
result.get(); | |||
} catch(ExecutionException e) { | |||
if(e.getCause() instanceof BuildFailureException) { | |||
result.get(); | |||
} catch (ExecutionException e) { | |||
if (e.getCause() instanceof BuildFailureException) { | |||
BuildFailureException bfe = (BuildFailureException) e.getCause(); | |||
assertThat(bfe.getResult().getLogs()).contains("Another SonarQube analysis is already in progress for this project"); | |||
expectedError = true; | |||
} | |||
} | |||
} | |||
if(!expectedError) { | |||
if (!expectedError) { | |||
fail("At least one of the threads should have failed"); | |||
} | |||
} | |||
@@ -370,4 +387,10 @@ public class IssuesModeTest { | |||
return runner; | |||
} | |||
private void setDefaultQualityProfile(String languageKey, String profileName) { | |||
orchestrator.getServer().adminWsClient().post("api/qualityprofiles/set_default", | |||
"language", languageKey, | |||
"profileName", profileName); | |||
} | |||
} |
@@ -45,6 +45,10 @@ public class ProjectRepositories { | |||
public Map<String, String> settings(String moduleKey) { | |||
return settingsByModule.containsKey(moduleKey) ? settingsByModule.get(moduleKey) : Collections.<String, String>emptyMap(); | |||
} | |||
public Map<String, Map<String, String>> settings() { | |||
return settingsByModule; | |||
} | |||
public ProjectRepositories addSettings(String moduleKey, Map<String, String> settings) { | |||
Map<String, String> existingSettings = settingsByModule.get(moduleKey); |
@@ -38,6 +38,7 @@ public class DefaultAnalysisMode extends AbstractAnalysisMode implements Analysi | |||
private static final Logger LOG = LoggerFactory.getLogger(DefaultAnalysisMode.class); | |||
private boolean mediumTestMode; | |||
private boolean notAssociated; | |||
public DefaultAnalysisMode(GlobalProperties globalProps, AnalysisProperties props) { | |||
init(globalProps.properties(), props.properties()); | |||
@@ -47,6 +48,10 @@ public class DefaultAnalysisMode extends AbstractAnalysisMode implements Analysi | |||
return mediumTestMode; | |||
} | |||
public boolean isNotAssociated() { | |||
return notAssociated; | |||
} | |||
private void init(Map<String, String> globalProps, Map<String, String> analysisProps) { | |||
// make sure analysis is consistent with global properties | |||
boolean globalPreview = isIssues(globalProps); | |||
@@ -64,6 +69,7 @@ public class DefaultAnalysisMode extends AbstractAnalysisMode implements Analysi | |||
validate(mode); | |||
issues = CoreProperties.ANALYSIS_MODE_ISSUES.equals(mode) || CoreProperties.ANALYSIS_MODE_PREVIEW.equals(mode); | |||
mediumTestMode = "true".equals(getPropertyWithFallback(analysisProps, globalProps, FakePluginInstaller.MEDIUM_TEST_ENABLED)); | |||
notAssociated = issues && rootProjectKeyMissing(analysisProps); | |||
} | |||
public void printMode() { | |||
@@ -77,6 +83,9 @@ public class DefaultAnalysisMode extends AbstractAnalysisMode implements Analysi | |||
if (mediumTestMode) { | |||
LOG.info("Medium test mode"); | |||
} | |||
if (notAssociated) { | |||
LOG.info("Project is not associated with the server"); | |||
} | |||
} | |||
private static String getPropertyWithFallback(Map<String, String> props1, Map<String, String> props2, String key) { | |||
@@ -93,4 +102,9 @@ public class DefaultAnalysisMode extends AbstractAnalysisMode implements Analysi | |||
return CoreProperties.ANALYSIS_MODE_ISSUES.equals(mode); | |||
} | |||
private static boolean rootProjectKeyMissing(Map<String, String> props) { | |||
// ProjectReactorBuilder depends on this class, so it will only create this property later | |||
return !props.containsKey(CoreProperties.PROJECT_KEY_PROPERTY); | |||
} | |||
} |
@@ -123,14 +123,22 @@ public class GlobalContainer extends ComponentContainer { | |||
public void executeAnalysis(Map<String, String> analysisProperties, Object... components) { | |||
AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(GlobalProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); | |||
if (isIssuesMode(props)) { | |||
new ProjectSyncContainer(this, props, false).execute(); | |||
String projectKey = getProjectKeyWithBranch(props); | |||
new ProjectSyncContainer(this, projectKey, false).execute(); | |||
} | |||
new ProjectScanContainer(this, props, components).execute(); | |||
} | |||
public void syncProject(Map<String, String> analysisProperties, boolean force) { | |||
AnalysisProperties props = new AnalysisProperties(analysisProperties, this.getComponentByType(GlobalProperties.class).property(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); | |||
new ProjectSyncContainer(this, props, force).execute(); | |||
private static String getProjectKeyWithBranch(AnalysisProperties props) { | |||
String projectKey = props.property(CoreProperties.PROJECT_KEY_PROPERTY); | |||
if (projectKey != null && props.property(CoreProperties.PROJECT_BRANCH_PROPERTY) != null) { | |||
projectKey = projectKey + ":" + props.property(CoreProperties.PROJECT_BRANCH_PROPERTY); | |||
} | |||
return projectKey; | |||
} | |||
public void syncProject(String projectKey, boolean force) { | |||
new ProjectSyncContainer(this, projectKey, force).execute(); | |||
} | |||
private boolean isIssuesMode(AnalysisProperties props) { |
@@ -19,6 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.bootstrap; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.google.common.base.Joiner; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Strings; | |||
@@ -27,10 +30,13 @@ import com.google.gson.JsonElement; | |||
import com.google.gson.JsonObject; | |||
import com.google.gson.JsonParser; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.net.URI; | |||
import java.nio.charset.StandardCharsets; | |||
import java.nio.file.Files; | |||
import java.nio.file.StandardCopyOption; | |||
import java.util.ArrayList; | |||
@@ -55,8 +61,8 @@ import org.sonar.core.util.DefaultHttpDownloader; | |||
*/ | |||
@BatchSide | |||
public class ServerClient { | |||
private static final String GET = "GET"; | |||
private static final Logger LOG = LoggerFactory.getLogger(ServerClient.class); | |||
private GlobalProperties props; | |||
private DefaultHttpDownloader.BaseHttpDownloader downloader; | |||
@@ -68,6 +74,20 @@ public class ServerClient { | |||
public String getURL() { | |||
return StringUtils.removeEnd(StringUtils.defaultIfBlank(props.property("sonar.host.url"), "http://localhost:9000"), "/"); | |||
} | |||
public String getServerVersion() { | |||
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sq-version.txt"); | |||
if (is == null) { | |||
LOG.warn("Failed to get SQ version"); | |||
return null; | |||
} | |||
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { | |||
return br.readLine(); | |||
} catch (IOException e) { | |||
LOG.warn("Failed to get SQ version", e); | |||
return null; | |||
} | |||
} | |||
public URI getURI(String pathStartingWithSlash) { | |||
Preconditions.checkArgument(pathStartingWithSlash.startsWith("/"), "Path must start with slash /: " + pathStartingWithSlash); |
@@ -19,9 +19,6 @@ | |||
*/ | |||
package org.sonar.batch.bootstrapper; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.sonar.api.CoreProperties; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Maps; | |||
@@ -134,8 +131,7 @@ public final class Batch { | |||
*/ | |||
public Batch syncProject(String projectKey) { | |||
checkStarted(); | |||
Map<String, String> props = ImmutableMap.of(CoreProperties.PROJECT_KEY_PROPERTY, projectKey); | |||
bootstrapContainer.syncProject(props, true); | |||
bootstrapContainer.syncProject(projectKey, true); | |||
return this; | |||
} | |||
@@ -19,6 +19,8 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.home.cache.PersistentCache; | |||
@@ -40,7 +42,7 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { | |||
} | |||
@Override | |||
public void save(String projectKey) { | |||
public void save(@Nullable String projectKey) { | |||
Date now = new Date(); | |||
try { | |||
@@ -55,7 +57,7 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { | |||
} | |||
@Override | |||
public void delete(String projectKey) { | |||
public void delete(@Nullable String projectKey) { | |||
try { | |||
cache.put(getKey(projectKey), new byte[0]); | |||
} catch (IOException e) { | |||
@@ -64,7 +66,7 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { | |||
} | |||
@Override | |||
public Date getSyncStatus(String projectKey) { | |||
public Date getSyncStatus(@Nullable String projectKey) { | |||
try { | |||
byte[] status = cache.get(getKey(projectKey), null); | |||
if (status == null || status.length == 0) { | |||
@@ -79,7 +81,11 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { | |||
} | |||
} | |||
private String getKey(String projectKey) { | |||
return STATUS_PREFIX + client.getURL() + "-" + projectKey; | |||
private String getKey(@Nullable String projectKey) { | |||
if (projectKey != null) { | |||
return STATUS_PREFIX + client.getURL() + "-" + client.getServerVersion() + "-" + projectKey; | |||
} else { | |||
return STATUS_PREFIX + client.getURL() + "-" + client.getServerVersion(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.cache; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import java.util.List; | |||
public class NonAssociatedCacheSynchronizer { | |||
private static final Logger LOG = LoggerFactory.getLogger(NonAssociatedCacheSynchronizer.class); | |||
private ProjectCacheStatus cacheStatus; | |||
private QualityProfileLoader qualityProfileLoader; | |||
private ActiveRulesLoader activeRulesLoader; | |||
public NonAssociatedCacheSynchronizer(QualityProfileLoader qualityProfileLoader, ActiveRulesLoader activeRulesLoader, ProjectCacheStatus cacheStatus) { | |||
this.qualityProfileLoader = qualityProfileLoader; | |||
this.activeRulesLoader = activeRulesLoader; | |||
this.cacheStatus = cacheStatus; | |||
} | |||
public void execute(boolean force) { | |||
Date lastSync = cacheStatus.getSyncStatus(null); | |||
if (lastSync != null) { | |||
if (!force) { | |||
LOG.info("Found cache [{}]", lastSync); | |||
return; | |||
} else { | |||
LOG.info("-- Found cache [{}], synchronizing data..", lastSync); | |||
} | |||
cacheStatus.delete(null); | |||
} else { | |||
LOG.info("-- Cache not found, synchronizing data.."); | |||
} | |||
loadData(); | |||
saveStatus(); | |||
} | |||
private static Collection<String> getKeys(Collection<QProfile> qProfiles) { | |||
List<String> list = new ArrayList<>(qProfiles.size()); | |||
for (QProfile qp : qProfiles) { | |||
list.add(qp.key()); | |||
} | |||
return list; | |||
} | |||
private void saveStatus() { | |||
cacheStatus.save(null); | |||
LOG.info("-- Succesfully synchronized cache"); | |||
} | |||
private void loadData() { | |||
Profiler profiler = Profiler.create(Loggers.get(ProjectCacheSynchronizer.class)); | |||
profiler.startInfo("Load default quality profiles"); | |||
Collection<QProfile> qProfiles = qualityProfileLoader.load(null, null); | |||
profiler.stopInfo(); | |||
profiler.startInfo("Load default active rules"); | |||
activeRulesLoader.load(getKeys(qProfiles), null); | |||
profiler.stopInfo(); | |||
} | |||
} |
@@ -49,14 +49,14 @@ public class PersistentCacheProvider extends ProviderAdapter { | |||
builder.setSonarHome(Paths.get(home)); | |||
} | |||
builder.setVersion(getVersion()); | |||
builder.setVersion(getServerVersion()); | |||
cache = builder.build(); | |||
} | |||
return cache; | |||
} | |||
private String getVersion() { | |||
private String getServerVersion() { | |||
InputStream is = this.getClass().getClassLoader().getResourceAsStream("sq-version.txt"); | |||
if (is == null) { | |||
LOG.warn("Failed to get SQ version"); |
@@ -19,12 +19,14 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import javax.annotation.Nullable; | |||
import java.util.Date; | |||
public interface ProjectCacheStatus { | |||
void save(String projectKey); | |||
void save(@Nullable String projectKey); | |||
void delete(String projectKey); | |||
void delete(@Nullable String projectKey); | |||
Date getSyncStatus(String projectKey); | |||
Date getSyncStatus(@Nullable String projectKey); | |||
} |
@@ -19,100 +19,98 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import com.google.common.base.Function; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.protocol.input.BatchInput.ServerIssue; | |||
import com.google.common.base.Function; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import org.sonar.batch.repository.ProjectSettingsLoader; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
import org.sonar.batch.repository.ServerIssuesLoader; | |||
import org.sonar.batch.repository.user.UserRepositoryLoader; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import java.util.HashSet; | |||
import java.util.Map; | |||
import java.util.Map.Entry; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.concurrent.Callable; | |||
import java.util.concurrent.ExecutorService; | |||
import java.util.concurrent.Executors; | |||
import java.util.concurrent.TimeUnit; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.batch.repository.user.UserRepositoryLoader; | |||
import org.sonar.batch.issue.tracking.ServerLineHashesLoader; | |||
import org.sonar.batch.repository.ServerIssuesLoader; | |||
import org.sonar.batch.repository.ProjectRepositoriesLoader; | |||
public class ProjectCacheSynchronizer { | |||
private static final Logger LOG = LoggerFactory.getLogger(ProjectCacheSynchronizer.class); | |||
private static final int NUM_THREAD = 2; | |||
private final ProjectDefinition project; | |||
private final AnalysisProperties properties; | |||
private final ProjectRepositoriesLoader projectRepositoryLoader; | |||
private final ServerIssuesLoader issuesLoader; | |||
private final ServerLineHashesLoader lineHashesLoader; | |||
private final UserRepositoryLoader userRepository; | |||
private final ProjectCacheStatus cacheStatus; | |||
public ProjectCacheSynchronizer(ProjectReactor project, ProjectRepositoriesLoader projectRepositoryLoader, AnalysisProperties properties, | |||
ServerIssuesLoader issuesLoader, ServerLineHashesLoader lineHashesLoader, UserRepositoryLoader userRepository, ProjectCacheStatus cacheStatus) { | |||
this.project = project.getRoot(); | |||
this.projectRepositoryLoader = projectRepositoryLoader; | |||
this.properties = properties; | |||
private final QualityProfileLoader qualityProfileLoader; | |||
private final ProjectSettingsLoader projectSettingsLoader; | |||
private final ActiveRulesLoader activeRulesLoader; | |||
public ProjectCacheSynchronizer(QualityProfileLoader qualityProfileLoader, ProjectSettingsLoader projectSettingsLoader, | |||
ActiveRulesLoader activeRulesLoader, ServerIssuesLoader issuesLoader, | |||
UserRepositoryLoader userRepository, ProjectCacheStatus cacheStatus) { | |||
this.qualityProfileLoader = qualityProfileLoader; | |||
this.projectSettingsLoader = projectSettingsLoader; | |||
this.activeRulesLoader = activeRulesLoader; | |||
this.issuesLoader = issuesLoader; | |||
this.lineHashesLoader = lineHashesLoader; | |||
this.userRepository = userRepository; | |||
this.cacheStatus = cacheStatus; | |||
} | |||
public void load(boolean force) { | |||
Date lastSync = cacheStatus.getSyncStatus(project.getKeyWithBranch()); | |||
public void load(String projectKey, boolean force) { | |||
Date lastSync = cacheStatus.getSyncStatus(projectKey); | |||
if (lastSync != null) { | |||
if (!force) { | |||
LOG.info("Found project [{}] cache [{}]", project.getKeyWithBranch(), lastSync); | |||
LOG.info("Found project [{}] cache [{}]", projectKey, lastSync); | |||
return; | |||
} else { | |||
LOG.info("-- Found project [{}] cache [{}], synchronizing data..", project.getKeyWithBranch(), lastSync); | |||
LOG.info("-- Found project [{}] cache [{}], synchronizing data..", projectKey, lastSync); | |||
} | |||
cacheStatus.delete(project.getKeyWithBranch()); | |||
cacheStatus.delete(projectKey); | |||
} else { | |||
LOG.info("-- Cache for project [{}] not found, synchronizing data..", project.getKeyWithBranch()); | |||
LOG.info("-- Cache for project [{}] not found, synchronizing data..", projectKey); | |||
} | |||
loadData(); | |||
saveStatus(); | |||
loadData(projectKey); | |||
saveStatus(projectKey); | |||
} | |||
private void saveStatus() { | |||
cacheStatus.save(project.getKeyWithBranch()); | |||
private void saveStatus(String projectKey) { | |||
cacheStatus.save(projectKey); | |||
LOG.info("-- Succesfully synchronized project cache"); | |||
} | |||
private static String getComponentKey(String moduleKey, String filePath) { | |||
return moduleKey + ":" + filePath; | |||
} | |||
private void loadData() { | |||
private void loadData(String projectKey) { | |||
Profiler profiler = Profiler.create(Loggers.get(ProjectCacheSynchronizer.class)); | |||
profiler.startInfo("Load project repository"); | |||
ProjectRepositories projectRepo = projectRepositoryLoader.load(project, properties, null); | |||
profiler.startInfo("Load project settings"); | |||
ProjectSettingsRepo settings = projectSettingsLoader.load(projectKey, null); | |||
profiler.stopInfo(); | |||
if (projectRepo.lastAnalysisDate() == null) { | |||
if (settings.lastAnalysisDate() == null) { | |||
LOG.debug("No previous analysis found"); | |||
return; | |||
} | |||
profiler.startInfo("Load project quality profiles"); | |||
Collection<QProfile> qProfiles = qualityProfileLoader.load(projectKey, null); | |||
profiler.stopInfo(); | |||
Collection<String> profileKeys = getKeys(qProfiles); | |||
profiler.startInfo("Load project active rules"); | |||
activeRulesLoader.load(profileKeys, projectKey); | |||
profiler.stopInfo(); | |||
profiler.startInfo("Load server issues"); | |||
UserLoginAccumulator consumer = new UserLoginAccumulator(); | |||
issuesLoader.load(project.getKeyWithBranch(), consumer); | |||
issuesLoader.load(projectKey, consumer); | |||
profiler.stopInfo(); | |||
profiler.startInfo("Load user information (" + consumer.loginSet.size() + " users)"); | |||
@@ -120,56 +118,15 @@ public class ProjectCacheSynchronizer { | |||
userRepository.load(login, null); | |||
} | |||
profiler.stopInfo("Load user information"); | |||
loadLineHashes(projectRepo.fileDataByModuleAndPath(), profiler); | |||
} | |||
private void loadLineHashes(Map<String, Map<String, FileData>> fileDataByModuleAndPath, Profiler profiler) { | |||
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREAD); | |||
int numFiles = 0; | |||
for (Map<String, FileData> fileDataByPath : fileDataByModuleAndPath.values()) { | |||
numFiles += fileDataByPath.size(); | |||
} | |||
profiler.startInfo("Load line file hashes (" + numFiles + " files)"); | |||
for (Entry<String, Map<String, FileData>> e1 : fileDataByModuleAndPath.entrySet()) { | |||
String moduleKey = e1.getKey(); | |||
for (Entry<String, FileData> e2 : e1.getValue().entrySet()) { | |||
String filePath = e2.getKey(); | |||
executor.submit(new LineHashLoadWorker(getComponentKey(moduleKey, filePath))); | |||
} | |||
} | |||
executor.shutdown(); | |||
try { | |||
boolean done = executor.awaitTermination(30, TimeUnit.MINUTES); | |||
if (!done) { | |||
executor.shutdownNow(); | |||
throw new IllegalStateException("Timeout while fetching line hashes"); | |||
} | |||
} catch (InterruptedException e) { | |||
executor.shutdownNow(); | |||
throw new IllegalStateException("Interrupted while fetching line hashes", e); | |||
private static Collection<String> getKeys(Collection<QProfile> qProfiles) { | |||
List<String> list = new ArrayList<>(qProfiles.size()); | |||
for (QProfile qp : qProfiles) { | |||
list.add(qp.key()); | |||
} | |||
profiler.stopInfo("Load line file hashes (done)"); | |||
} | |||
private class LineHashLoadWorker implements Callable<Void> { | |||
private String fileKey; | |||
LineHashLoadWorker(String fileKey) { | |||
this.fileKey = fileKey; | |||
} | |||
@Override | |||
public Void call() throws Exception { | |||
lineHashesLoader.getLineHashes(fileKey, null); | |||
return null; | |||
} | |||
return list; | |||
} | |||
private static class UserLoginAccumulator implements Function<ServerIssue, Void> { |
@@ -19,59 +19,73 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.batch.repository.ProjectRepositoriesFactoryProvider; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.cache.WSLoader.LoadStrategy; | |||
import org.sonar.api.CoreProperties; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.bootstrap.GlobalProperties; | |||
import org.sonar.batch.repository.ProjectSettingsLoader; | |||
import org.sonar.batch.repository.DefaultProjectSettingsLoader; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import org.sonar.batch.rule.DefaultActiveRulesLoader; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
import org.sonar.batch.repository.DefaultQualityProfileLoader; | |||
import org.sonar.batch.cache.WSLoader.LoadStrategy; | |||
import org.sonar.batch.repository.user.UserRepositoryLoader; | |||
import org.sonar.batch.issue.tracking.ServerLineHashesLoader; | |||
import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; | |||
import org.sonar.batch.repository.DefaultServerIssuesLoader; | |||
import org.sonar.batch.repository.ProjectRepositoriesLoader; | |||
import org.sonar.batch.repository.ServerIssuesLoader; | |||
import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader; | |||
import org.sonar.core.platform.ComponentContainer; | |||
public class ProjectSyncContainer extends ComponentContainer { | |||
private final boolean force; | |||
private final AnalysisProperties properties; | |||
private final String projectKey; | |||
public ProjectSyncContainer(ComponentContainer globalContainer, AnalysisProperties analysisProperties, boolean force) { | |||
public ProjectSyncContainer(ComponentContainer globalContainer, String projectKey, boolean force) { | |||
super(globalContainer); | |||
this.properties = analysisProperties; | |||
this.projectKey = projectKey; | |||
this.force = force; | |||
} | |||
@Override | |||
public void doBeforeStart() { | |||
ProjectReactor projectReactor = createProjectReactor(); | |||
add(projectReactor); | |||
addComponents(); | |||
} | |||
private ProjectReactor createProjectReactor() { | |||
ProjectDefinition rootProjectDefinition = ProjectDefinition.create(); | |||
rootProjectDefinition.setProperties(properties.properties()); | |||
return new ProjectReactor(rootProjectDefinition); | |||
} | |||
@Override | |||
public void doAfterStart() { | |||
getComponentByType(ProjectCacheSynchronizer.class).load(force); | |||
if (projectKey != null) { | |||
getComponentByType(ProjectCacheSynchronizer.class).load(projectKey, force); | |||
} else { | |||
getComponentByType(NonAssociatedCacheSynchronizer.class).execute(force); | |||
} | |||
} | |||
private static DefaultAnalysisMode createIssuesAnalisysMode() { | |||
Map<String, String> props = ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES); | |||
GlobalProperties globalProps = new GlobalProperties(props); | |||
AnalysisProperties analysisProps = new AnalysisProperties(props); | |||
return new DefaultAnalysisMode(globalProps, analysisProps); | |||
} | |||
private void addComponents() { | |||
add(new StrategyWSLoaderProvider(LoadStrategy.SERVER_FIRST), | |||
properties, | |||
DefaultAnalysisMode.class, | |||
ProjectCacheSynchronizer.class, | |||
UserRepositoryLoader.class); | |||
add(new StrategyWSLoaderProvider(LoadStrategy.SERVER_ONLY), | |||
projectKey != null ? ProjectCacheSynchronizer.class : NonAssociatedCacheSynchronizer.class, | |||
UserRepositoryLoader.class, | |||
new ProjectRepositoriesFactoryProvider(projectKey), | |||
createIssuesAnalisysMode()); | |||
addIfMissing(DefaultProjectCacheStatus.class, ProjectCacheStatus.class); | |||
addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); | |||
addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); | |||
addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class); | |||
addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class); | |||
addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class); | |||
addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); | |||
} | |||
} |
@@ -51,13 +51,13 @@ public class WSLoader { | |||
SERVER_FIRST, CACHE_FIRST, SERVER_ONLY, CACHE_ONLY; | |||
} | |||
private final LoadStrategy loadStrategy; | |||
private final LoadStrategy defautLoadStrategy; | |||
private ServerStatus serverStatus; | |||
private final ServerClient client; | |||
private final PersistentCache cache; | |||
public WSLoader(LoadStrategy strategy, PersistentCache cache, ServerClient client) { | |||
this.loadStrategy = strategy; | |||
this.defautLoadStrategy = strategy; | |||
this.serverStatus = UNKNOWN; | |||
this.cache = cache; | |||
this.client = client; | |||
@@ -65,19 +65,28 @@ public class WSLoader { | |||
@Nonnull | |||
public WSLoaderResult<ByteSource> loadSource(String id) { | |||
WSLoaderResult<byte[]> byteResult = load(id); | |||
WSLoaderResult<byte[]> byteResult = load(id, defautLoadStrategy); | |||
return new WSLoaderResult<ByteSource>(ByteSource.wrap(byteResult.get()), byteResult.isFromCache()); | |||
} | |||
@Nonnull | |||
public WSLoaderResult<String> loadString(String id) { | |||
WSLoaderResult<byte[]> byteResult = load(id); | |||
return loadString(id, defautLoadStrategy); | |||
} | |||
@Nonnull | |||
public WSLoaderResult<String> loadString(String id, WSLoader.LoadStrategy strategy) { | |||
WSLoaderResult<byte[]> byteResult = load(id, strategy); | |||
return new WSLoaderResult<String>(new String(byteResult.get(), StandardCharsets.UTF_8), byteResult.isFromCache()); | |||
} | |||
@Nonnull | |||
public WSLoaderResult<byte[]> load(String id) { | |||
switch (loadStrategy) { | |||
return load(id, defautLoadStrategy); | |||
} | |||
@Nonnull | |||
public WSLoaderResult<byte[]> load(String id, WSLoader.LoadStrategy strategy) { | |||
switch (strategy) { | |||
case CACHE_FIRST: | |||
return loadFromCacheFirst(id, true); | |||
case CACHE_ONLY: | |||
@@ -91,7 +100,7 @@ public class WSLoader { | |||
} | |||
public LoadStrategy getStrategy() { | |||
return this.loadStrategy; | |||
return this.defautLoadStrategy; | |||
} | |||
private void switchToOffline() { |
@@ -19,8 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.issue.tracking; | |||
import org.sonar.batch.cache.WSLoaderResult; | |||
import org.sonar.batch.cache.WSLoader.LoadStrategy; | |||
import org.sonar.batch.cache.WSLoaderResult; | |||
import org.sonar.batch.cache.WSLoader; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
@@ -50,7 +51,7 @@ public class DefaultServerLineHashesLoader implements ServerLineHashesLoader { | |||
Profiler profiler = Profiler.createIfDebug(Loggers.get(getClass())) | |||
.addContext("file", fileKey) | |||
.startDebug("Load line hashes"); | |||
WSLoaderResult<String> result = wsLoader.loadString("/api/sources/hash?key=" + BatchUtils.encodeForUrl(fileKey)); | |||
WSLoaderResult<String> result = wsLoader.loadString("/api/sources/hash?key=" + BatchUtils.encodeForUrl(fileKey), LoadStrategy.CACHE_FIRST); | |||
try { | |||
if (fromCache != null) { | |||
fromCache.setValue(result.isFromCache()); |
@@ -19,16 +19,22 @@ | |||
*/ | |||
package org.sonar.batch.issue.tracking; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Sets; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.rule.ActiveRule; | |||
@@ -41,7 +47,6 @@ import org.sonar.api.utils.KeyValueFormat; | |||
import org.sonar.batch.index.BatchComponent; | |||
import org.sonar.batch.index.BatchComponentCache; | |||
import org.sonar.batch.issue.IssueCache; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.protocol.output.BatchReport; | |||
import org.sonar.batch.protocol.output.BatchReportReader; | |||
import org.sonar.batch.report.ReportPublisher; | |||
@@ -72,7 +77,7 @@ public class LocalIssueTracking { | |||
public LocalIssueTracking(BatchComponentCache resourceCache, IssueCache issueCache, IssueTracking tracking, | |||
ServerLineHashesLoader lastLineHashes, IssueWorkflow workflow, IssueUpdater updater, | |||
ActiveRules activeRules, ServerIssueRepository serverIssueRepository, | |||
ProjectRepositories projectRepositories, ReportPublisher reportPublisher) { | |||
ProjectSettingsRepo projectRepositories, ReportPublisher reportPublisher, DefaultAnalysisMode mode) { | |||
this.componentCache = resourceCache; | |||
this.issueCache = issueCache; | |||
this.tracking = tracking; | |||
@@ -84,7 +89,7 @@ public class LocalIssueTracking { | |||
this.analysisDate = ((Project) resourceCache.getRoot().resource()).getAnalysisDate(); | |||
this.changeContext = IssueChangeContext.createScan(analysisDate); | |||
this.activeRules = activeRules; | |||
this.hasServerAnalysis = projectRepositories.lastAnalysisDate() != null; | |||
this.hasServerAnalysis = !mode.isNotAssociated() && projectRepositories.lastAnalysisDate() != null; | |||
} | |||
public void execute() { |
@@ -19,29 +19,42 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class ProjectRepositoriesProvider extends ProviderAdapter { | |||
public class DefaultProjectRepositoriesFactory implements ProjectRepositoriesFactory { | |||
private static final String LOG_MSG = "Load project repositories"; | |||
private static final Logger LOG = Loggers.get(ProjectRepositoriesProvider.class); | |||
private static final Logger LOG = Loggers.get(DefaultProjectRepositoriesFactory.class); | |||
private static final String NON_EXISTING = "non1-existing2-project3-key"; | |||
private final DefaultAnalysisMode analysisMode; | |||
private final ProjectRepositoriesLoader loader; | |||
private final AnalysisProperties props; | |||
private final ProjectReactor projectReactor; | |||
private ProjectRepositories projectReferentials; | |||
public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProjectReactor reactor, AnalysisProperties taskProps, AnalysisMode analysisMode) { | |||
public DefaultProjectRepositoriesFactory(ProjectReactor projectReactor, DefaultAnalysisMode analysisMode, ProjectRepositoriesLoader loader, AnalysisProperties props) { | |||
this.projectReactor = projectReactor; | |||
this.analysisMode = analysisMode; | |||
this.loader = loader; | |||
this.props = props; | |||
} | |||
@Override | |||
public ProjectRepositories create() { | |||
if (projectReferentials == null) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
MutableBoolean fromCache = new MutableBoolean(); | |||
projectReferentials = loader.load(reactor.getRoot(), taskProps, fromCache); | |||
projectReferentials = loader.load(getProjectKey(), getSonarProfile(), fromCache); | |||
profiler.stopInfo(fromCache.booleanValue()); | |||
if (analysisMode.isIssues() && projectReferentials.lastAnalysisDate() == null) { | |||
@@ -50,4 +63,19 @@ public class ProjectRepositoriesProvider extends ProviderAdapter { | |||
} | |||
return projectReferentials; | |||
} | |||
private String getProjectKey() { | |||
if (analysisMode.isNotAssociated()) { | |||
return NON_EXISTING; | |||
} | |||
return projectReactor.getRoot().getKeyWithBranch(); | |||
} | |||
private String getSonarProfile() { | |||
String profile = null; | |||
if (!analysisMode.isIssues()) { | |||
profile = props.property(ModuleQProfiles.SONAR_PROFILE_PROP); | |||
} | |||
return profile; | |||
} | |||
} |
@@ -23,12 +23,10 @@ import org.sonar.batch.cache.WSLoaderResult; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.cache.WSLoader; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.utils.MessageException; | |||
@@ -50,13 +48,12 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad | |||
} | |||
@Override | |||
public ProjectRepositories load(ProjectDefinition projectDefinition, AnalysisProperties taskProperties, @Nullable MutableBoolean fromCache) { | |||
String projectKey = projectDefinition.getKeyWithBranch(); | |||
String url = BATCH_PROJECT_URL + "?key=" + BatchUtils.encodeForUrl(projectKey); | |||
if (taskProperties.properties().containsKey(ModuleQProfiles.SONAR_PROFILE_PROP)) { | |||
public ProjectRepositories load(String projectKeyWithBranch, @Nullable String sonarProfile, @Nullable MutableBoolean fromCache) { | |||
String url = BATCH_PROJECT_URL + "?key=" + BatchUtils.encodeForUrl(projectKeyWithBranch); | |||
if (sonarProfile != null) { | |||
LOG.warn("Ability to set quality profile from command line using '" + ModuleQProfiles.SONAR_PROFILE_PROP | |||
+ "' is deprecated and will be dropped in a future SonarQube version. Please configure quality profile used by your project on SonarQube server."); | |||
url += "&profile=" + BatchUtils.encodeForUrl(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP)); | |||
url += "&profile=" + BatchUtils.encodeForUrl(sonarProfile); | |||
} | |||
url += "&preview=" + analysisMode.isIssues(); | |||
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import javax.annotation.Nullable; | |||
import java.util.Map; | |||
import com.google.common.collect.HashBasedTable; | |||
import com.google.common.collect.Table; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class DefaultProjectSettingsLoader implements ProjectSettingsLoader { | |||
private ProjectRepositoriesFactory projectRepositoryFactory; | |||
public DefaultProjectSettingsLoader(ProjectRepositoriesFactory projectRepositoryFactory) { | |||
this.projectRepositoryFactory = projectRepositoryFactory; | |||
} | |||
@Override | |||
public ProjectSettingsRepo load(String projectKey, @Nullable MutableBoolean fromCache) { | |||
ProjectRepositories pr = projectRepositoryFactory.create(); | |||
return new ProjectSettingsRepo(toTable(pr.settings()), toTable(pr.fileDataByModuleAndPath()), pr.lastAnalysisDate()); | |||
} | |||
private static <T, U, V> Table<T, U, V> toTable(Map<T, Map<U, V>> map) { | |||
Table<T, U, V> table = HashBasedTable.create(); | |||
for (Map.Entry<T, Map<U, V>> e1 : map.entrySet()) { | |||
for (Map.Entry<U, V> e2 : e1.getValue().entrySet()) { | |||
table.put(e1.getKey(), e2.getKey(), e2.getValue()); | |||
} | |||
} | |||
return table; | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import java.util.Collection; | |||
public class DefaultQualityProfileLoader implements QualityProfileLoader { | |||
private ProjectRepositoriesFactory projectRepositoriesFactory; | |||
public DefaultQualityProfileLoader(ProjectRepositoriesFactory projectRepositoriesFactory) { | |||
this.projectRepositoriesFactory = projectRepositoriesFactory; | |||
} | |||
@Override | |||
public Collection<QProfile> load(@Nullable String projectKey, @Nullable String sonarProfile) { | |||
ProjectRepositories pr = projectRepositoriesFactory.create(); | |||
validate(pr.qProfiles()); | |||
return pr.qProfiles(); | |||
} | |||
private static void validate(Collection<QProfile> profiles) { | |||
if (profiles == null || profiles.isEmpty()) { | |||
throw new IllegalStateException("No quality profiles has been found this project, you probably don't have any language plugin suitable for this analysis."); | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public interface ProjectRepositoriesFactory { | |||
ProjectRepositories create(); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
public class ProjectRepositoriesFactoryProvider extends ProviderAdapter { | |||
private final String projectKey; | |||
private SyncProjectRepositoriesFactory factory; | |||
public ProjectRepositoriesFactoryProvider(String projectKey) { | |||
this.projectKey = projectKey; | |||
this.factory = null; | |||
} | |||
public ProjectRepositoriesFactory provide(ProjectRepositoriesLoader loader) { | |||
if (factory == null) { | |||
factory = new SyncProjectRepositoriesFactory(projectKey, loader); | |||
} | |||
return factory; | |||
} | |||
} |
@@ -19,16 +19,14 @@ | |||
*/ | |||
package org.sonar.batch.repository; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public interface ProjectRepositoriesLoader { | |||
ProjectRepositories load(ProjectDefinition projectDefinition, AnalysisProperties taskProperties, @Nullable MutableBoolean fromCache); | |||
ProjectRepositories load(String projectKeyWithBranch, @Nullable String sonarProfile, @Nullable MutableBoolean fromCache); | |||
} |
@@ -0,0 +1,28 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import javax.annotation.Nullable; | |||
public interface ProjectSettingsLoader { | |||
ProjectSettingsRepo load(String projectKey, @Nullable MutableBoolean fromCache); | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import com.google.common.collect.Table; | |||
import com.google.common.collect.ImmutableTable; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
public class ProjectSettingsProvider extends ProviderAdapter { | |||
private static final Logger LOG = Loggers.get(ProjectSettingsProvider.class); | |||
private ProjectSettingsRepo settings = null; | |||
public ProjectSettingsRepo provide(@Nullable ProjectSettingsLoader loader, ProjectReactor projectReactor, DefaultAnalysisMode mode) { | |||
if (settings == null) { | |||
if (mode.isNotAssociated()) { | |||
settings = createNonAssociatedProjectSettings(); | |||
} else { | |||
MutableBoolean fromCache = new MutableBoolean(); | |||
settings = loader.load(projectReactor.getRoot().getKeyWithBranch(), fromCache); | |||
checkProject(mode); | |||
} | |||
} | |||
return settings; | |||
} | |||
private void checkProject(DefaultAnalysisMode mode) { | |||
if (mode.isIssues() && settings.lastAnalysisDate() == null) { | |||
LOG.warn("No analysis has been found on the server for this project. All issues will be marked as 'new'."); | |||
} | |||
} | |||
private static ProjectSettingsRepo createNonAssociatedProjectSettings() { | |||
Table<String, String, String> emptySettings = ImmutableTable.of(); | |||
Table<String, String, FileData> emptyFileData = ImmutableTable.of(); | |||
return new ProjectSettingsRepo(emptySettings, emptyFileData, null); | |||
} | |||
} |
@@ -0,0 +1,66 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import com.google.common.collect.Table; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import java.util.Date; | |||
import java.util.Map; | |||
public class ProjectSettingsRepo { | |||
private Table<String, String, String> settingsByModule = null; | |||
private Table<String, String, FileData> fileDataByModuleAndPath = null; | |||
private Date lastAnalysisDate; | |||
public ProjectSettingsRepo(Table<String, String, String> settingsByModule, Table<String, String, FileData> fileDataByModuleAndPath, | |||
@Nullable Date lastAnalysisDate) { | |||
super(); | |||
this.settingsByModule = settingsByModule; | |||
this.fileDataByModuleAndPath = fileDataByModuleAndPath; | |||
this.lastAnalysisDate = lastAnalysisDate; | |||
} | |||
public Map<String, FileData> fileDataByPath(String moduleKey) { | |||
return fileDataByModuleAndPath.row(moduleKey); | |||
} | |||
public Table<String, String, FileData> fileDataByModuleAndPath() { | |||
return fileDataByModuleAndPath; | |||
} | |||
public Map<String, String> settings(String moduleKey) { | |||
return settingsByModule.row(moduleKey); | |||
} | |||
@CheckForNull | |||
public FileData fileData(String projectKey, String path) { | |||
return fileDataByModuleAndPath.get(projectKey, path); | |||
} | |||
@CheckForNull | |||
public Date lastAnalysisDate() { | |||
return lastAnalysisDate; | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import java.util.Collection; | |||
public interface QualityProfileLoader { | |||
Collection<QProfile> load(@Nullable String projectKey, @Nullable String sonarProfile); | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import java.util.Collection; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
public class QualityProfileProvider extends ProviderAdapter { | |||
private ModuleQProfiles profiles = null; | |||
public ModuleQProfiles provide(ProjectReactor projectReactor, QualityProfileLoader loader, AnalysisProperties props, AnalysisMode mode) { | |||
if (this.profiles == null) { | |||
String profile = null; | |||
if (!mode.isIssues()) { | |||
profile = props.property(ModuleQProfiles.SONAR_PROFILE_PROP); | |||
} | |||
Collection<QProfile> qps = loader.load(projectReactor.getRoot().getKeyWithBranch(), profile); | |||
profiles = new ModuleQProfiles(qps); | |||
} | |||
return profiles; | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class SyncProjectRepositoriesFactory implements ProjectRepositoriesFactory { | |||
private static final String LOG_MSG = "Load project repositories"; | |||
private static final Logger LOG = Loggers.get(SyncProjectRepositoriesFactory.class); | |||
private static final String NON_EXISTING = "non1-existing2-project3-key"; | |||
private final ProjectRepositoriesLoader loader; | |||
private final String projectKey; | |||
private ProjectRepositories projectRepositories; | |||
public SyncProjectRepositoriesFactory(@Nullable String projectKey, ProjectRepositoriesLoader loader) { | |||
this.projectKey = projectKey; | |||
this.loader = loader; | |||
} | |||
@Override | |||
public ProjectRepositories create() { | |||
if (projectRepositories == null) { | |||
projectRepositories = newInstance(); | |||
} | |||
return projectRepositories; | |||
} | |||
public ProjectRepositories newInstance() { | |||
if (projectRepositories == null) { | |||
Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); | |||
MutableBoolean fromCache = new MutableBoolean(); | |||
projectRepositories = loader.load(getProjectKey(projectKey), null, fromCache); | |||
profiler.stopInfo(fromCache.booleanValue()); | |||
if (projectRepositories.lastAnalysisDate() == null) { | |||
LOG.warn("No analysis has been found on the server for this project. All issues will be marked as 'new'."); | |||
} | |||
} | |||
return projectRepositories; | |||
} | |||
private static String getProjectKey(@Nullable String projectKey) { | |||
if (projectKey == null) { | |||
return NON_EXISTING; | |||
} | |||
return projectKey; | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.rule; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import java.util.Collection; | |||
public interface ActiveRulesLoader { | |||
Collection<ActiveRule> load(Collection<String> qualityProfileKeys, String projectKey); | |||
} |
@@ -19,14 +19,17 @@ | |||
*/ | |||
package org.sonar.batch.rule; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.picocontainer.injectors.ProviderAdapter; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; | |||
import org.sonar.api.batch.rule.internal.NewActiveRule; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.Map.Entry; | |||
/** | |||
@@ -37,16 +40,16 @@ public class ActiveRulesProvider extends ProviderAdapter { | |||
private ActiveRules singleton = null; | |||
public ActiveRules provide(ProjectRepositories ref) { | |||
public ActiveRules provide(ActiveRulesLoader ref, ModuleQProfiles qProfiles, ProjectReactor projectReactor) { | |||
if (singleton == null) { | |||
singleton = load(ref); | |||
singleton = load(ref, qProfiles, projectReactor); | |||
} | |||
return singleton; | |||
} | |||
private static ActiveRules load(ProjectRepositories ref) { | |||
private static ActiveRules load(ActiveRulesLoader loader, ModuleQProfiles qProfiles, ProjectReactor projectReactor) { | |||
ActiveRulesBuilder builder = new ActiveRulesBuilder(); | |||
for (ActiveRule activeRule : ref.activeRules()) { | |||
for (ActiveRule activeRule : loader.load(getKeys(qProfiles), projectReactor.getRoot().getKeyWithBranch())) { | |||
NewActiveRule newActiveRule = builder.create(RuleKey.of(activeRule.repositoryKey(), activeRule.ruleKey())); | |||
newActiveRule.setName(activeRule.name()); | |||
newActiveRule.setSeverity(activeRule.severity()); | |||
@@ -63,4 +66,14 @@ public class ActiveRulesProvider extends ProviderAdapter { | |||
} | |||
return builder.build(); | |||
} | |||
private static Collection<String> getKeys(ModuleQProfiles qProfiles) { | |||
List<String> keys = new ArrayList<>(qProfiles.findAll().size()); | |||
for (QProfile qp : qProfiles.findAll()) { | |||
keys.add(qp.getKey()); | |||
} | |||
return keys; | |||
} | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.rule; | |||
import org.sonar.batch.repository.ProjectRepositoriesFactory; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import java.util.Collection; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class DefaultActiveRulesLoader implements ActiveRulesLoader { | |||
private final ProjectRepositoriesFactory projectRepositoriesFactory; | |||
public DefaultActiveRulesLoader(ProjectRepositoriesFactory projectRepositoriesFactory) { | |||
this.projectRepositoriesFactory = projectRepositoriesFactory; | |||
} | |||
@Override | |||
public Collection<ActiveRule> load(Collection<String> qualityProfileKeys, String projectKey) { | |||
ProjectRepositories pr = projectRepositoriesFactory.create(); | |||
return pr.activeRules(); | |||
} | |||
} |
@@ -21,7 +21,6 @@ package org.sonar.batch.rule; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import javax.annotation.CheckForNull; | |||
@@ -37,10 +36,10 @@ public class ModuleQProfiles { | |||
public static final String SONAR_PROFILE_PROP = "sonar.profile"; | |||
private final Map<String, QProfile> byLanguage; | |||
public ModuleQProfiles(ProjectRepositories ref) { | |||
public ModuleQProfiles(Collection<org.sonar.batch.protocol.input.QProfile> profiles) { | |||
ImmutableMap.Builder<String, QProfile> builder = ImmutableMap.builder(); | |||
for (org.sonar.batch.protocol.input.QProfile qProfile : ref.qProfiles()) { | |||
for (org.sonar.batch.protocol.input.QProfile qProfile : profiles) { | |||
builder.put(qProfile.language(), | |||
new QProfile().setKey(qProfile.key()).setName(qProfile.name()).setLanguage(qProfile.language()).setRulesUpdatedAt(qProfile.rulesUpdatedAt())); | |||
} |
@@ -148,7 +148,6 @@ public class ModuleScanContainer extends ComponentContainer { | |||
CoverageExclusions.class, | |||
// rules | |||
ModuleQProfiles.class, | |||
new RulesProfileProvider(), | |||
QProfileSensor.class, | |||
CheckFactory.class, |
@@ -19,8 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import com.google.common.collect.Lists; | |||
import java.util.List; | |||
@@ -30,20 +31,19 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
/** | |||
* @since 2.12 | |||
*/ | |||
public class ModuleSettings extends Settings { | |||
private final ProjectRepositories projectReferentials; | |||
private final ProjectSettingsRepo projectSettingsRepo; | |||
private DefaultAnalysisMode analysisMode; | |||
public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectRepositories projectReferentials, | |||
public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectSettingsRepo projectSettingsRepo, | |||
DefaultAnalysisMode analysisMode) { | |||
super(batchSettings.getDefinitions()); | |||
this.projectReferentials = projectReferentials; | |||
this.projectSettingsRepo = projectSettingsRepo; | |||
this.analysisMode = analysisMode; | |||
getEncryption().setPathToSecretKey(batchSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); | |||
@@ -58,13 +58,13 @@ public class ModuleSettings extends Settings { | |||
private void addProjectProperties(ProjectDefinition moduleDefinition, GlobalSettings batchSettings) { | |||
addProperties(batchSettings.getProperties()); | |||
addProperties(projectReferentials.settings(moduleDefinition.getKeyWithBranch())); | |||
addProperties(projectSettingsRepo.settings(moduleDefinition.getKeyWithBranch())); | |||
} | |||
private void addBuildProperties(ProjectDefinition project) { | |||
List<ProjectDefinition> orderedProjects = getTopDownParentProjects(project); | |||
for (ProjectDefinition p : orderedProjects) { | |||
addProperties(p.getProperties()); | |||
addProperties(p.properties()); | |||
} | |||
} | |||
@@ -55,7 +55,6 @@ public class ProjectLock implements Startable { | |||
if (lockFile == null) { | |||
failAlreadyInProgress(null); | |||
} | |||
} catch (OverlappingFileLockException e) { | |||
failAlreadyInProgress(e); | |||
} catch (IOException e) { |
@@ -19,8 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.apache.commons.lang.ArrayUtils; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.apache.commons.lang.ArrayUtils; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import com.google.common.collect.Lists; | |||
@@ -108,12 +109,16 @@ public class ProjectReactorBuilder { | |||
*/ | |||
private static final List<String> NON_HERITED_PROPERTIES_FOR_CHILD = Lists.newArrayList(PROPERTY_PROJECT_BASEDIR, CoreProperties.WORKING_DIRECTORY, PROPERTY_MODULES, | |||
CoreProperties.PROJECT_DESCRIPTION_PROPERTY); | |||
private static final String NON_ASSOCIATED_PROJECT_KEY = "project"; | |||
private AnalysisProperties taskProps; | |||
private final AnalysisProperties taskProps; | |||
private final AnalysisMode analysisMode; | |||
private File rootProjectWorkDir; | |||
public ProjectReactorBuilder(AnalysisProperties props) { | |||
public ProjectReactorBuilder(AnalysisProperties props, AnalysisMode analysisMode) { | |||
this.taskProps = props; | |||
this.analysisMode = analysisMode; | |||
} | |||
public ProjectReactor execute() { | |||
@@ -160,8 +165,16 @@ public class ProjectReactorBuilder { | |||
extractPropertiesByModule(propertiesByModuleId, moduleId, currentModuleProperties); | |||
} | |||
} | |||
private static void prepareNonAssociatedProject(Map<String, String> props, AnalysisMode mode) { | |||
if(mode.isIssues() && !props.containsKey(CoreProperties.PROJECT_KEY_PROPERTY)) { | |||
props.put(CoreProperties.PROJECT_KEY_PROPERTY, NON_ASSOCIATED_PROJECT_KEY); | |||
} | |||
} | |||
protected ProjectDefinition defineRootProject(Map<String, String> rootProperties, @Nullable ProjectDefinition parent) { | |||
prepareNonAssociatedProject(rootProperties, analysisMode); | |||
if (rootProperties.containsKey(PROPERTY_MODULES)) { | |||
checkMandatoryProperties(rootProperties, MANDATORY_PROPERTIES_FOR_MULTIMODULE_PROJECT); | |||
} else { |
@@ -28,7 +28,6 @@ import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.SonarException; | |||
import org.sonar.core.component.ComponentKeys; | |||
/** | |||
@@ -58,7 +57,7 @@ public class ProjectReactorValidator { | |||
validateBranch(validationMessages, branch); | |||
if (!validationMessages.isEmpty()) { | |||
throw new SonarException("Validation of project reactor failed:\n o " + Joiner.on("\n o ").join(validationMessages)); | |||
throw new IllegalStateException("Validation of project reactor failed:\n o " + Joiner.on("\n o ").join(validationMessages)); | |||
} | |||
} | |||
@@ -19,6 +19,16 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.repository.DefaultProjectRepositoriesFactory; | |||
import org.sonar.batch.repository.QualityProfileProvider; | |||
import org.sonar.batch.repository.DefaultQualityProfileLoader; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
import org.sonar.batch.repository.ProjectSettingsLoader; | |||
import org.sonar.batch.repository.DefaultProjectSettingsLoader; | |||
import org.sonar.batch.repository.ProjectSettingsProvider; | |||
import org.sonar.batch.rule.DefaultActiveRulesLoader; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.analysis.AnalysisWSLoaderProvider; | |||
import org.sonar.batch.analysis.AnalysisTempFolderProvider; | |||
@@ -69,7 +79,6 @@ import org.sonar.batch.report.MetadataPublisher; | |||
import org.sonar.batch.report.ReportPublisher; | |||
import org.sonar.batch.report.SourcePublisher; | |||
import org.sonar.batch.report.TestExecutionAndCoveragePublisher; | |||
import org.sonar.batch.repository.ProjectRepositoriesProvider; | |||
import org.sonar.batch.repository.language.DefaultLanguagesRepository; | |||
import org.sonar.batch.rule.ActiveRulesProvider; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
@@ -116,6 +125,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
props, | |||
DefaultAnalysisMode.class, | |||
ProjectReactorBuilder.class, | |||
DefaultProjectRepositoriesFactory.class, | |||
new MutableProjectReactorProvider(), | |||
new ImmutableProjectReactorProvider(), | |||
ProjectBuildersExecutor.class, | |||
@@ -126,7 +136,6 @@ public class ProjectScanContainer extends ComponentContainer { | |||
DefaultProjectTree.class, | |||
ProjectExclusions.class, | |||
ProjectReactorValidator.class, | |||
new ProjectRepositoriesProvider(), | |||
new AnalysisWSLoaderProvider(), | |||
CodeColorizers.class, | |||
MetricProvider.class, | |||
@@ -136,6 +145,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
Caches.class, | |||
BatchComponentCache.class, | |||
DefaultIssueCallback.class, | |||
new ProjectSettingsProvider(), | |||
// temp | |||
new AnalysisTempFolderProvider(), | |||
@@ -146,6 +156,7 @@ public class ProjectScanContainer extends ComponentContainer { | |||
// rules | |||
new ActiveRulesProvider(), | |||
new QualityProfileProvider(), | |||
// issues | |||
IssueUpdater.class, | |||
@@ -153,8 +164,8 @@ public class ProjectScanContainer extends ComponentContainer { | |||
IssueWorkflow.class, | |||
IssueCache.class, | |||
DefaultProjectIssues.class, | |||
LocalIssueTracking.class, | |||
ServerIssueRepository.class, | |||
LocalIssueTracking.class, | |||
// metrics | |||
DefaultMetricFinder.class, | |||
@@ -190,9 +201,16 @@ public class ProjectScanContainer extends ComponentContainer { | |||
ScanTaskObservers.class, | |||
UserRepositoryLoader.class); | |||
addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); | |||
addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); | |||
addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class); | |||
addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class); | |||
addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class); | |||
addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); | |||
addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); | |||
} | |||
private boolean isProjectAssociated() { | |||
return !getComponentByType(DefaultAnalysisMode.class).isNotAssociated(); | |||
} | |||
private void addBatchExtensions() { |
@@ -19,8 +19,9 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.util.Map; | |||
@@ -32,7 +33,6 @@ import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.bootstrap.DroppedPropertyChecker; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
public class ProjectSettings extends Settings { | |||
@@ -45,11 +45,11 @@ public class ProjectSettings extends Settings { | |||
); | |||
private final GlobalSettings globalSettings; | |||
private final ProjectRepositories projectRepositories; | |||
private final ProjectSettingsRepo projectRepositories; | |||
private final DefaultAnalysisMode mode; | |||
public ProjectSettings(ProjectReactor reactor, GlobalSettings globalSettings, PropertyDefinitions propertyDefinitions, | |||
ProjectRepositories projectRepositories, DefaultAnalysisMode mode) { | |||
ProjectSettingsRepo projectRepositories, DefaultAnalysisMode mode) { | |||
super(propertyDefinitions); | |||
this.mode = mode; | |||
getEncryption().setPathToSecretKey(globalSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); |
@@ -19,21 +19,22 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
class StatusDetection { | |||
private final ProjectRepositories projectReferentials; | |||
private final ProjectSettingsRepo projectSettings; | |||
StatusDetection(ProjectRepositories projectReferentials) { | |||
this.projectReferentials = projectReferentials; | |||
StatusDetection(ProjectSettingsRepo projectSettings) { | |||
this.projectSettings = projectSettings; | |||
} | |||
InputFile.Status status(String projectKey, String relativePath, String hash) { | |||
FileData fileDataPerPath = projectReferentials.fileData(projectKey, relativePath); | |||
FileData fileDataPerPath = projectSettings.fileData(projectKey, relativePath); | |||
if (fileDataPerPath == null) { | |||
return InputFile.Status.ADDED; | |||
} |
@@ -19,15 +19,16 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.sonar.api.batch.BatchSide; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
@BatchSide | |||
public class StatusDetectionFactory { | |||
private final ProjectRepositories projectReferentials; | |||
private final ProjectSettingsRepo projectReferentials; | |||
public StatusDetectionFactory(ProjectRepositories projectReferentials) { | |||
public StatusDetectionFactory(ProjectSettingsRepo projectReferentials) { | |||
this.projectReferentials = projectReferentials; | |||
} | |||
@@ -19,8 +19,11 @@ | |||
*/ | |||
package org.sonar.batch.scm; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.api.CoreProperties; | |||
@@ -33,7 +36,6 @@ import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.batch.index.BatchComponentCache; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.report.ReportPublisher; | |||
import org.sonar.batch.scan.filesystem.InputPathCache; | |||
@@ -44,16 +46,16 @@ public final class ScmSensor implements Sensor { | |||
private final ProjectDefinition projectDefinition; | |||
private final ScmConfiguration configuration; | |||
private final FileSystem fs; | |||
private final ProjectRepositories projectReferentials; | |||
private final ProjectSettingsRepo projectSettings; | |||
private final BatchComponentCache resourceCache; | |||
private final ReportPublisher publishReportJob; | |||
public ScmSensor(ProjectDefinition projectDefinition, ScmConfiguration configuration, | |||
ProjectRepositories projectReferentials, FileSystem fs, InputPathCache inputPathCache, BatchComponentCache resourceCache, | |||
ProjectSettingsRepo projectSettings, FileSystem fs, InputPathCache inputPathCache, BatchComponentCache resourceCache, | |||
ReportPublisher publishReportJob) { | |||
this.projectDefinition = projectDefinition; | |||
this.configuration = configuration; | |||
this.projectReferentials = projectReferentials; | |||
this.projectSettings = projectSettings; | |||
this.fs = fs; | |||
this.resourceCache = resourceCache; | |||
this.publishReportJob = publishReportJob; | |||
@@ -95,7 +97,7 @@ public final class ScmSensor implements Sensor { | |||
if (configuration.forceReloadAll()) { | |||
addIfNotEmpty(filesToBlame, f); | |||
} else { | |||
FileData fileData = projectReferentials.fileData(projectDefinition.getKeyWithBranch(), f.relativePath()); | |||
FileData fileData = projectSettings.fileData(projectDefinition.getKeyWithBranch(), f.relativePath()); | |||
if (f.status() != Status.SAME || fileData == null || fileData.needBlame()) { | |||
addIfNotEmpty(filesToBlame, f); | |||
} |
@@ -25,7 +25,6 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import org.sonar.home.cache.PersistentCacheLoader; | |||
import org.junit.internal.runners.statements.ExpectException; | |||
import org.junit.rules.ExpectedException; | |||
import java.io.IOException; | |||
@@ -58,6 +57,7 @@ public class DefaultProjectCacheStatusTest { | |||
public void setUp() { | |||
cache = new PersistentCache(tmp.getRoot().toPath(), Long.MAX_VALUE, mock(Logger.class), null); | |||
client = mock(ServerClient.class); | |||
when(client.getServerVersion()).thenReturn("5.2"); | |||
when(client.getURL()).thenReturn("localhost"); | |||
cacheStatus = new DefaultProjectCacheStatus(cache, client); | |||
} | |||
@@ -84,6 +84,17 @@ public class DefaultProjectCacheStatusTest { | |||
cacheStatus.save(PROJ_KEY); | |||
} | |||
@Test | |||
public void useServerVersionAsKey() { | |||
cacheStatus.save(PROJ_KEY); | |||
assertThat(cacheStatus.getSyncStatus(PROJ_KEY)).isNotNull(); | |||
assertThat(age(cacheStatus.getSyncStatus(PROJ_KEY))).isLessThan(2000); | |||
when(client.getServerVersion()).thenReturn("5.1"); | |||
assertThat(cacheStatus.getSyncStatus(PROJ_KEY)).isNull(); | |||
} | |||
@Test | |||
public void errorStatus() throws IOException { | |||
cache = mock(PersistentCache.class); |
@@ -0,0 +1,91 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.cache; | |||
import static org.mockito.Mockito.when; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import com.google.common.collect.ImmutableList; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import org.junit.Test; | |||
import java.util.Date; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import org.mockito.MockitoAnnotations; | |||
import org.junit.Before; | |||
import org.mockito.Mock; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
public class NonAssociatedCacheSynchronizerTest { | |||
private NonAssociatedCacheSynchronizer synchronizer; | |||
@Mock | |||
private QualityProfileLoader qualityProfileLoader; | |||
@Mock | |||
private ActiveRulesLoader activeRulesLoader; | |||
@Mock | |||
private ProjectCacheStatus cacheStatus; | |||
@Before | |||
public void setUp() { | |||
MockitoAnnotations.initMocks(this); | |||
QProfile pf = new QProfile("profile", "profile", "lang", new Date(1000)); | |||
ActiveRule ar = mock(ActiveRule.class); | |||
when(qualityProfileLoader.load(null, null)).thenReturn(ImmutableList.of(pf)); | |||
when(activeRulesLoader.load(ImmutableList.of("profile"), null)).thenReturn(ImmutableList.of(ar)); | |||
synchronizer = new NonAssociatedCacheSynchronizer(qualityProfileLoader, activeRulesLoader, cacheStatus); | |||
} | |||
@Test | |||
public void dont_sync_if_exists() { | |||
when(cacheStatus.getSyncStatus(null)).thenReturn(new Date()); | |||
synchronizer.execute(false); | |||
verifyNoMoreInteractions(qualityProfileLoader, activeRulesLoader); | |||
} | |||
@Test | |||
public void always_sync_if_force() { | |||
when(cacheStatus.getSyncStatus(null)).thenReturn(new Date()); | |||
synchronizer.execute(true); | |||
checkSync(); | |||
} | |||
@Test | |||
public void sync_if_doesnt_exist() { | |||
synchronizer.execute(false); | |||
checkSync(); | |||
} | |||
private void checkSync() { | |||
verify(cacheStatus).getSyncStatus(null); | |||
verify(cacheStatus).save(null); | |||
verify(qualityProfileLoader).load(null, null); | |||
verify(activeRulesLoader).load(ImmutableList.of("profile"), null); | |||
verifyNoMoreInteractions(qualityProfileLoader, activeRulesLoader); | |||
} | |||
} |
@@ -19,10 +19,12 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import org.junit.Rule; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.batch.bootstrap.GlobalProperties; | |||
import org.sonar.batch.cache.PersistentCacheProvider; | |||
import java.nio.file.Paths; | |||
import java.io.File; | |||
import java.util.Collections; | |||
import org.junit.Before; | |||
@@ -30,6 +32,9 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import org.junit.Test; | |||
public class PersistentCacheProviderTest { | |||
@Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
private PersistentCacheProvider provider = null; | |||
private GlobalProperties props = null; | |||
@@ -51,7 +56,8 @@ public class PersistentCacheProviderTest { | |||
@Test | |||
public void test_home() { | |||
props.properties().put("sonar.userHome", "myhome"); | |||
assertThat(provider.provide(props).getBaseDirectory()).isEqualTo(Paths.get("myhome/ws_cache")); | |||
File f = temp.getRoot(); | |||
props.properties().put("sonar.userHome", f.getAbsolutePath()); | |||
assertThat(provider.provide(props).getBaseDirectory()).isEqualTo(f.toPath().resolve("ws_cache")); | |||
} | |||
} |
@@ -20,11 +20,27 @@ | |||
package org.sonar.batch.cache; | |||
import static org.mockito.Mockito.when; | |||
import org.sonar.batch.repository.ProjectRepositoriesFactory; | |||
import org.sonar.batch.repository.DefaultProjectRepositoriesFactory; | |||
import org.junit.Rule; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import com.google.common.base.Function; | |||
import com.google.common.collect.ImmutableList; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.batch.repository.DefaultProjectSettingsLoader; | |||
import org.sonar.batch.rule.DefaultActiveRulesLoader; | |||
import org.sonar.batch.repository.DefaultQualityProfileLoader; | |||
import org.sonar.batch.repository.ProjectSettingsLoader; | |||
import org.sonar.batch.rule.ActiveRulesLoader; | |||
import org.sonar.batch.repository.QualityProfileLoader; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader; | |||
import org.sonar.batch.repository.DefaultServerIssuesLoader; | |||
import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
@@ -36,6 +52,7 @@ import java.nio.charset.StandardCharsets; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Matchers.any; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Matchers.anyString; | |||
@@ -47,7 +64,6 @@ import org.junit.Before; | |||
import org.mockito.MockitoAnnotations; | |||
import org.mockito.Mock; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.batch.issue.tracking.ServerLineHashesLoader; | |||
import org.sonar.batch.repository.ProjectRepositoriesLoader; | |||
import org.sonar.batch.repository.ServerIssuesLoader; | |||
import org.sonar.batch.repository.user.UserRepositoryLoader; | |||
@@ -55,8 +71,10 @@ import org.sonar.batch.repository.user.UserRepositoryLoader; | |||
public class ProjectCacheSynchronizerTest { | |||
private static final String BATCH_PROJECT = "/batch/project?key=org.codehaus.sonar-plugins%3Asonar-scm-git-plugin&preview=true"; | |||
private static final String ISSUES = "/batch/issues?key=org.codehaus.sonar-plugins%3Asonar-scm-git-plugin"; | |||
private static final String LINE_HASHES1 = "/api/sources/hash?key=org.codehaus.sonar-plugins%3Asonar-scm-git-plugin%3Asrc%2Ftest%2Fjava%2Forg%2Fsonar%2Fplugins%2Fscm%2Fgit%2FJGitBlameCommandTest.java"; | |||
private static final String LINE_HASHES2 = "/api/sources/hash?key=org.codehaus.sonar-plugins%3Asonar-scm-git-plugin%3Asrc%2Fmain%2Fjava%2Forg%2Fsonar%2Fplugins%2Fscm%2Fgit%2FGitScmProvider.java"; | |||
private static final String PROJECT_KEY = "org.codehaus.sonar-plugins:sonar-scm-git-plugin"; | |||
@Rule | |||
public ExpectedException exception = ExpectedException.none(); | |||
@Mock | |||
private ProjectDefinition project; | |||
@@ -73,10 +91,10 @@ public class ProjectCacheSynchronizerTest { | |||
private ProjectRepositoriesLoader projectRepositoryLoader; | |||
private ServerIssuesLoader issuesLoader; | |||
private ServerLineHashesLoader lineHashesLoader; | |||
private UserRepositoryLoader userRepositoryLoader; | |||
private ProjectCacheSynchronizer sync; | |||
private QualityProfileLoader qualityProfileLoader; | |||
private ActiveRulesLoader activeRulesLoader; | |||
private ProjectSettingsLoader projectSettingsLoader; | |||
@Before | |||
public void setUp() throws IOException { | |||
@@ -84,62 +102,108 @@ public class ProjectCacheSynchronizerTest { | |||
String batchProject = getResourceAsString("batch_project.json"); | |||
ByteSource issues = getResourceAsByteSource("batch_issues.protobuf"); | |||
String lineHashes2 = getResourceAsString("api_sources_hash_GitScmProvider.text"); | |||
String lineHashes1 = getResourceAsString("api_sources_hash_JGitBlameCommand.text"); | |||
when(ws.loadString(BATCH_PROJECT)).thenReturn(new WSLoaderResult<>(batchProject, false)); | |||
when(ws.loadSource(ISSUES)).thenReturn(new WSLoaderResult<>(issues, false)); | |||
when(ws.loadString(LINE_HASHES1)).thenReturn(new WSLoaderResult<>(lineHashes1, false)); | |||
when(ws.loadString(LINE_HASHES2)).thenReturn(new WSLoaderResult<>(lineHashes2, false)); | |||
when(analysisMode.isIssues()).thenReturn(true); | |||
when(project.getKeyWithBranch()).thenReturn("org.codehaus.sonar-plugins:sonar-scm-git-plugin"); | |||
when(projectReactor.getRoot()).thenReturn(project); | |||
when(properties.properties()).thenReturn(new HashMap<String, String>()); | |||
} | |||
private ProjectCacheSynchronizer create(ProjectRepositories projectRepositories) { | |||
if (projectRepositories == null) { | |||
projectRepositoryLoader = new DefaultProjectRepositoriesLoader(ws, analysisMode); | |||
} else { | |||
projectRepositoryLoader = mock(ProjectRepositoriesLoader.class); | |||
when(projectRepositoryLoader.load(anyString(), anyString(), any(MutableBoolean.class))).thenReturn(projectRepositories); | |||
} | |||
ProjectReactor reactor = mock(ProjectReactor.class); | |||
ProjectDefinition root = mock(ProjectDefinition.class); | |||
when(root.getKeyWithBranch()).thenReturn(PROJECT_KEY); | |||
when(reactor.getRoot()).thenReturn(root); | |||
ProjectRepositoriesFactory projectRepositoriesFactory = new DefaultProjectRepositoriesFactory(reactor, analysisMode, projectRepositoryLoader, properties); | |||
projectRepositoryLoader = new DefaultProjectRepositoriesLoader(ws, analysisMode); | |||
issuesLoader = new DefaultServerIssuesLoader(ws); | |||
lineHashesLoader = new DefaultServerLineHashesLoader(ws); | |||
userRepositoryLoader = new UserRepositoryLoader(ws); | |||
qualityProfileLoader = new DefaultQualityProfileLoader(projectRepositoriesFactory); | |||
activeRulesLoader = new DefaultActiveRulesLoader(projectRepositoriesFactory); | |||
projectSettingsLoader = new DefaultProjectSettingsLoader(projectRepositoriesFactory); | |||
return new ProjectCacheSynchronizer(qualityProfileLoader, projectSettingsLoader, activeRulesLoader, issuesLoader, userRepositoryLoader, cacheStatus); | |||
} | |||
private ProjectCacheSynchronizer createMockedLoaders(Date lastAnalysisDate) { | |||
issuesLoader = mock(DefaultServerIssuesLoader.class); | |||
userRepositoryLoader = mock(UserRepositoryLoader.class); | |||
qualityProfileLoader = mock(DefaultQualityProfileLoader.class); | |||
activeRulesLoader = mock(DefaultActiveRulesLoader.class); | |||
projectSettingsLoader = mock(DefaultProjectSettingsLoader.class); | |||
QProfile pf = new QProfile("profile", "profile", "lang", new Date(1000)); | |||
ActiveRule ar = mock(ActiveRule.class); | |||
ProjectSettingsRepo repo = mock(ProjectSettingsRepo.class); | |||
sync = new ProjectCacheSynchronizer(projectReactor, projectRepositoryLoader, properties, issuesLoader, lineHashesLoader, userRepositoryLoader, | |||
cacheStatus); | |||
when(qualityProfileLoader.load(PROJECT_KEY, null)).thenReturn(ImmutableList.of(pf)); | |||
when(activeRulesLoader.load(ImmutableList.of("profile"), PROJECT_KEY)).thenReturn(ImmutableList.of(ar)); | |||
when(repo.lastAnalysisDate()).thenReturn(lastAnalysisDate); | |||
when(projectSettingsLoader.load(anyString(), any(MutableBoolean.class))).thenReturn(repo); | |||
return new ProjectCacheSynchronizer(qualityProfileLoader, projectSettingsLoader, activeRulesLoader, issuesLoader, userRepositoryLoader, cacheStatus); | |||
} | |||
@Test | |||
public void testSync() { | |||
sync.load(false); | |||
ProjectCacheSynchronizer sync = create(null); | |||
sync.load(PROJECT_KEY, false); | |||
verify(ws).loadString(BATCH_PROJECT); | |||
verify(ws).loadSource(ISSUES); | |||
verify(ws).loadString(LINE_HASHES1); | |||
verify(ws).loadString(LINE_HASHES2); | |||
verifyNoMoreInteractions(ws); | |||
verify(cacheStatus).save(anyString()); | |||
} | |||
@Test | |||
public void testLoadersUsage() { | |||
ProjectCacheSynchronizer synchronizer = createMockedLoaders(new Date()); | |||
synchronizer.load(PROJECT_KEY, false); | |||
verify(issuesLoader).load(eq(PROJECT_KEY), any(Function.class)); | |||
verify(qualityProfileLoader).load(PROJECT_KEY, null); | |||
verify(activeRulesLoader).load(ImmutableList.of("profile"), PROJECT_KEY); | |||
verify(projectSettingsLoader).load(eq(PROJECT_KEY), any(MutableBoolean.class)); | |||
verifyNoMoreInteractions(issuesLoader, userRepositoryLoader, qualityProfileLoader, activeRulesLoader, projectSettingsLoader); | |||
} | |||
@Test | |||
public void testLoadersUsage_NoLastAnalysis() { | |||
ProjectCacheSynchronizer synchronizer = createMockedLoaders(null); | |||
synchronizer.load(PROJECT_KEY, false); | |||
verify(projectSettingsLoader).load(eq(PROJECT_KEY), any(MutableBoolean.class)); | |||
verifyNoMoreInteractions(issuesLoader, userRepositoryLoader, qualityProfileLoader, activeRulesLoader, projectSettingsLoader); | |||
} | |||
@Test | |||
public void testSyncNoLastAnalysis() { | |||
projectRepositoryLoader = mock(DefaultProjectRepositoriesLoader.class); | |||
ProjectRepositories mockedProjectRepositories = mock(ProjectRepositories.class); | |||
when(mockedProjectRepositories.lastAnalysisDate()).thenReturn(null); | |||
when(projectRepositoryLoader.load(any(ProjectDefinition.class), any(AnalysisProperties.class), any(MutableBoolean.class))).thenReturn(mockedProjectRepositories); | |||
sync = new ProjectCacheSynchronizer(projectReactor, projectRepositoryLoader, properties, issuesLoader, lineHashesLoader, userRepositoryLoader, | |||
cacheStatus); | |||
sync.load(true); | |||
verify(cacheStatus).save("org.codehaus.sonar-plugins:sonar-scm-git-plugin"); | |||
ProjectCacheSynchronizer sync = create(mockedProjectRepositories); | |||
sync.load(PROJECT_KEY, true); | |||
verify(cacheStatus).save(PROJECT_KEY); | |||
} | |||
@Test | |||
public void testDontSyncIfNotForce() { | |||
when(cacheStatus.getSyncStatus("org.codehaus.sonar-plugins:sonar-scm-git-plugin")).thenReturn(new Date()); | |||
ProjectCacheSynchronizer sync = new ProjectCacheSynchronizer(projectReactor, projectRepositoryLoader, properties, issuesLoader, lineHashesLoader, userRepositoryLoader, | |||
cacheStatus); | |||
sync.load(false); | |||
when(cacheStatus.getSyncStatus(PROJECT_KEY)).thenReturn(new Date()); | |||
ProjectCacheSynchronizer sync = create(null); | |||
sync.load(PROJECT_KEY, false); | |||
verifyNoMoreInteractions(ws); | |||
} |
@@ -19,16 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.cache; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.bootstrap.GlobalProperties; | |||
import org.sonar.batch.bootstrap.ServerClient; | |||
import org.sonar.home.cache.PersistentCache; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import org.sonar.core.platform.ComponentContainer; | |||
@@ -47,24 +44,11 @@ public class ProjectSyncContainerTest { | |||
return parent; | |||
} | |||
public AnalysisProperties createProjectProperties() { | |||
Map<String, String> properties = new HashMap<>(); | |||
properties.put("sonar.branch", "branch"); | |||
properties.put("sonar.projectKey", "my:project"); | |||
properties.put("sonar.projectName", "My project"); | |||
properties.put("sonar.projectVersion", "1.0"); | |||
properties.put("sonar.sources", "."); | |||
properties.put("sonar.projectBaseDir", "."); | |||
return new AnalysisProperties(properties); | |||
} | |||
@Test | |||
public void testProjectKeyWithBranch() { | |||
ProjectSyncContainer container = new ProjectSyncContainer(createParentContainer(), createProjectProperties(), true); | |||
public void testProjectRepository() { | |||
ProjectSyncContainer container = new ProjectSyncContainer(createParentContainer(), "my:project", true); | |||
container.doBeforeStart(); | |||
container.getPicoContainer().start(); | |||
ProjectReactor projectReactor = container.getComponentByType(ProjectReactor.class); | |||
assertThat(projectReactor.getRoot().getKeyWithBranch()).isEqualTo("my:project:branch"); | |||
container.getComponentByType(ProjectRepositories.class); | |||
} | |||
} |
@@ -19,8 +19,8 @@ | |||
*/ | |||
package org.sonar.batch.issue.tracking; | |||
import org.sonar.batch.cache.WSLoader.LoadStrategy; | |||
import org.sonar.batch.cache.WSLoaderResult; | |||
import org.sonar.batch.cache.WSLoader; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.junit.Before; | |||
@@ -32,6 +32,8 @@ import org.sonar.api.utils.HttpDownloader; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import static org.mockito.Matchers.any; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Mockito.mock; | |||
@@ -50,19 +52,19 @@ public class DefaultServerLineHashesLoaderTest { | |||
@Test | |||
public void should_download_source_from_ws_if_preview_mode() { | |||
WSLoader wsLoader = mock(WSLoader.class); | |||
when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); | |||
when(wsLoader.loadString(anyString(), any(LoadStrategy.class))).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(wsLoader); | |||
String[] hashes = lastSnapshots.getLineHashes("myproject:org/foo/Bar.c", null); | |||
assertThat(hashes).containsOnly("ae12", "", "43fb"); | |||
verify(wsLoader).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FBar.c"); | |||
verify(wsLoader).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FBar.c", LoadStrategy.CACHE_FIRST); | |||
} | |||
@Test | |||
public void should_download_source_with_space_from_ws_if_preview_mode() { | |||
WSLoader server = mock(WSLoader.class); | |||
when(server.loadString(anyString())).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); | |||
when(server.loadString(anyString(), any(LoadStrategy.class))).thenReturn(new WSLoaderResult<>("ae12\n\n43fb", true)); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); | |||
@@ -70,13 +72,13 @@ public class DefaultServerLineHashesLoaderTest { | |||
String[] hashes = lastSnapshots.getLineHashes("myproject:org/foo/Foo Bar.c", fromCache); | |||
assertThat(fromCache.booleanValue()).isTrue(); | |||
assertThat(hashes).containsOnly("ae12", "", "43fb"); | |||
verify(server).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FFoo+Bar.c"); | |||
verify(server).loadString("/api/sources/hash?key=myproject%3Aorg%2Ffoo%2FFoo+Bar.c", LoadStrategy.CACHE_FIRST); | |||
} | |||
@Test | |||
public void should_fail_to_download_source_from_ws() throws URISyntaxException { | |||
WSLoader server = mock(WSLoader.class); | |||
when(server.loadString(anyString())).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); | |||
when(server.loadString(anyString(), any(LoadStrategy.class))).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); | |||
ServerLineHashesLoader lastSnapshots = new DefaultServerLineHashesLoader(server); | |||
@@ -19,27 +19,26 @@ | |||
*/ | |||
package org.sonar.batch.mediumtest; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import javax.annotation.Nullable; | |||
import org.sonar.batch.cache.ProjectCacheStatus; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonarqube.ws.Rules.ListResponse.Rule; | |||
import org.sonar.batch.bootstrapper.IssueListener; | |||
import org.sonar.api.server.rule.RulesDefinition.Repository; | |||
import org.sonar.api.server.rule.RulesDefinition; | |||
import org.sonar.batch.rule.RulesLoader; | |||
import com.google.common.base.Function; | |||
import com.google.common.io.Files; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStreamReader; | |||
import java.io.Reader; | |||
import java.nio.charset.StandardCharsets; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
@@ -75,12 +74,41 @@ public class BatchMediumTester { | |||
public static final String MEDIUM_TEST_ENABLED = "sonar.mediumTest.enabled"; | |||
private Batch batch; | |||
private static Path workingDir = null; | |||
private static Path globalWorkingDir = null; | |||
private static void createWorkingDirs() throws IOException { | |||
destroyWorkingDirs(); | |||
workingDir = java.nio.file.Files.createTempDirectory("mediumtest-working-dir"); | |||
globalWorkingDir = java.nio.file.Files.createTempDirectory("mediumtest-global-working-dir"); | |||
} | |||
private static void destroyWorkingDirs() throws IOException { | |||
if(workingDir != null) { | |||
FileUtils.deleteDirectory(workingDir.toFile()); | |||
workingDir = null; | |||
} | |||
if(globalWorkingDir != null) { | |||
FileUtils.deleteDirectory(globalWorkingDir.toFile()); | |||
globalWorkingDir = null; | |||
} | |||
} | |||
public static BatchMediumTesterBuilder builder() { | |||
try { | |||
createWorkingDirs(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
BatchMediumTesterBuilder builder = new BatchMediumTesterBuilder().registerCoreMetrics(); | |||
builder.bootstrapProperties.put(MEDIUM_TEST_ENABLED, "true"); | |||
builder.bootstrapProperties.put(ReportPublisher.KEEP_REPORT_PROP_KEY, "true"); | |||
builder.bootstrapProperties.put(CoreProperties.WORKING_DIRECTORY, Files.createTempDir().getAbsolutePath()); | |||
builder.bootstrapProperties.put(CoreProperties.WORKING_DIRECTORY, workingDir.toString()); | |||
builder.bootstrapProperties.put(CoreProperties.GLOBAL_WORKING_DIRECTORY, globalWorkingDir.toString()); | |||
return builder; | |||
} | |||
@@ -93,12 +121,18 @@ public class BatchMediumTester { | |||
private final Map<String, String> bootstrapProperties = new HashMap<>(); | |||
private final FakeRulesLoader rulesLoader = new FakeRulesLoader(); | |||
private final FakeProjectCacheStatus projectCacheStatus = new FakeProjectCacheStatus(); | |||
private boolean associated = true; | |||
private LogOutput logOutput = null; | |||
public BatchMediumTester build() { | |||
return new BatchMediumTester(this); | |||
} | |||
public BatchMediumTesterBuilder setAssociated(boolean associated) { | |||
this.associated = associated; | |||
return this; | |||
} | |||
public BatchMediumTesterBuilder setLogOutput(LogOutput logOutput) { | |||
this.logOutput = logOutput; | |||
return this; | |||
@@ -210,6 +244,11 @@ public class BatchMediumTester { | |||
public void stop() { | |||
batch.stop(); | |||
try { | |||
destroyWorkingDirs(); | |||
} catch (IOException e) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
public void syncProject(String projectKey) { | |||
@@ -217,21 +256,24 @@ public class BatchMediumTester { | |||
} | |||
private BatchMediumTester(BatchMediumTesterBuilder builder) { | |||
batch = Batch.builder() | |||
Batch.Builder batchBuilder = Batch.builder() | |||
.setEnableLoggingConfiguration(true) | |||
.addComponents( | |||
new EnvironmentInformation("mediumTest", "1.0"), | |||
builder.pluginInstaller, | |||
builder.globalRefProvider, | |||
builder.projectRefProvider, | |||
builder.serverIssues, | |||
builder.serverLineHashes, | |||
builder.rulesLoader, | |||
builder.projectCacheStatus, | |||
builder.projectRefProvider, | |||
new DefaultDebtModel()) | |||
.setBootstrapProperties(builder.bootstrapProperties) | |||
.setLogOutput(builder.logOutput) | |||
.build(); | |||
.setLogOutput(builder.logOutput); | |||
if (builder.associated) { | |||
batchBuilder.addComponents( | |||
builder.serverIssues); | |||
} | |||
batch = batchBuilder.build(); | |||
} | |||
public TaskBuilder newTask() { | |||
@@ -343,7 +385,7 @@ public class BatchMediumTester { | |||
private ProjectRepositories ref = new ProjectRepositories(); | |||
@Override | |||
public ProjectRepositories load(ProjectDefinition projDefinition, AnalysisProperties taskProperties, @Nullable MutableBoolean fromCache) { | |||
public ProjectRepositories load(String projectKey, @Nullable String sonarProfile, @Nullable MutableBoolean fromCache) { | |||
return ref; | |||
} | |||
@@ -385,7 +427,6 @@ public class BatchMediumTester { | |||
} | |||
return true; | |||
} | |||
} | |||
private static class FakeProjectCacheStatus implements ProjectCacheStatus { |
@@ -19,22 +19,25 @@ | |||
*/ | |||
package org.sonar.batch.mediumtest.cache; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.junit.Test; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.junit.After; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.batch.mediumtest.BatchMediumTester; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.xoo.XooPlugin; | |||
import org.sonar.xoo.rule.XooRulesDefinition; | |||
import java.util.Date; | |||
public class CacheSyncTest { | |||
@Rule | |||
public ExpectedException exception = ExpectedException.none(); | |||
public BatchMediumTester tester; | |||
private BatchMediumTester tester; | |||
@After | |||
public void stop() { | |||
@@ -47,23 +50,57 @@ public class CacheSyncTest { | |||
@Test | |||
public void testSyncFirstTime() { | |||
FileData file1 = new FileData("hash", true); | |||
String[] hashes = new String[] { | |||
"line1", "line2" | |||
}; | |||
tester = BatchMediumTester.builder() | |||
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) | |||
.registerPlugin("xoo", new XooPlugin()) | |||
.addRules(new XooRulesDefinition()) | |||
.addQProfile("lang", "name") | |||
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) | |||
.setPreviousAnalysisDate(new Date()) | |||
.addFileData("test-project", "file1", file1) | |||
.mockLineHashes("test-project:file1", hashes) | |||
.build(); | |||
tester.start(); | |||
tester.syncProject("test-project"); | |||
} | |||
@Test | |||
public void testNonAssociated() { | |||
FileData file1 = new FileData("hash", true); | |||
tester = BatchMediumTester.builder() | |||
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) | |||
.registerPlugin("xoo", new XooPlugin()) | |||
.addRules(new XooRulesDefinition()) | |||
.addQProfile("lang", "name") | |||
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) | |||
.setPreviousAnalysisDate(new Date()) | |||
.addFileData("test-project", "file1", file1) | |||
.build(); | |||
tester.start(); | |||
tester.syncProject(null); | |||
} | |||
@Test | |||
public void testNoQProfile() { | |||
FileData file1 = new FileData("hash", true); | |||
tester = BatchMediumTester.builder() | |||
.bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES)) | |||
.registerPlugin("xoo", new XooPlugin()) | |||
.addRules(new XooRulesDefinition()) | |||
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "my/internal/key", "xoo")) | |||
.setPreviousAnalysisDate(new Date()) | |||
.addFileData("test-project", "file1", file1) | |||
.build(); | |||
tester.start(); | |||
exception.expect(IllegalStateException.class); | |||
exception.expectMessage("No quality"); | |||
tester.syncProject("test-project"); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.mediumtest.issuesmode; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.apache.commons.io.FileUtils; | |||
import org.apache.commons.io.filefilter.FileFilterUtils; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.utils.log.LogTester; | |||
import org.sonar.batch.mediumtest.BatchMediumTester; | |||
import org.sonar.batch.mediumtest.TaskResult; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import org.sonar.xoo.XooPlugin; | |||
import org.sonar.xoo.rule.XooRulesDefinition; | |||
import java.io.File; | |||
import java.io.IOException; | |||
public class NonAssociatedProject { | |||
@org.junit.Rule | |||
public TemporaryFolder temp = new TemporaryFolder(); | |||
@org.junit.Rule | |||
public LogTester logTester = new LogTester(); | |||
public BatchMediumTester tester; | |||
@Before | |||
public void prepare() throws IOException { | |||
tester = BatchMediumTester.builder() | |||
.bootstrapProperties(ImmutableMap.of( | |||
CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES, | |||
CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.newFolder().getAbsolutePath())) | |||
.registerPlugin("xoo", new XooPlugin()) | |||
.addQProfile("xoo", "Sonar Way") | |||
.addRules(new XooRulesDefinition()) | |||
.addRule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue") | |||
.addRule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue") | |||
.activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")) | |||
.activateRule(new ActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")) | |||
.activateRule(new ActiveRule("xoo", "OneIssuePerModule", null, "OneIssuePerModule", "MAJOR", null, "xoo")) | |||
.activateRule(new ActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null)) | |||
.setAssociated(false) | |||
.build(); | |||
tester.start(); | |||
} | |||
@After | |||
public void stop() { | |||
tester.stop(); | |||
} | |||
private File copyProject(String path) throws Exception { | |||
File projectDir = temp.newFolder(); | |||
File originalProjectDir = new File(IssueModeAndReportsMediumTest.class.getResource(path).toURI()); | |||
FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); | |||
return projectDir; | |||
} | |||
@Test | |||
public void testNonAssociated() throws Exception { | |||
File projectDir = copyProject("/mediumtest/xoo/multi-modules-sample-not-associated"); | |||
TaskResult result = tester | |||
.newScanTask(new File(projectDir, "sonar-project.properties")) | |||
.start(); | |||
} | |||
} |
@@ -23,10 +23,8 @@ import org.sonar.batch.cache.WSLoaderResult; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.cache.WSLoader; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.apache.commons.lang.mutable.MutableBoolean; | |||
import org.apache.commons.io.IOUtils; | |||
import com.google.common.collect.Maps; | |||
import java.io.IOException; | |||
import java.util.Date; | |||
@@ -40,7 +38,6 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
import static org.mockito.Matchers.anyString; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.spy; | |||
@@ -56,7 +53,6 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
private WSLoader wsLoader; | |||
private DefaultAnalysisMode analysisMode; | |||
private ProjectDefinition project; | |||
private AnalysisProperties taskProperties; | |||
@Before | |||
public void prepare() { | |||
@@ -65,7 +61,6 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
loader = new DefaultProjectRepositoriesLoader(wsLoader, analysisMode); | |||
loader = spy(loader); | |||
when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>("{}", true)); | |||
taskProperties = new AnalysisProperties(Maps.<String, String>newHashMap(), ""); | |||
} | |||
@Test | |||
@@ -73,11 +68,11 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
addQualityProfile(); | |||
project = ProjectDefinition.create().setKey("foo"); | |||
when(analysisMode.isIssues()).thenReturn(false); | |||
loader.load(project, taskProperties, null); | |||
loader.load(project.getKeyWithBranch(), null, null); | |||
verify(wsLoader).loadString("/batch/project?key=foo&preview=false"); | |||
when(analysisMode.isIssues()).thenReturn(true); | |||
loader.load(project, taskProperties, null); | |||
loader.load(project.getKeyWithBranch(), null, null); | |||
verify(wsLoader).loadString("/batch/project?key=foo&preview=true"); | |||
} | |||
@@ -88,7 +83,7 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>(response, true)); | |||
project = ProjectDefinition.create().setKey("foo"); | |||
MutableBoolean fromCache = new MutableBoolean(); | |||
ProjectRepositories projectRepo = loader.load(project, taskProperties, fromCache); | |||
ProjectRepositories projectRepo = loader.load(project.getKeyWithBranch(), null, fromCache); | |||
assertThat(fromCache.booleanValue()).isTrue(); | |||
assertThat(projectRepo.activeRules().size()).isEqualTo(221); | |||
@@ -100,7 +95,7 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
public void passAndEncodeProjectKeyParameter() { | |||
addQualityProfile(); | |||
project = ProjectDefinition.create().setKey("foo bàr"); | |||
loader.load(project, taskProperties, null); | |||
loader.load(project.getKeyWithBranch(), null, null); | |||
verify(wsLoader).loadString("/batch/project?key=foo+b%C3%A0r&preview=false"); | |||
} | |||
@@ -108,8 +103,7 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
public void passAndEncodeProfileParameter() { | |||
addQualityProfile(); | |||
project = ProjectDefinition.create().setKey("foo"); | |||
taskProperties.properties().put(ModuleQProfiles.SONAR_PROFILE_PROP, "my-profile#2"); | |||
loader.load(project, taskProperties, null); | |||
loader.load(project.getKeyWithBranch(), "my-profile#2", null); | |||
verify(wsLoader).loadString("/batch/project?key=foo&profile=my-profile%232&preview=false"); | |||
} | |||
@@ -121,7 +115,7 @@ public class DefaultProjectRepositoriesLoaderTest { | |||
project = ProjectDefinition.create().setKey("foo"); | |||
when(wsLoader.loadString(anyString())).thenReturn(new WSLoaderResult<>(new ProjectRepositories().toJson(), true)); | |||
loader.load(project, taskProperties, null); | |||
loader.load(project.getKeyWithBranch(), null, null); | |||
} | |||
private void addQualityProfile() { |
@@ -0,0 +1,77 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import java.util.Date; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.when; | |||
public class DefaultProjectSettingsLoaderTest { | |||
private DefaultProjectSettingsLoader loader; | |||
private DefaultProjectRepositoriesFactory factory; | |||
private ProjectRepositories projectRepositories; | |||
private FileData f1; | |||
private FileData f2; | |||
@Before | |||
public void setUp() { | |||
createProjectRepo(); | |||
factory = mock(DefaultProjectRepositoriesFactory.class); | |||
when(factory.create()).thenReturn(projectRepositories); | |||
loader = new DefaultProjectSettingsLoader(factory); | |||
} | |||
private void createProjectRepo() { | |||
projectRepositories = new ProjectRepositories(); | |||
projectRepositories.setLastAnalysisDate(new Date(1000)); | |||
f1 = new FileData("hash1", true); | |||
f2 = new FileData("hash2", true); | |||
projectRepositories.addFileData("module1", "file1", f1); | |||
projectRepositories.addFileData("module1", "file2", f2); | |||
projectRepositories.addSettings("module1", ImmutableMap.of("key", "value")); | |||
} | |||
@Test | |||
public void test() { | |||
ProjectSettingsRepo loaded = loader.load("project", null); | |||
assertThat(loaded.fileData("module1", "file1")).isEqualTo(f1); | |||
assertThat(loaded.fileData("module1", "file2")).isEqualTo(f2); | |||
assertThat(loaded.settings("module1")).isEqualTo(ImmutableMap.of("key", "value")); | |||
assertThat(loaded.lastAnalysisDate()).isEqualTo(new Date(1000)); | |||
verify(factory).create(); | |||
verifyNoMoreInteractions(factory); | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import org.junit.Rule; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class DefaultQualityProfileLoaderTest { | |||
@Rule | |||
public ExpectedException exception = ExpectedException.none(); | |||
private DefaultQualityProfileLoader qpLoader; | |||
private DefaultProjectRepositoriesFactory factory; | |||
private ProjectRepositories projectRepositories; | |||
@Before | |||
public void setUp() { | |||
projectRepositories = new ProjectRepositories(); | |||
projectRepositories.addQProfile(new QProfile("profile", "name", "lang", new Date())); | |||
factory = mock(DefaultProjectRepositoriesFactory.class); | |||
when(factory.create()).thenReturn(projectRepositories); | |||
qpLoader = new DefaultQualityProfileLoader(factory); | |||
} | |||
@Test | |||
public void test() { | |||
Collection<QProfile> loaded = qpLoader.load("project", null); | |||
assertThat(loaded).hasSize(1); | |||
assertThat(loaded.iterator().next().key()).isEqualTo("profile"); | |||
verify(factory).create(); | |||
verifyNoMoreInteractions(factory); | |||
} | |||
@Test | |||
public void testNoProfile() { | |||
projectRepositories = new ProjectRepositories(); | |||
when(factory.create()).thenReturn(projectRepositories); | |||
exception.expect(IllegalStateException.class); | |||
exception.expectMessage("No quality profiles"); | |||
qpLoader.load("project", null); | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.repository; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import org.sonar.batch.protocol.input.QProfile; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import static org.mockito.Mockito.verify; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import org.sonar.batch.rule.ModuleQProfiles; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.junit.Test; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import org.mockito.MockitoAnnotations; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.mockito.Mock; | |||
import org.junit.Before; | |||
public class QualityProfileProviderTest { | |||
private QualityProfileProvider qualityProfileProvider; | |||
@Mock | |||
private QualityProfileLoader loader; | |||
@Mock | |||
private ProjectReactor projectReactor; | |||
@Mock | |||
private AnalysisMode mode; | |||
@Mock | |||
private AnalysisProperties props; | |||
private Collection<QProfile> response; | |||
@Before | |||
public void setUp() { | |||
MockitoAnnotations.initMocks(this); | |||
qualityProfileProvider = new QualityProfileProvider(); | |||
ProjectDefinition root = mock(ProjectDefinition.class); | |||
when(root.getKeyWithBranch()).thenReturn("project"); | |||
when(projectReactor.getRoot()).thenReturn(root); | |||
response = new ArrayList<QProfile>(1); | |||
response.add(new QProfile("profile", "name", "lang", new Date())); | |||
} | |||
@Test | |||
public void testProvide() { | |||
when(loader.load("project", null)).thenReturn(response); | |||
ModuleQProfiles qps = qualityProfileProvider.provide(projectReactor, loader, props, mode); | |||
assertResponse(qps); | |||
verify(loader).load("project", null); | |||
} | |||
@Test | |||
public void testProfileProp() { | |||
when(loader.load("project", "custom")).thenReturn(response); | |||
when(props.property(ModuleQProfiles.SONAR_PROFILE_PROP)).thenReturn("custom"); | |||
ModuleQProfiles qps = qualityProfileProvider.provide(projectReactor, loader, props, mode); | |||
assertResponse(qps); | |||
verify(loader).load("project", "custom"); | |||
} | |||
private void assertResponse(ModuleQProfiles qps) { | |||
assertThat(qps.findAll()).hasSize(1); | |||
assertThat(qps.findAll()).extracting("key").containsExactly("profile"); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube 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. | |||
* | |||
* SonarQube 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.batch.rule; | |||
import org.sonar.batch.repository.DefaultProjectRepositoriesFactory; | |||
import com.google.common.collect.ImmutableList; | |||
import org.sonar.batch.protocol.input.ActiveRule; | |||
import org.junit.Test; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import java.util.Collection; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.when; | |||
import org.junit.Before; | |||
public class DefaultActiveRulesLoaderTest { | |||
private DefaultActiveRulesLoader loader; | |||
private DefaultProjectRepositoriesFactory factory; | |||
private ProjectRepositories projectRepositories; | |||
private ActiveRule response; | |||
@Before | |||
public void setUp() { | |||
response = mock(ActiveRule.class); | |||
when(response.ruleKey()).thenReturn("rule"); | |||
projectRepositories = new ProjectRepositories(); | |||
projectRepositories.addActiveRule(response); | |||
factory = mock(DefaultProjectRepositoriesFactory.class); | |||
when(factory.create()).thenReturn(projectRepositories); | |||
loader = new DefaultActiveRulesLoader(factory); | |||
} | |||
@Test | |||
public void test() { | |||
Collection<String> profiles = ImmutableList.of("profile1"); | |||
Collection<ActiveRule> activeRules = loader.load(profiles, "project"); | |||
assertThat(activeRules).hasSize(1); | |||
assertThat(activeRules.iterator().next().ruleKey()).isEqualTo("rule"); | |||
verify(factory).create(); | |||
verifyNoMoreInteractions(factory); | |||
} | |||
} |
@@ -19,9 +19,11 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import com.google.common.collect.HashBasedTable; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.ImmutableTable; | |||
import com.google.common.collect.Table; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -29,10 +31,13 @@ import org.junit.rules.ExpectedException; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.config.PropertyDefinitions; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import java.util.List; | |||
import java.util.Map; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -43,15 +48,23 @@ public class ModuleSettingsTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
ProjectRepositories projectRef; | |||
private DefaultAnalysisMode mode; | |||
@Before | |||
public void before() { | |||
projectRef = new ProjectRepositories(); | |||
mode = mock(DefaultAnalysisMode.class); | |||
} | |||
private ProjectSettingsRepo createSettings(String module, Map<String, String> settingsMap) { | |||
Table<String, String, FileData> fileData = ImmutableTable.of(); | |||
Table<String, String, String> settings = HashBasedTable.create(); | |||
for (Map.Entry<String, String> e : settingsMap.entrySet()) { | |||
settings.put(module, e.getKey(), e.getValue()); | |||
} | |||
return new ProjectSettingsRepo(settings, fileData, null); | |||
} | |||
@Test | |||
public void testOrderedProjects() { | |||
ProjectDefinition grandParent = ProjectDefinition.create(); | |||
@@ -74,11 +87,12 @@ public class ModuleSettingsTest { | |||
"overridding", "batch", | |||
"on-batch", "true" | |||
)); | |||
projectRef.addSettings("struts-core", ImmutableMap.of("on-module", "true", "overridding", "module")); | |||
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("on-module", "true", "overridding", "module")); | |||
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core"); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projectRef, mode); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode); | |||
assertThat(moduleSettings.getString("overridding")).isEqualTo("module"); | |||
assertThat(moduleSettings.getString("on-batch")).isEqualTo("true"); | |||
@@ -93,11 +107,12 @@ public class ModuleSettingsTest { | |||
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of( | |||
"sonar.foo.secured", "bar" | |||
)); | |||
projectRef.addSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2")); | |||
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2")); | |||
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core"); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projectRef, mode); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode); | |||
assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2"); | |||
assertThat(moduleSettings.getString("sonar.foo.secured")).isEqualTo("bar"); | |||
@@ -110,13 +125,14 @@ public class ModuleSettingsTest { | |||
when(batchSettings.getProperties()).thenReturn(ImmutableMap.of( | |||
"sonar.foo.secured", "bar" | |||
)); | |||
projectRef.addSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2")); | |||
ProjectSettingsRepo projSettingsRepo = createSettings("struts-core", ImmutableMap.of("sonar.foo.license.secured", "bar2")); | |||
when(mode.isIssues()).thenReturn(true); | |||
ProjectDefinition module = ProjectDefinition.create().setKey("struts-core"); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projectRef, mode); | |||
ModuleSettings moduleSettings = new ModuleSettings(batchSettings, module, projSettingsRepo, mode); | |||
assertThat(moduleSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2"); | |||
@@ -20,7 +20,8 @@ | |||
package org.sonar.batch.scan; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.junit.Before; | |||
import org.sonar.api.batch.AnalysisMode; | |||
import org.sonar.batch.analysis.AnalysisProperties; | |||
import com.google.common.collect.Maps; | |||
import org.junit.Rule; | |||
@@ -38,6 +39,9 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Properties; | |||
import static org.mockito.Mockito.when; | |||
import static org.mockito.Mockito.mock; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class ProjectReactorBuilderTest { | |||
@@ -45,6 +49,13 @@ public class ProjectReactorBuilderTest { | |||
@Rule | |||
public ExpectedException thrown = ExpectedException.none(); | |||
private AnalysisMode mode; | |||
@Before | |||
public void setUp() { | |||
mode = mock(AnalysisMode.class); | |||
} | |||
@Test | |||
public void shouldDefineSimpleProject() { | |||
ProjectDefinition projectDefinition = loadProjectDefinition("simple-project"); | |||
@@ -78,12 +89,11 @@ public class ProjectReactorBuilderTest { | |||
public void shouldNotFailIfBlankSourceDirectory() { | |||
loadProjectDefinition("simple-project-with-blank-source-dir"); | |||
} | |||
@Test | |||
public void modulesRepeatedIds() { | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("Two modules have the same id: module1"); | |||
loadProjectDefinition("multi-module-repeated-id"); | |||
} | |||
@@ -101,8 +111,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(rootProject.getTestDirs().contains("tests")).isFalse(); | |||
assertThat(rootProject.getBinaries().contains("target/classes")).isFalse(); | |||
// and module properties must have been cleaned | |||
assertThat(rootProject.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(rootProject.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-all-in-root")); | |||
@@ -125,8 +135,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(module1.getTestDirs()).contains("tests"); | |||
assertThat(module1.getBinaries()).contains("target/classes"); | |||
// and module properties must have been cleaned | |||
assertThat(module1.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(module1.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(module1.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-all-in-root/module1")); | |||
@@ -144,8 +154,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(module2.getTestDirs()).contains("tests"); | |||
assertThat(module2.getBinaries()).contains("target/classes"); | |||
// and module properties must have been cleaned | |||
assertThat(module2.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(module2.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(module2.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(module2.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(module2.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-all-in-root/module2")); | |||
@@ -160,8 +170,8 @@ public class ProjectReactorBuilderTest { | |||
// CHECK ROOT | |||
// module properties must have been cleaned | |||
assertThat(rootProject.getProperties().getProperty("module1.sonar.moduleKey")).isNull(); | |||
assertThat(rootProject.getProperties().getProperty("module2.sonar.moduleKey")).isNull(); | |||
assertThat(rootProject.properties().get("module1.sonar.moduleKey")).isNull(); | |||
assertThat(rootProject.properties().get("module2.sonar.moduleKey")).isNull(); | |||
// CHECK MODULES | |||
List<ProjectDefinition> modules = rootProject.getSubProjects(); | |||
@@ -301,8 +311,8 @@ public class ProjectReactorBuilderTest { | |||
public void multiModuleProperties() { | |||
ProjectDefinition projectDefinition = loadProjectDefinition("big-multi-module-definitions-all-in-root"); | |||
assertThat(projectDefinition.getProperties().getProperty("module11.property")).isNull(); | |||
assertThat(projectDefinition.getProperties().getProperty("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(projectDefinition.properties().get("module11.property")).isNull(); | |||
assertThat(projectDefinition.properties().get("sonar.profile")).isEqualTo("Foo"); | |||
ProjectDefinition module1 = null; | |||
ProjectDefinition module2 = null; | |||
for (ProjectDefinition prj : projectDefinition.getSubProjects()) { | |||
@@ -312,12 +322,12 @@ public class ProjectReactorBuilderTest { | |||
module2 = prj; | |||
} | |||
} | |||
assertThat(module1.getProperties().getProperty("module11.property")).isNull(); | |||
assertThat(module1.getProperties().getProperty("property")).isNull(); | |||
assertThat(module1.getProperties().getProperty("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module2.getProperties().getProperty("module11.property")).isNull(); | |||
assertThat(module2.getProperties().getProperty("property")).isNull(); | |||
assertThat(module2.getProperties().getProperty("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module1.properties().get("module11.property")).isNull(); | |||
assertThat(module1.properties().get("property")).isNull(); | |||
assertThat(module1.properties().get("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module2.properties().get("module11.property")).isNull(); | |||
assertThat(module2.properties().get("property")).isNull(); | |||
assertThat(module2.properties().get("sonar.profile")).isEqualTo("Foo"); | |||
ProjectDefinition module11 = null; | |||
ProjectDefinition module12 = null; | |||
@@ -328,13 +338,13 @@ public class ProjectReactorBuilderTest { | |||
module12 = prj; | |||
} | |||
} | |||
assertThat(module11.getProperties().getProperty("module1.module11.property")).isNull(); | |||
assertThat(module11.getProperties().getProperty("module11.property")).isNull(); | |||
assertThat(module11.getProperties().getProperty("property")).isEqualTo("My module11 property"); | |||
assertThat(module11.getProperties().getProperty("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module12.getProperties().getProperty("module11.property")).isNull(); | |||
assertThat(module12.getProperties().getProperty("property")).isNull(); | |||
assertThat(module12.getProperties().getProperty("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module11.properties().get("module1.module11.property")).isNull(); | |||
assertThat(module11.properties().get("module11.property")).isNull(); | |||
assertThat(module11.properties().get("property")).isEqualTo("My module11 property"); | |||
assertThat(module11.properties().get("sonar.profile")).isEqualTo("Foo"); | |||
assertThat(module12.properties().get("module11.property")).isNull(); | |||
assertThat(module12.properties().get("property")).isNull(); | |||
assertThat(module12.properties().get("sonar.profile")).isEqualTo("Foo"); | |||
} | |||
@Test | |||
@@ -344,7 +354,7 @@ public class ProjectReactorBuilderTest { | |||
AnalysisProperties taskProperties = new AnalysisProperties(props, null); | |||
assertThat(taskProperties.property("module1.module11.property")).isEqualTo("My module11 property"); | |||
new ProjectReactorBuilder(taskProperties).execute(); | |||
new ProjectReactorBuilder(taskProperties, mode).execute(); | |||
assertThat(taskProperties.property("module1.module11.property")).isNull(); | |||
} | |||
@@ -443,19 +453,27 @@ public class ProjectReactorBuilderTest { | |||
@Test | |||
public void shouldInitRootWorkDir() { | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(Maps.<String, String>newHashMap(), null)); | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(Maps.<String, String>newHashMap(), null), mode); | |||
File baseDir = new File("target/tmp/baseDir"); | |||
File workDir = builder.initRootProjectWorkDir(baseDir, Maps.<String, String>newHashMap()); | |||
assertThat(workDir).isEqualTo(new File(baseDir, ".sonar")); | |||
} | |||
@Test | |||
public void nonAssociatedMode() { | |||
when(mode.isIssues()).thenReturn(true); | |||
ProjectDefinition project = loadProjectDefinition("multi-module-with-basedir-not-associated"); | |||
assertThat(project.getKey()).isEqualTo("project"); | |||
} | |||
@Test | |||
public void shouldInitWorkDirWithCustomRelativeFolder() { | |||
Map<String, String> props = Maps.<String, String>newHashMap(); | |||
props.put("sonar.working.directory", ".foo"); | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(props, null)); | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(props, null), mode); | |||
File baseDir = new File("target/tmp/baseDir"); | |||
File workDir = builder.initRootProjectWorkDir(baseDir, props); | |||
@@ -467,7 +485,7 @@ public class ProjectReactorBuilderTest { | |||
public void shouldInitRootWorkDirWithCustomAbsoluteFolder() { | |||
Map<String, String> props = Maps.<String, String>newHashMap(); | |||
props.put("sonar.working.directory", new File("src").getAbsolutePath()); | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(props, null)); | |||
ProjectReactorBuilder builder = new ProjectReactorBuilder(new AnalysisProperties(props, null), mode); | |||
File baseDir = new File("target/tmp/baseDir"); | |||
File workDir = builder.initRootProjectWorkDir(baseDir, props); | |||
@@ -477,16 +495,16 @@ public class ProjectReactorBuilderTest { | |||
@Test | |||
public void shouldFailIf2ModulesWithSameKey() { | |||
Properties props = new Properties(); | |||
Map<String, String> props = new HashMap<>(); | |||
props.put("sonar.projectKey", "root"); | |||
ProjectDefinition root = ProjectDefinition.create().setProperties(props); | |||
Properties props1 = new Properties(); | |||
Map<String, String> props1 = new HashMap<>(); | |||
props1.put("sonar.projectKey", "mod1"); | |||
root.addSubProject(ProjectDefinition.create().setProperties(props1)); | |||
// Check uniqueness of a new module: OK | |||
Properties props2 = new Properties(); | |||
Map<String, String> props2 = new HashMap<>(); | |||
props2.put("sonar.projectKey", "mod2"); | |||
ProjectDefinition mod2 = ProjectDefinition.create().setProperties(props2); | |||
ProjectReactorBuilder.checkUniquenessOfChildKey(mod2, root); | |||
@@ -519,7 +537,7 @@ public class ProjectReactorBuilderTest { | |||
private ProjectDefinition loadProjectDefinition(String projectFolder) { | |||
Map<String, String> props = loadProps(projectFolder); | |||
AnalysisProperties bootstrapProps = new AnalysisProperties(props, null); | |||
ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps).execute(); | |||
ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps,mode).execute(); | |||
return projectReactor.getRoot(); | |||
} | |||
@@ -594,8 +612,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(rootProject.getTestDirs().contains("tests")).isFalse(); | |||
assertThat(rootProject.getBinaries().contains("target/classes")).isFalse(); | |||
// and module properties must have been cleaned | |||
assertThat(rootProject.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(rootProject.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(rootProject.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-same-prefix")); | |||
@@ -618,8 +636,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(module1.getTestDirs()).contains("tests"); | |||
assertThat(module1.getBinaries()).contains("target/classes"); | |||
// and module properties must have been cleaned | |||
assertThat(module1.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(module1.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(module1.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-same-prefix/module1")); | |||
@@ -637,8 +655,8 @@ public class ProjectReactorBuilderTest { | |||
assertThat(module1Feature.getTestDirs()).contains("tests"); | |||
assertThat(module1Feature.getBinaries()).contains("target/classes"); | |||
// and module properties must have been cleaned | |||
assertThat(module1Feature.getProperties().getProperty("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1Feature.getProperties().getProperty("module2.sonar.projectKey")).isNull(); | |||
assertThat(module1Feature.properties().get("module1.sonar.projectKey")).isNull(); | |||
assertThat(module1Feature.properties().get("module2.sonar.projectKey")).isNull(); | |||
// Check baseDir and workDir | |||
assertThat(module1Feature.getBaseDir().getCanonicalFile()) | |||
.isEqualTo(TestUtils.getResource(this.getClass(), "multi-module-definitions-same-prefix/module1.feature")); |
@@ -27,7 +27,6 @@ import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.bootstrap.ProjectReactor; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.utils.SonarException; | |||
public class ProjectReactorValidatorTest { | |||
@@ -90,7 +89,7 @@ public class ProjectReactorValidatorTest { | |||
public void fail_with_invalid_key() { | |||
ProjectReactor reactor = createProjectReactor("foo$bar"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"foo$bar\" is not a valid project or module key"); | |||
validator.validate(reactor); | |||
} | |||
@@ -99,7 +98,7 @@ public class ProjectReactorValidatorTest { | |||
public void fail_with_backslash_in_key() { | |||
ProjectReactor reactor = createProjectReactor("foo\\bar"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"foo\\bar\" is not a valid project or module key"); | |||
validator.validate(reactor); | |||
} | |||
@@ -117,7 +116,7 @@ public class ProjectReactorValidatorTest { | |||
@Test | |||
public void fail_with_invalid_branch() { | |||
ProjectReactor reactor = createProjectReactor("foo", "bran#ch"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"bran#ch\" is not a valid branch name"); | |||
validator.validate(reactor); | |||
} | |||
@@ -125,7 +124,7 @@ public class ProjectReactorValidatorTest { | |||
@Test | |||
public void fail_with_colon_in_branch() { | |||
ProjectReactor reactor = createProjectReactor("foo", "bran:ch"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"bran:ch\" is not a valid branch name"); | |||
validator.validate(reactor); | |||
} | |||
@@ -134,7 +133,7 @@ public class ProjectReactorValidatorTest { | |||
public void fail_with_only_digits() { | |||
ProjectReactor reactor = createProjectReactor("12345"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"12345\" is not a valid project or module key"); | |||
validator.validate(reactor); | |||
} | |||
@@ -144,7 +143,7 @@ public class ProjectReactorValidatorTest { | |||
ProjectReactor reactor = createProjectReactor("foo"); | |||
settings.setProperty("sonar.phase", "phase"); | |||
thrown.expect(SonarException.class); | |||
thrown.expect(IllegalStateException.class); | |||
thrown.expectMessage("\"sonar.phase\" is deprecated"); | |||
validator.validate(reactor); | |||
} |
@@ -19,8 +19,13 @@ | |||
*/ | |||
package org.sonar.batch.scan; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import com.google.common.collect.HashBasedTable; | |||
import com.google.common.collect.Table; | |||
import com.google.common.collect.ImmutableTable; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.sonar.batch.analysis.DefaultAnalysisMode; | |||
import org.sonar.batch.bootstrap.GlobalMode; | |||
import com.google.common.collect.ImmutableMap; | |||
@@ -40,7 +45,6 @@ import org.sonar.api.utils.log.LoggerLevel; | |||
import org.sonar.batch.bootstrap.GlobalProperties; | |||
import org.sonar.batch.bootstrap.GlobalSettings; | |||
import org.sonar.batch.protocol.input.GlobalRepositories; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
@@ -52,16 +56,20 @@ public class ProjectSettingsTest { | |||
@Rule | |||
public LogTester logTester = new LogTester(); | |||
ProjectRepositories projectRef; | |||
ProjectDefinition project = ProjectDefinition.create().setKey("struts"); | |||
GlobalSettings bootstrapProps; | |||
private ProjectSettingsRepo projectRef; | |||
private ProjectDefinition project; | |||
private GlobalSettings bootstrapProps; | |||
private Table<String, String, FileData> emptyFileData; | |||
private Table<String, String, String> emptySettings; | |||
private GlobalMode globalMode; | |||
private DefaultAnalysisMode mode; | |||
@Before | |||
public void prepare() { | |||
projectRef = new ProjectRepositories(); | |||
emptyFileData = ImmutableTable.of(); | |||
emptySettings = ImmutableTable.of(); | |||
project = ProjectDefinition.create().setKey("struts"); | |||
globalMode = mock(GlobalMode.class); | |||
mode = mock(DefaultAnalysisMode.class); | |||
bootstrapProps = new GlobalSettings(new GlobalProperties(Collections.<String, String>emptyMap()), new PropertyDefinitions(), new GlobalRepositories(), globalMode); | |||
@@ -71,6 +79,7 @@ public class ProjectSettingsTest { | |||
public void should_load_project_props() { | |||
project.setProperty("project.prop", "project"); | |||
projectRef = new ProjectSettingsRepo(emptySettings, emptyFileData, null); | |||
ProjectSettings batchSettings = new ProjectSettings(new ProjectReactor(project), bootstrapProps, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(batchSettings.getString("project.prop")).isEqualTo("project"); | |||
@@ -78,10 +87,12 @@ public class ProjectSettingsTest { | |||
@Test | |||
public void should_load_project_root_settings() { | |||
projectRef.addSettings("struts", ImmutableMap.of("sonar.cpd.cross", "true", "sonar.java.coveragePlugin", "jacoco")); | |||
Table<String, String, String> settings = HashBasedTable.create(); | |||
settings.put("struts", "sonar.cpd.cross", "true"); | |||
settings.put("struts", "sonar.java.coveragePlugin", "jacoco"); | |||
projectRef = new ProjectSettingsRepo(settings, emptyFileData, null); | |||
ProjectSettings batchSettings = new ProjectSettings(new ProjectReactor(project), bootstrapProps, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(batchSettings.getString("sonar.java.coveragePlugin")).isEqualTo("jacoco"); | |||
} | |||
@@ -89,7 +100,11 @@ public class ProjectSettingsTest { | |||
public void should_load_project_root_settings_on_branch() { | |||
project.setProperty(CoreProperties.PROJECT_BRANCH_PROPERTY, "mybranch"); | |||
projectRef.addSettings("struts:mybranch", ImmutableMap.of("sonar.cpd.cross", "true", "sonar.java.coveragePlugin", "jacoco")); | |||
Table<String, String, String> settings = HashBasedTable.create(); | |||
settings.put("struts:mybranch", "sonar.cpd.cross", "true"); | |||
settings.put("struts:mybranch", "sonar.java.coveragePlugin", "jacoco"); | |||
projectRef = new ProjectSettingsRepo(settings, emptyFileData, null); | |||
ProjectSettings batchSettings = new ProjectSettings(new ProjectReactor(project), bootstrapProps, new PropertyDefinitions(), projectRef, mode); | |||
@@ -98,8 +113,11 @@ public class ProjectSettingsTest { | |||
@Test | |||
public void should_not_fail_when_accessing_secured_properties() { | |||
projectRef.addSettings("struts", ImmutableMap.of("sonar.foo.secured", "bar", "sonar.foo.license.secured", "bar2")); | |||
Table<String, String, String> settings = HashBasedTable.create(); | |||
settings.put("struts", "sonar.foo.secured", "bar"); | |||
settings.put("struts", "sonar.foo.license.secured", "bar2"); | |||
projectRef = new ProjectSettingsRepo(settings, emptyFileData, null); | |||
ProjectSettings batchSettings = new ProjectSettings(new ProjectReactor(project), bootstrapProps, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(batchSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2"); | |||
@@ -108,10 +126,13 @@ public class ProjectSettingsTest { | |||
@Test | |||
public void should_fail_when_accessing_secured_properties_in_issues_mode() { | |||
projectRef.addSettings("struts", ImmutableMap.of("sonar.foo.secured", "bar", "sonar.foo.license.secured", "bar2")); | |||
Table<String, String, String> settings = HashBasedTable.create(); | |||
settings.put("struts", "sonar.foo.secured", "bar"); | |||
settings.put("struts", "sonar.foo.license.secured", "bar2"); | |||
when(mode.isIssues()).thenReturn(true); | |||
projectRef = new ProjectSettingsRepo(settings, emptyFileData, null); | |||
ProjectSettings batchSettings = new ProjectSettings(new ProjectReactor(project), bootstrapProps, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(batchSettings.getString("sonar.foo.license.secured")).isEqualTo("bar2"); | |||
@@ -123,10 +144,13 @@ public class ProjectSettingsTest { | |||
@Test | |||
public void should_log_a_warning_when_a_dropper_property_is_present() { | |||
GlobalSettings settings = new GlobalSettings(new GlobalProperties(ImmutableMap.of("sonar.qualitygate", "somevalue")), new PropertyDefinitions(), new GlobalRepositories(), globalMode); | |||
GlobalSettings settings = new GlobalSettings(new GlobalProperties(ImmutableMap.of("sonar.qualitygate", "somevalue")), new PropertyDefinitions(), new GlobalRepositories(), | |||
globalMode); | |||
projectRef = new ProjectSettingsRepo(emptySettings, emptyFileData, null); | |||
new ProjectSettings(new ProjectReactor(project), settings, new PropertyDefinitions(), projectRef, mode); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).containsOnly("Property 'sonar.qualitygate' is not supported any more. It will be ignored."); | |||
} | |||
} |
@@ -19,16 +19,16 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import org.junit.Test; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.junit.Test; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
public class StatusDetectionFactoryTest { | |||
@Test | |||
public void testCreate() throws Exception { | |||
StatusDetectionFactory factory = new StatusDetectionFactory(mock(ProjectRepositories.class)); | |||
StatusDetectionFactory factory = new StatusDetectionFactory(mock(ProjectSettingsRepo.class)); | |||
StatusDetection detection = factory.create(); | |||
assertThat(detection).isNotNull(); | |||
} |
@@ -19,23 +19,35 @@ | |||
*/ | |||
package org.sonar.batch.scan.filesystem; | |||
import com.google.common.collect.ImmutableTable; | |||
import com.google.common.collect.HashBasedTable; | |||
import com.google.common.collect.Table; | |||
import org.sonar.batch.repository.ProjectSettingsRepo; | |||
import org.junit.Test; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.batch.protocol.input.FileData; | |||
import org.sonar.batch.protocol.input.ProjectRepositories; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class StatusDetectionTest { | |||
@Test | |||
public void detect_status() { | |||
ProjectRepositories ref = new ProjectRepositories(); | |||
ref.addFileData("foo", "src/Foo.java", new FileData("ABCDE", true)); | |||
ref.addFileData("foo", "src/Bar.java", new FileData("FGHIJ", true)); | |||
Table<String, String, String> t = ImmutableTable.of(); | |||
ProjectSettingsRepo ref = new ProjectSettingsRepo(t, createTable(), null); | |||
StatusDetection statusDetection = new StatusDetection(ref); | |||
assertThat(statusDetection.status("foo", "src/Foo.java", "ABCDE")).isEqualTo(InputFile.Status.SAME); | |||
assertThat(statusDetection.status("foo", "src/Foo.java", "XXXXX")).isEqualTo(InputFile.Status.CHANGED); | |||
assertThat(statusDetection.status("foo", "src/Other.java", "QWERT")).isEqualTo(InputFile.Status.ADDED); | |||
} | |||
private static Table<String, String, FileData> createTable() { | |||
Table<String, String, FileData> t = HashBasedTable.create(); | |||
t.put("foo", "src/Foo.java", new FileData("ABCDE", true)); | |||
t.put("foo", "src/Bar.java", new FileData("FGHIJ", true)); | |||
return t; | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package com.sonar.it.samples.modules.a1; | |||
public class HelloA1 { | |||
private int i; | |||
private HelloA1() { | |||
} | |||
public void hello() { | |||
System.out.println("hello" + " xoo"); | |||
} | |||
protected String getHello() { | |||
return "hello"; | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.sonar.it.samples.modules.a2; | |||
public class HelloA2 { | |||
private int i; | |||
private HelloA2() { | |||
} | |||
public void hello() { | |||
System.out.println("hello" + " xoo"); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.sonar.it.samples.modules.b1; | |||
public class HelloB1 { | |||
private int i; | |||
private HelloB1() { | |||
} | |||
public void hello() { | |||
System.out.println("hello" + " world"); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
package com.sonar.it.samples.modules.b2; | |||
public class HelloB2 { | |||
private int i; | |||
private HelloB2() { | |||
} | |||
public void hello() { | |||
System.out.println("hello" + " world"); | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
# Root project information | |||
#sonar.projectKey=com.sonarsource.it.samples:multi-modules-sample | |||
sonar.projectName=Sonar :: Integration Tests :: Multi-modules Sample | |||
sonar.projectVersion=1.0-SNAPSHOT | |||
sonar.language=xoo | |||
# Some properties that will be inherited by the modules | |||
sonar.sources=src/main/xoo | |||
# List of the module identifiers | |||
sonar.modules=module_a,module_b | |||
module_a.sonar.projectKey=module_a | |||
module_a.sonar.projectName=Module A | |||
module_a.sonar.modules=module_a1,module_a2 | |||
module_a.module_a1.sonar.projectName=Sub-module A1 | |||
module_a.module_a2.sonar.projectName=Sub-module A2 | |||
module_b.sonar.projectKey=module_b | |||
module_b.sonar.projectName=Module B | |||
module_b.sonar.modules=module_b1,module_b2 | |||
module_b.module_b1.sonar.projectName=Sub-module B1 | |||
module_b.module_b2.sonar.projectName=Sub-module B2 |
@@ -1,49 +0,0 @@ | |||
523048e7f5ca9550505f2d8ea6d587e7 | |||
50ff1975ec4309da19591231c6b5104b | |||
eba1d423f8632818ce94c4eac1b90713 | |||
6112a40c70ed55453a0753030d5564a4 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
eac5fc1130394e7268b1cfbc54cd7e4d | |||
c0b153d8c08365f2de343e278d3b54c7 | |||
eb4521cb5d193e1d37ecac25b0ffea43 | |||
9210ed0dec59ed663c744d7fb68f0275 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
cd0fbdfa49d32525ecbdb8dab19dafe6 | |||
ea12a10f5b7730daa639fe133867e088 | |||
69739b9bc9312dfb1a6b8625a08c652a | |||
ec21e054f7f5748d0161fe27cdad6462 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
951a83e8074813100da0cba92092b385 | |||
c93caecd79a332773cfb06cd5d3b8895 | |||
5832d52d5fcb22a3350f62c856993f0d | |||
c4c9bdd47ee05028cb84873da0ebf2b5 | |||
f89e422b117e518acef69df33f199d10 | |||
90aa2aae2384f6412c3b86d085d5ffa5 | |||
647f262205ad09f32b0091df388992ed | |||
943d54ba3e8812437c4d26ef8aa263f8 | |||
340385b760d1441d3b74e5e39399cc0c | |||
a94613fd32125cd63160b0c1cf2bd078 | |||
3415664f5f4a608772e6a4c73a993804 | |||
597b7f5598c56e77bd28b9ff15a30802 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
2c953c12d2eb6ea958b7f3045ecf8e81 | |||
864d4d5a0cd65f52d791700443cec75e | |||
1b2437750694bba602fedc0a568c65de | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
2c953c12d2eb6ea958b7f3045ecf8e81 | |||
d18a921e891f6f9af8564a882efea289 | |||
8bc5ef2851a7dcf1cf096a68e2a47ba6 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
2c953c12d2eb6ea958b7f3045ecf8e81 | |||
9cf0f8aa69740d88788fb437589ed33f | |||
0df2777822bbc7799716a10478ca58d4 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf |
@@ -1,149 +0,0 @@ | |||
523048e7f5ca9550505f2d8ea6d587e7 | |||
50ff1975ec4309da19591231c6b5104b | |||
eba1d423f8632818ce94c4eac1b90713 | |||
6112a40c70ed55453a0753030d5564a4 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
eac5fc1130394e7268b1cfbc54cd7e4d | |||
c0b153d8c08365f2de343e278d3b54c7 | |||
eb4521cb5d193e1d37ecac25b0ffea43 | |||
9210ed0dec59ed663c744d7fb68f0275 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
cd0fbdfa49d32525ecbdb8dab19dafe6 | |||
ea12a10f5b7730daa639fe133867e088 | |||
69739b9bc9312dfb1a6b8625a08c652a | |||
ec21e054f7f5748d0161fe27cdad6462 | |||
3389dae361af79b04c9c8e7057f60cc6 | |||
951a83e8074813100da0cba92092b385 | |||
c93caecd79a332773cfb06cd5d3b8895 | |||
5832d52d5fcb22a3350f62c856993f0d | |||
c4c9bdd47ee05028cb84873da0ebf2b5 | |||
f89e422b117e518acef69df33f199d10 | |||
9e0ae10d6ada18721c856844d765b465 | |||
ea3c894506f93b88c9fc6c9790da9008 | |||
c5c303a0f47f5f15f22b6776fc1c8c93 | |||
4f592acdcfc11c97e7f19231de9d69b0 | |||
6aea6951956275cb62d01063a1e695fe | |||
293f7a3f08e54359c17d5e984f721665 | |||
18d24bd6a2c2c15d3914502e2776e372 | |||
107e08f15be7e18888da7e69948ac3ba | |||
90aa2aae2384f6412c3b86d085d5ffa5 | |||
ef76944333105582ae8d3a51d29b3b8a | |||
2a592c3d07126847ae4cbbed4a2b4d46 | |||
6f382821d6f35beb6ae4080607046898 | |||
943d54ba3e8812437c4d26ef8aa263f8 | |||
6fa05171389dfbeda44181c98e580d18 | |||
391715e38dad3a13b75205d527e82c8a | |||
bb3900a63a8cecc1e79592e054915c97 | |||
7c8d40302b1200413bc859331a4f241d | |||
0e2ad2ad1ad56b970e4348a3967d1e81 | |||
049ace1ff1516be8a5fd7cddc0ab2f30 | |||
d2c44db3922004ac2ae41fb402d005b1 | |||
b0ba7766e9e1fddaf40e86b62a5c2900 | |||
62e220c0092e8ae61f5937f18e4b03bc | |||
a5eeb3bd06bd4499f8a9ad20ba426bbd | |||
2bb44a6b46970b3efd87cc8a68848fae | |||
5b9e24bad64529f3e35ba4f1aed892f2 | |||
78f4e1ffbbf29629025b20f6b1be36f5 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
2c953c12d2eb6ea958b7f3045ecf8e81 | |||
0f253056876c021c4fd3f3e5ddc4d5b6 | |||
520e98566046a173f9250aa3b7a40ec9 | |||
c31394024dee65cba7e5c526c69af278 | |||
80d5b17efc16ace990c07580fc3e85eb | |||
d28bc6d296024d650b16efe1369128b0 | |||
38ba857d93d3a54a6b7f1bfc1b8fb090 | |||
d41f14cd3267e8d9c17b47ddcb71b0c1 | |||
54f339c05c18199eca937a31fdc07857 | |||
7efc34bf8e2ba01cec26c50875ac8acd | |||
5a29aee8cfe3a5110dc892ab8adfc17f | |||
d271e10accbea4cb6365b85150505b0d | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
319f70c2d340b01002c3539d09dabbec | |||
b225a5ae163bfc56684d172522993825 | |||
791c95e71dd996b4d723f96df3f37ca4 | |||
80d5b17efc16ace990c07580fc3e85eb | |||
2a8af480cbdcc0ee9b44187a078c8fe7 | |||
4340b548cda0dbc6043cbf4cf49d1b12 | |||
2df758e8d85494e7ee23a02d4c3aa6a7 | |||
e44feb14b61ab99767239eaded464459 | |||
eb375774c265dedeefeb29283ceea9bc | |||
c87c662bc284c5f9c01d3551957ee32e | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
1fcefdfae441ded6478da69428a30f12 | |||
8fcd1ffa896d0e214539b1bfa179f3e8 | |||
7a64b5f6e57cc9f13d5a1be99b9f7c23 | |||
8884d72adb8d93474c6af620a7d6fdba | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
7e53b1d2085d8c7ae88417eccc5a0893 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
5f68d8059a28922be107658c3890c230 | |||
6ded45bc62f1d535345e67001dac69d5 | |||
34165242e2230ffca31d7942ec577e6b | |||
02f5ec563dbaaef9ef402c6941a36c98 | |||
784b65e21ca0539f3cefb1710ccc7768 | |||
982e86cf85e0f121ba1a2f0ef462aa6b | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
80d5b17efc16ace990c07580fc3e85eb | |||
34c0d764eb79cc7c6dccb53e711fd4be | |||
a5b2391dd7127292b7240c7c8c1ee92a | |||
54d7949984c901073fffda9956190c12 | |||
da38c234aa3fdca9ec1e0e2b991d3568 | |||
6b2decb38be3882440910fd75ec508cd | |||
ce51581950deb12616108c0e909f9c53 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
e8165f1ae4cf11035542d4b60ac7b14d | |||
c8272ad357e7feaf2671a0612e52d3b5 | |||
2c953c12d2eb6ea958b7f3045ecf8e81 | |||
209935c0f7c635d91164fe2b14314a3d | |||
448b1c0a64288dbeac516ba67c9f2574 | |||
540c13e9e156b687226421b24f2df178 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
c0c97e22db5055def551d1cef15fb251 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
8983f749749a87599ea48c8bc08cac86 | |||
f298d78afda5708f64ded32af0e7f541 | |||
248e216059cad9c12bc8ff8b3b6289e2 | |||
80d5b17efc16ace990c07580fc3e85eb | |||
318ddd60a422c3d0435acd5f7aa6923c | |||
7c3bca9656325d15227ffac4ce5dfde9 | |||
7d992ab2241888573c1c7bdfe5d33a35 | |||
cd620097a91b074942d29535e822ebb0 | |||
a50e423de97896afb97123424a960664 | |||
35bb4ed816814a612f9605aec97c69fb | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
280db1f26dcc577de8fc62d40627112b | |||
e5b027822061ae041ced3d958b6f7f37 | |||
11a0dde589dec02e8d95c4ea6d83780f | |||
e5acab4c66ae60432ccc5a45d718d152 | |||
3c4b4570f7e4c7037693b1aa1fd5a9ca | |||
420d9af4c91e3248bb2a4e72a683a03a | |||
d69bf14adaf9ea45b48c0fdfefa4f69d | |||
505b97969baa28c3f607a38ee02f4f2d | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
da94121a62e940229bd622927ad7702f | |||
9d2a20a55b185c4a864efd3484a870fa | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
daada2d57491a2d0b4d237f29fc039dc | |||
53220ad5b69915dec696a01167d5237b | |||
2fb05fbd558fb020eacca16faa325246 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
423c485e2882c1fd9a1b19983b812f50 | |||
cbb184dd8e05c9709e5dcaedaa0495cf | |||
cbb184dd8e05c9709e5dcaedaa0495cf |
@@ -0,0 +1 @@ | |||
class Fake {} |
@@ -0,0 +1,14 @@ | |||
#sonar.projectKey=com.foo.project | |||
sonar.projectName=Foo Project | |||
sonar.projectVersion=1.0-SNAPSHOT | |||
sonar.projectDescription=Description of Foo Project | |||
sonar.sources=sources | |||
sonar.tests=tests | |||
sonar.binaries=target/classes | |||
sonar.modules=module1 | |||
module1.sonar.projectBaseDir=modules/module1 | |||
module1.sonar.projectKey=com.foo.project.module1 | |||
module1.sonar.projectName=Foo Module 1 |
@@ -117,7 +117,7 @@ public class FileCache { | |||
return new File(dir, hash); | |||
} | |||
private void mkdirQuietly(File hashDir) { | |||
private static void mkdirQuietly(File hashDir) { | |||
try { | |||
Files.createDirectories(hashDir.toPath()); | |||
} catch (IOException e) { |
@@ -56,7 +56,7 @@ public class FileHashes { | |||
} | |||
} | |||
private byte[] digest(InputStream input, MessageDigest digest) throws IOException { | |||
private static byte[] digest(InputStream input, MessageDigest digest) throws IOException { | |||
final byte[] buffer = new byte[STREAM_BUFFER_LENGTH]; | |||
int read = input.read(buffer, 0, STREAM_BUFFER_LENGTH); | |||
while (read > -1) { |
@@ -19,7 +19,9 @@ | |||
*/ | |||
package org.sonar.home.cache; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.RandomAccessFile; | |||
import java.nio.channels.FileChannel; | |||
import java.nio.channels.FileLock; | |||
@@ -28,6 +30,7 @@ import java.nio.charset.StandardCharsets; | |||
import java.nio.file.DirectoryStream; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import java.nio.file.StandardCopyOption; | |||
import java.nio.file.attribute.BasicFileAttributes; | |||
import java.security.MessageDigest; | |||
import java.security.NoSuchAlgorithmException; | |||
@@ -77,7 +80,7 @@ public class PersistentCache { | |||
@CheckForNull | |||
public synchronized String getString(@Nonnull String obj, @Nullable final PersistentCacheLoader<String> valueLoader) throws IOException { | |||
ValueLoaderDecoder decoder = valueLoader != null ? new ValueLoaderDecoder(valueLoader) : null; | |||
byte[] cached = get(obj, decoder); | |||
if (cached == null) { | |||
@@ -87,6 +90,20 @@ public class PersistentCache { | |||
return new String(cached, ENCODING); | |||
} | |||
@CheckForNull | |||
public synchronized InputStream getStream(@Nonnull String obj) throws IOException { | |||
String key = getKey(obj); | |||
try { | |||
lock(); | |||
Path path = getCacheCopy(key); | |||
return new DeleteOnCloseInputStream(new FileInputStream(path.toFile()), path); | |||
} finally { | |||
unlock(); | |||
} | |||
} | |||
@CheckForNull | |||
public synchronized byte[] get(@Nonnull String obj, @Nullable PersistentCacheLoader<byte[]> valueLoader) throws IOException { | |||
String key = getKey(obj); | |||
@@ -116,6 +133,16 @@ public class PersistentCache { | |||
return null; | |||
} | |||
public synchronized void put(@Nonnull String obj, @Nonnull InputStream stream) throws IOException { | |||
String key = getKey(obj); | |||
try { | |||
lock(); | |||
putCache(key, stream); | |||
} finally { | |||
unlock(); | |||
} | |||
} | |||
public synchronized void put(@Nonnull String obj, @Nonnull byte[] value) throws IOException { | |||
String key = getKey(obj); | |||
@@ -266,6 +293,11 @@ public class PersistentCache { | |||
Path cachePath = getCacheEntryPath(key); | |||
Files.write(cachePath, value, CREATE, WRITE, TRUNCATE_EXISTING); | |||
} | |||
private void putCache(String key, InputStream stream) throws IOException { | |||
Path cachePath = getCacheEntryPath(key); | |||
Files.copy(stream, cachePath, StandardCopyOption.REPLACE_EXISTING); | |||
} | |||
private byte[] getCache(String key) throws IOException { | |||
Path cachePath = getCacheEntryPath(key); | |||
@@ -277,6 +309,39 @@ public class PersistentCache { | |||
return Files.readAllBytes(cachePath); | |||
} | |||
private Path getCacheCopy(String key) throws IOException { | |||
Path cachePath = getCacheEntryPath(key); | |||
if (!validateCacheEntry(cachePath, this.defaultDurationToExpireMs)) { | |||
return null; | |||
} | |||
Path temp = Files.createTempFile("sonar_cache", null); | |||
Files.copy(cachePath, temp, StandardCopyOption.REPLACE_EXISTING); | |||
return temp; | |||
} | |||
private static class DeleteOnCloseInputStream extends InputStream { | |||
private final InputStream stream; | |||
private final Path p; | |||
private DeleteOnCloseInputStream(InputStream stream, Path p) { | |||
this.stream = stream; | |||
this.p = p; | |||
} | |||
@Override | |||
public int read() throws IOException { | |||
return stream.read(); | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
stream.close(); | |||
Files.delete(p); | |||
} | |||
} | |||
private boolean validateCacheEntry(Path cacheEntryPath, long durationToExpireMs) throws IOException { | |||
if (!Files.exists(cacheEntryPath)) { | |||
return false; |