Selaa lähdekoodia

SONAR-11507 WS /batch/project new file structure

tags/7.6
Michal Duda 5 vuotta sitten
vanhempi
commit
cf1c8d7618
25 muutettua tiedostoa jossa 628 lisäystä ja 145 poistoa
  1. 20
    19
      server/sonar-server/src/main/java/org/sonar/server/batch/ProjectAction.java
  2. 24
    5
      server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataLoader.java
  3. 48
    4
      server/sonar-server/src/test/java/org/sonar/server/batch/ProjectActionTest.java
  4. 16
    6
      server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java
  5. 22
    15
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java
  6. 45
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/MultiModuleProjectRepository.java
  7. 10
    25
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java
  8. 49
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/SingleProjectRepository.java
  9. 4
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java
  10. 3
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java
  11. 10
    9
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java
  12. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java
  13. 2
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issuesmode/ScanOnlyChangedTest.java
  14. 4
    4
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java
  15. 5
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoaderTest.java
  16. 61
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/MultiModuleProjectRepositoryTest.java
  17. 4
    4
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java
  18. 55
    0
      sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/SingleProjectRepositoryTest.java
  19. 13
    13
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java
  20. 52
    0
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepository.java
  21. 2
    28
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/ProjectRepositories.java
  22. 45
    0
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/SingleProjectRepository.java
  23. 68
    0
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepositoryTest.java
  24. 64
    0
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/SingleProjectRepositoryTest.java
  25. 1
    0
      sonar-ws/src/main/protobuf/ws-batch.proto

+ 20
- 19
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectAction.java Näytä tiedosto

@@ -19,15 +19,18 @@
*/
package org.sonar.server.batch;

import com.google.common.collect.Maps;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.scanner.protocol.input.FileData;
import org.sonar.scanner.protocol.input.MultiModuleProjectRepository;
import org.sonar.scanner.protocol.input.ProjectRepositories;
import org.sonar.scanner.protocol.input.SingleProjectRepository;
import org.sonarqube.ws.Batch.WsProjectResponse;
import org.sonarqube.ws.Batch.WsProjectResponse.FileData.Builder;

@@ -109,33 +112,31 @@ public class ProjectAction implements BatchWsAction {
WsProjectResponse.Builder response = WsProjectResponse.newBuilder();
setNullable(data.lastAnalysisDate(), response::setLastAnalysisDate, Date::getTime);
response.setTimestamp(data.timestamp());
response.getMutableFileDataByModuleAndPath()
.putAll(buildFileDataByModuleAndPath(data));
if (data instanceof SingleProjectRepository) {
response.putAllFileDataByPath(buildFileDataByPath((SingleProjectRepository) data));
} else {
response.putAllFileDataByModuleAndPath(buildFileDataByModuleAndPath((MultiModuleProjectRepository) data));
}

return response.build();
}

private static Map<String, WsProjectResponse.FileDataByPath> buildFileDataByModuleAndPath(ProjectRepositories data) {
Map<String, WsProjectResponse.FileDataByPath> fileDataByModuleAndPathResponse = new HashMap<>();
for (Map.Entry<String, Map<String, FileData>> moduleAndFileDataByPathEntry : data.fileDataByModuleAndPath().entrySet()) {
fileDataByModuleAndPathResponse.put(
moduleAndFileDataByPathEntry.getKey(),
buildFileDataByPath(moduleAndFileDataByPathEntry.getValue()));
}
private static Map<String, WsProjectResponse.FileDataByPath> buildFileDataByModuleAndPath(MultiModuleProjectRepository data) {
return data.repositoriesByModule().entrySet()
.stream()
.map(entry -> Maps.immutableEntry(entry.getKey(), buildFileDataByPath(entry.getValue().fileData())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

return fileDataByModuleAndPathResponse;
private static Map<String, WsProjectResponse.FileData> buildFileDataByPath(SingleProjectRepository data) {
return data.fileData().entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> toFileDataResponse(e.getValue())));
}

private static WsProjectResponse.FileDataByPath buildFileDataByPath(Map<String, FileData> fileDataByPath) {
WsProjectResponse.FileDataByPath.Builder response = WsProjectResponse.FileDataByPath.newBuilder();
Map<String, WsProjectResponse.FileData> fileDataByPathResponse = response.getMutableFileDataByPath();

for (Map.Entry<String, FileData> pathFileDataEntry : fileDataByPath.entrySet()) {
fileDataByPathResponse.put(
pathFileDataEntry.getKey(),
toFileDataResponse(pathFileDataEntry.getValue()));
}

fileDataByPath.forEach((key, value) -> response.putFileDataByPath(key, toFileDataResponse(value)));
return response.build();
}


+ 24
- 5
server/sonar-server/src/main/java/org/sonar/server/batch/ProjectDataLoader.java Näytä tiedosto

@@ -32,7 +32,9 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.permission.OrganizationPermission;
import org.sonar.scanner.protocol.input.FileData;
import org.sonar.scanner.protocol.input.MultiModuleProjectRepository;
import org.sonar.scanner.protocol.input.ProjectRepositories;
import org.sonar.scanner.protocol.input.SingleProjectRepository;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.user.UserSession;
@@ -56,7 +58,6 @@ public class ProjectDataLoader {

public ProjectRepositories load(ProjectDataQuery query) {
try (DbSession session = dbClient.openSession(false)) {
ProjectRepositories data = new ProjectRepositories();
String projectKey = query.getProjectKey();
String branch = query.getBranch();
String pullRequest = query.getPullRequest();
@@ -72,12 +73,23 @@ public class ProjectDataLoader {
List<ComponentDto> modulesTree = dbClient.componentDao().selectEnabledDescendantModules(session, branchOrMainModule.uuid());

List<FilePathWithHashDto> files = searchFilesWithHashAndRevision(session, branchOrMainModule);
addFileData(data, modulesTree, files);

// MMF-365 we still have to support multi-module projects because it's not possible to transform from logical to
// physical structure for some multi-module projects
ProjectRepositories data;
if (modulesTree.size() > 1) {
MultiModuleProjectRepository repository = new MultiModuleProjectRepository();
addFileDataPerModule(repository, modulesTree, files);
data = repository;
} else {
SingleProjectRepository repository = new SingleProjectRepository();
addFileData(repository, files);
data = repository;
}

// FIXME need real value but actually only used to know if there is a previous analysis in local issue tracking mode so any value is
// ok
data.setLastAnalysisDate(new Date());

return data;
}
}
@@ -90,7 +102,7 @@ public class ProjectDataLoader {
: dbClient.componentDao().selectEnabledDescendantFiles(session, module.uuid());
}

private static void addFileData(ProjectRepositories data, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
private static void addFileDataPerModule(MultiModuleProjectRepository data, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
Map<String, String> moduleKeysByUuid = newHashMap();
for (ComponentDto module : moduleChildren) {
moduleKeysByUuid.put(module.uuid(), module.getKey());
@@ -98,7 +110,14 @@ public class ProjectDataLoader {

for (FilePathWithHashDto file : files) {
FileData fileData = new FileData(file.getSrcHash(), file.getRevision());
data.addFileData(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
data.addFileDataToModule(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
}
}

private static void addFileData(SingleProjectRepository data, List<FilePathWithHashDto> files) {
for (FilePathWithHashDto file : files) {
FileData fileData = new FileData(file.getSrcHash(), file.getRevision());
data.addFileData(file.getPath(), fileData);
}
}


+ 48
- 4
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectActionTest.java Näytä tiedosto

@@ -22,7 +22,9 @@ package org.sonar.server.batch;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.scanner.protocol.input.FileData;
import org.sonar.scanner.protocol.input.MultiModuleProjectRepository;
import org.sonar.scanner.protocol.input.ProjectRepositories;
import org.sonar.scanner.protocol.input.SingleProjectRepository;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Batch.WsProjectResponse;
@@ -42,7 +44,7 @@ public class ProjectActionTest {
public void project_referentials() {
String projectKey = "org.codehaus.sonar:sonar";

ProjectRepositories projectReferentials = mock(ProjectRepositories.class);
ProjectRepositories projectReferentials = mock(SingleProjectRepository.class);

ArgumentCaptor<ProjectDataQuery> queryArgumentCaptor = ArgumentCaptor.forClass(ProjectDataQuery.class);
when(projectDataLoader.load(queryArgumentCaptor.capture())).thenReturn(projectReferentials);
@@ -53,7 +55,7 @@ public class ProjectActionTest {
.setParam("profile", "Default")
.setParam("preview", "false")
.execute();
assertJson(response.getInput()).isSimilarTo("{\"fileDataByModuleAndPath\": {}}");
assertJson(response.getInput()).isSimilarTo("{\"fileDataByPath\": {}}");

assertThat(queryArgumentCaptor.getValue().getProjectKey()).isEqualTo(projectKey);
assertThat(queryArgumentCaptor.getValue().getProfileName()).isEqualTo("Default");
@@ -68,13 +70,55 @@ public class ProjectActionTest {
public void do_not_fail_when_a_path_is_null() {
String projectKey = "org.codehaus.sonar:sonar";

ProjectRepositories projectRepositories = new ProjectRepositories().addFileData("module-1", null, new FileData(null, null));
ProjectRepositories projectRepositories = new MultiModuleProjectRepository()
.addFileDataToModule("module-1", null, new FileData(null, null));
when(projectDataLoader.load(any(ProjectDataQuery.class))).thenReturn(projectRepositories);

WsProjectResponse wsProjectResponse = ws.newRequest()
.setParam("key", projectKey)
.setParam("profile", "Default")
.executeProtobuf(WsProjectResponse.class);
assertThat(wsProjectResponse.getFileDataByModuleAndPath()).isEmpty();
assertThat(wsProjectResponse.getFileDataByModuleAndPathMap()).isEmpty();
}

@Test
public void use_new_file_structure_for_projects_without_submodules() {
String projectKey = "org.codehaus.sonar:sonar";

ProjectRepositories projectRepositories = new SingleProjectRepository()
.addFileData("src/main/java/SomeClass.java", new FileData("789456", "123456789"));
when(projectDataLoader.load(any(ProjectDataQuery.class))).thenReturn(projectRepositories);

WsProjectResponse wsProjectResponse = ws.newRequest()
.setParam("key", projectKey)
.setParam("profile", "Default")
.executeProtobuf(WsProjectResponse.class);
assertThat(wsProjectResponse.getFileDataByModuleAndPathMap()).isEmpty();
assertThat(wsProjectResponse.getFileDataByPathCount()).isEqualTo(1);
assertThat(wsProjectResponse.getFileDataByPathMap().get("src/main/java/SomeClass.java")).isNotNull();
}

@Test
public void use_old_file_structure_for_projects_with_submodules() {
String projectKey = "org.codehaus.sonar:sonar";

ProjectRepositories projectRepositories = new MultiModuleProjectRepository()
.addFileDataToModule("module-1", "src/main/java/SomeClass.java", new FileData("789456", "123456789"));
when(projectDataLoader.load(any(ProjectDataQuery.class))).thenReturn(projectRepositories);

WsProjectResponse wsProjectResponse = ws.newRequest()
.setParam("key", projectKey)
.setParam("profile", "Default")
.executeProtobuf(WsProjectResponse.class);

assertThat(wsProjectResponse.getFileDataByPathMap()).isEmpty();
assertThat(wsProjectResponse.getFileDataByModuleAndPathCount()).isEqualTo(1);
WsProjectResponse.FileDataByPath moduleData = wsProjectResponse.getFileDataByModuleAndPathMap().get("module-1");
assertThat(moduleData).isNotNull();
assertThat(moduleData.getFileDataByPathCount()).isEqualTo(1);
WsProjectResponse.FileData fileData = moduleData.getFileDataByPathMap().get("src/main/java/SomeClass.java");
assertThat(fileData).isNotNull();
assertThat(fileData.getHash()).isEqualTo("789456");
assertThat(fileData.getRevision()).isEqualTo("123456789");
}
}

+ 16
- 6
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java Näytä tiedosto

@@ -34,7 +34,9 @@ import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.source.FileSourceDto;
import org.sonar.scanner.protocol.input.FileData;
import org.sonar.scanner.protocol.input.MultiModuleProjectRepository;
import org.sonar.scanner.protocol.input.ProjectRepositories;
import org.sonar.scanner.protocol.input.SingleProjectRepository;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
@@ -44,6 +46,7 @@ import org.sonar.server.tester.UserSessionRule;
import static com.google.common.collect.ImmutableList.of;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
import static org.sonar.db.component.ComponentTesting.newFileDto;
@@ -89,8 +92,11 @@ public class ProjectDataLoaderTest {

ProjectRepositories ref = underTest.load(ProjectDataQuery.create().setProjectKey(project.getKey()));

assertThat(ref.fileDataByPath(project.getKey())).hasSize(1);
FileData fileData = ref.fileData(project.getKey(), file.path());
assertTrue(ref instanceof SingleProjectRepository);
SingleProjectRepository singleProjectRepository = ((SingleProjectRepository) ref);
assertThat(singleProjectRepository.fileData()).hasSize(1);
FileData fileData = singleProjectRepository.fileDataByPath(file.path());
assertThat(fileData).isNotNull();
assertThat(fileData.hash()).isEqualTo("123456");
}

@@ -110,8 +116,10 @@ public class ProjectDataLoaderTest {

ProjectRepositories ref = underTest.load(ProjectDataQuery.create().setProjectKey(project.getKey()));

assertThat(ref.fileData(project.getKey(), projectFile.path()).hash()).isEqualTo("123456");
assertThat(ref.fileData(module.getKey(), moduleFile.path()).hash()).isEqualTo("789456");
assertTrue(ref instanceof MultiModuleProjectRepository);
MultiModuleProjectRepository repository = ((MultiModuleProjectRepository) ref);
assertThat(repository.fileData(project.getKey(), projectFile.path()).hash()).isEqualTo("123456");
assertThat(repository.fileData(module.getKey(), moduleFile.path()).hash()).isEqualTo("789456");
}

@Test
@@ -133,8 +141,10 @@ public class ProjectDataLoaderTest {
.setProjectKey(project.getKey())
.setBranch("my_branch"));

assertThat(ref.fileData(branch.getKey(), projectFile.path()).hash()).isEqualTo("123456");
assertThat(ref.fileData(moduleBranch.getKey(), moduleFile.path()).hash()).isEqualTo("789456");
assertTrue(ref instanceof MultiModuleProjectRepository);
MultiModuleProjectRepository repository = ((MultiModuleProjectRepository) ref);
assertThat(repository.fileData(branch.getKey(), projectFile.path()).hash()).isEqualTo("123456");
assertThat(repository.fileData(moduleBranch.getKey(), moduleFile.path()).hash()).isEqualTo("789456");
}

@Test

+ 22
- 15
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoader.java Näytä tiedosto

@@ -20,12 +20,11 @@
package org.sonar.scanner.repository;

import com.google.common.base.Throwables;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
@@ -34,9 +33,7 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.bootstrap.ScannerWsClient;
import org.sonar.scanner.util.ScannerUtils;
import org.sonarqube.ws.Batch;
import org.sonarqube.ws.Batch.WsProjectResponse;
import org.sonarqube.ws.Batch.WsProjectResponse.FileDataByPath;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsResponse;
@@ -62,7 +59,7 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
}

LOG.debug("Project repository not available - continuing without it");
return new ProjectRepositories();
return new SingleProjectRepository();
}
}

@@ -97,22 +94,32 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
private static ProjectRepositories processStream(InputStream is, String projectKey) {
try {
WsProjectResponse response = WsProjectResponse.parseFrom(is);

Table<String, String, FileData> fileDataTable = HashBasedTable.create();

Map<String, FileDataByPath> fileDataByModuleAndPath = response.getFileDataByModuleAndPath();
for (Map.Entry<String, FileDataByPath> e1 : fileDataByModuleAndPath.entrySet()) {
for (Map.Entry<String, Batch.WsProjectResponse.FileData> e2 : e1.getValue().getFileDataByPath().entrySet()) {
FileData fd = new FileData(e2.getValue().getHash(), e2.getValue().getRevision());
fileDataTable.put(e1.getKey(), e2.getKey(), fd);
}
if (response.getFileDataByModuleAndPathCount() == 0) {
return new SingleProjectRepository(constructFileDataMap(response.getFileDataByPathMap()), new Date(response.getLastAnalysisDate()));
} else {
final Map<String, SingleProjectRepository> repositoriesPerModule = new HashMap<>();
response.getFileDataByModuleAndPathMap().keySet().forEach(moduleKey -> {
WsProjectResponse.FileDataByPath filePaths = response.getFileDataByModuleAndPathMap().get(moduleKey);
repositoriesPerModule.put(moduleKey, new SingleProjectRepository(
constructFileDataMap(filePaths.getFileDataByPathMap()), new Date(response.getLastAnalysisDate())));
});
return new MultiModuleProjectRepository(repositoriesPerModule, new Date(response.getLastAnalysisDate()));
}

return new ProjectRepositories(fileDataTable, new Date(response.getLastAnalysisDate()));
} catch (IOException e) {
throw new IllegalStateException("Couldn't load project repository for " + projectKey, e);
} finally {
IOUtils.closeQuietly(is);
}
}

private static Map<String, FileData> constructFileDataMap(Map<String, WsProjectResponse.FileData> content) {
Map<String, FileData> fileDataMap = new HashMap<>();
content.forEach((key, value) -> {
FileData fd = new FileData(value.getHash(), value.getRevision());
fileDataMap.put(key, fd);
});

return fileDataMap;
}
}

+ 45
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/MultiModuleProjectRepository.java Näytä tiedosto

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

import com.google.common.collect.ImmutableMap;
import java.util.Date;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

@Immutable
public class MultiModuleProjectRepository extends ProjectRepositories {

private Map<String, SingleProjectRepository> repositoriesPerModule;

public MultiModuleProjectRepository(Map<String, SingleProjectRepository> repositoriesPerModule, @Nullable Date lastAnalysisDate) {
super(lastAnalysisDate, true);
this.repositoriesPerModule = ImmutableMap.copyOf(repositoriesPerModule);
}

@CheckForNull
public FileData fileData(String moduleKeyWithBranch, String path) {
SingleProjectRepository repository = repositoriesPerModule.get(moduleKeyWithBranch);
return repository == null ? null : repository.fileData(path);
}

}

+ 10
- 25
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/ProjectRepositories.java Näytä tiedosto

@@ -19,48 +19,33 @@
*/
package org.sonar.scanner.repository;

import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import java.util.Date;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.fs.internal.DefaultInputFile;

@Immutable
public class ProjectRepositories {
private final ImmutableTable<String, String, FileData> fileDataByModuleAndPath;
public abstract class ProjectRepositories {
private final Date lastAnalysisDate;
private final boolean exists;

public ProjectRepositories() {
this.exists = false;
this.fileDataByModuleAndPath = new ImmutableTable.Builder<String, String, FileData>().build();
this.lastAnalysisDate = null;
}

public ProjectRepositories(Table<String, String, FileData> fileDataByModuleAndPath,
@Nullable Date lastAnalysisDate) {
this.fileDataByModuleAndPath = ImmutableTable.copyOf(fileDataByModuleAndPath);
public ProjectRepositories(@Nullable Date lastAnalysisDate, boolean exists) {
this.lastAnalysisDate = lastAnalysisDate;
this.exists = true;
this.exists = exists;
}

public boolean exists() {
return exists;
}

public Map<String, FileData> fileDataByPath(String moduleKey) {
return fileDataByModuleAndPath.row(moduleKey);
}

public Table<String, String, FileData> fileDataByModuleAndPath() {
return fileDataByModuleAndPath;
}

@CheckForNull
public FileData fileData(String projectKeyWithBranch, String path) {
return fileDataByModuleAndPath.get(projectKeyWithBranch, path);
public FileData fileData(String moduleKeyWithBranch, DefaultInputFile inputFile) {
if (this instanceof SingleProjectRepository) {
return ((SingleProjectRepository) this).fileData(inputFile.getProjectRelativePath());
} else {
return ((MultiModuleProjectRepository) this).fileData(moduleKeyWithBranch, inputFile.getModuleRelativePath());
}
}

@CheckForNull

+ 49
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/repository/SingleProjectRepository.java Näytä tiedosto

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

import com.google.common.collect.ImmutableMap;
import java.util.Date;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

@Immutable
public class SingleProjectRepository extends ProjectRepositories {

private final ImmutableMap<String, FileData> fileDataByPath;

public SingleProjectRepository() {
super(null, false);
this.fileDataByPath = ImmutableMap.<String, FileData>builder().build();
}

public SingleProjectRepository(Map<String, FileData> fileDataByPath,
@Nullable Date lastAnalysisDate) {
super(lastAnalysisDate, true);
this.fileDataByPath = ImmutableMap.copyOf(fileDataByPath);
}

@CheckForNull
public FileData fileData(String path) {
return fileDataByPath.get(path);
}
}

+ 4
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/StatusDetection.java Näytä tiedosto

@@ -34,7 +34,6 @@ import static org.sonar.api.batch.fs.InputFile.Status.SAME;

@Immutable
public class StatusDetection {

private final ProjectRepositories projectRepositories;
private final ScmChangedFiles scmChangedFiles;

@@ -43,8 +42,8 @@ public class StatusDetection {
this.scmChangedFiles = scmChangedFiles;
}

InputFile.Status status(String projectKeyWithBranch, DefaultInputFile inputFile, String hash) {
FileData fileDataPerPath = projectRepositories.fileData(projectKeyWithBranch, inputFile.relativePath());
InputFile.Status status(String moduleKeyWithBranch, DefaultInputFile inputFile, String hash) {
FileData fileDataPerPath = projectRepositories.fileData(moduleKeyWithBranch, inputFile);
if (fileDataPerPath == null) {
return checkChanged(ADDED, inputFile);
}
@@ -64,8 +63,8 @@ public class StatusDetection {
* @return null if it was not possible to get the status without calculating metadata
*/
@CheckForNull
public InputFile.Status getStatusWithoutMetadata(String projectKeyWithBranch, DefaultInputFile inputFile) {
FileData fileDataPerPath = projectRepositories.fileData(projectKeyWithBranch, inputFile.relativePath());
public InputFile.Status getStatusWithoutMetadata(String moduleKeyWithBranch, DefaultInputFile inputFile) {
FileData fileDataPerPath = projectRepositories.fileData(moduleKeyWithBranch, inputFile);
if (fileDataPerPath == null) {
return checkChanged(ADDED, inputFile);
}

+ 3
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/scm/ScmPublisher.java Näytä tiedosto

@@ -27,8 +27,8 @@ import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Status;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -57,7 +57,7 @@ public final class ScmPublisher {
private final BranchConfiguration branchConfiguration;

public ScmPublisher(AbstractProjectOrModule inputModule, ScmConfiguration configuration, ProjectRepositories projectRepositories,
ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
ModuleInputComponentStore componentStore, DefaultModuleFileSystem fs, ReportPublisher reportPublisher, BranchConfiguration branchConfiguration) {
this.inputModule = inputModule;
this.configuration = configuration;
this.projectRepositories = projectRepositories;
@@ -108,7 +108,7 @@ public final class ScmPublisher {
addIfNotEmpty(filesToBlame, f);
} else if (!branchConfiguration.isShortOrPullRequest()) {
// File status is SAME so that mean fileData exists
FileData fileData = projectRepositories.fileData(inputModule.definition().getKeyWithBranch(), inputFile.getModuleRelativePath());
FileData fileData = projectRepositories.fileData(inputModule.definition().getKeyWithBranch(), inputFile);
if (StringUtils.isEmpty(fileData.revision())) {
addIfNotEmpty(filesToBlame, f);
} else {

+ 10
- 9
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java Näytä tiedosto

@@ -20,6 +20,7 @@
package org.sonar.scanner.mediumtest;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import java.io.File;
import java.io.FileInputStream;
@@ -62,6 +63,7 @@ import org.sonar.scanner.repository.ProjectRepositories;
import org.sonar.scanner.repository.ProjectRepositoriesLoader;
import org.sonar.scanner.repository.QualityProfileLoader;
import org.sonar.scanner.repository.ServerIssuesLoader;
import org.sonar.scanner.repository.SingleProjectRepository;
import org.sonar.scanner.repository.settings.SettingsLoader;
import org.sonar.scanner.rule.ActiveRulesLoader;
import org.sonar.scanner.rule.LoadedActiveRule;
@@ -199,22 +201,22 @@ public class ScannerMediumTester extends ExternalResource {
}

public ScannerMediumTester addActiveRule(String repositoryKey, String ruleKey, @Nullable String templateRuleKey, String name, @Nullable String severity,
@Nullable String internalKey, @Nullable String languag) {
@Nullable String internalKey, @Nullable String language) {
LoadedActiveRule r = new LoadedActiveRule();

r.setInternalKey(internalKey);
r.setRuleKey(RuleKey.of(repositoryKey, ruleKey));
r.setName(name);
r.setTemplateRuleKey(templateRuleKey);
r.setLanguage(languag);
r.setLanguage(language);
r.setSeverity(severity);

activeRules.addActiveRule(r);
return this;
}

public ScannerMediumTester addFileData(String moduleKey, String path, FileData fileData) {
projectRefProvider.addFileData(moduleKey, path, fileData);
public ScannerMediumTester addFileData(String path, FileData fileData) {
projectRefProvider.addFileData(path, fileData);
return this;
}

@@ -368,17 +370,16 @@ public class ScannerMediumTester extends ExternalResource {
}

private static class FakeProjectRepositoriesLoader implements ProjectRepositoriesLoader {

private Table<String, String, FileData> fileDataTable = HashBasedTable.create();
private Map<String, FileData> fileDataMap = Maps.newHashMap();
private Date lastAnalysisDate;

@Override
public ProjectRepositories load(String projectKey, boolean isIssuesMode, @Nullable String branchBase) {
return new ProjectRepositories(fileDataTable, lastAnalysisDate);
return new SingleProjectRepository(fileDataMap, lastAnalysisDate);
}

public FakeProjectRepositoriesLoader addFileData(String moduleKey, String path, FileData fileData) {
fileDataTable.put(moduleKey, path, fileData);
public FakeProjectRepositoriesLoader addFileData(String path, FileData fileData) {
fileDataMap.put(path, fileData);
return this;
}


+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java Näytä tiedosto

@@ -66,7 +66,7 @@ public class BranchMediumTest {
String md5sum = new FileMetadata()
.readMetadata(Files.newInputStream(filepath), StandardCharsets.UTF_8, FILE_PATH)
.hash();
tester.addFileData(PROJECT_KEY, FILE_PATH, new FileData(md5sum, "1.1"));
tester.addFileData(FILE_PATH, new FileData(md5sum, "1.1"));
}

@Test

+ 2
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issuesmode/ScanOnlyChangedTest.java Näytä tiedosto

@@ -47,9 +47,9 @@ import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.utils.log.LogTester;
import org.sonar.scanner.issue.tracking.TrackedIssue;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.ScannerMediumTester.AnalysisBuilder;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.Constants.Severity;
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
import org.sonar.scanner.repository.FileData;
@@ -104,7 +104,7 @@ public class ScanOnlyChangedTest {

tester
// this will cause the file to have status==SAME
.addFileData(projectKey, filePath, new FileData(md5sum, null))
.addFileData(filePath, new FileData(md5sum, null))
.setPreviousAnalysisDate(new Date())
// Existing issue that is copied
.mockServerIssue(ServerIssue.newBuilder().setKey("xyz")

+ 4
- 4
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java Näytä tiedosto

@@ -69,10 +69,10 @@ public class ScmMediumTest {
.addRules(new XooRulesDefinition())
// active a rule just to be sure that xoo files are published
.addActiveRule("xoo", "xoo:OneIssuePerFile", null, "One Issue Per File", null, null, null)
.addFileData("com.foo.project", CHANGED_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
.addFileData("com.foo.project", SAME_CONTENT_NO_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
.addFileData("com.foo.project", SAME_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"))
.addFileData("com.foo.project", NO_BLAME_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"));
.addFileData(CHANGED_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
.addFileData(SAME_CONTENT_NO_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), null))
.addFileData(SAME_CONTENT_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"))
.addFileData(NO_BLAME_SCM_ON_SERVER_XOO, new FileData(DigestUtils.md5Hex(SAMPLE_XOO_CONTENT), "1.1"));

@Test
public void testScmMeasure() throws IOException, URISyntaxException {

+ 5
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/DefaultProjectRepositoriesLoaderTest.java Näytä tiedosto

@@ -28,6 +28,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.WsTestUtil;
import org.sonar.scanner.bootstrap.ScannerWsClient;
@@ -124,9 +125,11 @@ public class DefaultProjectRepositoriesLoaderTest {
InputStream is = getTestResource("project.protobuf");
WsTestUtil.mockStream(wsClient, "/batch/project.protobuf?key=org.sonarsource.github%3Asonar-github-plugin&issues_mode=true", is);

DefaultInputFile file = mock(DefaultInputFile.class);
when(file.getModuleRelativePath()).thenReturn("src/test/java/org/sonar/plugins/github/PullRequestIssuePostJobTest.java");

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

assertThat(fd.revision()).isEqualTo("27bf2c54633d05c5df402bbe09471fe43bd9e2e5");
assertThat(fd.hash()).isEqualTo("edb6b3b9ab92d8dc53ba90ab86cd422e");

+ 61
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/MultiModuleProjectRepositoryTest.java Näytä tiedosto

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

import java.util.Date;
import java.util.Map;
import org.assertj.core.util.Maps;
import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;

public class MultiModuleProjectRepositoryTest {

private MultiModuleProjectRepository repository;

@Before
public void setUp() {
Date lastAnalysisDate = new Date();
SingleProjectRepository repository1 = new SingleProjectRepository(Maps.newHashMap("/Abc.java", new FileData("123", "456")), lastAnalysisDate);
SingleProjectRepository repository2 = new SingleProjectRepository(Maps.newHashMap("/Def.java", new FileData("567", "321")), lastAnalysisDate);
Map<String, SingleProjectRepository> moduleRepositories = Maps.newHashMap("module1", repository1);
moduleRepositories.put("module2", repository2);

repository = new MultiModuleProjectRepository(moduleRepositories, lastAnalysisDate);
}

@Test
public void test_file_data_when_module_and_file_exist() {
FileData fileData = repository.fileData("module2", "/Def.java");

assertNotNull(fileData);
assertThat(fileData.hash()).isEqualTo("567");
assertThat(fileData.revision()).isEqualTo("321");
}

@Test
public void test_file_data_when_module_does_not_exist() {
FileData fileData = repository.fileData("unknown", "/Def.java");

assertThat(fileData).isNull();
}
}

+ 4
- 4
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/ProjectRepositoriesProviderTest.java Näytä tiedosto

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

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.Maps;
import java.util.Date;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -55,9 +55,9 @@ public class ProjectRepositoriesProviderTest {
public void setUp() {
MockitoAnnotations.initMocks(this);

Table<String, String, FileData> t2 = HashBasedTable.create();
Map<String, FileData> fileMap = Maps.newHashMap();

project = new ProjectRepositories(t2, new Date());
project = new SingleProjectRepository(fileMap, new Date());
provider = new ProjectRepositoriesProvider();

when(props.getKeyWithBranch()).thenReturn("key");

+ 55
- 0
sonar-scanner-engine/src/test/java/org/sonar/scanner/repository/SingleProjectRepositoryTest.java Näytä tiedosto

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

import java.util.Date;
import org.assertj.core.util.Maps;
import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;

public class SingleProjectRepositoryTest {

private SingleProjectRepository repository;

@Before
public void setUp() {
Date lastAnalysisDate = new Date();
repository = new SingleProjectRepository(Maps.newHashMap("/Abc.java", new FileData("123", "456")), lastAnalysisDate);
}

@Test
public void test_file_data_when_file_exists() {
FileData fileData = repository.fileData("/Abc.java");

assertNotNull(fileData);
assertThat(fileData.hash()).isEqualTo("123");
assertThat(fileData.revision()).isEqualTo("456");
}

@Test
public void test_file_data_when_file_does_not_exist() {
FileData fileData = repository.fileData("/Def.java");

assertThat(fileData).isNull();
}
}

+ 13
- 13
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/StatusDetectionTest.java Näytä tiedosto

@@ -19,16 +19,16 @@
*/
package org.sonar.scanner.scan.filesystem;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.scanner.repository.FileData;
import org.sonar.scanner.repository.ProjectRepositories;
import org.sonar.scanner.repository.SingleProjectRepository;
import org.sonar.scanner.scm.ScmChangedFiles;

import static org.assertj.core.api.Assertions.assertThat;
@@ -40,7 +40,7 @@ import static org.mockito.Mockito.when;
public class StatusDetectionTest {
@Test
public void detect_status() {
ProjectRepositories ref = new ProjectRepositories(createTable(), null);
SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap(), null);
ScmChangedFiles changedFiles = new ScmChangedFiles(null);
StatusDetection statusDetection = new StatusDetection(ref, changedFiles);

@@ -51,7 +51,7 @@ public class StatusDetectionTest {

@Test
public void detect_status_branches_exclude() {
ProjectRepositories ref = new ProjectRepositories(createTable(), null);
SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap(), null);
ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.emptyList());
StatusDetection statusDetection = new StatusDetection(ref, changedFiles);

@@ -65,34 +65,34 @@ public class StatusDetectionTest {
@Test
public void detect_status_without_metadata() {
DefaultInputFile mockedFile = mock(DefaultInputFile.class);
when(mockedFile.relativePath()).thenReturn("module/src/Foo.java");
when(mockedFile.getProjectRelativePath()).thenReturn("module/src/Foo.java");
when(mockedFile.path()).thenReturn(Paths.get("module", "src", "Foo.java"));

ProjectRepositories ref = new ProjectRepositories(createTable(), null);
SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap(), null);
ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.singletonList(Paths.get("module", "src", "Foo.java")));
StatusDetection statusDetection = new StatusDetection(ref, changedFiles);

assertThat(statusDetection.getStatusWithoutMetadata("foo", mockedFile)).isEqualTo(InputFile.Status.ADDED);

verify(mockedFile).path();
verify(mockedFile).relativePath();
verify(mockedFile).getProjectRelativePath();
verifyNoMoreInteractions(mockedFile);
}

@Test
public void detect_status_branches_confirm() {
ProjectRepositories ref = new ProjectRepositories(createTable(), null);
SingleProjectRepository ref = new SingleProjectRepository(createFileDataPerPathMap(), null);
ScmChangedFiles changedFiles = new ScmChangedFiles(Collections.singletonList(Paths.get("module", "src", "Foo.java")));
StatusDetection statusDetection = new StatusDetection(ref, changedFiles);

assertThat(statusDetection.status("foo", createFile("src/Foo.java"), "XXXXX")).isEqualTo(InputFile.Status.CHANGED);
}

private static Table<String, String, FileData> createTable() {
Table<String, String, FileData> t = HashBasedTable.create();
private static Map<String, FileData> createFileDataPerPathMap() {
Map<String, FileData> t = new HashMap<>();

t.put("foo", "src/Foo.java", new FileData("ABCDE", "12345789"));
t.put("foo", "src/Bar.java", new FileData("FGHIJ", "123456789"));
t.put("src/Foo.java", new FileData("ABCDE", "12345789"));
t.put("src/Bar.java", new FileData("FGHIJ", "123456789"));

return t;
}

+ 52
- 0
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepository.java Näytä tiedosto

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

import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

public class MultiModuleProjectRepository extends ProjectRepositories {
private Map<String, SingleProjectRepository> repositoryPerModule = Maps.newHashMap();

public ProjectRepositories addFileDataToModule(String moduleKey, @Nullable String path, FileData fileData) {
if (path == null || (fileData.hash() == null && fileData.revision() == null)) {
return this;
}

SingleProjectRepository repository = repositoryPerModule.computeIfAbsent(moduleKey, k -> new SingleProjectRepository());
repository.addFileData(path, fileData);
return this;
}

public Map<String, SingleProjectRepository> repositoriesByModule() {
return repositoryPerModule;
}

@CheckForNull
public FileData fileData(String moduleKeyWithBranch, @Nullable String path) {
Optional<SingleProjectRepository> moduleRepository = Optional.ofNullable(repositoryPerModule.get(moduleKeyWithBranch));
return moduleRepository
.map(singleProjectRepository -> singleProjectRepository.fileDataByPath(path))
.orElse(null);
}
}

+ 2
- 28
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/ProjectRepositories.java Näytä tiedosto

@@ -19,10 +19,7 @@
*/
package org.sonar.scanner.protocol.input;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

@@ -30,34 +27,11 @@ import javax.annotation.Nullable;
* Container for all project data going from server to batch.
* This is not an API since server and batch always share the same version.
*/
public class ProjectRepositories {
public abstract class ProjectRepositories {

private long timestamp;
private Map<String, Map<String, FileData>> fileDataByModuleAndPath = new HashMap<>();
private Date lastAnalysisDate;

public Map<String, Map<String, FileData>> fileDataByModuleAndPath() {
return fileDataByModuleAndPath;
}

public Map<String, FileData> fileDataByPath(String moduleKey) {
return fileDataByModuleAndPath.containsKey(moduleKey) ? fileDataByModuleAndPath.get(moduleKey) : Collections.<String, FileData>emptyMap();
}

public ProjectRepositories addFileData(String moduleKey, @Nullable String path, FileData fileData) {
if (path == null || (fileData.hash() == null && fileData.revision() == null)) {
return this;
}

Map<String, FileData> existingFileDataByPath = fileDataByModuleAndPath.computeIfAbsent(moduleKey, k -> new HashMap<>());
existingFileDataByPath.put(path, fileData);
return this;
}

@CheckForNull
public FileData fileData(String projectKey, String path) {
return fileDataByPath(projectKey).get(path);
}
private Date lastAnalysisDate;

public long timestamp() {
return timestamp;

+ 45
- 0
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/SingleProjectRepository.java Näytä tiedosto

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

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

public class SingleProjectRepository extends ProjectRepositories {
private Map<String, FileData> fileDataByPath = new HashMap<>();

public ProjectRepositories addFileData(@Nullable String path, FileData fileData) {
if (path == null || (fileData.hash() == null && fileData.revision() == null)) {
return this;
}

fileDataByPath.put(path, fileData);
return this;
}

public Map<String, FileData> fileData() {
return fileDataByPath;
}

public FileData fileDataByPath(@Nullable String path) {
return fileDataByPath.get(path);
}
}

+ 68
- 0
sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepositoryTest.java Näytä tiedosto

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

import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class MultiModuleProjectRepositoryTest {

private MultiModuleProjectRepository repository;

@Before
public void setUp() {
repository = new MultiModuleProjectRepository();
}

@Test
public void add_file_data_to_nodule() {
FileData fileData1 = new FileData("123", "456");
FileData fileData2 = new FileData("153", "6432");
FileData fileData3 = new FileData("987", "6343");

repository.addFileDataToModule("Module1", "/Abc.java", fileData1);
repository.addFileDataToModule("Module1", "/Xyz.java", fileData2);
repository.addFileDataToModule("Module2", "/Def.java", fileData3);

assertThat(repository.repositoriesByModule()).hasSize(2);
assertThat(repository.fileData("Module1", "/Xyz.java")).isEqualTo(fileData2);
assertThat(repository.fileData("Module2", "/Def.java")).isEqualTo(fileData3);
}

@Test
public void add_file_does_not_add_the_file_without_path() {
FileData fileData = new FileData("123", "456");

repository.addFileDataToModule("module1", null, fileData);

assertThat(repository.repositoriesByModule()).hasSize(0);
}

@Test
public void add_file_does_not_add_the_file_without_revision_and_hash() {
FileData fileData = new FileData(null, null);

repository.addFileDataToModule("module2", "/Abc.java", fileData);

assertThat(repository.repositoriesByModule()).hasSize(0);
}
}

+ 64
- 0
sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/SingleProjectRepositoryTest.java Näytä tiedosto

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

import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class SingleProjectRepositoryTest {
private SingleProjectRepository repository;

@Before
public void setUp() {
repository = new SingleProjectRepository();
}

@Test
public void add_file_data() {
FileData fileData = new FileData("123", "456");

repository.addFileData("/Abc.java", fileData);

assertThat(repository.fileData()).hasSize(1);
assertThat(repository.fileData()).contains(Maps.immutableEntry("/Abc.java", fileData));
assertThat(repository.fileDataByPath("/Abc.java")).isEqualTo(fileData);
}

@Test
public void add_file_data_doesnt_add_the_file_without_path() {
FileData fileData = new FileData("123", "456");

repository.addFileData(null, fileData);

assertThat(repository.fileData()).hasSize(0);
}

@Test
public void add_file_data_doesnt_add_the_file_without_revision_and_hash() {
FileData fileData = new FileData(null, null);

repository.addFileData("/Abc.java", fileData);

assertThat(repository.fileData()).hasSize(0);
}
}

+ 1
- 0
sonar-ws/src/main/protobuf/ws-batch.proto Näytä tiedosto

@@ -30,6 +30,7 @@ message WsProjectResponse {
optional int64 timestamp = 1;
map<string, FileDataByPath> fileDataByModuleAndPath = 3;
optional int64 lastAnalysisDate = 4;
map<string, FileData> fileDataByPath = 5;

message FileDataByPath {
map<string, FileData> FileDataByPath = 1;

Loading…
Peruuta
Tallenna