From: Julien HENRY Date: Mon, 26 Jan 2015 10:21:26 +0000 (+0100) Subject: Fix some quality flaws X-Git-Tag: latest-silver-master-#65~84 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1a2f1cf907543e7a3612bb822121ed844c9f156a;p=sonarqube.git Fix some quality flaws --- diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/issues/PreviousIssue.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/issues/PreviousIssue.java index f519286ff4a..d4d8a5ca7c9 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/issues/PreviousIssue.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/input/issues/PreviousIssue.java @@ -24,6 +24,9 @@ import javax.annotation.Nullable; import java.io.Serializable; import java.util.Date; +/** + * Issues from previous analysis. USed by local issue tracking. + */ public class PreviousIssue implements Serializable { private String key; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java index d3749c4cf7f..c49e4c1fef1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java @@ -35,11 +35,11 @@ import org.sonar.batch.components.PastSnapshotFinderByDays; import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis; import org.sonar.batch.components.PastSnapshotFinderByPreviousVersion; import org.sonar.batch.components.PastSnapshotFinderByVersion; -import org.sonar.batch.repository.DefaultGlobalReferentialsLoader; +import org.sonar.batch.repository.DefaultGlobalRepositoriesLoader; import org.sonar.batch.repository.DefaultPreviousIssuesLoader; -import org.sonar.batch.repository.DefaultProjectReferentialsLoader; -import org.sonar.batch.repository.GlobalReferentialsLoader; -import org.sonar.batch.repository.GlobalReferentialsProvider; +import org.sonar.batch.repository.DefaultProjectRepositoriesLoader; +import org.sonar.batch.repository.GlobalRepositoriesLoader; +import org.sonar.batch.repository.GlobalRepositoriesProvider; import org.sonar.batch.repository.PreviousIssuesLoader; import org.sonar.batch.repository.ProjectRepositoriesLoader; import org.sonar.batch.user.UserRepository; @@ -107,16 +107,16 @@ public class BootstrapContainer extends ComponentContainer { UriReader.class, new FileCacheProvider(), System2.INSTANCE, - new GlobalReferentialsProvider(), + new GlobalRepositoriesProvider(), UserRepository.class); if (getComponentByType(PluginsReferential.class) == null) { add(DefaultPluginsReferential.class); } - if (getComponentByType(GlobalReferentialsLoader.class) == null) { - add(DefaultGlobalReferentialsLoader.class); + if (getComponentByType(GlobalRepositoriesLoader.class) == null) { + add(DefaultGlobalRepositoriesLoader.class); } if (getComponentByType(ProjectRepositoriesLoader.class) == null) { - add(DefaultProjectReferentialsLoader.class); + add(DefaultProjectRepositoriesLoader.class); } if (getComponentByType(PreviousIssuesLoader.class) == null) { add(DefaultPreviousIssuesLoader.class); diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java index 455257aab8d..f6cc8e660a6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java +++ b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java @@ -25,6 +25,8 @@ import org.sonar.api.CoreProperties; import org.sonar.api.config.Settings; import org.sonar.api.measures.Metric; +import javax.annotation.Nullable; + public class SqaleRatingSettings implements BatchComponent { private final Settings settings; @@ -48,11 +50,13 @@ public class SqaleRatingSettings implements BatchComponent { } } - public long getDevCost(String languageKey) { + public long getDevCost(@Nullable String languageKey) { try { - LanguageSpecificConfiguration languageSpecificConfig = getSpecificParametersForLanguage(languageKey); - if (languageSpecificConfig != null && languageSpecificConfig.getManDays() != null) { - return Long.parseLong(languageSpecificConfig.getManDays()); + if (languageKey != null) { + LanguageSpecificConfiguration languageSpecificConfig = getSpecificParametersForLanguage(languageKey); + if (languageSpecificConfig != null && languageSpecificConfig.getManDays() != null) { + return Long.parseLong(languageSpecificConfig.getManDays()); + } } return Long.parseLong(settings.getString(CoreProperties.DEVELOPMENT_COST)); } catch (Exception e) { @@ -61,10 +65,12 @@ public class SqaleRatingSettings implements BatchComponent { } } - public Metric getSizeMetric(String languageKey, Metric[] metrics) { - LanguageSpecificConfiguration languageSpecificConfig = getSpecificParametersForLanguage(languageKey); - if (languageSpecificConfig != null && languageSpecificConfig.getMetric() != null) { - return getMetricForKey(languageSpecificConfig.getMetric(), metrics); + public Metric getSizeMetric(@Nullable String languageKey, Metric[] metrics) { + if (languageKey != null) { + LanguageSpecificConfiguration languageSpecificConfig = getSpecificParametersForLanguage(languageKey); + if (languageSpecificConfig != null && languageSpecificConfig.getMetric() != null) { + return getMetricForKey(languageSpecificConfig.getMetric(), metrics); + } } return getMetricForKey(settings.getString(CoreProperties.SIZE_METRIC), metrics); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java index 36ac996ae58..b01efa10063 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java @@ -45,6 +45,9 @@ public class EventPersister { public void saveEvent(Resource resource, Event event) { BatchResource batchResource = resourceCache.get(resource.getEffectiveKey()); + if (batchResource == null) { + throw new IllegalStateException("Unknow component: " + resource); + } if (event.getDate() == null) { event.setSnapshot(batchResource.snapshot()); } else { diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java index 88f6ac854c4..512e13be07e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/SourcePersister.java @@ -294,8 +294,9 @@ public class SourcePersister implements ScanPersister { @CheckForNull private SyntaxHighlightingData loadHighlighting(DefaultInputFile file) { SyntaxHighlightingData highlighting = componentDataCache.getData(file.key(), SnapshotDataTypes.SYNTAX_HIGHLIGHTING); - if (highlighting == null) { - highlighting = codeColorizers.toSyntaxHighlighting(file.file(), file.encoding(), file.language()); + String language = file.language(); + if (highlighting == null && language != null) { + highlighting = codeColorizers.toSyntaxHighlighting(file.file(), file.encoding(), language); } return highlighting; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/PreviousIssueRepository.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/PreviousIssueRepository.java index 6bad06cf818..d1142691ba3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/PreviousIssueRepository.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/PreviousIssueRepository.java @@ -33,6 +33,8 @@ import org.sonar.batch.index.ResourceCache; import org.sonar.batch.protocol.input.issues.PreviousIssue; import org.sonar.batch.repository.PreviousIssuesLoader; +import javax.annotation.Nullable; + @InstantiationStrategy(InstantiationStrategy.PER_BATCH) public class PreviousIssueRepository implements BatchComponent { @@ -58,7 +60,10 @@ public class PreviousIssueRepository implements BatchComponent { previousIssuesLoader.load(reactor, new Function() { @Override - public Void apply(PreviousIssue issue) { + public Void apply(@Nullable PreviousIssue issue) { + if (issue == null) { + return null; + } String componentKey = issue.componentKey(); BatchResource r = resourceCache.get(componentKey); if (r == null) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java index 80f52440152..e5ac2e3046f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -35,7 +35,7 @@ import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.batch.protocol.input.GlobalRepositories; import org.sonar.batch.protocol.input.ProjectRepositories; import org.sonar.batch.protocol.input.issues.PreviousIssue; -import org.sonar.batch.repository.GlobalReferentialsLoader; +import org.sonar.batch.repository.GlobalRepositoriesLoader; import org.sonar.batch.repository.PreviousIssuesLoader; import org.sonar.batch.repository.ProjectRepositoriesLoader; import org.sonar.core.plugins.DefaultPluginMetadata; @@ -194,7 +194,7 @@ public class BatchMediumTester { } } - private static class FakeGlobalReferentialsLoader implements GlobalReferentialsLoader { + private static class FakeGlobalReferentialsLoader implements GlobalRepositoriesLoader { private int metricId = 1; diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalReferentialsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalReferentialsLoader.java deleted file mode 100644 index 409e776ab31..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalReferentialsLoader.java +++ /dev/null @@ -1,40 +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.batch.bootstrap.ServerClient; -import org.sonar.batch.protocol.input.GlobalRepositories; - -public class DefaultGlobalReferentialsLoader implements GlobalReferentialsLoader { - - private static final String BATCH_GLOBAL_URL = "/batch/global"; - - private final ServerClient serverClient; - - public DefaultGlobalReferentialsLoader(ServerClient serverClient) { - this.serverClient = serverClient; - } - - @Override - public GlobalRepositories load() { - return GlobalRepositories.fromJson(serverClient.request(BATCH_GLOBAL_URL)); - } - -} 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 new file mode 100644 index 00000000000..428e9bccab5 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultGlobalRepositoriesLoader.java @@ -0,0 +1,40 @@ +/* + * 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.bootstrap.ServerClient; +import org.sonar.batch.protocol.input.GlobalRepositories; + +public class DefaultGlobalRepositoriesLoader implements GlobalRepositoriesLoader { + + private static final String BATCH_GLOBAL_URL = "/batch/global"; + + private final ServerClient serverClient; + + public DefaultGlobalRepositoriesLoader(ServerClient serverClient) { + this.serverClient = serverClient; + } + + @Override + public GlobalRepositories load() { + return GlobalRepositories.fromJson(serverClient.request(BATCH_GLOBAL_URL)); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectReferentialsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectReferentialsLoader.java deleted file mode 100644 index d653570d37a..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectReferentialsLoader.java +++ /dev/null @@ -1,177 +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 com.google.common.collect.Maps; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.database.model.MeasureModel; -import org.sonar.api.database.model.ResourceModel; -import org.sonar.api.database.model.Snapshot; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Qualifiers; -import org.sonar.batch.bootstrap.AnalysisMode; -import org.sonar.batch.bootstrap.ServerClient; -import org.sonar.batch.bootstrap.TaskProperties; -import org.sonar.batch.protocol.input.FileData; -import org.sonar.batch.protocol.input.ProjectRepositories; -import org.sonar.batch.rule.ModuleQProfiles; - -import javax.annotation.CheckForNull; -import javax.persistence.NoResultException; -import javax.persistence.Query; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -public class DefaultProjectReferentialsLoader implements ProjectRepositoriesLoader { - - private static final Logger LOG = LoggerFactory.getLogger(DefaultProjectReferentialsLoader.class); - - private static final String BATCH_PROJECT_URL = "/batch/project"; - - private final ServerClient serverClient; - private final AnalysisMode analysisMode; - private final DatabaseSession session; - - public DefaultProjectReferentialsLoader(DatabaseSession session, ServerClient serverClient, AnalysisMode analysisMode) { - this.session = session; - this.serverClient = serverClient; - this.analysisMode = analysisMode; - } - - public DefaultProjectReferentialsLoader(ServerClient serverClient, AnalysisMode analysisMode) { - this.session = null; - this.serverClient = serverClient; - this.analysisMode = analysisMode; - } - - @Override - public ProjectRepositories load(ProjectReactor reactor, TaskProperties taskProperties) { - String projectKey = reactor.getRoot().getKeyWithBranch(); - String url = BATCH_PROJECT_URL + "?key=" + ServerClient.encodeForUrl(projectKey); - if (taskProperties.properties().containsKey(ModuleQProfiles.SONAR_PROFILE_PROP)) { - 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=" + ServerClient.encodeForUrl(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP)); - } - url += "&preview=" + analysisMode.isPreview(); - ProjectRepositories ref = ProjectRepositories.fromJson(serverClient.request(url)); - - if (session != null) { - for (ProjectDefinition module : reactor.getProjects()) { - - for (Entry fileDataByPaths : ref.fileDataByPath(module.getKeyWithBranch()).entrySet()) { - String path = fileDataByPaths.getKey(); - FileData fileData = fileDataByPaths.getValue(); - String lastCommits = null; - String revisions = null; - String authors = null; - List measuresByKey = query(projectKey + ":" + path, CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, - CoreMetrics.SCM_AUTHORS_BY_LINE_KEY); - for (Object[] measureByKey : measuresByKey) { - if (measureByKey[0].equals(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY)) { - lastCommits = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); - } else if (measureByKey[0].equals(CoreMetrics.SCM_REVISIONS_BY_LINE_KEY)) { - revisions = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_REVISIONS_BY_LINE); - } else if (measureByKey[0].equals(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY)) { - authors = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_AUTHORS_BY_LINE); - } - } - ref.addFileData(module.getKeyWithBranch(), path, new FileData(fileData.hash(), authors == null, lastCommits, revisions, authors)); - } - } - ref.setLastAnalysisDate(lastSnapshotCreationDate(projectKey)); - } - return ref; - } - - public List query(String resourceKey, String... metricKeys) { - StringBuilder sb = new StringBuilder(); - Map params = Maps.newHashMap(); - - sb.append("SELECT met.key, m"); - sb.append(" FROM ") - .append(MeasureModel.class.getSimpleName()) - .append(" m, ") - .append(Metric.class.getSimpleName()) - .append(" met, ") - .append(ResourceModel.class.getSimpleName()) - .append(" r, ") - .append(Snapshot.class.getSimpleName()) - .append(" s WHERE met.id=m.metricId AND m.snapshotId=s.id AND s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); - params.put("kee", resourceKey); - params.put("status", Snapshot.STATUS_PROCESSED); - params.put("lib", Qualifiers.LIBRARY); - - sb.append(" AND m.characteristicId IS NULL"); - sb.append(" AND m.personId IS NULL"); - sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL"); - if (metricKeys.length > 0) { - sb.append(" AND met.key IN (:metricKeys) "); - params.put("metricKeys", Arrays.asList(metricKeys)); - } - sb.append(" AND s.last=true "); - sb.append(" ORDER BY s.createdAt "); - - Query jpaQuery = session.createQuery(sb.toString()); - - for (Map.Entry entry : params.entrySet()) { - jpaQuery.setParameter(entry.getKey(), entry.getValue()); - } - return jpaQuery.getResultList(); - } - - @CheckForNull - Date lastSnapshotCreationDate(String resourceKey) { - StringBuilder sb = new StringBuilder(); - Map params = Maps.newHashMap(); - - sb.append("SELECT s.buildDate"); - sb.append(" FROM ") - .append(ResourceModel.class.getSimpleName()) - .append(" r, ") - .append(Snapshot.class.getSimpleName()) - .append(" s WHERE s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); - params.put("kee", resourceKey); - params.put("status", Snapshot.STATUS_PROCESSED); - params.put("lib", Qualifiers.LIBRARY); - - sb.append(" AND s.last=true "); - - Query jpaQuery = session.createQuery(sb.toString()); - - for (Map.Entry entry : params.entrySet()) { - jpaQuery.setParameter(entry.getKey(), entry.getValue()); - } - try { - return (Date) jpaQuery.getSingleResult(); - } catch (NoResultException e) { - return null; - } - } -} 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 new file mode 100644 index 00000000000..922e9a82adf --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java @@ -0,0 +1,177 @@ +/* + * 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.Maps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.database.DatabaseSession; +import org.sonar.api.database.model.MeasureModel; +import org.sonar.api.database.model.ResourceModel; +import org.sonar.api.database.model.Snapshot; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.api.resources.Qualifiers; +import org.sonar.batch.bootstrap.AnalysisMode; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.batch.bootstrap.TaskProperties; +import org.sonar.batch.protocol.input.FileData; +import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonar.batch.rule.ModuleQProfiles; + +import javax.annotation.CheckForNull; +import javax.persistence.NoResultException; +import javax.persistence.Query; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +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 ServerClient serverClient; + private final AnalysisMode analysisMode; + private final DatabaseSession session; + + public DefaultProjectRepositoriesLoader(DatabaseSession session, ServerClient serverClient, AnalysisMode analysisMode) { + this.session = session; + this.serverClient = serverClient; + this.analysisMode = analysisMode; + } + + public DefaultProjectRepositoriesLoader(ServerClient serverClient, AnalysisMode analysisMode) { + this.session = null; + this.serverClient = serverClient; + this.analysisMode = analysisMode; + } + + @Override + public ProjectRepositories load(ProjectReactor reactor, TaskProperties taskProperties) { + String projectKey = reactor.getRoot().getKeyWithBranch(); + String url = BATCH_PROJECT_URL + "?key=" + ServerClient.encodeForUrl(projectKey); + if (taskProperties.properties().containsKey(ModuleQProfiles.SONAR_PROFILE_PROP)) { + 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=" + ServerClient.encodeForUrl(taskProperties.properties().get(ModuleQProfiles.SONAR_PROFILE_PROP)); + } + url += "&preview=" + analysisMode.isPreview(); + ProjectRepositories ref = ProjectRepositories.fromJson(serverClient.request(url)); + + if (session != null) { + for (ProjectDefinition module : reactor.getProjects()) { + + for (Entry fileDataByPaths : ref.fileDataByPath(module.getKeyWithBranch()).entrySet()) { + String path = fileDataByPaths.getKey(); + FileData fileData = fileDataByPaths.getValue(); + String lastCommits = null; + String revisions = null; + String authors = null; + List measuresByKey = query(projectKey + ":" + path, CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, + CoreMetrics.SCM_AUTHORS_BY_LINE_KEY); + for (Object[] measureByKey : measuresByKey) { + if (measureByKey[0].equals(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY)) { + lastCommits = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE); + } else if (measureByKey[0].equals(CoreMetrics.SCM_REVISIONS_BY_LINE_KEY)) { + revisions = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_REVISIONS_BY_LINE); + } else if (measureByKey[0].equals(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY)) { + authors = ((MeasureModel) measureByKey[1]).getData(CoreMetrics.SCM_AUTHORS_BY_LINE); + } + } + ref.addFileData(module.getKeyWithBranch(), path, new FileData(fileData.hash(), authors == null, lastCommits, revisions, authors)); + } + } + ref.setLastAnalysisDate(lastSnapshotCreationDate(projectKey)); + } + return ref; + } + + public List query(String resourceKey, String... metricKeys) { + StringBuilder sb = new StringBuilder(); + Map params = Maps.newHashMap(); + + sb.append("SELECT met.key, m"); + sb.append(" FROM ") + .append(MeasureModel.class.getSimpleName()) + .append(" m, ") + .append(Metric.class.getSimpleName()) + .append(" met, ") + .append(ResourceModel.class.getSimpleName()) + .append(" r, ") + .append(Snapshot.class.getSimpleName()) + .append(" s WHERE met.id=m.metricId AND m.snapshotId=s.id AND s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); + params.put("kee", resourceKey); + params.put("status", Snapshot.STATUS_PROCESSED); + params.put("lib", Qualifiers.LIBRARY); + + sb.append(" AND m.characteristicId IS NULL"); + sb.append(" AND m.personId IS NULL"); + sb.append(" AND m.ruleId IS NULL AND m.rulePriority IS NULL"); + if (metricKeys.length > 0) { + sb.append(" AND met.key IN (:metricKeys) "); + params.put("metricKeys", Arrays.asList(metricKeys)); + } + sb.append(" AND s.last=true "); + sb.append(" ORDER BY s.createdAt "); + + Query jpaQuery = session.createQuery(sb.toString()); + + for (Map.Entry entry : params.entrySet()) { + jpaQuery.setParameter(entry.getKey(), entry.getValue()); + } + return jpaQuery.getResultList(); + } + + @CheckForNull + Date lastSnapshotCreationDate(String resourceKey) { + StringBuilder sb = new StringBuilder(); + Map params = Maps.newHashMap(); + + sb.append("SELECT s.buildDate"); + sb.append(" FROM ") + .append(ResourceModel.class.getSimpleName()) + .append(" r, ") + .append(Snapshot.class.getSimpleName()) + .append(" s WHERE s.resourceId=r.id AND r.key=:kee AND s.status=:status AND s.qualifier<>:lib"); + params.put("kee", resourceKey); + params.put("status", Snapshot.STATUS_PROCESSED); + params.put("lib", Qualifiers.LIBRARY); + + sb.append(" AND s.last=true "); + + Query jpaQuery = session.createQuery(sb.toString()); + + for (Map.Entry entry : params.entrySet()) { + jpaQuery.setParameter(entry.getKey(), entry.getValue()); + } + try { + return (Date) jpaQuery.getSingleResult(); + } catch (NoResultException e) { + return null; + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsLoader.java deleted file mode 100644 index 1d101827f14..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsLoader.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.sonar.batch.protocol.input.GlobalRepositories; - -public interface GlobalReferentialsLoader { - - GlobalRepositories load(); - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsProvider.java deleted file mode 100644 index eddee9c0deb..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalReferentialsProvider.java +++ /dev/null @@ -1,45 +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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.utils.TimeProfiler; -import org.sonar.batch.protocol.input.GlobalRepositories; - -public class GlobalReferentialsProvider extends ProviderAdapter { - - private static final Logger LOG = LoggerFactory.getLogger(GlobalReferentialsProvider.class); - - private GlobalRepositories globalReferentials; - - public GlobalRepositories provide(GlobalReferentialsLoader loader) { - if (globalReferentials == null) { - TimeProfiler profiler = new TimeProfiler(LOG).start("Load global referentials"); - try { - globalReferentials = loader.load(); - } finally { - profiler.stop(); - } - } - return globalReferentials; - } -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesLoader.java new file mode 100644 index 00000000000..e7f56510fdc --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesLoader.java @@ -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.GlobalRepositories; + +public interface GlobalRepositoriesLoader { + + GlobalRepositories load(); + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesProvider.java new file mode 100644 index 00000000000..6f13f3878de --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/GlobalRepositoriesProvider.java @@ -0,0 +1,45 @@ +/* + * 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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.utils.TimeProfiler; +import org.sonar.batch.protocol.input.GlobalRepositories; + +public class GlobalRepositoriesProvider extends ProviderAdapter { + + private static final Logger LOG = LoggerFactory.getLogger(GlobalRepositoriesProvider.class); + + private GlobalRepositories globalReferentials; + + public GlobalRepositories provide(GlobalRepositoriesLoader loader) { + if (globalReferentials == null) { + TimeProfiler profiler = new TimeProfiler(LOG).start("Load global repositories"); + try { + globalReferentials = loader.load(); + } finally { + profiler.stop(); + } + } + return globalReferentials; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java index 390f81786af..11e9510ea8b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/repository/ProjectRepositoriesProvider.java @@ -35,7 +35,7 @@ public class ProjectRepositoriesProvider extends ProviderAdapter { public ProjectRepositories provide(ProjectRepositoriesLoader loader, ProjectReactor reactor, TaskProperties taskProps) { if (projectReferentials == null) { - TimeProfiler profiler = new TimeProfiler(LOG).start("Load project referentials"); + TimeProfiler profiler = new TimeProfiler(LOG).start("Load project repositories"); try { projectReferentials = loader.load(reactor, taskProps); } finally { diff --git a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectReferentialsLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectReferentialsLoaderTest.java deleted file mode 100644 index 108151f5aac..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectReferentialsLoaderTest.java +++ /dev/null @@ -1,87 +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.batch.repository.DefaultProjectReferentialsLoader; - -import com.google.common.collect.Maps; -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.batch.bootstrap.ProjectReactor; -import org.sonar.api.database.DatabaseSession; -import org.sonar.batch.bootstrap.AnalysisMode; -import org.sonar.batch.bootstrap.ServerClient; -import org.sonar.batch.bootstrap.TaskProperties; -import org.sonar.batch.rule.ModuleQProfiles; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class DefaultProjectReferentialsLoaderTest { - - private DefaultProjectReferentialsLoader loader; - private ServerClient serverClient; - private AnalysisMode analysisMode; - private ProjectReactor reactor; - private TaskProperties taskProperties; - - @Before - public void prepare() { - serverClient = mock(ServerClient.class); - analysisMode = mock(AnalysisMode.class); - loader = new DefaultProjectReferentialsLoader(mock(DatabaseSession.class), serverClient, analysisMode); - loader = spy(loader); - doReturn(null).when(loader).lastSnapshotCreationDate(anyString()); - when(serverClient.request(anyString())).thenReturn("{}"); - taskProperties = new TaskProperties(Maps.newHashMap(), ""); - } - - @Test - public void passPreviewParameter() { - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); - when(analysisMode.isPreview()).thenReturn(false); - loader.load(reactor, taskProperties); - verify(serverClient).request("/batch/project?key=foo&preview=false"); - - when(analysisMode.isPreview()).thenReturn(true); - loader.load(reactor, taskProperties); - verify(serverClient).request("/batch/project?key=foo&preview=true"); - } - - @Test - public void passAndEncodeProjectKeyParameter() { - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo bàr")); - loader.load(reactor, taskProperties); - verify(serverClient).request("/batch/project?key=foo+b%C3%A0r&preview=false"); - } - - @Test - public void passAndEncodeProfileParameter() { - reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); - taskProperties.properties().put(ModuleQProfiles.SONAR_PROFILE_PROP, "my-profile#2"); - loader.load(reactor, taskProperties); - verify(serverClient).request("/batch/project?key=foo&profile=my-profile%232&preview=false"); - } - -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java new file mode 100644 index 00000000000..27e07d7edc0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java @@ -0,0 +1,87 @@ +/* + * 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.repository.DefaultProjectRepositoriesLoader; + +import com.google.common.collect.Maps; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.bootstrap.ProjectDefinition; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.api.database.DatabaseSession; +import org.sonar.batch.bootstrap.AnalysisMode; +import org.sonar.batch.bootstrap.ServerClient; +import org.sonar.batch.bootstrap.TaskProperties; +import org.sonar.batch.rule.ModuleQProfiles; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class DefaultProjectRepositoriesLoaderTest { + + private DefaultProjectRepositoriesLoader loader; + private ServerClient serverClient; + private AnalysisMode analysisMode; + private ProjectReactor reactor; + private TaskProperties taskProperties; + + @Before + public void prepare() { + serverClient = mock(ServerClient.class); + analysisMode = mock(AnalysisMode.class); + loader = new DefaultProjectRepositoriesLoader(mock(DatabaseSession.class), serverClient, analysisMode); + loader = spy(loader); + doReturn(null).when(loader).lastSnapshotCreationDate(anyString()); + when(serverClient.request(anyString())).thenReturn("{}"); + taskProperties = new TaskProperties(Maps.newHashMap(), ""); + } + + @Test + public void passPreviewParameter() { + reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); + when(analysisMode.isPreview()).thenReturn(false); + loader.load(reactor, taskProperties); + verify(serverClient).request("/batch/project?key=foo&preview=false"); + + when(analysisMode.isPreview()).thenReturn(true); + loader.load(reactor, taskProperties); + verify(serverClient).request("/batch/project?key=foo&preview=true"); + } + + @Test + public void passAndEncodeProjectKeyParameter() { + reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo bàr")); + loader.load(reactor, taskProperties); + verify(serverClient).request("/batch/project?key=foo+b%C3%A0r&preview=false"); + } + + @Test + public void passAndEncodeProfileParameter() { + reactor = new ProjectReactor(ProjectDefinition.create().setKey("foo")); + taskProperties.properties().put(ModuleQProfiles.SONAR_PROFILE_PROP, "my-profile#2"); + loader.load(reactor, taskProperties); + verify(serverClient).request("/batch/project?key=foo&profile=my-profile%232&preview=false"); + } + +} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java index ecfd73199af..393e69331fa 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java @@ -22,6 +22,9 @@ package org.sonar.api.batch.fs.internal; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.utils.PathUtils; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + import java.io.File; import java.io.Serializable; @@ -67,6 +70,7 @@ public class DefaultInputFile implements InputFile, Serializable { return new File(absolutePath); } + @CheckForNull @Override public String language() { return language; @@ -129,7 +133,7 @@ public class DefaultInputFile implements InputFile, Serializable { return this; } - public DefaultInputFile setLanguage(String language) { + public DefaultInputFile setLanguage(@Nullable String language) { this.language = language; return this; }