@@ -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; | |||
} | |||
} |
@@ -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(), | |||
@@ -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); | |||
} | |||
} |
@@ -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) { |
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -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); |
@@ -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")); | |||
} | |||
} |
@@ -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() { |
@@ -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)); | |||
@@ -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); | |||
} |
@@ -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 | |||
*/ |
@@ -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); | |||
} |
@@ -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); |
@@ -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"/> |
@@ -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 <> '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 |
@@ -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(); |
@@ -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(); |
@@ -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); |
@@ -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; |
@@ -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); |
@@ -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); |
@@ -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"); | |||
} | |||
} |
@@ -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 |
@@ -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; |
@@ -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() |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; |
@@ -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(); | |||
} | |||
} |
@@ -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() { |