diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2015-09-21 18:09:30 +0200 |
---|---|---|
committer | Duarte Meneses <duarte.meneses@sonarsource.com> | 2015-09-30 16:27:12 +0200 |
commit | 80b9f52b80c5ae3fcc81b8b8cc3209000a886b7f (patch) | |
tree | 6309fa9d853be81dd6ae47a1e07d7350480b3905 /sonar-batch/src/main/java/org | |
parent | 0847774db59344316629a7171c3943dbfaa3f52d (diff) | |
download | sonarqube-80b9f52b80c5ae3fcc81b8b8cc3209000a886b7f.tar.gz sonarqube-80b9f52b80c5ae3fcc81b8b8cc3209000a886b7f.zip |
SONAR-6818 Split batch/project WS in several simpler WS
Diffstat (limited to 'sonar-batch/src/main/java/org')
31 files changed, 451 insertions, 532 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/NonAssociatedCacheSynchronizer.java b/sonar-batch/src/main/java/org/sonar/batch/cache/NonAssociatedCacheSynchronizer.java index 44743f5c120..5242184a30f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/cache/NonAssociatedCacheSynchronizer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/NonAssociatedCacheSynchronizer.java @@ -19,9 +19,9 @@ */ package org.sonar.batch.cache; +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; 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; @@ -61,15 +61,15 @@ public class NonAssociatedCacheSynchronizer { } loadData(); - + cacheStatus.save(); LOG.info("-- Succesfully synchronized cache"); } - private static Collection<String> getKeys(Collection<QProfile> qProfiles) { + private static Collection<String> getKeys(Collection<QualityProfile> qProfiles) { List<String> list = new ArrayList<>(qProfiles.size()); - for (QProfile qp : qProfiles) { - list.add(qp.key()); + for (QualityProfile qp : qProfiles) { + list.add(qp.getKey()); } return list; @@ -79,11 +79,14 @@ public class NonAssociatedCacheSynchronizer { Profiler profiler = Profiler.create(Loggers.get(ProjectCacheSynchronizer.class)); profiler.startInfo("Load default quality profiles"); - Collection<QProfile> qProfiles = qualityProfileLoader.load(null, null); + Collection<QualityProfile> qProfiles = qualityProfileLoader.loadDefault(null); profiler.stopInfo(); profiler.startInfo("Load default active rules"); - activeRulesLoader.load(getKeys(qProfiles), null); + Collection<String> keys = getKeys(qProfiles); + for (String k : keys) { + activeRulesLoader.load(k, null); + } profiler.stopInfo(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java index 20d16fbaaad..4445eaae606 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectCacheSynchronizer.java @@ -19,6 +19,9 @@ */ package org.sonar.batch.cache; +import org.sonar.batch.repository.ProjectRepositoriesLoader; + +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; import com.google.common.base.Function; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -26,9 +29,7 @@ import org.slf4j.LoggerFactory; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; import org.sonar.batch.protocol.input.BatchInput.ServerIssue; -import org.sonar.batch.protocol.input.QProfile; -import org.sonar.batch.repository.ProjectSettingsLoader; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.ProjectRepositories; import org.sonar.batch.repository.QualityProfileLoader; import org.sonar.batch.repository.ServerIssuesLoader; import org.sonar.batch.repository.user.UserRepositoryLoader; @@ -48,14 +49,14 @@ public class ProjectCacheSynchronizer { private final UserRepositoryLoader userRepository; private final ProjectCacheStatus cacheStatus; private final QualityProfileLoader qualityProfileLoader; - private final ProjectSettingsLoader projectSettingsLoader; + private final ProjectRepositoriesLoader projectRepositoriesLoader; private final ActiveRulesLoader activeRulesLoader; - public ProjectCacheSynchronizer(QualityProfileLoader qualityProfileLoader, ProjectSettingsLoader projectSettingsLoader, + public ProjectCacheSynchronizer(QualityProfileLoader qualityProfileLoader, ProjectRepositoriesLoader projectSettingsLoader, ActiveRulesLoader activeRulesLoader, ServerIssuesLoader issuesLoader, UserRepositoryLoader userRepository, ProjectCacheStatus cacheStatus) { this.qualityProfileLoader = qualityProfileLoader; - this.projectSettingsLoader = projectSettingsLoader; + this.projectRepositoriesLoader = projectSettingsLoader; this.activeRulesLoader = activeRulesLoader; this.issuesLoader = issuesLoader; this.userRepository = userRepository; @@ -88,42 +89,51 @@ public class ProjectCacheSynchronizer { private void loadData(String projectKey) { Profiler profiler = Profiler.create(Loggers.get(ProjectCacheSynchronizer.class)); + ProjectRepositories projectRepo = null; profiler.startInfo("Load project settings"); - ProjectSettingsRepo settings = projectSettingsLoader.load(projectKey, null); - profiler.stopInfo(); + projectRepo = projectRepositoriesLoader.load(projectKey, true, null); - if (settings.lastAnalysisDate() == null) { + if (!projectRepo.exists()) { + LOG.debug("Project doesn't exist in the server"); + } else if (projectRepo.lastAnalysisDate() == null) { LOG.debug("No previous analysis found"); - return; } + profiler.stopInfo(); profiler.startInfo("Load project quality profiles"); - Collection<QProfile> qProfiles = qualityProfileLoader.load(projectKey, null); + Collection<QualityProfile> qProfiles; + if (projectRepo.exists()) { + qProfiles = qualityProfileLoader.load(projectKey, null, null); + } else { + qProfiles = qualityProfileLoader.loadDefault(null); + } profiler.stopInfo(); - Collection<String> profileKeys = getKeys(qProfiles); - profiler.startInfo("Load project active rules"); - activeRulesLoader.load(profileKeys, projectKey); - profiler.stopInfo(); + Collection<String> keys = getKeys(qProfiles); + for (String k : keys) { + activeRulesLoader.load(k, null); + } - profiler.startInfo("Load server issues"); - UserLoginAccumulator consumer = new UserLoginAccumulator(); - issuesLoader.load(projectKey, consumer); - profiler.stopInfo(); + if (projectRepo.lastAnalysisDate() != null) { + profiler.startInfo("Load server issues"); + UserLoginAccumulator consumer = new UserLoginAccumulator(); + issuesLoader.load(projectKey, consumer); + profiler.stopInfo(); - profiler.startInfo("Load user information (" + consumer.loginSet.size() + " users)"); - for (String login : consumer.loginSet) { - userRepository.load(login, null); + profiler.startInfo("Load user information (" + consumer.loginSet.size() + " users)"); + for (String login : consumer.loginSet) { + userRepository.load(login, null); + } + profiler.stopInfo("Load user information"); } - profiler.stopInfo("Load user information"); } - private static Collection<String> getKeys(Collection<QProfile> qProfiles) { + private static Collection<String> getKeys(Collection<QualityProfile> qProfiles) { List<String> list = new ArrayList<>(qProfiles.size()); - for (QProfile qp : qProfiles) { - list.add(qp.key()); + for (QualityProfile qp : qProfiles) { + list.add(qp.getKey()); } return list; diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java index 79be9383f10..2bfc9dd12fa 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/ProjectSyncContainer.java @@ -21,7 +21,6 @@ package org.sonar.batch.cache; import javax.annotation.Nullable; -import org.sonar.batch.repository.ProjectRepositoriesFactoryProvider; import org.sonar.batch.analysis.DefaultAnalysisMode; import org.sonar.api.CoreProperties; @@ -30,15 +29,13 @@ import java.util.Map; import org.sonar.batch.analysis.AnalysisProperties; import org.sonar.batch.bootstrap.GlobalProperties; -import org.sonar.batch.repository.ProjectSettingsLoader; -import org.sonar.batch.repository.DefaultProjectSettingsLoader; +import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; 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.repository.DefaultProjectRepositoriesLoader; import org.sonar.batch.repository.DefaultServerIssuesLoader; import org.sonar.batch.repository.ProjectRepositoriesLoader; import org.sonar.batch.repository.ServerIssuesLoader; @@ -84,7 +81,6 @@ public class ProjectSyncContainer extends ComponentContainer { new ProjectKeySupplier(projectKey), projectKey != null ? ProjectCacheSynchronizer.class : NonAssociatedCacheSynchronizer.class, UserRepositoryLoader.class, - new ProjectRepositoriesFactoryProvider(projectKey), new ProjectPersistentCacheProvider(), createIssuesAnalysisMode(projectKey)); @@ -93,6 +89,5 @@ public class ProjectSyncContainer extends ComponentContainer { addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class); addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class); addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class); - addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java b/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java index 96a83811d08..6535e2c6445 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java @@ -19,6 +19,8 @@ */ package org.sonar.batch.cache; +import org.sonar.api.utils.HttpDownloader.HttpException; + import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -27,7 +29,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.io.IOUtils; -import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.batch.bootstrap.ServerClient; @@ -52,9 +53,9 @@ public class WSLoader { } private final LoadStrategy defautLoadStrategy; - private ServerStatus serverStatus; private final ServerClient client; private final PersistentCache cache; + private ServerStatus serverStatus; public WSLoader(LoadStrategy strategy, PersistentCache cache, ServerClient client) { this.defautLoadStrategy = strategy; @@ -65,7 +66,7 @@ public class WSLoader { @Nonnull public WSLoaderResult<InputStream> loadStream(String id) { - return load(id, defautLoadStrategy, createStreamLoaderServer(), createStreamLoaderCache()); + return load(id, defautLoadStrategy, streamServerLoader, streamCacheLoader); } @Nonnull @@ -75,7 +76,7 @@ public class WSLoader { @Nonnull public WSLoaderResult<String> loadString(String id, WSLoader.LoadStrategy strategy) { - return load(id, strategy, createStringLoaderServer(), createStringLoaderCache()); + return load(id, strategy, stringServerLoader, stringCacheLoader); } @Nonnull @@ -149,7 +150,7 @@ public class WSLoader { @Nonnull private <T> WSLoaderResult<T> loadFromCache(String id, DataLoader<T> loader) throws NotAvailableException { T result = null; - + try { result = loader.load(id); } catch (IOException e) { @@ -172,7 +173,7 @@ public class WSLoader { switchToOnline(); return new WSLoaderResult<T>(t, false); } catch (IllegalStateException e) { - if (e.getCause() instanceof HttpDownloader.HttpException) { + if (e.getCause() instanceof HttpException) { // fail fast if it could connect but there was a application-level error throw e; } @@ -184,56 +185,48 @@ public class WSLoader { } } - private DataLoader<String> createStringLoaderServer() { - return new DataLoader<String>() { - @Override - public String load(String id) throws IOException { - InputStream is = client.load(id, REQUEST_METHOD, true, CONNECT_TIMEOUT, READ_TIMEOUT); - String str = IOUtils.toString(is, StandardCharsets.UTF_8); - try { - cache.put(id, str.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new IllegalStateException("Error saving to WS cache", e); - } - return str; + private DataLoader<String> stringServerLoader = new DataLoader<String>() { + @Override + public String load(String id) throws IOException { + InputStream is = client.load(id, REQUEST_METHOD, true, CONNECT_TIMEOUT, READ_TIMEOUT); + String str = IOUtils.toString(is, StandardCharsets.UTF_8); + try { + cache.put(id, str.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new IllegalStateException("Error saving to WS cache", e); } - }; - } + return str; + } + }; - private DataLoader<String> createStringLoaderCache() { - return new DataLoader<String>() { - @Override - public String load(String id) throws IOException { - return cache.getString(id); + private DataLoader<String> stringCacheLoader = new DataLoader<String>() { + @Override + public String load(String id) throws IOException { + return cache.getString(id); + } + }; + + private DataLoader<InputStream> streamServerLoader = new DataLoader<InputStream>() { + @Override + public InputStream load(String id) throws IOException { + InputStream is = client.load(id, REQUEST_METHOD, true, CONNECT_TIMEOUT, READ_TIMEOUT); + try { + cache.put(id, is); + } catch (IOException e) { + throw new IllegalStateException("Error saving to WS cache", e); } - }; - } + is.close(); + return cache.getStream(id); + } + }; - private DataLoader<InputStream> createStreamLoaderServer() { - return new DataLoader<InputStream>() { - @Override - public InputStream load(String id) throws IOException { - InputStream is = client.load(id, REQUEST_METHOD, true, CONNECT_TIMEOUT, READ_TIMEOUT); - try { - cache.put(id, is); - } catch (IOException e) { - throw new IllegalStateException("Error saving to WS cache", e); - } - is.close(); - return cache.getStream(id); - } - }; - } + private DataLoader<InputStream> streamCacheLoader = new DataLoader<InputStream>() { + @Override + public InputStream load(String id) throws IOException { + return cache.getStream(id); + } + }; - private DataLoader<InputStream> createStreamLoaderCache() { - return new DataLoader<InputStream>() { - @Override - public InputStream load(String id) throws IOException { - return cache.getStream(id); - } - }; - } - private class NotAvailableException extends Exception { private static final long serialVersionUID = 1L; diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java index 0acf38329c5..19cdeb7f1b5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java @@ -19,7 +19,7 @@ */ package org.sonar.batch.issue.tracking; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.ProjectRepositories; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; @@ -64,7 +64,7 @@ public class LocalIssueTracking { private boolean hasServerAnalysis; public LocalIssueTracking(BatchComponentCache resourceCache, IssueTracking tracking, ServerLineHashesLoader lastLineHashes, IssueUpdater updater, - ActiveRules activeRules, ServerIssueRepository serverIssueRepository, ProjectSettingsRepo projectRepositories, ReportPublisher reportPublisher) { + ActiveRules activeRules, ServerIssueRepository serverIssueRepository, ProjectRepositories projectRepositories, ReportPublisher reportPublisher) { this.tracking = tracking; this.lastLineHashes = lastLineHashes; this.updater = updater; diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalRepositoriesLoader.java index 0575d6a2c72..51e7aaa4635 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalRepositoriesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalRepositoriesLoader.java @@ -30,7 +30,7 @@ import org.sonar.batch.protocol.input.GlobalRepositories; public class DefaultGlobalRepositoriesLoader implements GlobalRepositoriesLoader { - private static final String BATCH_GLOBAL_URL = "/scanner/global"; + private static final String BATCH_GLOBAL_URL = "/batch/global"; private final WSLoader wsLoader; diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesFactory.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesFactory.java deleted file mode 100644 index 3861684da2e..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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.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.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 DefaultProjectRepositoriesFactory implements ProjectRepositoriesFactory { - private static final String LOG_MSG = "Load project repositories"; - 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 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(getProjectKey(), getSonarProfile(), fromCache); - profiler.stopInfo(fromCache.booleanValue()); - - if (analysisMode.isIssues() && projectReferentials.lastAnalysisDate() == null) { - LOG.warn("No analysis has been found on the server for this project. All issues will be marked as 'new'."); - } - } - 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; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java index ab0f960c6a1..990a6c903f0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java @@ -19,48 +19,88 @@ */ 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.batch.analysis.DefaultAnalysisMode; -import org.sonar.batch.cache.WSLoader; -import org.sonar.batch.cache.WSLoaderResult; -import org.sonar.batch.protocol.input.ProjectRepositories; -import org.sonar.batch.rule.ModuleQProfiles; +import org.apache.commons.io.IOUtils; + import org.sonar.batch.util.BatchUtils; +import org.sonarqube.ws.WsScanner.WsProjectResponse.FileDataByPath; +import org.sonarqube.ws.WsScanner.WsProjectResponse.Settings; +import org.sonarqube.ws.WsScanner.WsProjectResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.common.collect.Table; +import com.google.common.collect.HashBasedTable; +import org.sonar.batch.cache.WSLoaderResult; +import org.sonar.batch.cache.WSLoader; +import org.apache.commons.lang.mutable.MutableBoolean; -public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoader { +import javax.annotation.Nullable; - private static final Logger LOG = Loggers.get(DefaultProjectRepositoriesLoader.class); - private static final String BATCH_PROJECT_URL = "/scanner/project"; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; +import java.util.Map; - private final WSLoader wsLoader; - private final DefaultAnalysisMode analysisMode; +public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoader { + private static final Logger LOG = LoggerFactory.getLogger(DefaultProjectRepositoriesLoader.class); + private static final String BATCH_PROJECT_URL = "/batch/project"; + private final WSLoader loader; - public DefaultProjectRepositoriesLoader(WSLoader wsLoader, DefaultAnalysisMode analysisMode) { - this.wsLoader = wsLoader; - this.analysisMode = analysisMode; + public DefaultProjectRepositoriesLoader(WSLoader loader) { + this.loader = loader; } @Override - 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(sonarProfile); + public ProjectRepositories load(String projectKey, boolean issuesMode, @Nullable MutableBoolean fromCache) { + try { + WSLoaderResult<InputStream> result = loader.loadStream(getUrl(projectKey, issuesMode)); + if (fromCache != null) { + fromCache.setValue(result.isFromCache()); + } + return processStream(result.get(), projectKey); + } catch (IllegalStateException e) { + LOG.debug("Couldn't get project repositories - continuing without it", e); + return new ProjectRepositories(); } - url += "&preview=" + analysisMode.isIssues(); + } - return load(url, fromCache); + private static String getUrl(String projectKey, boolean issuesMode) { + StringBuilder builder = new StringBuilder(); + + builder.append(BATCH_PROJECT_URL) + .append("?key=").append(BatchUtils.encodeForUrl(projectKey)); + if (issuesMode) { + builder.append("&issues=true"); + } + return builder.toString(); } - private ProjectRepositories load(String resource, @Nullable MutableBoolean fromCache) { - WSLoaderResult<String> result = wsLoader.loadString(resource); - if (fromCache != null) { - fromCache.setValue(result.isFromCache()); + private static ProjectRepositories processStream(InputStream is, String projectKey) { + try { + WsProjectResponse response = WsProjectResponse.parseFrom(is); + + Table<String, String, FileData> fileDataTable = HashBasedTable.create(); + Table<String, String, String> settings = HashBasedTable.create(); + + Map<String, Settings> settingsByModule = response.getSettingsByModule(); + for (Map.Entry<String, Settings> e1 : settingsByModule.entrySet()) { + for (Map.Entry<String, String> e2 : e1.getValue().getSettings().entrySet()) { + settings.put(e1.getKey(), e2.getKey(), e2.getValue()); + } + } + + Map<String, FileDataByPath> fileDataByModuleAndPath = response.getFileDataByModuleAndPath(); + for (Map.Entry<String, FileDataByPath> e1 : fileDataByModuleAndPath.entrySet()) { + for (Map.Entry<String, org.sonarqube.ws.WsScanner.WsProjectResponse.FileData> e2 : e1.getValue().getFileDataByPath().entrySet()) { + FileData fd = new FileData(e2.getValue().getHash(), e2.getValue().getRevision()); + fileDataTable.put(e1.getKey(), e2.getKey(), fd); + } + } + + return new ProjectRepositories(settings, fileDataTable, new Date(response.getLastAnalysisDate())); + } catch (IOException e) { + throw new IllegalStateException("Couldn't load project settings for " + projectKey, e); + } finally { + IOUtils.closeQuietly(is); } - return ProjectRepositories.fromJson(result.get()); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectSettingsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectSettingsLoader.java deleted file mode 100644 index acb23823686..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectSettingsLoader.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultQualityProfileLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultQualityProfileLoader.java index ab86309f3d5..9e041e1e46e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultQualityProfileLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultQualityProfileLoader.java @@ -19,32 +19,71 @@ */ package org.sonar.batch.repository; -import javax.annotation.Nullable; +import org.sonarqube.ws.QualityProfiles.WsSearchResponse; + +import org.sonar.batch.util.BatchUtils; +import org.apache.commons.io.IOUtils; +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; +import org.apache.commons.lang.mutable.MutableBoolean; +import org.sonar.batch.cache.WSLoaderResult; +import org.sonar.batch.cache.WSLoader; -import org.sonar.batch.protocol.input.ProjectRepositories; -import org.sonar.batch.protocol.input.QProfile; +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; import java.util.Collection; +import java.util.List; public class DefaultQualityProfileLoader implements QualityProfileLoader { + private static final String WS_URL = "/qualityprofiles/search"; - private ProjectRepositoriesFactory projectRepositoriesFactory; + private WSLoader wsLoader; - public DefaultQualityProfileLoader(ProjectRepositoriesFactory projectRepositoriesFactory) { - this.projectRepositoriesFactory = projectRepositoriesFactory; + public DefaultQualityProfileLoader(WSLoader wsLoader) { + this.wsLoader = wsLoader; } @Override - public Collection<QProfile> load(@Nullable String projectKey, @Nullable String sonarProfile) { - ProjectRepositories pr = projectRepositoriesFactory.create(); - validate(pr.qProfiles()); - return pr.qProfiles(); + public List<QualityProfile> loadDefault(@Nullable MutableBoolean fromCache) { + String url = WS_URL + "?defaults=true"; + return loadResource(url, fromCache); + } + + @Override + public List<QualityProfile> load(String projectKey, @Nullable String profileName, @Nullable MutableBoolean fromCache) { + String url = WS_URL + "?projectKey=" + BatchUtils.encodeForUrl(projectKey); + if (profileName != null) { + url += "&profileName=" + BatchUtils.encodeForUrl(profileName); + } + return loadResource(url, fromCache); } - private static void validate(Collection<QProfile> profiles) { + private static void validate(Collection<QualityProfile> 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."); } } + private List<QualityProfile> loadResource(String url, @Nullable MutableBoolean fromCache) { + WSLoaderResult<InputStream> result = wsLoader.loadStream(url); + if (fromCache != null) { + fromCache.setValue(result.isFromCache()); + } + InputStream is = result.get(); + WsSearchResponse profiles = null; + + try { + profiles = WsSearchResponse.parseFrom(is); + } catch (IOException e) { + throw new IllegalStateException("Failed to load quality profiles", e); + } finally { + IOUtils.closeQuietly(is); + } + + List<QualityProfile> profilesList = profiles.getProfilesList(); + validate(profilesList); + return profilesList; + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultServerIssuesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultServerIssuesLoader.java index 0989cd5e616..bf238c03aed 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultServerIssuesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultServerIssuesLoader.java @@ -20,7 +20,6 @@ package org.sonar.batch.repository; import com.google.common.base.Function; -import com.google.common.io.ByteSource; import java.io.IOException; import java.io.InputStream; import org.apache.commons.io.IOUtils; @@ -39,7 +38,7 @@ public class DefaultServerIssuesLoader implements ServerIssuesLoader { @Override public boolean load(String componentKey, Function<ServerIssue, Void> consumer) { - WSLoaderResult<ByteSource> result = wsLoader.loadSource("/scanner/issues?key=" + BatchUtils.encodeForUrl(componentKey)); + WSLoaderResult<InputStream> result = wsLoader.loadStream("/batch/issues?key=" + BatchUtils.encodeForUrl(componentKey)); parseIssues(result.get(), consumer); return result.isFromCache(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesFactory.java b/sonar-batch/src/main/java/org/sonar/batch/repository/FileData.java index 13ce299d8f9..0c1572c2f80 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/FileData.java @@ -19,10 +19,23 @@ */ package org.sonar.batch.repository; -import org.sonar.batch.protocol.input.ProjectRepositories; +import javax.annotation.concurrent.Immutable; -public interface ProjectRepositoriesFactory { +@Immutable +public class FileData { + private final String hash; + private final String revision; - ProjectRepositories create(); + public FileData(String hash, String revision) { + this.hash = hash; + this.revision = revision; + } + public String hash() { + return hash; + } + + public String revision() { + return revision; + } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsRepo.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositories.java index 1e53de437bc..4c12eb40886 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsRepo.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositories.java @@ -19,27 +19,38 @@ */ package org.sonar.batch.repository; +import com.google.common.collect.HashBasedTable; 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 class ProjectRepositories { + private final Table<String, String, String> settingsByModule; + private final Table<String, String, FileData> fileDataByModuleAndPath; + private final Date lastAnalysisDate; + private final boolean exists; + + public ProjectRepositories() { + this.exists = false; + this.settingsByModule = HashBasedTable.create(); + this.fileDataByModuleAndPath = HashBasedTable.create(); + this.lastAnalysisDate = null; + } - public ProjectSettingsRepo(Table<String, String, String> settingsByModule, Table<String, String, FileData> fileDataByModuleAndPath, + public ProjectRepositories(Table<String, String, String> settingsByModule, Table<String, String, FileData> fileDataByModuleAndPath, @Nullable Date lastAnalysisDate) { - super(); this.settingsByModule = settingsByModule; this.fileDataByModuleAndPath = fileDataByModuleAndPath; this.lastAnalysisDate = lastAnalysisDate; + this.exists = true; + } + + public boolean exists() { + return exists; } public Map<String, FileData> fileDataByPath(String moduleKey) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesFactoryProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesFactoryProvider.java deleted file mode 100644 index 609d7a73f5d..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesFactoryProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java index d066b488940..acf32cdda32 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesLoader.java @@ -19,14 +19,10 @@ */ package org.sonar.batch.repository; - import javax.annotation.Nullable; import org.apache.commons.lang.mutable.MutableBoolean; -import org.sonar.batch.protocol.input.ProjectRepositories; public interface ProjectRepositoriesLoader { - - ProjectRepositories load(String projectKeyWithBranch, @Nullable String sonarProfile, @Nullable MutableBoolean fromCache); - + ProjectRepositories load(String projectKeyWithBranch, boolean issuesMode, @Nullable MutableBoolean fromCache); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/SyncProjectRepositoriesFactory.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java index f01cce9102b..2006167509e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/SyncProjectRepositoriesFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java @@ -19,56 +19,52 @@ */ package org.sonar.batch.repository; -import javax.annotation.Nullable; +import org.sonar.api.utils.log.Profiler; -import org.apache.commons.lang.mutable.MutableBoolean; +import org.sonar.api.batch.bootstrap.ProjectKey; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.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"; +import javax.annotation.Nullable; - private final ProjectRepositoriesLoader loader; - private final String projectKey; +import org.sonar.batch.analysis.DefaultAnalysisMode; +import org.apache.commons.lang.mutable.MutableBoolean; +import org.picocontainer.injectors.ProviderAdapter; - private ProjectRepositories projectRepositories; +public class ProjectRepositoriesProvider extends ProviderAdapter { + private static final Logger LOG = Loggers.get(ProjectRepositoriesProvider.class); + private static final String LOG_MSG = "Load project repositories"; + private ProjectRepositories project = null; - public SyncProjectRepositoriesFactory(@Nullable String projectKey, ProjectRepositoriesLoader loader) { - this.projectKey = projectKey; - this.loader = loader; - } + public ProjectRepositories provide(@Nullable ProjectRepositoriesLoader loader, ProjectKey projectKey, DefaultAnalysisMode mode) { + if (project == null) { + MutableBoolean fromCache = new MutableBoolean(false); + Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); + if (mode.isNotAssociated()) { + project = createNonAssociatedProjectRepositories(); + profiler.stopInfo(); + } else { + project = loader.load(projectKey.get(), mode.isIssues(), fromCache); + checkProject(mode); + profiler.stopInfo(fromCache.booleanValue()); + } - @Override - public ProjectRepositories create() { - if (projectRepositories == null) { - projectRepositories = newInstance(); } - return projectRepositories; + return project; } - 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) { + private void checkProject(DefaultAnalysisMode mode) { + if (mode.isIssues()) { + if (!project.exists()) { + LOG.warn("Project doesn't exist on the server. All issues will be marked as 'new'."); + } else if (project.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; + private static ProjectRepositories createNonAssociatedProjectRepositories() { + return new ProjectRepositories(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsLoader.java deleted file mode 100644 index dc0efbcc4e4..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsLoader.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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); -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsProvider.java deleted file mode 100644 index 5fa0db433b5..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectSettingsProvider.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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); - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileLoader.java index 1d41398bff4..1ab61a9e438 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileLoader.java @@ -19,12 +19,15 @@ */ package org.sonar.batch.repository; -import javax.annotation.Nullable; +import org.apache.commons.lang.mutable.MutableBoolean; +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; -import org.sonar.batch.protocol.input.QProfile; +import javax.annotation.Nullable; -import java.util.Collection; +import java.util.List; public interface QualityProfileLoader { - Collection<QProfile> load(@Nullable String projectKey, @Nullable String sonarProfile); + List<QualityProfile> load(String projectKey, @Nullable String profileName, @Nullable MutableBoolean fromCache); + + List<QualityProfile> loadDefault(@Nullable MutableBoolean fromCache); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileProvider.java index 6f40ef0c7a8..d35ab28fb6b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/QualityProfileProvider.java @@ -19,30 +19,49 @@ */ package org.sonar.batch.repository; -import org.sonar.batch.protocol.input.QProfile; +import org.sonar.api.utils.log.Profiler; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.apache.commons.lang.mutable.MutableBoolean; +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; +import org.sonar.batch.analysis.DefaultAnalysisMode; +import org.sonar.api.batch.bootstrap.ProjectKey; -import java.util.Collection; +import java.util.List; -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 static final Logger LOG = Loggers.get(QualityProfileProvider.class); + private static final String LOG_MSG = "Load quality profiles"; private ModuleQProfiles profiles = null; - public ModuleQProfiles provide(ProjectReactor projectReactor, QualityProfileLoader loader, AnalysisProperties props, AnalysisMode mode) { + public ModuleQProfiles provide(ProjectKey projectKey, QualityProfileLoader loader, ProjectRepositories projectRepositories, AnalysisProperties props, DefaultAnalysisMode mode) { if (this.profiles == null) { - String profile = null; - if (!mode.isIssues()) { - profile = props.property(ModuleQProfiles.SONAR_PROFILE_PROP); + List<QualityProfile> profileList; + MutableBoolean fromCache = new MutableBoolean(); + + Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); + if (mode.isNotAssociated() || !projectRepositories.exists()) { + profileList = loader.loadDefault(fromCache); + } else { + profileList = loader.load(projectKey.get(), getSonarProfile(props, mode), fromCache); } - Collection<QProfile> qps = loader.load(projectReactor.getRoot().getKeyWithBranch(), profile); - profiles = new ModuleQProfiles(qps); + profiler.stopInfo(fromCache.booleanValue()); + profiles = new ModuleQProfiles(profileList); } return profiles; } + private static String getSonarProfile(AnalysisProperties props, DefaultAnalysisMode mode) { + String profile = null; + if (!mode.isIssues()) { + profile = props.property(ModuleQProfiles.SONAR_PROFILE_PROP); + } + return profile; + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java index a7b9dc71d4a..cb973bba454 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/user/UserRepositoryLoader.java @@ -73,7 +73,7 @@ public class UserRepositoryLoader { } private InputStream loadQuery(String loginsQuery, @Nullable MutableBoolean fromCache) { - WSLoaderResult<InputStream> result = wsLoader.loadStream("/scanner/users?logins=" + loginsQuery); + WSLoaderResult<InputStream> result = wsLoader.loadStream("/batch/users?logins=" + loginsQuery); if (fromCache != null) { fromCache.setValue(result.isFromCache()); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesLoader.java index bf2ff6d406a..72f33bdb43c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesLoader.java @@ -19,10 +19,13 @@ */ package org.sonar.batch.rule; -import org.sonar.batch.protocol.input.ActiveRule; +import org.sonarqube.ws.Rules.Rule; +import org.apache.commons.lang.mutable.MutableBoolean; -import java.util.Collection; +import javax.annotation.Nullable; + +import java.util.List; public interface ActiveRulesLoader { - Collection<ActiveRule> load(Collection<String> qualityProfileKeys, String projectKey); + List<Rule> load(String qualityProfileKey, @Nullable MutableBoolean fromCache); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java index ee2529cadff..5373c36f945 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java @@ -19,47 +19,80 @@ */ package org.sonar.batch.rule; -import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.utils.log.Profiler; + +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonarqube.ws.Rules.Rule.Param; +import org.sonarqube.ws.Rules.Rule; 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 java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; -import java.util.Map.Entry; +import java.util.Map; /** * Loads the rules that are activated on the Quality profiles - * used by the current project and build {@link org.sonar.api.batch.rule.ActiveRules}. + * used by the current project and builds {@link org.sonar.api.batch.rule.ActiveRules}. */ public class ActiveRulesProvider extends ProviderAdapter { - + private static final Logger LOG = Loggers.get(ActiveRulesProvider.class); + private static final String LOG_MSG = "Load active rules"; private ActiveRules singleton = null; - public ActiveRules provide(ActiveRulesLoader ref, ModuleQProfiles qProfiles, ProjectReactor projectReactor) { + public ActiveRules provide(ActiveRulesLoader loader, ModuleQProfiles qProfiles) { if (singleton == null) { - singleton = load(ref, qProfiles, projectReactor); + Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); + singleton = load(loader, qProfiles); + profiler.stopInfo(); } return singleton; } - private static ActiveRules load(ActiveRulesLoader loader, ModuleQProfiles qProfiles, ProjectReactor projectReactor) { + private static ActiveRules load(ActiveRulesLoader loader, ModuleQProfiles qProfiles) { + + Collection<String> qProfileKeys = getKeys(qProfiles); + Map<String, Rule> loadedRulesByKey = new HashMap<>(); + + try { + for (String qProfileKey : qProfileKeys) { + Collection<Rule> qProfileRules; + qProfileRules = load(loader, qProfileKey); + + for (Rule r : qProfileRules) { + if (!loadedRulesByKey.containsKey(r.getKey())) { + loadedRulesByKey.put(r.getKey(), r); + } + } + } + } catch (IOException e) { + throw new IllegalStateException("Error loading active rules", e); + } + + return transform(loadedRulesByKey.values()); + } + + private static ActiveRules transform(Collection<Rule> loadedRules) { ActiveRulesBuilder builder = new ActiveRulesBuilder(); - 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()); - newActiveRule.setLanguage(activeRule.language()); - newActiveRule.setInternalKey(activeRule.internalKey()); - newActiveRule.setTemplateRuleKey(activeRule.templateRuleKey()); + + for (Rule activeRule : loadedRules) { + NewActiveRule newActiveRule = builder.create(RuleKey.of(activeRule.getRepo(), activeRule.getKey())); + newActiveRule.setName(activeRule.getName()); + newActiveRule.setSeverity(activeRule.getSeverity()); + newActiveRule.setLanguage(activeRule.getLang()); + newActiveRule.setInternalKey(activeRule.getInternalKey()); + newActiveRule.setTemplateRuleKey(activeRule.getTemplateKey()); // load parameters - for (Entry<String, String> param : activeRule.params().entrySet()) { - newActiveRule.setParam(param.getKey(), param.getValue()); + for (Param param : activeRule.getParams().getParamsList()) { + newActiveRule.setParam(param.getKey(), param.getDefaultValue()); } newActiveRule.activate(); @@ -67,6 +100,10 @@ public class ActiveRulesProvider extends ProviderAdapter { return builder.build(); } + private static List<Rule> load(ActiveRulesLoader loader, String qProfileKey) throws IOException { + return loader.load(qProfileKey, null); + } + private static Collection<String> getKeys(ModuleQProfiles qProfiles) { List<String> keys = new ArrayList<>(qProfiles.findAll().size()); diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/DefaultActiveRulesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/rule/DefaultActiveRulesLoader.java index 05e58846648..112efd60995 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/rule/DefaultActiveRulesLoader.java +++ b/sonar-batch/src/main/java/org/sonar/batch/rule/DefaultActiveRulesLoader.java @@ -19,25 +19,53 @@ */ package org.sonar.batch.rule; -import org.sonar.batch.repository.ProjectRepositoriesFactory; +import org.sonarqube.ws.Rules.SearchResponse; -import org.sonar.batch.protocol.input.ActiveRule; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.mutable.MutableBoolean; +import org.sonar.batch.cache.WSLoader; +import org.sonar.batch.cache.WSLoaderResult; -import java.util.Collection; +import javax.annotation.Nullable; -import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonarqube.ws.Rules.Rule; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; public class DefaultActiveRulesLoader implements ActiveRulesLoader { - private final ProjectRepositoriesFactory projectRepositoriesFactory; + private static final String RULES_SEARCH_URL = "/api/rules/search?f=repo,name,severity,lang,internalKey,templateKey"; + + private final WSLoader wsLoader; - public DefaultActiveRulesLoader(ProjectRepositoriesFactory projectRepositoriesFactory) { - this.projectRepositoriesFactory = projectRepositoriesFactory; + public DefaultActiveRulesLoader(WSLoader wsLoader) { + this.wsLoader = wsLoader; } @Override - public Collection<ActiveRule> load(Collection<String> qualityProfileKeys, String projectKey) { - ProjectRepositories pr = projectRepositoriesFactory.create(); - return pr.activeRules(); + public List<Rule> load(String qualityProfileKey, @Nullable MutableBoolean fromCache) { + WSLoaderResult<InputStream> result = wsLoader.loadStream(getUrl(qualityProfileKey)); + List<Rule> ruleList = loadFromStream(result.get()); + if (fromCache != null) { + fromCache.setValue(result.isFromCache()); + } + return ruleList; + } + + private static String getUrl(String qualityProfileKey) { + return RULES_SEARCH_URL + "&qprofile=" + qualityProfileKey; + } + + private static List<Rule> loadFromStream(InputStream is) { + try { + SearchResponse response = SearchResponse.parseFrom(is); + return response.getRulesList(); + } catch (IOException e) { + throw new IllegalStateException("Failed to load quality profiles", e); + } finally { + IOUtils.closeQuietly(is); + } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java index 3ac70d83150..3f8d5cdd8ae 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java +++ b/sonar-batch/src/main/java/org/sonar/batch/rule/ModuleQProfiles.java @@ -19,6 +19,9 @@ */ package org.sonar.batch.rule; +import org.sonar.api.utils.DateUtils; + +import org.sonarqube.ws.QualityProfiles.WsSearchResponse.QualityProfile; import com.google.common.collect.ImmutableMap; import org.sonar.api.batch.BatchSide; @@ -36,12 +39,16 @@ public class ModuleQProfiles { public static final String SONAR_PROFILE_PROP = "sonar.profile"; private final Map<String, QProfile> byLanguage; - public ModuleQProfiles(Collection<org.sonar.batch.protocol.input.QProfile> profiles) { + public ModuleQProfiles(Collection<QualityProfile> profiles) { ImmutableMap.Builder<String, QProfile> builder = ImmutableMap.builder(); - 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())); + for (QualityProfile qProfile : profiles) { + builder.put(qProfile.getLanguage(), + new QProfile() + .setKey(qProfile.getKey()) + .setName(qProfile.getName()) + .setLanguage(qProfile.getLanguage()) + .setRulesUpdatedAt(DateUtils.parseDateTime(qProfile.getRulesUpdatedAt()))); } byLanguage = builder.build(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java index 43ca0dd6ac1..96f085d76b2 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleSettings.java @@ -28,17 +28,17 @@ import org.sonar.api.utils.MessageException; import org.sonar.batch.analysis.DefaultAnalysisMode; import org.sonar.batch.bootstrap.GlobalSettings; import org.sonar.batch.report.AnalysisContextReportPublisher; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.ProjectRepositories; /** * @since 2.12 */ public class ModuleSettings extends Settings { - private final ProjectSettingsRepo projectSettingsRepo; + private final ProjectRepositories projectSettingsRepo; private final DefaultAnalysisMode analysisMode; - public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectSettingsRepo projectSettingsRepo, + public ModuleSettings(GlobalSettings batchSettings, ProjectDefinition moduleDefinition, ProjectRepositories projectSettingsRepo, DefaultAnalysisMode analysisMode, AnalysisContextReportPublisher contextReportPublisher) { super(batchSettings.getDefinitions()); this.projectSettingsRepo = projectSettingsRepo; diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java index 5c7bbb9e026..b882d231243 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java @@ -19,17 +19,15 @@ */ package org.sonar.batch.scan; -import org.sonar.batch.cache.ProjectPersistentCacheProvider; +import org.sonar.batch.repository.ProjectRepositoriesProvider; +import org.sonar.batch.repository.ProjectRepositories; +import org.sonar.batch.cache.ProjectPersistentCacheProvider; import org.sonar.batch.issue.tracking.LocalIssueTracking; import org.sonar.batch.issue.tracking.IssueTransition; -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; @@ -131,7 +129,6 @@ public class ProjectScanContainer extends ComponentContainer { props, DefaultAnalysisMode.class, ProjectReactorBuilder.class, - DefaultProjectRepositoriesFactory.class, new MutableProjectReactorProvider(), new ImmutableProjectReactorProvider(), ProjectBuildersExecutor.class, @@ -151,7 +148,7 @@ public class ProjectScanContainer extends ComponentContainer { Caches.class, BatchComponentCache.class, DefaultIssueCallback.class, - new ProjectSettingsProvider(), + new ProjectRepositoriesProvider(), new ProjectPersistentCacheProvider(), // temp @@ -211,7 +208,6 @@ public class ProjectScanContainer extends ComponentContainer { addIfMissing(DefaultActiveRulesLoader.class, ActiveRulesLoader.class); addIfMissing(DefaultQualityProfileLoader.class, QualityProfileLoader.class); addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class); - addIfMissing(DefaultProjectSettingsLoader.class, ProjectSettingsLoader.class); } private void addIssueTrackingComponents() { @@ -227,7 +223,7 @@ public class ProjectScanContainer extends ComponentContainer { return false; } - return getComponentByType(DefaultProjectRepositoriesFactory.class).create().lastAnalysisDate() != null; + return getComponentByType(ProjectRepositories.class).lastAnalysisDate() != null; } private void addBatchExtensions() { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectSettings.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectSettings.java index df9b5135100..c022541bd96 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectSettings.java @@ -19,7 +19,7 @@ */ package org.sonar.batch.scan; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.ProjectRepositories; import org.sonar.batch.analysis.DefaultAnalysisMode; import com.google.common.collect.ImmutableMap; @@ -45,11 +45,11 @@ public class ProjectSettings extends Settings { ); private final GlobalSettings globalSettings; - private final ProjectSettingsRepo projectRepositories; + private final ProjectRepositories projectRepositories; private final DefaultAnalysisMode mode; public ProjectSettings(ProjectReactor reactor, GlobalSettings globalSettings, PropertyDefinitions propertyDefinitions, - ProjectSettingsRepo projectRepositories, DefaultAnalysisMode mode) { + ProjectRepositories projectRepositories, DefaultAnalysisMode mode) { super(propertyDefinitions); this.mode = mode; getEncryption().setPathToSecretKey(globalSettings.getString(CoreProperties.ENCRYPTION_SECRET_KEY_PATH)); diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetection.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetection.java index 51232ec5701..54270befcca 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetection.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetection.java @@ -19,17 +19,17 @@ */ package org.sonar.batch.scan.filesystem; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.FileData; +import org.sonar.batch.repository.ProjectRepositories; import org.apache.commons.lang.StringUtils; import org.sonar.api.batch.fs.InputFile; -import org.sonar.batch.protocol.input.FileData; class StatusDetection { - private final ProjectSettingsRepo projectSettings; + private final ProjectRepositories projectSettings; - StatusDetection(ProjectSettingsRepo projectSettings) { + StatusDetection(ProjectRepositories projectSettings) { this.projectSettings = projectSettings; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetectionFactory.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetectionFactory.java index f372b171df2..4ee5057c9ff 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetectionFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/StatusDetectionFactory.java @@ -19,16 +19,16 @@ */ package org.sonar.batch.scan.filesystem; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.ProjectRepositories; import org.sonar.api.batch.BatchSide; @BatchSide public class StatusDetectionFactory { - private final ProjectSettingsRepo projectReferentials; + private final ProjectRepositories projectReferentials; - public StatusDetectionFactory(ProjectSettingsRepo projectReferentials) { + public StatusDetectionFactory(ProjectRepositories projectReferentials) { this.projectReferentials = projectReferentials; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java index 7d24836072d..8ff079170e8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java @@ -19,7 +19,9 @@ */ package org.sonar.batch.scm; -import org.sonar.batch.repository.ProjectSettingsRepo; +import org.sonar.batch.repository.FileData; + +import org.sonar.batch.repository.ProjectRepositories; import java.util.LinkedList; import java.util.List; @@ -35,7 +37,6 @@ import org.sonar.api.batch.sensor.Sensor; 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.report.ReportPublisher; import org.sonar.batch.scan.filesystem.InputPathCache; @@ -46,12 +47,12 @@ public final class ScmSensor implements Sensor { private final ProjectDefinition projectDefinition; private final ScmConfiguration configuration; private final FileSystem fs; - private final ProjectSettingsRepo projectSettings; + private final ProjectRepositories projectSettings; private final BatchComponentCache resourceCache; private final ReportPublisher publishReportJob; public ScmSensor(ProjectDefinition projectDefinition, ScmConfiguration configuration, - ProjectSettingsRepo projectSettings, FileSystem fs, InputPathCache inputPathCache, BatchComponentCache resourceCache, + ProjectRepositories projectSettings, FileSystem fs, InputPathCache inputPathCache, BatchComponentCache resourceCache, ReportPublisher publishReportJob) { this.projectDefinition = projectDefinition; this.configuration = configuration; @@ -98,7 +99,7 @@ public final class ScmSensor implements Sensor { addIfNotEmpty(filesToBlame, f); } else { FileData fileData = projectSettings.fileData(projectDefinition.getKeyWithBranch(), f.relativePath()); - if (f.status() != Status.SAME || fileData == null || fileData.needBlame()) { + if (f.status() != Status.SAME || fileData == null || fileData.revision() != null) { addIfNotEmpty(filesToBlame, f); } } |