Browse Source

SONAR-17706 Drop support for modules in WS

tags/10.0.0.68432
Duarte Meneses 1 year ago
parent
commit
3d33985aa4
32 changed files with 92 additions and 864 deletions
  1. 0
    42
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ReportModulesPath.java
  2. 0
    2
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java
  3. 2
    83
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ProjectTrackerBaseLazyInput.java
  4. 2
    14
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactory.java
  5. 1
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java
  6. 0
    53
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ReportModulesPathTest.java
  7. 1
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
  8. 2
    79
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ProjectTrackerBaseLazyInputTest.java
  9. 1
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactoryTest.java
  10. 4
    6
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStepTest.java
  11. 2
    15
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
  12. 2
    17
      server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java
  13. 0
    5
      server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java
  14. 0
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java
  15. 6
    65
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
  16. 0
    13
      server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml
  17. 14
    38
      server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java
  18. 0
    92
      server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java
  19. 2
    2
      server/sonar-server-common/src/main/java/org/sonar/server/view/index/ViewIndexer.java
  20. 0
    2
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/IssuesAction.java
  21. 5
    25
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/ProjectAction.java
  22. 9
    37
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/ProjectDataLoader.java
  23. 6
    33
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/batch/ProjectActionTest.java
  24. 4
    37
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java
  25. 2
    16
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
  26. 0
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
  27. 0
    52
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepository.java
  28. 23
    1
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/ProjectRepositories.java
  29. 0
    45
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/SingleProjectRepository.java
  30. 2
    1
      sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
  31. 0
    68
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepositoryTest.java
  32. 2
    7
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/ProjectRepositoriesTest.java

+ 0
- 42
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ReportModulesPath.java View File

@@ -1,42 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.ce.task.projectanalysis.component;

import java.util.Map;
import java.util.function.Supplier;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
import org.sonar.scanner.protocol.output.ScannerReport;

public class ReportModulesPath implements Supplier<Map<String, String>> {
private final BatchReportReader reader;
private Map<String, String> cache;

public ReportModulesPath(BatchReportReader reader) {
this.reader = reader;
}

public Map<String, String> get() {
if (cache == null) {
ScannerReport.Metadata metadata = reader.readMetadata();
cache = metadata.getModulesProjectRelativePathByKeyMap();
}
return cache;
}
}

+ 0
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/container/ProjectAnalysisTaskContainerPopulator.java View File

@@ -38,7 +38,6 @@ import org.sonar.ce.task.projectanalysis.component.FileStatusesImpl;
import org.sonar.ce.task.projectanalysis.component.PreviousSourceHashRepositoryImpl;
import org.sonar.ce.task.projectanalysis.component.ProjectPersister;
import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.component.SiblingComponentsWithOpenIssues;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderImpl;
import org.sonar.ce.task.projectanalysis.duplication.CrossProjectDuplicationStatusHolderImpl;
@@ -198,7 +197,6 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop
// File System
new ComputationTempFolderProvider(),

ReportModulesPath.class,
FileStatusesImpl.class,
new MetricModule(),


+ 2
- 83
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/ProjectTrackerBaseLazyInput.java View File

@@ -19,102 +19,21 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.resources.Qualifiers;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.issue.IssueFieldsSetter;

import static org.apache.commons.lang.StringUtils.trimToEmpty;
import static org.sonar.core.issue.IssueChangeContext.issueChangeContextByUserBuilder;

class ProjectTrackerBaseLazyInput extends BaseInputFactory.BaseLazyInput {

private final AnalysisMetadataHolder analysisMetadataHolder;
private final ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues;
private final DbClient dbClient;
private final IssueFieldsSetter issueUpdater;
private final ComponentIssuesLoader issuesLoader;
private final ReportModulesPath reportModulesPath;

ProjectTrackerBaseLazyInput(AnalysisMetadataHolder analysisMetadataHolder, ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues, DbClient dbClient,
IssueFieldsSetter issueUpdater, ComponentIssuesLoader issuesLoader, ReportModulesPath reportModulesPath, Component component) {
ProjectTrackerBaseLazyInput(DbClient dbClient, ComponentIssuesLoader issuesLoader, Component component) {
super(dbClient, component, null);
this.analysisMetadataHolder = analysisMetadataHolder;
this.componentsWithUnprocessedIssues = componentsWithUnprocessedIssues;
this.dbClient = dbClient;
this.issueUpdater = issueUpdater;
this.issuesLoader = issuesLoader;
this.reportModulesPath = reportModulesPath;
}

@Override
protected List<DefaultIssue> loadIssues() {
List<DefaultIssue> result = new ArrayList<>();
try (DbSession dbSession = dbClient.openSession(false)) {
Set<String> dirOrModulesUuidsWithIssues = dbClient.issueDao().selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(dbSession, component.getUuid());
if (!dirOrModulesUuidsWithIssues.isEmpty()) {
Map<String, String> pathByModuleKey = reportModulesPath.get();
// Migrate issues that were previously on modules or directories to the root project
String branchKey = analysisMetadataHolder.isBranch() ? analysisMetadataHolder.getBranch().getName() : null;
String prKey = analysisMetadataHolder.isPullRequest() ? analysisMetadataHolder.getBranch().getPullRequestKey() : null;

Map<String, ComponentDto> modulesByUuid = dbClient.componentDao()
.selectProjectAndModulesFromProjectKey(dbSession, component.getKey(), true, branchKey, prKey)
.stream().collect(Collectors.toMap(ComponentDto::uuid, Function.identity()));
List<ComponentDto> dirOrModulesWithIssues = dbClient.componentDao().selectByUuids(dbSession, dirOrModulesUuidsWithIssues);
dirOrModulesWithIssues.forEach(c -> {
List<DefaultIssue> issuesOnModuleOrDir = issuesLoader.loadOpenIssues(c.uuid());
String moduleOrDirProjectRelativePath = c.qualifier().equals(Qualifiers.MODULE) ? buildModuleProjectRelativePath(pathByModuleKey, c)
: buildDirectoryProjectRelativePath(pathByModuleKey, c, modulesByUuid.get(c.moduleUuid()));
result.addAll(migrateIssuesToTheRoot(issuesOnModuleOrDir, moduleOrDirProjectRelativePath));
componentsWithUnprocessedIssues.remove(c.uuid());
});
}
result.addAll(issuesLoader.loadOpenIssues(effectiveUuid));
return result;
}
}

private static String buildDirectoryProjectRelativePath(Map<String, String> pathByModuleKey, ComponentDto c, ComponentDto parentModule) {
String moduleProjectRelativePath = buildModuleProjectRelativePath(pathByModuleKey, parentModule);
return Stream.of(moduleProjectRelativePath, c.path())
.map(StringUtils::trimToNull)
.filter(s -> s != null && !"/".equals(s))
.collect(Collectors.joining("/"));
}

private static String buildModuleProjectRelativePath(Map<String, String> pathByModuleKey, ComponentDto parentModule) {
return Optional.ofNullable(pathByModuleKey.get(parentModule.getKey()))
// If module is not in the scanner report, we can't guess the path accurately. Fallback on what we have in DB
.orElse(trimToEmpty(parentModule.path()));
}

private Collection<? extends DefaultIssue> migrateIssuesToTheRoot(List<DefaultIssue> issuesOnModule, String modulePath) {
for (DefaultIssue i : issuesOnModule) {
// changes the issue's component uuid, add a change and set issue as changed to enforce it is persisted to DB
IssueChangeContext context = issueChangeContextByUserBuilder(new Date(analysisMetadataHolder.getAnalysisDate()), null).build();
if (StringUtils.isNotBlank(modulePath)) {
issueUpdater.setMessage(i, "[" + modulePath + "] " + i.getMessage(), context);
}
issueUpdater.setIssueComponent(i, component.getUuid(), component.getKey(), context.date());
}
return issuesOnModule;
return issuesLoader.loadOpenIssues(effectiveUuid);
}
}

+ 2
- 14
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactory.java View File

@@ -22,15 +22,12 @@ package org.sonar.ce.task.projectanalysis.issue;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository.OriginalFile;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Input;
import org.sonar.db.DbClient;
import org.sonar.server.issue.IssueFieldsSetter;

/**
* Factory of {@link Input} of base data for issue tracking. Data are lazy-loaded.
@@ -40,25 +37,16 @@ public class TrackerBaseInputFactory extends BaseInputFactory {
private final ComponentIssuesLoader issuesLoader;
private final DbClient dbClient;
private final MovedFilesRepository movedFilesRepository;
private final ReportModulesPath reportModulesPath;
private final AnalysisMetadataHolder analysisMetadataHolder;
private final IssueFieldsSetter issueUpdater;
private final ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues;

public TrackerBaseInputFactory(ComponentIssuesLoader issuesLoader, DbClient dbClient, MovedFilesRepository movedFilesRepository, ReportModulesPath reportModulesPath,
AnalysisMetadataHolder analysisMetadataHolder, IssueFieldsSetter issueUpdater, ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues) {
public TrackerBaseInputFactory(ComponentIssuesLoader issuesLoader, DbClient dbClient, MovedFilesRepository movedFilesRepository) {
this.issuesLoader = issuesLoader;
this.dbClient = dbClient;
this.movedFilesRepository = movedFilesRepository;
this.reportModulesPath = reportModulesPath;
this.analysisMetadataHolder = analysisMetadataHolder;
this.issueUpdater = issueUpdater;
this.componentsWithUnprocessedIssues = componentsWithUnprocessedIssues;
}

public Input<DefaultIssue> create(Component component) {
if (component.getType() == Component.Type.PROJECT) {
return new ProjectTrackerBaseLazyInput(analysisMetadataHolder, componentsWithUnprocessedIssues, dbClient, issueUpdater, issuesLoader, reportModulesPath, component);
return new ProjectTrackerBaseLazyInput(dbClient, issuesLoader, component);
}

if (component.getType() == Component.Type.DIRECTORY) {

+ 1
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java View File

@@ -31,7 +31,6 @@ import org.sonar.ce.task.projectanalysis.component.ComponentUuidFactory;
import org.sonar.ce.task.projectanalysis.component.ComponentUuidFactoryImpl;
import org.sonar.ce.task.projectanalysis.component.MutableTreeRootHolder;
import org.sonar.ce.task.projectanalysis.component.ProjectAttributes;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -52,15 +51,13 @@ public class BuildComponentTreeStep implements ComputationStep {
private final BatchReportReader reportReader;
private final MutableTreeRootHolder treeRootHolder;
private final MutableAnalysisMetadataHolder analysisMetadataHolder;
private final ReportModulesPath reportModulesPath;

public BuildComponentTreeStep(DbClient dbClient, BatchReportReader reportReader, MutableTreeRootHolder treeRootHolder,
MutableAnalysisMetadataHolder analysisMetadataHolder, ReportModulesPath reportModulesPath) {
MutableAnalysisMetadataHolder analysisMetadataHolder) {
this.dbClient = dbClient;
this.reportReader = reportReader;
this.treeRootHolder = treeRootHolder;
this.analysisMetadataHolder = analysisMetadataHolder;
this.reportModulesPath = reportModulesPath;
}

@Override

+ 0
- 53
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ReportModulesPathTest.java View File

@@ -1,53 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.ce.task.projectanalysis.component;

import java.util.Map;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
import org.sonar.scanner.protocol.output.ScannerReport;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;

public class ReportModulesPathTest {
private BatchReportReader reader = mock(BatchReportReader.class);
private ReportModulesPath reportModulesPath = new ReportModulesPath(reader);

@Test
public void should_cache_report_data() {
when(reader.readMetadata()).thenReturn(ScannerReport.Metadata.newBuilder()
.putModulesProjectRelativePathByKey("module1", "path1")
.setRootComponentRef(1)
.build());
Map<String, String> pathByModuleKey = reportModulesPath.get();
assertThat(pathByModuleKey).containsExactly(entry("module1", "path1"));
pathByModuleKey = reportModulesPath.get();
assertThat(pathByModuleKey).containsExactly(entry("module1", "path1"));

verify(reader, times(1)).readMetadata();
verifyNoMoreInteractions(reader);
}
}

+ 1
- 3
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java View File

@@ -39,7 +39,6 @@ import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.FileStatuses;
import org.sonar.ce.task.projectanalysis.component.ReferenceBranchComponentUuids;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitor;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
@@ -152,8 +151,7 @@ public class IntegrateIssuesVisitorTest {
DbClient dbClient = dbTester.getDbClient();
TrackerRawInputFactory rawInputFactory = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash, new CommonRuleEngineImpl(), issueFilter,
ruleRepositoryRule, activeRulesHolder);
TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository, mock(ReportModulesPath.class), analysisMetadataHolder,
new IssueFieldsSetter(), mock(ComponentsWithUnprocessedIssues.class));
TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository);
TrackerTargetBranchInputFactory targetInputFactory = new TrackerTargetBranchInputFactory(issuesLoader, targetBranchComponentUuids, dbClient, movedFilesRepository);
TrackerReferenceBranchInputFactory mergeInputFactory = new TrackerReferenceBranchInputFactory(issuesLoader, mergeBranchComponentsUuids, dbClient);
ClosedIssuesInputFactory closedIssuesInputFactory = new ClosedIssuesInputFactory(issuesLoader, dbClient, movedFilesRepository);

+ 2
- 79
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/ProjectTrackerBaseLazyInputTest.java View File

@@ -19,8 +19,6 @@
*/
package org.sonar.ce.task.projectanalysis.issue;

import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.Date;
import org.junit.Before;
import org.junit.Rule;
@@ -30,7 +28,6 @@ import org.sonar.api.utils.System2;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.db.DbClient;
@@ -38,12 +35,10 @@ import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.issue.IssueFieldsSetter;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.api.utils.DateUtils.parseDate;
import static org.sonar.db.component.ComponentTesting.newDirectory;
import static org.sonar.db.component.ComponentTesting.newFileDto;
@@ -68,7 +63,6 @@ public class ProjectTrackerBaseLazyInputTest {
private ComponentDto rootProjectDto;
private ComponentIssuesLoader issuesLoader = new ComponentIssuesLoader(dbTester.getDbClient(), ruleRepositoryRule, activeRulesHolderRule, new MapSettings().asConfig(),
System2.INSTANCE, mock(IssueChangesToDeleteRepository.class));
private ReportModulesPath reportModulesPath;

@Before
public void prepare() {
@@ -78,13 +72,11 @@ public class ProjectTrackerBaseLazyInputTest {
ReportComponent rootProject = ReportComponent.builder(Component.Type.FILE, 1)
.setKey(rootProjectDto.getKey())
.setUuid(rootProjectDto.uuid()).build();
reportModulesPath = mock(ReportModulesPath.class);
underTest = new ProjectTrackerBaseLazyInput(analysisMetadataHolder, mock(ComponentsWithUnprocessedIssues.class), dbClient, new IssueFieldsSetter(), issuesLoader,
reportModulesPath, rootProject);
underTest = new ProjectTrackerBaseLazyInput(dbClient, issuesLoader, rootProject);
}

@Test
public void return_only_open_project_issues_if_no_modules_and_folders() {
public void return_only_open_project_issues_if_no_folders() {
ComponentDto file = dbTester.components().insertComponent(newFileDto(rootProjectDto));
IssueDto openIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("OPEN").setResolution(null));
IssueDto closedIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("CLOSED").setResolution("FIXED"));
@@ -92,73 +84,4 @@ public class ProjectTrackerBaseLazyInputTest {

assertThat(underTest.loadIssues()).extracting(DefaultIssue::key).containsOnly(openIssueOnProject.getKey());
}

@Test
public void migrate_and_return_folder_issues_on_root_project() {
when(reportModulesPath.get()).thenReturn(Collections.emptyMap());
ComponentDto folder = dbTester.components().insertComponent(newDirectory(rootProjectDto, "src"));
ComponentDto file = dbTester.components().insertComponent(newFileDto(rootProjectDto));
IssueDto openIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("OPEN").setResolution(null));
IssueDto openIssueOnDir = dbTester.issues().insert(rule, rootProjectDto, folder, i -> i.setStatus("OPEN").setMessage("Issue on dir").setResolution(null));
IssueDto openIssue1OnFile = dbTester.issues().insert(rule, rootProjectDto, file, i -> i.setStatus("OPEN").setResolution(null));

assertThat(underTest.loadIssues()).extracting(DefaultIssue::key, DefaultIssue::getMessage)
.containsExactlyInAnyOrder(
tuple(openIssueOnProject.getKey(), openIssueOnProject.getMessage()),
tuple(openIssueOnDir.getKey(), "[src] Issue on dir"));

}

@Test
public void migrate_and_return_module_and_folder_issues_on_module() {
ComponentDto module = dbTester.components().insertComponent(newModuleDto(rootProjectDto).setPath("moduleAInDb"));
when(reportModulesPath.get()).thenReturn(ImmutableMap.of(module.getKey(), "moduleAInReport"));
ComponentDto folder = dbTester.components().insertComponent(newDirectory(module, "src"));
ComponentDto file = dbTester.components().insertComponent(newFileDto(module));
IssueDto openIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("OPEN").setResolution(null));
IssueDto openIssueOnModule = dbTester.issues().insert(rule, rootProjectDto, module, i -> i.setStatus("OPEN").setMessage("Issue on module").setResolution(null));
IssueDto openIssueOnDir = dbTester.issues().insert(rule, rootProjectDto, folder, i -> i.setStatus("OPEN").setMessage("Issue on dir").setResolution(null));
IssueDto openIssue1OnFile = dbTester.issues().insert(rule, rootProjectDto, file, i -> i.setStatus("OPEN").setResolution(null));

assertThat(underTest.loadIssues()).extracting(DefaultIssue::key, DefaultIssue::getMessage)
.containsExactlyInAnyOrder(
tuple(openIssueOnProject.getKey(), openIssueOnProject.getMessage()),
tuple(openIssueOnModule.getKey(), "[moduleAInReport] Issue on module"),
tuple(openIssueOnDir.getKey(), "[moduleAInReport/src] Issue on dir"));

}

@Test
public void use_db_path_if_module_missing_in_report() {
ComponentDto module = dbTester.components().insertComponent(newModuleDto(rootProjectDto).setPath("moduleAInDb"));
when(reportModulesPath.get()).thenReturn(Collections.emptyMap());
ComponentDto folder = dbTester.components().insertComponent(newDirectory(module, "src"));
IssueDto openIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("OPEN").setResolution(null));
IssueDto openIssueOnModule = dbTester.issues().insert(rule, rootProjectDto, module, i -> i.setStatus("OPEN").setMessage("Issue on module").setResolution(null));
IssueDto openIssueOnDir = dbTester.issues().insert(rule, rootProjectDto, folder, i -> i.setStatus("OPEN").setMessage("Issue on dir").setResolution(null));

assertThat(underTest.loadIssues()).extracting(DefaultIssue::key, DefaultIssue::getMessage)
.containsExactlyInAnyOrder(
tuple(openIssueOnProject.getKey(), openIssueOnProject.getMessage()),
tuple(openIssueOnModule.getKey(), "[moduleAInDb] Issue on module"),
tuple(openIssueOnDir.getKey(), "[moduleAInDb/src] Issue on dir"));

}

@Test
public void empty_path_if_module_missing_in_report_and_db_and_for_slash_folder() {
ComponentDto module = dbTester.components().insertComponent(newModuleDto(rootProjectDto).setPath(null));
when(reportModulesPath.get()).thenReturn(Collections.emptyMap());
ComponentDto folder = dbTester.components().insertComponent(newDirectory(module, "/"));
IssueDto openIssueOnProject = dbTester.issues().insert(rule, rootProjectDto, rootProjectDto, i -> i.setStatus("OPEN").setResolution(null));
IssueDto openIssueOnModule = dbTester.issues().insert(rule, rootProjectDto, module, i -> i.setStatus("OPEN").setMessage("Issue on module").setResolution(null));
IssueDto openIssueOnDir = dbTester.issues().insert(rule, rootProjectDto, folder, i -> i.setStatus("OPEN").setMessage("Issue on dir").setResolution(null));

assertThat(underTest.loadIssues()).extracting(DefaultIssue::key, DefaultIssue::getMessage)
.containsExactlyInAnyOrder(
tuple(openIssueOnProject.getKey(), openIssueOnProject.getMessage()),
tuple(openIssueOnModule.getKey(), "Issue on module"),
tuple(openIssueOnDir.getKey(), "Issue on dir"));

}
}

+ 1
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerBaseInputFactoryTest.java View File

@@ -25,14 +25,12 @@ import org.junit.Test;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Input;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDao;
import org.sonar.server.issue.IssueFieldsSetter;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -57,8 +55,7 @@ public class TrackerBaseInputFactoryTest {

private MovedFilesRepository movedFilesRepository = mock(MovedFilesRepository.class);

private TrackerBaseInputFactory underTest = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository, mock(ReportModulesPath.class), analysisMetadataHolder,
new IssueFieldsSetter(), mock(ComponentsWithUnprocessedIssues.class));
private TrackerBaseInputFactory underTest = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository);

@Before
public void setUp() {

+ 4
- 6
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStepTest.java View File

@@ -36,7 +36,6 @@ import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
import org.sonar.ce.task.projectanalysis.component.MutableTreeRootHolderRule;
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.step.TestComputationStepContext;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
@@ -94,10 +93,9 @@ public class BuildComponentTreeStepTest {
public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule();
@Rule
public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule();
private ReportModulesPath reportModulesPath = new ReportModulesPath(reportReader);

private DbClient dbClient = dbTester.getDbClient();
private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, reportModulesPath);
private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);

@Test
public void fails_if_root_component_does_not_exist_in_reportReader() {
@@ -263,7 +261,7 @@ public class BuildComponentTreeStepTest {
.setAnalysisDate(ANALYSIS_DATE)
.setProject(Project.from(newPrivateProjectDto().setKey(REPORT_PROJECT_KEY)))
.setBranch(branch);
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, reportModulesPath);
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));

@@ -286,7 +284,7 @@ public class BuildComponentTreeStepTest {
.setAnalysisDate(ANALYSIS_DATE)
.setProject(Project.from(projectDto))
.setBranch(branch);
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, reportModulesPath);
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
reportReader.putComponent(component(ROOT_REF, PROJECT, componentDto.getKey()));

underTest.execute(new TestComputationStepContext());
@@ -297,7 +295,7 @@ public class BuildComponentTreeStepTest {
@Test
public void generate_keys_when_using_main_branch() {
setAnalysisMetadataHolder();
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, reportModulesPath);
BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));


+ 2
- 15
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java View File

@@ -82,12 +82,8 @@ public class ComponentDao implements Dao {
return mapper(session).selectSubProjectsByComponentUuids(uuids);
}

public List<ComponentDto> selectEnabledDescendantModules(DbSession session, String rootComponentUuid) {
return mapper(session).selectDescendantModules(rootComponentUuid, Scopes.PROJECT, true);
}

public List<FilePathWithHashDto> selectEnabledDescendantFiles(DbSession session, String rootComponentUuid) {
return mapper(session).selectDescendantFiles(rootComponentUuid, Scopes.FILE, true);
public List<ComponentDto> selectEnabledViewsFromRootView(DbSession session, String rootViewUuid) {
return mapper(session).selectEnabledViewsFromRootView(rootViewUuid);
}

public List<FilePathWithHashDto> selectEnabledFilesFromProject(DbSession session, String rootComponentUuid) {
@@ -158,15 +154,6 @@ public class ComponentDao implements Dao {
return mapper(session).selectUuidsByKeyFromProjectKeyAndBranchOrPr(projectKey, null, pullrequest);
}

/**
* If no branch or pull request is provided, returns components in the main branch
*/
public List<ComponentDto> selectProjectAndModulesFromProjectKey(DbSession session, String projectKey, boolean excludeDisabled,
@Nullable String branch, @Nullable String pullRequest) {
checkState(branch == null || pullRequest == null, "Can't set both branch and pull request");
return mapper(session).selectComponentsFromProjectKeyAndScope(projectKey, Scopes.PROJECT, excludeDisabled, branch, pullRequest);
}

public List<ComponentDto> selectByKeys(DbSession session, Collection<String> keys) {
return selectByKeys(session, keys, null, null);
}

+ 2
- 17
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java View File

@@ -70,22 +70,15 @@ public interface ComponentMapper {
List<ComponentDto> selectProjects();

/**
* Return all descendant modules (including itself) from a given component uuid and scope
* Return all descendant views (including itself) from a given root view
*/
List<ComponentDto> selectDescendantModules(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope,
@Param(value = "excludeDisabled") boolean excludeDisabled);
List<ComponentDto> selectEnabledViewsFromRootView(@Param("rootViewUuid") String rootViewUuid);

/**
* Return all files from a given project uuid and scope
*/
List<FilePathWithHashDto> selectEnabledFilesFromProject(@Param("projectUuid") String projectUuid);

/**
* Return all descendant files from a given module uuid and scope
*/
List<FilePathWithHashDto> selectDescendantFiles(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope,
@Param(value = "excludeDisabled") boolean excludeDisabled);

/**
* Return uuids and project uuids from list of qualifiers
* <p/>
@@ -93,14 +86,6 @@ public interface ComponentMapper {
*/
List<UuidWithBranchUuidDto> selectUuidsForQualifiers(@Param("qualifiers") String... qualifiers);

/**
* Return components of a given scope of a project
*
* @param scope scope of components to return. If null, all components are returned
*/
List<ComponentDto> selectComponentsFromProjectKeyAndScope(@Param("projectKey") String projectKey, @Nullable @Param("scope") String scope,
@Param(value = "excludeDisabled") boolean excludeDisabled, @Nullable @Param("branch") String branch, @Nullable @Param("pullRequest") String pullRequest);

/**
* Return keys and UUIDs of all components belonging to a project
*/

+ 0
- 5
server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDao.java View File

@@ -30,7 +30,6 @@ import org.sonar.db.RowNotFoundException;
import org.sonar.db.WildcardPosition;
import org.sonar.db.component.ComponentDto;

import static java.util.Collections.emptyList;
import static org.sonar.db.DaoUtils.buildLikeValue;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;

@@ -86,10 +85,6 @@ public class IssueDao implements Dao {
return mapper(session).selectComponentUuidsOfOpenIssuesForProjectUuid(projectUuid);
}

public Set<String> selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(DbSession session, String projectUuid) {
return mapper(session).selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(projectUuid);
}

public List<IssueDto> selectNonClosedByComponentUuidExcludingExternalsAndSecurityHotspots(DbSession dbSession, String componentUuid) {
return mapper(dbSession).selectNonClosedByComponentUuidExcludingExternals(componentUuid);
}

+ 0
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueMapper.java View File

@@ -34,8 +34,6 @@ public interface IssueMapper {

Set<String> selectComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid);

Set<String> selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(String projectUuid);

List<IssueDto> selectByKeys(List<String> keys);

Set<String> selectIssueKeysByComponentUuid(@Param("componentUuid") String componentUuid);

+ 6
- 65
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml View File

@@ -177,33 +177,16 @@
</foreach>
</select>

<select id="selectDescendantModules" parameterType="map" resultType="Component">
<select id="selectEnabledViewsFromRootView" parameterType="map" resultType="Component">
SELECT
<include refid="componentColumns"/>
FROM components p
<include refid="modulesTreeQuery"/>
</select>

<sql id="modulesTreeQuery">
INNER JOIN components module ON
module.branch_uuid = p.branch_uuid
and module.uuid = #{moduleUuid}
and module.scope='PRJ' AND module.enabled = ${_true}
where
p.scope = #{scope,jdbcType=VARCHAR}
<if test="excludeDisabled">
and p.enabled = ${_true}
</if>
and
<choose>
<when test="_databaseId == 'mssql'">
p.module_uuid_path LIKE module.module_uuid_path + '%'
</when>
<otherwise>
p.module_uuid_path LIKE module.module_uuid_path || '%'
</otherwise>
</choose>
</sql>
p.enabled=${_true}
and p.scope='PRJ'
and p.qualifier in ('VW', 'SVW', 'APP')
and p.branch_uuid=#{rootViewUuid,jdbcType=VARCHAR}
</select>

<select id="selectEnabledFilesFromProject" parameterType="map" resultType="FilePathWithHash">
SELECT
@@ -223,19 +206,6 @@
root.uuid=#{projectUuid,jdbcType=VARCHAR}
</select>

<select id="selectDescendantFiles" parameterType="map" resultType="FilePathWithHash">
SELECT
p.uuid,
p.path,
p.module_uuid as moduleUuid,
fs.src_hash as srcHash,
fs.revision
FROM components p
INNER JOIN file_sources fs ON
fs.file_uuid=p.uuid
<include refid="modulesTreeQuery"/>
</select>

<select id="selectProjects" resultType="Component">
select
<include refid="componentColumns"/>
@@ -494,35 +464,6 @@
and p.copy_component_uuid is not null
</select>

<select id="selectComponentsFromProjectKeyAndScope" parameterType="map" resultType="Component">
SELECT
<include refid="componentColumns"/>
FROM components p
INNER JOIN components root ON root.uuid=p.branch_uuid AND root.kee=#{projectKey,jdbcType=VARCHAR}
<if test="branch != null || pullRequest != null">
INNER JOIN project_branches pb ON pb.uuid=p.branch_uuid
</if>
<where>
<if test="excludeDisabled">
p.enabled = ${_true}
</if>
<if test="scope != null">
AND p.scope=#{scope,jdbcType=VARCHAR}
</if>
<choose>
<when test="branch != null">
AND pb.kee=#{branch,jdbcType=VARCHAR} AND pb.branch_type = 'BRANCH'
</when>
<when test="pullRequest != null">
AND pb.kee=#{pullRequest,jdbcType=VARCHAR} AND pb.branch_type = 'PULL_REQUEST'
</when>
<otherwise>
AND root.main_branch_project_uuid is null
</otherwise>
</choose>
</where>
</select>

<select id="selectByBranchUuid" parameterType="map" resultType="Component">
SELECT
<include refid="componentColumns"/>

+ 0
- 13
server/sonar-db-dao/src/main/resources/org/sonar/db/issue/IssueMapper.xml View File

@@ -272,19 +272,6 @@
i.kee, ic.issue_change_creation_date desc
</select>

<select id="selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid" parameterType="string" resultType="string">
select
distinct(i.component_uuid)
from issues i
inner join components p on
p.uuid = i.component_uuid
and p.enabled = ${_true}
where
i.project_uuid=#{projectUuid,jdbcType=VARCHAR}
and i.status &lt;&gt; 'CLOSED'
and (p.qualifier = 'DIR' OR p.qualifier = 'BRC')
</select>

<select id="selectComponentUuidsOfOpenIssuesForProjectUuid" parameterType="string" resultType="string">
select distinct(i.component_uuid)
from issues i

+ 14
- 38
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java View File

@@ -456,44 +456,7 @@ public class ComponentDaoTest {
}

@Test
public void select_enabled_module_files_tree_from_module() {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto module = db.components().insertComponent(newModuleDto(project));
ComponentDto fileDirectlyOnModule = db.components().insertComponent(newFileDto(module));
FileSourceDto fileSourceDirectlyOnModule = db.fileSources().insertFileSource(fileDirectlyOnModule);
ComponentDto subModule = db.components().insertComponent(newModuleDto(module));
ComponentDto directory = db.components().insertComponent(newDirectory(subModule, "src"));
ComponentDto file = db.components().insertComponent(newFileDto(subModule, directory));
FileSourceDto fileSource = db.fileSources().insertFileSource(file);

// From root project
assertThat(underTest.selectEnabledDescendantFiles(dbSession, project.uuid()))
.extracting(FilePathWithHashDto::getUuid, FilePathWithHashDto::getModuleUuid, FilePathWithHashDto::getSrcHash, FilePathWithHashDto::getPath, FilePathWithHashDto::getRevision)
.containsExactlyInAnyOrder(
tuple(fileDirectlyOnModule.uuid(), module.uuid(), fileSourceDirectlyOnModule.getSrcHash(), fileDirectlyOnModule.path(), fileSourceDirectlyOnModule.getRevision()),
tuple(file.uuid(), subModule.uuid(), fileSource.getSrcHash(), file.path(), fileSource.getRevision()));

// From module
assertThat(underTest.selectEnabledDescendantFiles(dbSession, module.uuid()))
.extracting(FilePathWithHashDto::getUuid, FilePathWithHashDto::getModuleUuid, FilePathWithHashDto::getSrcHash, FilePathWithHashDto::getPath, FilePathWithHashDto::getRevision)
.containsExactlyInAnyOrder(
tuple(fileDirectlyOnModule.uuid(), module.uuid(), fileSourceDirectlyOnModule.getSrcHash(), fileDirectlyOnModule.path(), fileSourceDirectlyOnModule.getRevision()),
tuple(file.uuid(), subModule.uuid(), fileSource.getSrcHash(), file.path(), fileSource.getRevision()));

// From sub module
assertThat(underTest.selectEnabledDescendantFiles(dbSession, subModule.uuid()))
.extracting(FilePathWithHashDto::getUuid, FilePathWithHashDto::getModuleUuid, FilePathWithHashDto::getSrcHash, FilePathWithHashDto::getPath, FilePathWithHashDto::getRevision)
.containsExactlyInAnyOrder(
tuple(file.uuid(), subModule.uuid(), fileSource.getSrcHash(), file.path(), fileSource.getRevision()));

// From directory
assertThat(underTest.selectEnabledDescendantFiles(dbSession, directory.uuid())).isEmpty();

assertThat(underTest.selectEnabledDescendantFiles(dbSession, "unknown")).isEmpty();
}

@Test
public void select_enabled_module_files_tree_from_project() {
public void select_enabled_files_from_project() {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto module = db.components().insertComponent(newModuleDto(project));
ComponentDto fileDirectlyOnModule = db.components().insertComponent(newFileDto(module));
@@ -930,6 +893,19 @@ public class ComponentDaoTest {
assertThat(underTest.selectProjectsFromView(dbSession, "Unknown", "Unknown")).isEmpty();
}

@Test
public void select_enabled_views_from_root_view() {
ComponentDto rootPortfolio = db.components().insertPrivatePortfolio();
ComponentDto subPortfolio = db.components().insertSubView(rootPortfolio);
ComponentDto project = db.components().insertPrivateProject();
db.components().insertComponent(newProjectCopy(project, subPortfolio));

assertThat(underTest.selectEnabledViewsFromRootView(dbSession, rootPortfolio.uuid()))
.extracting(ComponentDto::uuid)
.containsOnly(rootPortfolio.uuid(), subPortfolio.uuid());
assertThat(underTest.selectEnabledViewsFromRootView(dbSession, project.uuid())).isEmpty();
}

@Test
public void select_projects_from_view_should_escape_like_sensitive_characters() {
ComponentDto project1 = db.components().insertPrivateProject();

+ 0
- 92
server/sonar-db-dao/src/test/java/org/sonar/db/issue/IssueDaoTest.java View File

@@ -526,98 +526,6 @@ public class IssueDaoTest {
assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isOne();
}

@Test
public void selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid() {
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), randomAlphabetic(12)))
.isEmpty();

ComponentDto project1 = db.components().insertPrivateProject();
ComponentDto module11 = db.components().insertComponent(newModuleDto(project1));
ComponentDto dir11 = db.components().insertComponent(newDirectory(module11, randomAlphabetic(10)));
ComponentDto dir12 = db.components().insertComponent(newDirectory(module11, randomAlphabetic(11)));
ComponentDto module12 = db.components().insertComponent(newModuleDto(project1));
ComponentDto dir13 = db.components().insertComponent(newDirectory(module12, randomAlphabetic(12)));
ComponentDto dir14 = db.components().insertComponent(newDirectory(project1, randomAlphabetic(13)));
ComponentDto file11 = db.components().insertComponent(newFileDto(project1));
ComponentDto application = db.components().insertPrivateApplication();
ComponentDto view = db.components().insertPublicPortfolio();
ComponentDto subview = db.components().insertSubView(view);
ComponentDto project2 = db.components().insertPublicProject();
ComponentDto module21 = db.components().insertComponent(newModuleDto(project2));
ComponentDto dir21 = db.components().insertComponent(newDirectory(project2, randomAlphabetic(15)));
ComponentDto file21 = db.components().insertComponent(newFileDto(project2));
List<ComponentDto> allcomponents = asList(project1, module11, dir11, dir12, module12, dir13, dir14, file11, application, view, subview, project2, module21, dir21, file21);
List<ComponentDto> allModuleOrDirs = asList(module11, dir11, dir12, module12, dir13, dir14, module21, dir21);

// no issues => always empty
allcomponents.stream()
.map(ComponentDto::uuid)
.forEach(uuid -> assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), uuid))
.isEmpty());

// return module or dir only if has issue with status different from CLOSED
allModuleOrDirs
.forEach(moduleOrDir -> {
String projectUuid = moduleOrDir.branchUuid();
// CLOSED issue => not returned
db.issues().insertIssue(t -> t.setProjectUuid(projectUuid).setComponent(moduleOrDir).setStatus(STATUS_CLOSED));
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.isEmpty();

// status != CLOSED => returned
STATUSES.stream()
.filter(t -> !STATUS_CLOSED.equals(t))
.forEach(status -> {
IssueDto issue = db.issues().insertIssue(t -> t.setProjectUuid(projectUuid).setComponent(moduleOrDir).setStatus(status));
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.containsOnly(moduleOrDir.uuid());

db.executeDdl("delete from issues where kee='" + issue.getKey() + "'");
db.commit();
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.isEmpty();
});
});

// never return project, view, subview, app or file, whatever the issue status
Stream.of(project1, file11, application, view, subview, project2, file21)
.forEach(neitherModuleNorDir -> {
String projectUuid = neitherModuleNorDir.branchUuid();
STATUSES
.forEach(status -> {
db.issues().insertIssue(t -> t.setProjectUuid(projectUuid).setComponent(neitherModuleNorDir).setStatus(status));
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.isEmpty();
});
});

// never return whatever the component if it is disabled
allcomponents
.forEach(component -> {
String projectUuid = component.branchUuid();

// issues for each status => returned if component is dir or module
STATUSES
.forEach(status -> db.issues().insertIssue(t -> t.setProjectUuid(projectUuid).setComponent(component).setStatus(status)));
if (allModuleOrDirs.contains(component)) {
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.containsOnly(component.uuid());
} else {
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.isEmpty();
}

// disable component and test again => not returned anymore
db.getDbClient().componentDao().update(db.getSession(), ComponentUpdateDto.copyFrom(component).setBEnabled(false).setBChanged(true), component.qualifier());
db.getDbClient().componentDao().applyBChangesForRootComponentUuid(db.getSession(), projectUuid);
db.commit();
assertThat(db.getDbClient().componentDao().selectByUuid(db.getSession(), component.uuid()).get().isEnabled())
.isFalse();
assertThat(underTest.selectModuleAndDirComponentUuidsOfOpenIssuesForProjectUuid(db.getSession(), projectUuid))
.isEmpty();
});
}

@Test
public void selectByKey_givenOneIssueNewOnReferenceBranch_selectOneIssueWithNewOnReferenceBranch() {
prepareIssuesComponent();

+ 2
- 2
server/sonar-server-common/src/main/java/org/sonar/server/view/index/ViewIndexer.java View File

@@ -79,7 +79,7 @@ public class ViewIndexer implements ResilientIndexer {
}

/**
* Index a root view : it will load projects on each sub views and index it.
* Index a root view : it will a view and its subviews and index them.
* Used by the compute engine to reindex a root view.
* <p/>
* The views lookup cache will be cleared
@@ -87,7 +87,7 @@ public class ViewIndexer implements ResilientIndexer {
public void index(String rootViewUuid) {
try (DbSession dbSession = dbClient.openSession(false)) {
Map<String, String> viewAndProjectViewUuidMap = new HashMap<>();
for (ComponentDto viewOrSubView : dbClient.componentDao().selectEnabledDescendantModules(dbSession, rootViewUuid)) {
for (ComponentDto viewOrSubView : dbClient.componentDao().selectEnabledViewsFromRootView(dbSession, rootViewUuid)) {
viewAndProjectViewUuidMap.put(viewOrSubView.uuid(), viewOrSubView.branchUuid());
}
index(dbSession, viewAndProjectViewUuidMap, true, Size.REGULAR);

+ 0
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/IssuesAction.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.batch;

import com.google.common.base.Splitter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -52,7 +51,6 @@ public class IssuesAction implements BatchWsAction {

private static final String PARAM_KEY = "key";
private static final String PARAM_BRANCH = "branch";
private static final Splitter MODULE_PATH_SPLITTER = Splitter.on('.').trimResults().omitEmptyStrings();

private final DbClient dbClient;
private final UserSession userSession;

+ 5
- 25
server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/ProjectAction.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.batch;

import com.google.common.collect.Maps;
import java.util.Map;
import java.util.stream.Collectors;
import org.sonar.api.server.ws.Change;
@@ -27,9 +26,7 @@ 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;

@@ -61,14 +58,15 @@ public class ProjectAction implements BatchWsAction {
.setChangelog(
new Change("7.6", String.format("The use of module keys in parameter '%s' is deprecated", PARAM_KEY)),
new Change("7.6", "Stop returning settings"),
new Change("7.7", "Stop supporting preview mode, removed timestamp and last analysis date"))
new Change("7.7", "Stop supporting preview mode, removed timestamp and last analysis date"),
new Change("10.0", String.format("No longer possible to use module keys with parameter '%s'", PARAM_KEY)))
.setInternal(true)
.setHandler(this);

action
.createParam(PARAM_KEY)
.setRequired(true)
.setDescription("Project or module key")
.setDescription("Project key")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);

action
@@ -103,34 +101,16 @@ public class ProjectAction implements BatchWsAction {

private static WsProjectResponse buildResponse(ProjectRepositories data) {
WsProjectResponse.Builder response = WsProjectResponse.newBuilder();
if (data instanceof SingleProjectRepository singleProjectRepository) {
response.putAllFileDataByPath(buildFileDataByPath(singleProjectRepository));
} else {
response.putAllFileDataByModuleAndPath(buildFileDataByModuleAndPath((MultiModuleProjectRepository) data));
}

response.putAllFileDataByPath(buildFileDataByPath(data));
return response.build();
}

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));
}

private static Map<String, WsProjectResponse.FileData> buildFileDataByPath(SingleProjectRepository data) {
private static Map<String, WsProjectResponse.FileData> buildFileDataByPath(ProjectRepositories 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();
fileDataByPath.forEach((key, value) -> response.putFileDataByPath(key, toFileDataResponse(value)));
return response.build();
}

private static WsProjectResponse.FileData toFileDataResponse(FileData fileData) {
Builder fileDataBuilder = WsProjectResponse.FileData.newBuilder();
ofNullable(fileData.hash()).ifPresent(fileDataBuilder::setHash);

+ 9
- 37
server/sonar-webserver-webapi/src/main/java/org/sonar/server/batch/ProjectDataLoader.java View File

@@ -20,9 +20,7 @@
package org.sonar.server.batch;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
@@ -32,9 +30,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.FilePathWithHashDto;
import org.sonar.db.permission.GlobalPermission;
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;
@@ -64,48 +60,24 @@ public class ProjectDataLoader {
boolean hasScanPerm = userSession.hasComponentPermission(UserRole.SCAN, project) ||
userSession.hasPermission(GlobalPermission.SCAN);
checkPermission(hasScanPerm);
ComponentDto branchOrMainModule = (branch == null && pullRequest == null) ? project
ComponentDto branchComponent = (branch == null && pullRequest == null) ? project
: componentFinder.getByKeyAndOptionalBranchOrPullRequest(session, projectKey, branch, pullRequest);

List<ComponentDto> modulesTree = dbClient.componentDao().selectEnabledDescendantModules(session, branchOrMainModule.uuid());

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

// 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
if (modulesTree.size() > 1) {
MultiModuleProjectRepository repository = new MultiModuleProjectRepository();
addFileDataPerModule(repository, modulesTree, files);
return repository;
} else {
SingleProjectRepository repository = new SingleProjectRepository();
addFileData(repository, files);
return repository;
}
List<FilePathWithHashDto> files = searchFilesWithHashAndRevision(session, branchComponent);
ProjectRepositories repository = new ProjectRepositories();
addFileData(repository, files);
return repository;
}
}

private List<FilePathWithHashDto> searchFilesWithHashAndRevision(DbSession session, @Nullable ComponentDto module) {
if (module == null) {
private List<FilePathWithHashDto> searchFilesWithHashAndRevision(DbSession session, @Nullable ComponentDto branchComponent) {
if (branchComponent == null) {
return Collections.emptyList();
}
return module.isRootProject() ? dbClient.componentDao().selectEnabledFilesFromProject(session, module.uuid())
: dbClient.componentDao().selectEnabledDescendantFiles(session, module.uuid());
}

private static void addFileDataPerModule(MultiModuleProjectRepository data, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
Map<String, String> moduleKeysByUuid = new HashMap<>();
for (ComponentDto module : moduleChildren) {
moduleKeysByUuid.put(module.uuid(), module.getKey());
}

for (FilePathWithHashDto file : files) {
FileData fileData = new FileData(file.getSrcHash(), file.getRevision());
data.addFileDataToModule(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
}
return dbClient.componentDao().selectEnabledFilesFromProject(session, branchComponent.uuid());
}

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

+ 6
- 33
server/sonar-webserver-webapi/src/test/java/org/sonar/server/batch/ProjectActionTest.java View File

@@ -22,9 +22,7 @@ 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;
@@ -36,15 +34,14 @@ import static org.mockito.Mockito.when;
import static org.sonar.test.JsonAssert.assertJson;

public class ProjectActionTest {

private ProjectDataLoader projectDataLoader = mock(ProjectDataLoader.class);
private WsActionTester ws = new WsActionTester(new ProjectAction(projectDataLoader));
private final ProjectDataLoader projectDataLoader = mock(ProjectDataLoader.class);
private final WsActionTester ws = new WsActionTester(new ProjectAction(projectDataLoader));

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

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

ArgumentCaptor<ProjectDataQuery> queryArgumentCaptor = ArgumentCaptor.forClass(ProjectDataQuery.class);
when(projectDataLoader.load(queryArgumentCaptor.capture())).thenReturn(projectReferentials);
@@ -69,8 +66,8 @@ public class ProjectActionTest {
public void do_not_fail_when_a_path_is_null() {
String projectKey = "org.codehaus.sonar:sonar";

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

WsProjectResponse wsProjectResponse = ws.newRequest()
@@ -84,7 +81,7 @@ public class ProjectActionTest {
public void use_new_file_structure_for_projects_without_submodules() {
String projectKey = "org.codehaus.sonar:sonar";

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

@@ -96,28 +93,4 @@ public class ProjectActionTest {
assertThat(wsProjectResponse.getFileDataByPathCount()).isOne();
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()).isOne();
WsProjectResponse.FileDataByPath moduleData = wsProjectResponse.getFileDataByModuleAndPathMap().get("module-1");
assertThat(moduleData).isNotNull();
assertThat(moduleData.getFileDataByPathCount()).isOne();
WsProjectResponse.FileData fileData = moduleData.getFileDataByPathMap().get("src/main/java/SomeClass.java");
assertThat(fileData).isNotNull();
assertThat(fileData.getHash()).isEqualTo("789456");
assertThat(fileData.getRevision()).isEqualTo("123456789");
}
}

+ 4
- 37
server/sonar-webserver-webapi/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java View File

@@ -32,9 +32,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
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;
@@ -86,59 +84,28 @@ public class ProjectDataLoaderTest {
dbClient.fileSourceDao().insert(dbSession, newFileSourceDto(file).setSrcHash("123456"));
db.commit();

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

assertTrue(ref instanceof SingleProjectRepository);
SingleProjectRepository singleProjectRepository = ((SingleProjectRepository) ref);
assertThat(singleProjectRepository.fileData()).hasSize(1);
FileData fileData = singleProjectRepository.fileDataByPath(file.path());
ProjectRepositories projectRepository = underTest.load(ProjectDataQuery.create().setProjectKey(project.getKey()));
assertThat(projectRepository.fileData()).hasSize(1);
FileData fileData = projectRepository.fileDataByPath(file.path());
assertThat(fileData).isNotNull();
assertThat(fileData.hash()).isEqualTo("123456");
}

@Test
public void return_file_data_from_multi_modules() {
ComponentDto project = db.components().insertPrivateProject();
userSession.logIn().addProjectPermission(SCAN_EXECUTION, project);
ComponentDto module = db.components().insertComponent(newModuleDto(project));
// File on project
ComponentDto projectFile = db.components().insertComponent(newFileDto(project));
dbClient.fileSourceDao().insert(dbSession, newFileSourceDto(projectFile).setSrcHash("123456"));
// File on module
ComponentDto moduleFile = db.components().insertComponent(newFileDto(module));
dbClient.fileSourceDao().insert(dbSession, newFileSourceDto(moduleFile).setSrcHash("789456"));
dbSession.commit();

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

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
public void return_file_data_from_branch() {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
userSession.logIn().addProjectPermission(SCAN_EXECUTION, project);
ComponentDto moduleBranch = db.components().insertComponent(newModuleDto(branch));
// File on branch
ComponentDto projectFile = db.components().insertComponent(newFileDto(branch));
dbClient.fileSourceDao().insert(dbSession, newFileSourceDto(projectFile).setSrcHash("123456"));
// File on moduleBranch branch
ComponentDto moduleFile = db.components().insertComponent(newFileDto(moduleBranch));
dbClient.fileSourceDao().insert(dbSession, newFileSourceDto(moduleFile).setSrcHash("789456"));
dbSession.commit();

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

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");
assertThat(ref.fileDataByPath(projectFile.path()).hash()).isEqualTo("123456");
}

@Test

+ 2
- 16
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java View File

@@ -21,11 +21,9 @@ package org.sonar.scanner.report;

import java.io.File;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -112,24 +110,12 @@ public class MetadataPublisher implements ReportPublisherStep {
.setUpdatedAt(pluginEntry.getValue().getUpdatedAt()).build());
}

addModulesRelativePaths(builder);
addRelativePathFromScmRoot(builder);

writer.writeMetadata(builder.build());
}

private void addModulesRelativePaths(ScannerReport.Metadata.Builder builder) {
LinkedList<DefaultInputModule> queue = new LinkedList<>();
queue.add(moduleHierarchy.root());

while (!queue.isEmpty()) {
DefaultInputModule module = queue.removeFirst();
queue.addAll(moduleHierarchy.children(module));
String relativePath = moduleHierarchy.relativePathToRoot(module);
if (relativePath != null) {
builder.putModulesProjectRelativePathByKey(module.key(), relativePath);
}
}

private void addRelativePathFromScmRoot(ScannerReport.Metadata.Builder builder) {
ScmProvider scmProvider = scmConfiguration.provider();
if (scmProvider == null) {
return;

+ 0
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java View File

@@ -138,7 +138,6 @@ public class MetadataPublisherTest {
assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
assertThat(metadata.getNewCodeReferenceBranch()).isEqualTo("newCodeReference");
assertThat(metadata.getProjectKey()).isEqualTo("root");
assertThat(metadata.getModulesProjectRelativePathByKeyMap()).containsOnly(entry("module", "modulePath"), entry("root", ""));
assertThat(metadata.getProjectVersion()).isEmpty();
assertThat(metadata.getNotAnalyzedFilesByLanguageCount()).isZero();
assertThat(metadata.getQprofilesPerLanguageMap()).containsOnly(entry("java", org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile.newBuilder()

+ 0
- 52
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepository.java View File

@@ -1,52 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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 java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

public class MultiModuleProjectRepository implements ProjectRepositories {
private Map<String, SingleProjectRepository> repositoryPerModule = new HashMap<>();

public MultiModuleProjectRepository 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);
}
}

+ 23
- 1
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/ProjectRepositories.java View File

@@ -19,5 +19,27 @@
*/
package org.sonar.scanner.protocol.input;

public interface ProjectRepositories {
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

public class ProjectRepositories {
private final 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);
}
}

+ 0
- 45
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/input/SingleProjectRepository.java View File

@@ -1,45 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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 implements ProjectRepositories {
private Map<String, FileData> fileDataByPath = new HashMap<>();

public SingleProjectRepository 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);
}
}

+ 2
- 1
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto View File

@@ -49,7 +49,8 @@ message Metadata {
string scm_revision_id = 13;

string pull_request_key = 14;
map<string, string> modules_project_relative_path_by_key = 15;

reserved 15; // modules_project_relative_path_by_key (no longer used)

string projectVersion = 16;
string buildString = 17;

+ 0
- 68
sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/MultiModuleProjectRepositoryTest.java View File

@@ -1,68 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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()).isEmpty();
}

@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()).isEmpty();
}
}

sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/SingleProjectRepositoryTest.java → sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/input/ProjectRepositoriesTest.java View File

@@ -25,13 +25,8 @@ 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();
}
public class ProjectRepositoriesTest {
private final ProjectRepositories repository = new ProjectRepositories();

@Test
public void add_file_data() {

Loading…
Cancel
Save