/* | |||||
* 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.Collections; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.function.Function; | |||||
import javax.annotation.CheckForNull; | |||||
import javax.annotation.Nullable; | |||||
import org.apache.commons.lang.StringUtils; | |||||
import org.sonar.api.resources.Qualifiers; | |||||
import org.sonar.api.resources.Scopes; | |||||
import org.sonar.ce.task.projectanalysis.analysis.Branch; | |||||
import org.sonar.core.util.Uuids; | |||||
import org.sonar.db.DbClient; | |||||
import org.sonar.db.DbSession; | |||||
import org.sonar.db.component.BranchType; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import org.sonar.db.component.ComponentWithModuleUuidDto; | |||||
import org.sonar.db.component.KeyWithUuidDto; | |||||
public class ComponentUuidFactoryWithMigration implements ComponentUuidFactory { | |||||
private final Map<String, String> uuidsByDbKey = new HashMap<>(); | |||||
private final Map<String, String> uuidsByMigratedKey = new HashMap<>(); | |||||
public ComponentUuidFactoryWithMigration(DbClient dbClient, DbSession dbSession, String rootKey, Branch branch, | |||||
Function<String, String> pathToKey, Map<String, String> reportModulesPath) { | |||||
Map<String, String> modulePathsByUuid; | |||||
List<KeyWithUuidDto> keys; | |||||
if (branch.isMain()) { | |||||
keys = dbClient.componentDao().selectUuidsByKeyFromProjectKey(dbSession, rootKey); | |||||
} else if (branch.getType() == BranchType.PULL_REQUEST) { | |||||
keys = dbClient.componentDao().selectUuidsByKeyFromProjectKeyAndPullRequest(dbSession, rootKey, branch.getPullRequestKey()); | |||||
} else { | |||||
keys = dbClient.componentDao().selectUuidsByKeyFromProjectKeyAndBranch(dbSession, rootKey, branch.getName()); | |||||
} | |||||
keys.forEach(dto -> uuidsByDbKey.put(dto.key(), dto.uuid())); | |||||
if (!reportModulesPath.isEmpty()) { | |||||
modulePathsByUuid = loadModulePathsByUuid(dbClient, dbSession, rootKey, branch, reportModulesPath); | |||||
if (!modulePathsByUuid.isEmpty()) { | |||||
doMigration(dbClient, dbSession, rootKey, pathToKey, modulePathsByUuid); | |||||
} | |||||
} | |||||
} | |||||
private void doMigration(DbClient dbClient, DbSession dbSession, String rootKey, Function<String, String> pathToKey, Map<String, String> modulePathsByUuid) { | |||||
List<ComponentWithModuleUuidDto> dtos = loadComponentsWithModuleUuid(dbClient, dbSession, rootKey); | |||||
for (ComponentWithModuleUuidDto dto : dtos) { | |||||
if ("/".equals(dto.path())) { | |||||
// skip root folders | |||||
continue; | |||||
} | |||||
if (Scopes.PROJECT.equals(dto.scope())) { | |||||
String modulePathFromRootProject = modulePathsByUuid.get(dto.uuid()); | |||||
if (modulePathFromRootProject != null || StringUtils.isEmpty(dto.moduleUuid())) { | |||||
// means that it's a root or a module with a valid path (to avoid overwriting key of root) | |||||
pathToKey.apply(modulePathFromRootProject); | |||||
uuidsByMigratedKey.put(pathToKey.apply(modulePathFromRootProject), dto.uuid()); | |||||
} | |||||
} else { | |||||
String modulePathFromRootProject = modulePathsByUuid.get(dto.moduleUuid()); | |||||
String componentPath = createComponentPath(dto, modulePathFromRootProject); | |||||
uuidsByMigratedKey.put(pathToKey.apply(componentPath), dto.uuid()); | |||||
} | |||||
} | |||||
} | |||||
@CheckForNull | |||||
private static String createComponentPath(ComponentWithModuleUuidDto dto, @Nullable String modulePathFromRootProject) { | |||||
if (StringUtils.isEmpty(modulePathFromRootProject)) { | |||||
return dto.path(); | |||||
} | |||||
if (StringUtils.isEmpty(dto.path())) { | |||||
// will be the case for modules | |||||
return modulePathFromRootProject; | |||||
} | |||||
return modulePathFromRootProject + "/" + dto.path(); | |||||
} | |||||
private static List<ComponentWithModuleUuidDto> loadComponentsWithModuleUuid(DbClient dbClient, DbSession dbSession, String rootKey) { | |||||
return dbClient.componentDao().selectEnabledComponentsWithModuleUuidFromProjectKey(dbSession, rootKey); | |||||
} | |||||
private static Map<String, String> loadModulePathsByUuid(DbClient dbClient, DbSession dbSession, String rootKey, | |||||
Branch branch, Map<String, String> pathByModuleKey) { | |||||
String branchKey = branch.getType() == BranchType.BRANCH ? branch.getName() : null; | |||||
String prKey = branch.getType() == BranchType.PULL_REQUEST ? branch.getPullRequestKey() : null; | |||||
List<ComponentDto> moduleDtos = dbClient.componentDao() | |||||
.selectProjectAndModulesFromProjectKey(dbSession, rootKey, true, branchKey, prKey).stream() | |||||
.filter(c -> Qualifiers.MODULE.equals(c.qualifier())) | |||||
.toList(); | |||||
if (moduleDtos.isEmpty()) { | |||||
return Collections.emptyMap(); | |||||
} | |||||
Map<String, String> modulePathByUuid = new HashMap<>(); | |||||
for (ComponentDto dto : moduleDtos) { | |||||
String relativePath = pathByModuleKey.get(dto.getKey()); | |||||
if (relativePath != null) { | |||||
modulePathByUuid.put(dto.uuid(), relativePath); | |||||
} | |||||
} | |||||
return modulePathByUuid; | |||||
} | |||||
/** | |||||
* Get UUID from component having the same key in database if it exists, otherwise look for migrated keys, and finally generate a new one. | |||||
*/ | |||||
@Override | |||||
public String getOrCreateForKey(String key) { | |||||
return uuidsByDbKey.computeIfAbsent(key, k1 -> uuidsByMigratedKey.computeIfAbsent(k1, k2 -> Uuids.create())); | |||||
} | |||||
} |
package org.sonar.ce.task.projectanalysis.step; | package org.sonar.ce.task.projectanalysis.step; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.function.Function; | |||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.sonar.ce.task.projectanalysis.analysis.Analysis; | import org.sonar.ce.task.projectanalysis.analysis.Analysis; | ||||
import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | ||||
import org.sonar.ce.task.projectanalysis.component.Component; | import org.sonar.ce.task.projectanalysis.component.Component; | ||||
import org.sonar.ce.task.projectanalysis.component.ComponentKeyGenerator; | import org.sonar.ce.task.projectanalysis.component.ComponentKeyGenerator; | ||||
import org.sonar.ce.task.projectanalysis.component.ComponentTreeBuilder; | import org.sonar.ce.task.projectanalysis.component.ComponentTreeBuilder; | ||||
import org.sonar.ce.task.projectanalysis.component.ComponentUuidFactoryWithMigration; | |||||
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.MutableTreeRootHolder; | ||||
import org.sonar.ce.task.projectanalysis.component.ProjectAttributes; | import org.sonar.ce.task.projectanalysis.component.ProjectAttributes; | ||||
import org.sonar.ce.task.projectanalysis.component.ReportModulesPath; | import org.sonar.ce.task.projectanalysis.component.ReportModulesPath; | ||||
// root key of branch, not necessarily of project | // root key of branch, not necessarily of project | ||||
String rootKey = keyGenerator.generateKey(reportProject.getKey(), null); | String rootKey = keyGenerator.generateKey(reportProject.getKey(), null); | ||||
Function<String, String> pathToKey = path -> keyGenerator.generateKey(reportProject.getKey(), path); | |||||
// loads the UUIDs from database. If they don't exist, then generate new ones | // loads the UUIDs from database. If they don't exist, then generate new ones | ||||
ComponentUuidFactoryWithMigration componentUuidFactoryWithMigration = | |||||
new ComponentUuidFactoryWithMigration(dbClient, dbSession, rootKey, analysisMetadataHolder.getBranch(), pathToKey, reportModulesPath.get()); | |||||
ComponentUuidFactory componentUuidFactory = new ComponentUuidFactoryImpl(dbClient, dbSession, rootKey, analysisMetadataHolder.getBranch()); | |||||
String rootUuid = componentUuidFactoryWithMigration.getOrCreateForKey(rootKey); | |||||
String rootUuid = componentUuidFactory.getOrCreateForKey(rootKey); | |||||
Optional<SnapshotDto> baseAnalysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, rootUuid); | Optional<SnapshotDto> baseAnalysis = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, rootUuid); | ||||
ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, | ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, | ||||
componentUuidFactoryWithMigration::getOrCreateForKey, | |||||
componentUuidFactory::getOrCreateForKey, | |||||
reportReader::readComponent, | reportReader::readComponent, | ||||
analysisMetadataHolder.getProject(), | analysisMetadataHolder.getProject(), | ||||
analysisMetadataHolder.getBranch(), | analysisMetadataHolder.getBranch(), |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.stream.Collectors; | |||||
import org.sonar.api.utils.MessageException; | import org.sonar.api.utils.MessageException; | ||||
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; | import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; | ||||
import org.sonar.ce.task.projectanalysis.component.Component; | import org.sonar.ce.task.projectanalysis.component.Component; | ||||
@Override | @Override | ||||
public void execute(ComputationStep.Context context) { | public void execute(ComputationStep.Context context) { | ||||
try (DbSession dbSession = dbClient.openSession(false)) { | try (DbSession dbSession = dbClient.openSession(false)) { | ||||
validateTargetBranch(dbSession); | |||||
Component root = treeRootHolder.getRoot(); | Component root = treeRootHolder.getRoot(); | ||||
// FIXME if module have really be dropped, no more need to load them | |||||
String branchKey = analysisMetadataHolder.isBranch() ? analysisMetadataHolder.getBranch().getName() : null; | String branchKey = analysisMetadataHolder.isBranch() ? analysisMetadataHolder.getBranch().getName() : null; | ||||
String prKey = analysisMetadataHolder.isPullRequest() ? analysisMetadataHolder.getBranch().getPullRequestKey() : null; | String prKey = analysisMetadataHolder.isPullRequest() ? analysisMetadataHolder.getBranch().getPullRequestKey() : null; | ||||
List<ComponentDto> baseModules = dbClient.componentDao().selectEnabledModulesFromProjectKey(dbSession, root.getKey(), branchKey, prKey); | |||||
Map<String, ComponentDto> baseModulesByKey = baseModules.stream().collect(Collectors.toMap(ComponentDto::getKey, x -> x)); | |||||
ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(dbSession, dbClient.componentDao(), baseModulesByKey); | |||||
ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(dbSession, dbClient.componentDao()); | |||||
new DepthTraversalTypeAwareCrawler(visitor).visit(root); | new DepthTraversalTypeAwareCrawler(visitor).visit(root); | ||||
if (!visitor.validationMessages.isEmpty()) { | if (!visitor.validationMessages.isEmpty()) { | ||||
} | } | ||||
} | } | ||||
private void validateTargetBranch(DbSession session) { | |||||
if (!analysisMetadataHolder.isPullRequest()) { | |||||
return; | |||||
} | |||||
String referenceBranchUuid = analysisMetadataHolder.getBranch().getReferenceBranchUuid(); | |||||
int moduleCount = dbClient.componentDao().countEnabledModulesByBranchUuid(session, referenceBranchUuid); | |||||
if (moduleCount > 0) { | |||||
Optional<BranchDto> opt = dbClient.branchDao().selectByUuid(session, referenceBranchUuid); | |||||
checkState(opt.isPresent(), "Reference branch '%s' does not exist", referenceBranchUuid); | |||||
throw MessageException.of(String.format( | |||||
"Due to an upgrade, you need first to re-analyze the target branch '%s' before analyzing this pull request.", opt.get().getKey())); | |||||
} | |||||
} | |||||
@Override | @Override | ||||
public String getDescription() { | public String getDescription() { | ||||
return "Validate project"; | return "Validate project"; | ||||
private class ValidateProjectsVisitor extends TypeAwareVisitorAdapter { | private class ValidateProjectsVisitor extends TypeAwareVisitorAdapter { | ||||
private final DbSession session; | private final DbSession session; | ||||
private final ComponentDao componentDao; | private final ComponentDao componentDao; | ||||
private final Map<String, ComponentDto> baseModulesByKey; | |||||
private final List<String> validationMessages = new ArrayList<>(); | private final List<String> validationMessages = new ArrayList<>(); | ||||
public ValidateProjectsVisitor(DbSession session, ComponentDao componentDao, Map<String, ComponentDto> baseModulesByKey) { | |||||
public ValidateProjectsVisitor(DbSession session, ComponentDao componentDao) { | |||||
super(CrawlerDepthLimit.PROJECT, ComponentVisitor.Order.PRE_ORDER); | super(CrawlerDepthLimit.PROJECT, ComponentVisitor.Order.PRE_ORDER); | ||||
this.session = session; | this.session = session; | ||||
this.componentDao = componentDao; | this.componentDao = componentDao; | ||||
this.baseModulesByKey = baseModulesByKey; | |||||
} | } | ||||
@Override | @Override | ||||
} | } | ||||
private Optional<ComponentDto> loadBaseComponent(String rawComponentKey) { | private Optional<ComponentDto> loadBaseComponent(String rawComponentKey) { | ||||
ComponentDto baseComponent = baseModulesByKey.get(rawComponentKey); | |||||
if (baseComponent == null) { | |||||
// Load component from key to be able to detect issue (try to analyze a module, etc.) | |||||
if (analysisMetadataHolder.isBranch()) { | |||||
return componentDao.selectByKeyAndBranch(session, rawComponentKey, analysisMetadataHolder.getBranch().getName()); | |||||
} else { | |||||
return componentDao.selectByKeyAndPullRequest(session, rawComponentKey, analysisMetadataHolder.getBranch().getPullRequestKey()); | |||||
} | |||||
// Load component from key to be able to detect issue (try to analyze a module, etc.) | |||||
if (analysisMetadataHolder.isBranch()) { | |||||
return componentDao.selectByKeyAndBranch(session, rawComponentKey, analysisMetadataHolder.getBranch().getName()); | |||||
} else { | |||||
return componentDao.selectByKeyAndPullRequest(session, rawComponentKey, analysisMetadataHolder.getBranch().getPullRequestKey()); | |||||
} | } | ||||
return Optional.of(baseComponent); | |||||
} | } | ||||
} | } | ||||
} | } |
/* | |||||
* 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 org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.sonar.api.utils.System2; | |||||
import org.sonar.ce.task.projectanalysis.analysis.Branch; | |||||
import org.sonar.db.DbTester; | |||||
import org.sonar.db.component.BranchType; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME; | |||||
public class ComponentUuidFactoryImplTest { | |||||
private final Branch mainBranch = new DefaultBranchImpl(DEFAULT_MAIN_BRANCH_NAME); | |||||
private final Branch mockedBranch = mock(Branch.class); | |||||
@Rule | |||||
public DbTester db = DbTester.create(System2.INSTANCE); | |||||
@Test | |||||
public void getOrCreateForKey_when_existingComponentsInDbForMainBranch_should_load() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), project.getKey(), mainBranch); | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void getOrCreateForKey_when_existingComponentsInDbForNonMainBranch_should_load() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("b1")); | |||||
when(mockedBranch.getType()).thenReturn(BranchType.BRANCH); | |||||
when(mockedBranch.isMain()).thenReturn(false); | |||||
when(mockedBranch.getName()).thenReturn("b1"); | |||||
ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), project.getKey(), mockedBranch); | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(branch.uuid()); | |||||
} | |||||
@Test | |||||
public void getOrCreateForKey_when_existingComponentsInDbForPr_should_load() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto pr = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST).setKey("pr1")); | |||||
when(mockedBranch.getType()).thenReturn(BranchType.PULL_REQUEST); | |||||
when(mockedBranch.isMain()).thenReturn(false); | |||||
when(mockedBranch.getPullRequestKey()).thenReturn("pr1"); | |||||
ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), project.getKey(), mockedBranch); | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(pr.uuid()); | |||||
} | |||||
@Test | |||||
public void getOrCreateForKey_when_componentsNotInDb_should_generate() { | |||||
ComponentUuidFactory underTest = new ComponentUuidFactoryImpl(db.getDbClient(), db.getSession(), "theProjectKey", mainBranch); | |||||
String generatedKey = underTest.getOrCreateForKey("foo"); | |||||
assertThat(generatedKey).isNotEmpty(); | |||||
// uuid is kept in memory for further calls with same key | |||||
assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey); | |||||
} | |||||
} |
/* | |||||
* 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.Collections; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import java.util.function.Function; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.sonar.api.utils.System2; | |||||
import org.sonar.ce.task.projectanalysis.analysis.Branch; | |||||
import org.sonar.db.DbTester; | |||||
import org.sonar.db.component.ComponentDto; | |||||
import org.sonar.db.component.ComponentTesting; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME; | |||||
public class ComponentUuidFactoryWithMigrationTest { | |||||
private final Branch mainBranch = new DefaultBranchImpl(DEFAULT_MAIN_BRANCH_NAME); | |||||
@Rule | |||||
public DbTester db = DbTester.create(System2.INSTANCE); | |||||
private Function<String, String> pathToKey = path -> path != null ? "project:" + path : "project"; | |||||
@Test | |||||
public void load_uuids_from_existing_components_in_db() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); | |||||
Map<String, String> reportModulesPath = Collections.singletonMap(module.getKey(), "module1_path"); | |||||
pathToKey = path -> path != null ? project.getKey() + ":" + path : project.getKey(); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, reportModulesPath); | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
assertThat(underTest.getOrCreateForKey(module.getKey())).isEqualTo(module.uuid()); | |||||
} | |||||
@Test | |||||
public void migrate_project_with_modules() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto module2 = db.components().insertComponent(ComponentTesting.newModuleDto(module1) | |||||
.setKey("project:module1:module2")); | |||||
ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file1") | |||||
.setPath("file1_path")); | |||||
ComponentDto file2 = db.components().insertComponent(ComponentTesting.newFileDto(module2) | |||||
.setKey("project:module1:module2:file2") | |||||
.setPath("file2_path")); | |||||
assertThat(file2.moduleUuidPath()).isEqualTo("." + project.uuid() + "." + module1.uuid() + "." + module2.uuid() + "."); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project:module1", "module1_path"); | |||||
modulesRelativePaths.put("project:module1:module2", "module1_path/module2_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// migrated files | |||||
assertThat(underTest.getOrCreateForKey("project:file1_path")).isEqualTo(file1.uuid()); | |||||
assertThat(underTest.getOrCreateForKey("project:module1_path/module2_path/file2_path")).isEqualTo(file2.uuid()); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void migrate_project_with_disabled_components_no_path() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file1") | |||||
.setPath("file1")); | |||||
ComponentDto disabledFileNoPath = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file2") | |||||
.setPath(null) | |||||
.setEnabled(false)); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project:module1", "module1_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// migrated files | |||||
assertThat(underTest.getOrCreateForKey("project:file1")).isEqualTo(file1.uuid()); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void migrate_project_with_disabled_components_same_path() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file1") | |||||
.setPath("file1")); | |||||
ComponentDto disabledFileSamePath = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file2") | |||||
.setPath("file1") | |||||
.setEnabled(false)); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project:module1", "module1_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// migrated files | |||||
assertThat(underTest.getOrCreateForKey("project:file1")).isEqualTo(file1.uuid()); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void prefers_component_having_same_key() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(module1) | |||||
.setKey("project:module1:file1") | |||||
.setPath("file1")); | |||||
ComponentDto disabledFileSameKey = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:module1/file1") | |||||
.setPath("module1_path/file1") | |||||
.setEnabled(false)); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project:module1", "module1_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// in theory we should migrate file1. But since disabledFileSameKey already have the expected migrated key, let's reuse it. | |||||
assertThat(underTest.getOrCreateForKey("project:module1/file1")).isEqualTo(disabledFileSameKey.uuid()); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void migrate_branch_with_modules() { | |||||
pathToKey = path -> path != null ? "project:" + path : "project"; | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto module2 = db.components().insertComponent(ComponentTesting.newModuleDto(module1) | |||||
.setKey("project:module1:module2")); | |||||
ComponentDto file1 = db.components().insertComponent(ComponentTesting.newFileDto(project) | |||||
.setKey("project:file1") | |||||
.setPath("file1_path")); | |||||
ComponentDto file2 = db.components().insertComponent(ComponentTesting.newFileDto(module2) | |||||
.setKey("project:module1:module2:file2") | |||||
.setPath("file2_path")); | |||||
assertThat(file2.moduleUuidPath()).isEqualTo("." + project.uuid() + "." + module1.uuid() + "." + module2.uuid() + "."); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project:module1", "module1_path"); | |||||
modulesRelativePaths.put("project:module1:module2", "module1_path/module2_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// migrated files | |||||
assertThat(underTest.getOrCreateForKey("project:file1_path")).isEqualTo(file1.uuid()); | |||||
assertThat(underTest.getOrCreateForKey("project:module1_path/module2_path/file2_path")).isEqualTo(file2.uuid()); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void migrate_project_with_root_folders() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1")); | |||||
ComponentDto dir1 = db.components().insertComponent(ComponentTesting.newDirectory(module1, "/") | |||||
.setKey("project:module1:/")); | |||||
Map<String, String> modulesRelativePaths = Collections.singletonMap("project:module1", "module1_path"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// project remains the same | |||||
assertThat(underTest.getOrCreateForKey(project.getKey())).isEqualTo(project.uuid()); | |||||
// module migrated to folder | |||||
assertThat(underTest.getOrCreateForKey("project:module1_path")).isEqualTo(module1.uuid()); | |||||
} | |||||
@Test | |||||
public void dont_override_root_uuid_if_module_path_is_not_sent() { | |||||
ComponentDto project = db.components().insertPrivateProject(dto -> dto.setKey("project")); | |||||
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module1") | |||||
.setEnabled(false)); | |||||
ComponentDto module2 = db.components().insertComponent(ComponentTesting.newModuleDto(project) | |||||
.setKey("project:module2") | |||||
.setEnabled(false)); | |||||
Map<String, String> modulesRelativePaths = new HashMap<>(); | |||||
modulesRelativePaths.put("project", ""); | |||||
modulesRelativePaths.put("project:module2", "module2"); | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), project.getKey(), mainBranch, pathToKey, modulesRelativePaths); | |||||
// check root project. | |||||
assertThat(underTest.getOrCreateForKey("project")).isEqualTo(project.uuid()); | |||||
} | |||||
@Test | |||||
public void generate_uuid_if_it_does_not_exist_in_db() { | |||||
ComponentUuidFactoryWithMigration underTest = | |||||
new ComponentUuidFactoryWithMigration(db.getDbClient(), db.getSession(), "theProjectKey", mainBranch, pathToKey, Collections.emptyMap()); | |||||
String generatedKey = underTest.getOrCreateForKey("foo"); | |||||
assertThat(generatedKey).isNotEmpty(); | |||||
// uuid is kept in memory for further calls with same key | |||||
assertThat(underTest.getOrCreateForKey("foo")).isEqualTo(generatedKey); | |||||
} | |||||
} |
import org.sonar.db.component.ComponentDto; | import org.sonar.db.component.ComponentDto; | ||||
import org.sonar.db.component.ComponentKeyUpdaterMapper; | import org.sonar.db.component.ComponentKeyUpdaterMapper; | ||||
import org.sonar.db.component.ComponentMapper; | import org.sonar.db.component.ComponentMapper; | ||||
import org.sonar.db.component.ComponentWithModuleUuidDto; | |||||
import org.sonar.db.component.FilePathWithHashDto; | import org.sonar.db.component.FilePathWithHashDto; | ||||
import org.sonar.db.component.KeyWithUuidDto; | import org.sonar.db.component.KeyWithUuidDto; | ||||
import org.sonar.db.component.PrBranchAnalyzedLanguageCountByProjectDto; | import org.sonar.db.component.PrBranchAnalyzedLanguageCountByProjectDto; | ||||
confBuilder.loadAlias("ApplicationProject", ApplicationProjectDto.class); | confBuilder.loadAlias("ApplicationProject", ApplicationProjectDto.class); | ||||
confBuilder.loadAlias("CeTaskCharacteristic", CeTaskCharacteristicDto.class); | confBuilder.loadAlias("CeTaskCharacteristic", CeTaskCharacteristicDto.class); | ||||
confBuilder.loadAlias("Component", ComponentDto.class); | confBuilder.loadAlias("Component", ComponentDto.class); | ||||
confBuilder.loadAlias("ComponentWithModuleUuid", ComponentWithModuleUuidDto.class); | |||||
confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class); | confBuilder.loadAlias("DuplicationUnit", DuplicationUnitDto.class); | ||||
confBuilder.loadAlias("Event", EventDto.class); | confBuilder.loadAlias("Event", EventDto.class); | ||||
confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class); | confBuilder.loadAlias("FilePathWithHash", FilePathWithHashDto.class); |
return mapper(dbSession).selectByBranchUuid(branchUuid); | return mapper(dbSession).selectByBranchUuid(branchUuid); | ||||
} | } | ||||
public int countEnabledModulesByBranchUuid(DbSession session, String branchUuid) { | |||||
return mapper(session).countEnabledModulesByBranchUuid(branchUuid); | |||||
} | |||||
/* | /* | ||||
SELECT BY QUERY | SELECT BY QUERY | ||||
*/ | */ | ||||
return mapper(session).selectComponentsFromProjectKeyAndScope(projectKey, Scopes.PROJECT, excludeDisabled, branch, pullRequest); | return mapper(session).selectComponentsFromProjectKeyAndScope(projectKey, Scopes.PROJECT, excludeDisabled, branch, pullRequest); | ||||
} | } | ||||
/** | |||||
* If no branch or pull request is provided, returns components in the main branch | |||||
*/ | |||||
public List<ComponentDto> selectEnabledModulesFromProjectKey(DbSession session, String projectKey, @Nullable String branch, @Nullable String pullRequest) { | |||||
return selectProjectAndModulesFromProjectKey(session, projectKey, true, branch, pullRequest); | |||||
} | |||||
public List<ComponentDto> selectByKeys(DbSession session, Collection<String> keys) { | public List<ComponentDto> selectByKeys(DbSession session, Collection<String> keys) { | ||||
return selectByKeys(session, keys, null, null); | return selectByKeys(session, keys, null, null); | ||||
} | } | ||||
return new HashSet<>(mapper(dbSession).selectComponentsByQualifiers(qualifiers)); | return new HashSet<>(mapper(dbSession).selectComponentsByQualifiers(qualifiers)); | ||||
} | } | ||||
public List<ComponentWithModuleUuidDto> selectEnabledComponentsWithModuleUuidFromProjectKey(DbSession dbSession, String projectKey) { | |||||
return mapper(dbSession).selectEnabledComponentsWithModuleUuidFromProjectKey(projectKey); | |||||
} | |||||
/** | /** | ||||
* Returns components with open issues from P/Rs that use a certain branch as reference (reference branch). | * Returns components with open issues from P/Rs that use a certain branch as reference (reference branch). | ||||
* Excludes components from the current branch. | * Excludes components from the current branch. |
List<ComponentDto> selectComponentsByQualifiers(@Param("qualifiers") Collection<String> qualifiers); | List<ComponentDto> selectComponentsByQualifiers(@Param("qualifiers") Collection<String> qualifiers); | ||||
int countEnabledModulesByBranchUuid(@Param("branchUuid") String branchUuid); | |||||
List<ComponentDto> selectByQuery(@Param("query") ComponentQuery query, RowBounds rowBounds); | List<ComponentDto> selectByQuery(@Param("query") ComponentQuery query, RowBounds rowBounds); | ||||
int countByQuery(@Param("query") ComponentQuery query); | int countByQuery(@Param("query") ComponentQuery query); | ||||
List<ProjectNclocDistributionDto> selectPrivateProjectsWithNcloc(); | List<ProjectNclocDistributionDto> selectPrivateProjectsWithNcloc(); | ||||
List<ComponentWithModuleUuidDto> selectEnabledComponentsWithModuleUuidFromProjectKey(String projectKey); | |||||
short checkIfAnyOfComponentsWithQualifiers(@Param("componentKeys") Collection<String> componentKeys, @Param("qualifiers") Set<String> qualifiers); | short checkIfAnyOfComponentsWithQualifiers(@Param("componentKeys") Collection<String> componentKeys, @Param("qualifiers") Set<String> qualifiers); | ||||
} | } |
</foreach> | </foreach> | ||||
</select> | </select> | ||||
<select id="countEnabledModulesByBranchUuid" resultType="int"> | |||||
select | |||||
count(1) | |||||
from components p | |||||
where | |||||
p.enabled=${_true} | |||||
and p.branch_uuid = #{branchUuid,jdbcType=VARCHAR} | |||||
and p.qualifier = 'BRC' | |||||
</select> | |||||
<select id="selectByQuery" resultType="Component"> | <select id="selectByQuery" resultType="Component"> | ||||
select | select | ||||
<include refid="componentColumns"/> | <include refid="componentColumns"/> | ||||
p.branch_uuid = #{branchUuid,jdbcType=VARCHAR} | p.branch_uuid = #{branchUuid,jdbcType=VARCHAR} | ||||
</select> | </select> | ||||
<select id="selectEnabledComponentsWithModuleUuidFromProjectKey" resultType="ComponentWithModuleUuid"> | |||||
SELECT | |||||
p.uuid as uuid, p.module_uuid as moduleUuid, p.path as path, p.scope as scope | |||||
FROM | |||||
components p | |||||
INNER JOIN | |||||
components root ON root.uuid=p.branch_uuid AND p.enabled = ${_true} AND root.kee=#{projectKey,jdbcType=VARCHAR} | |||||
</select> | |||||
<select id="selectUuidsByKeyFromProjectKeyAndBranchOrPr" parameterType="string" resultType="KeyWithUuid"> | <select id="selectUuidsByKeyFromProjectKeyAndBranchOrPr" parameterType="string" resultType="KeyWithUuid"> | ||||
SELECT | SELECT | ||||
p.kee, p.uuid | p.kee, p.uuid |
.hasMessage("Qualifiers cannot be empty"); | .hasMessage("Qualifiers cannot be empty"); | ||||
} | } | ||||
@Test | |||||
public void count_enabled_modules_by_project_uuid() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
db.components().insertComponent(newModuleDto(module)); | |||||
ComponentDto subModule2 = newModuleDto(module); | |||||
subModule2.setEnabled(false); | |||||
db.components().insertComponent(subModule2); | |||||
int result = underTest.countEnabledModulesByBranchUuid(dbSession, project.uuid()); | |||||
assertThat(result).isEqualTo(2); | |||||
} | |||||
@Test | @Test | ||||
public void find_sub_projects_by_component_keys() { | public void find_sub_projects_by_component_keys() { | ||||
ComponentDto project = db.components().insertPrivateProject(); | ComponentDto project = db.components().insertPrivateProject(); | ||||
assertThat(underTest.selectEnabledDescendantModules(dbSession, "unknown")).isEmpty(); | assertThat(underTest.selectEnabledDescendantModules(dbSession, "unknown")).isEmpty(); | ||||
} | } | ||||
@Test | |||||
public void select_enabled_components_with_module_dto() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto removedModule = db.components().insertComponent(newModuleDto(project).setEnabled(false)); | |||||
ComponentDto subModule = db.components().insertComponent(newModuleDto(module)); | |||||
ComponentDto removedSubModule = db.components().insertComponent(newModuleDto(module).setEnabled(false)); | |||||
ComponentDto directory = db.components().insertComponent(newDirectory(subModule, "src")); | |||||
ComponentDto removedDirectory = db.components().insertComponent(newDirectory(subModule, "src2").setEnabled(false)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(subModule, directory)); | |||||
ComponentDto removedFile = db.components().insertComponent(newFileDto(subModule, directory).setEnabled(false)); | |||||
// From root project | |||||
assertThat(underTest.selectEnabledComponentsWithModuleUuidFromProjectKey(dbSession, project.getKey())) | |||||
.extracting(ComponentWithModuleUuidDto::uuid) | |||||
.containsExactlyInAnyOrder( | |||||
project.uuid(), | |||||
module.uuid(), | |||||
subModule.uuid(), | |||||
directory.uuid(), | |||||
file.uuid()); | |||||
} | |||||
@Test | @Test | ||||
public void select_all_modules_tree() { | public void select_all_modules_tree() { | ||||
ComponentDto project = db.components().insertPrivateProject(); | ComponentDto project = db.components().insertPrivateProject(); | ||||
entry(file.getKey(), file.uuid())); | entry(file.getKey(), file.uuid())); | ||||
} | } | ||||
@Test | |||||
public void select_enabled_modules_from_project() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto removedProject = db.components().insertPrivateProject(p -> p.setEnabled(false)); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(project)); | |||||
ComponentDto removedModule = db.components().insertComponent(newModuleDto(project).setEnabled(false)); | |||||
ComponentDto subModule = db.components().insertComponent(newModuleDto(module)); | |||||
ComponentDto removedSubModule = db.components().insertComponent(newModuleDto(module).setEnabled(false)); | |||||
ComponentDto directory = db.components().insertComponent(newDirectory(subModule, "src")); | |||||
ComponentDto removedDirectory = db.components().insertComponent(newDirectory(subModule, "src2").setEnabled(false)); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(subModule, directory)); | |||||
ComponentDto removedFile = db.components().insertComponent(newFileDto(subModule, directory).setEnabled(false)); | |||||
// Removed modules are not included | |||||
assertThat(underTest.selectEnabledModulesFromProjectKey(dbSession, project.getKey(), null, null)) | |||||
.extracting(ComponentDto::getKey) | |||||
.containsExactlyInAnyOrder(project.getKey(), module.getKey(), subModule.getKey()); | |||||
assertThat(underTest.selectEnabledModulesFromProjectKey(dbSession, "UNKNOWN", null, null)).isEmpty(); | |||||
} | |||||
@Test | |||||
public void select_enabled_modules_from_branch() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1")); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(branch)); | |||||
ComponentDto subModule = db.components().insertComponent(newModuleDto(module)); | |||||
ComponentDto directory = db.components().insertComponent(newDirectory(subModule, "src")); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(subModule, directory)); | |||||
// Removed modules are not included | |||||
assertThat(underTest.selectEnabledModulesFromProjectKey(dbSession, project.getKey(), "branch1", null)) | |||||
.extracting(ComponentDto::getKey) | |||||
.containsExactlyInAnyOrder(project.getKey(), module.getKey(), subModule.getKey()); | |||||
} | |||||
@Test | |||||
public void select_enabled_modules_from_pr() { | |||||
ComponentDto project = db.components().insertPrivateProject(); | |||||
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST).setKey("pr1")); | |||||
ComponentDto module = db.components().insertComponent(newModuleDto(branch)); | |||||
ComponentDto subModule = db.components().insertComponent(newModuleDto(module)); | |||||
ComponentDto directory = db.components().insertComponent(newDirectory(subModule, "src")); | |||||
ComponentDto file = db.components().insertComponent(newFileDto(subModule, directory)); | |||||
// Removed modules are not included | |||||
assertThat(underTest.selectEnabledModulesFromProjectKey(dbSession, project.getKey(), null, "pr1")) | |||||
.extracting(ComponentDto::getKey) | |||||
.containsExactlyInAnyOrder(project.getKey(), module.getKey(), subModule.getKey()); | |||||
} | |||||
@Test | @Test | ||||
public void select_views_and_sub_views_and_applications() { | public void select_views_and_sub_views_and_applications() { | ||||
db.components().insertPublicPortfolio("ABCD", p -> { | db.components().insertPublicPortfolio("ABCD", p -> { |
import org.sonar.server.es.textsearch.ComponentTextSearchFeatureRepertoire; | import org.sonar.server.es.textsearch.ComponentTextSearchFeatureRepertoire; | ||||
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static org.sonar.api.resources.Qualifiers.DIRECTORY; | |||||
import static org.sonar.api.resources.Qualifiers.FILE; | import static org.sonar.api.resources.Qualifiers.FILE; | ||||
import static org.sonar.api.resources.Qualifiers.MODULE; | |||||
import static org.sonar.api.resources.Qualifiers.PROJECT; | import static org.sonar.api.resources.Qualifiers.PROJECT; | ||||
public class ComponentIndexScoreTest extends ComponentIndexTest { | public class ComponentIndexScoreTest extends ComponentIndexTest { | ||||
assertSearch(SuggestionQuery.builder() | assertSearch(SuggestionQuery.builder() | ||||
.setQuery("File") | .setQuery("File") | ||||
.setQualifiers(asList(PROJECT, MODULE, FILE)) | |||||
.setQualifiers(asList(PROJECT, DIRECTORY, FILE)) | |||||
.setRecentlyBrowsedKeys(ImmutableSet.of(file1.getKey())) | .setRecentlyBrowsedKeys(ImmutableSet.of(file1.getKey())) | ||||
.setFavoriteKeys(ImmutableSet.of(file2.getKey())) | .setFavoriteKeys(ImmutableSet.of(file2.getKey())) | ||||
.build()).containsExactly(uuids(file2, file1)); | .build()).containsExactly(uuids(file2, file1)); | ||||
assertSearch(SuggestionQuery.builder() | assertSearch(SuggestionQuery.builder() | ||||
.setQuery("File") | .setQuery("File") | ||||
.setQualifiers(asList(PROJECT, MODULE, FILE)) | |||||
.setQualifiers(asList(PROJECT, DIRECTORY, FILE)) | |||||
.setRecentlyBrowsedKeys(ImmutableSet.of(file2.getKey())) | .setRecentlyBrowsedKeys(ImmutableSet.of(file2.getKey())) | ||||
.setFavoriteKeys(ImmutableSet.of(file1.getKey())) | .setFavoriteKeys(ImmutableSet.of(file1.getKey())) | ||||
.build()).containsExactly(uuids(file1, file2)); | .build()).containsExactly(uuids(file1, file2)); |
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.sonar.api.resources.Qualifiers.FILE; | import static org.sonar.api.resources.Qualifiers.FILE; | ||||
import static org.sonar.api.resources.Qualifiers.MODULE; | |||||
import static org.sonar.api.resources.Qualifiers.PROJECT; | import static org.sonar.api.resources.Qualifiers.PROJECT; | ||||
public abstract class ComponentIndexTest { | public abstract class ComponentIndexTest { | ||||
} | } | ||||
protected ListAssert<String> assertSearch(String query) { | protected ListAssert<String> assertSearch(String query) { | ||||
return assertSearch(SuggestionQuery.builder().setQuery(query).setQualifiers(asList(PROJECT, MODULE, FILE)).build()); | |||||
return assertSearch(SuggestionQuery.builder().setQuery(query).setQualifiers(asList(PROJECT, FILE)).build()); | |||||
} | } | ||||
protected ListAssert<String> assertSearch(SuggestionQuery query) { | protected ListAssert<String> assertSearch(SuggestionQuery query) { | ||||
} | } | ||||
protected void assertSearchResults(String query, ComponentDto... expectedComponents) { | protected void assertSearchResults(String query, ComponentDto... expectedComponents) { | ||||
assertSearchResults(SuggestionQuery.builder().setQuery(query).setQualifiers(asList(PROJECT, MODULE, FILE)).build(), expectedComponents); | |||||
assertSearchResults(SuggestionQuery.builder().setQuery(query).setQualifiers(asList(PROJECT, FILE)).build(), expectedComponents); | |||||
} | } | ||||
protected void assertSearchResults(SuggestionQuery query, ComponentDto... expectedComponents) { | protected void assertSearchResults(SuggestionQuery query, ComponentDto... expectedComponents) { |
Set<String> projectUuidsToSearch = components.stream() | Set<String> projectUuidsToSearch = components.stream() | ||||
.map(ComponentDto::branchUuid) | .map(ComponentDto::branchUuid) | ||||
.collect(toHashSet()); | .collect(toHashSet()); | ||||
List<ComponentDto> projects = dbClient.componentDao() | |||||
.selectByUuids(dbSession, projectUuidsToSearch) | |||||
.stream() | |||||
.filter(c -> !c.qualifier().equals(Qualifiers.MODULE)) | |||||
.toList(); | |||||
List<ComponentDto> projects = dbClient.componentDao().selectByUuids(dbSession, projectUuidsToSearch); | |||||
return projects.stream().collect(toMap(ComponentDto::uuid, ComponentDto::getKey)); | return projects.stream().collect(toMap(ComponentDto::uuid, ComponentDto::getKey)); | ||||
} | } | ||||
"sonar.security.config.pythonsecurity", | "sonar.security.config.pythonsecurity", | ||||
"sonar.security.config.roslyn.sonaranalyzer.security.cs" | "sonar.security.config.roslyn.sonaranalyzer.security.cs" | ||||
); | ); | ||||
private static final Set<String> SUPPORTED_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP, Qualifiers.MODULE, Qualifiers.SUBVIEW); | |||||
private static final Set<String> SUPPORTED_QUALIFIERS = Set.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP, Qualifiers.SUBVIEW); | |||||
private final PropertyDefinitions definitions; | private final PropertyDefinitions definitions; | ||||
private final DbClient dbClient; | private final DbClient dbClient; | ||||
validateJsonSchema(jsonContent.get(), definition); | validateJsonSchema(jsonContent.get(), definition); | ||||
} catch (ValidationException e) { | } catch (ValidationException e) { | ||||
throw new IllegalArgumentException(String.format("Provided JSON is invalid [%s]", e.getMessage())); | throw new IllegalArgumentException(String.format("Provided JSON is invalid [%s]", e.getMessage())); | ||||
} catch (IOException e){ | |||||
} catch (IOException e) { | |||||
throw new IllegalArgumentException("Provided JSON is invalid"); | throw new IllegalArgumentException("Provided JSON is invalid"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private void validateJsonSchema(String json, PropertyDefinition definition) { | private void validateJsonSchema(String json, PropertyDefinition definition) { | ||||
if(SECURITY_JSON_PROPERTIES.contains(definition.key())){ | |||||
if (SECURITY_JSON_PROPERTIES.contains(definition.key())) { | |||||
InputStream jsonSchemaInputStream = this.getClass().getClassLoader().getResourceAsStream("json-schemas/security.json"); | InputStream jsonSchemaInputStream = this.getClass().getClassLoader().getResourceAsStream("json-schemas/security.json"); | ||||
if(jsonSchemaInputStream != null){ | |||||
if (jsonSchemaInputStream != null) { | |||||
JSONObject jsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); | JSONObject jsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); | ||||
JSONObject jsonSubject = new JSONObject(new JSONTokener(json)); | JSONObject jsonSubject = new JSONObject(new JSONTokener(json)); | ||||
SchemaLoader.load(jsonSchema).validate(jsonSubject); | SchemaLoader.load(jsonSchema).validate(jsonSubject); |
import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||||
import static org.assertj.core.groups.Tuple.tuple; | import static org.assertj.core.groups.Tuple.tuple; | ||||
import static org.sonar.api.resources.Qualifiers.MODULE; | |||||
import static org.sonar.api.resources.Qualifiers.PROJECT; | import static org.sonar.api.resources.Qualifiers.PROJECT; | ||||
import static org.sonar.api.web.UserRole.ADMIN; | import static org.sonar.api.web.UserRole.ADMIN; | ||||
import static org.sonar.api.web.UserRole.CODEVIEWER; | import static org.sonar.api.web.UserRole.CODEVIEWER; | ||||
public void return_JSON_property() { | public void return_JSON_property() { | ||||
logIn(); | logIn(); | ||||
propertyDefinitions.addComponent(PropertyDefinition | propertyDefinitions.addComponent(PropertyDefinition | ||||
.builder("foo") | |||||
.type(PropertyType.JSON) | |||||
.build()); | |||||
.builder("foo") | |||||
.type(PropertyType.JSON) | |||||
.build()); | |||||
ListDefinitionsWsResponse result = executeRequest(); | ListDefinitionsWsResponse result = executeRequest(); | ||||
propertyDefinitions.addComponents(asList( | propertyDefinitions.addComponents(asList( | ||||
PropertyDefinition.builder("global").build(), | PropertyDefinition.builder("global").build(), | ||||
PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), | PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), | ||||
PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(), | |||||
PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build())); | |||||
PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build())); | |||||
ListDefinitionsWsResponse result = executeRequest(); | ListDefinitionsWsResponse result = executeRequest(); | ||||
propertyDefinitions.addComponents(asList( | propertyDefinitions.addComponents(asList( | ||||
PropertyDefinition.builder("global").build(), | PropertyDefinition.builder("global").build(), | ||||
PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), | PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), | ||||
PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(), | |||||
PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build())); | |||||
PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build())); | |||||
ListDefinitionsWsResponse result = executeRequest(project.getKey()); | ListDefinitionsWsResponse result = executeRequest(project.getKey()); | ||||
*/ | */ | ||||
package org.sonar.core.component; | package org.sonar.core.component; | ||||
import org.sonar.api.scanner.ScannerSide; | |||||
import org.sonar.api.ce.ComputeEngineSide; | import org.sonar.api.ce.ComputeEngineSide; | ||||
import org.sonar.api.resources.Qualifiers; | import org.sonar.api.resources.Qualifiers; | ||||
import org.sonar.api.resources.ResourceType; | import org.sonar.api.resources.ResourceType; | ||||
import org.sonar.api.resources.ResourceTypeTree; | import org.sonar.api.resources.ResourceTypeTree; | ||||
import org.sonar.api.scanner.ScannerSide; | |||||
import org.sonar.api.server.ServerSide; | import org.sonar.api.server.ServerSide; | ||||
@ScannerSide | @ScannerSide | ||||
.hasSourceCode() | .hasSourceCode() | ||||
.build()) | .build()) | ||||
.addRelations(Qualifiers.PROJECT, Qualifiers.MODULE) | |||||
.addRelations(Qualifiers.MODULE, Qualifiers.DIRECTORY) | |||||
.addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY) | |||||
.addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE) | .addRelations(Qualifiers.DIRECTORY, Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE) | ||||
.build(); | .build(); |
import org.sonar.core.extension.PluginRiskConsent; | import org.sonar.core.extension.PluginRiskConsent; | ||||
import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||
import static org.sonar.api.PropertyType.*; | |||||
import static org.sonar.api.PropertyType.BOOLEAN; | |||||
import static org.sonar.api.PropertyType.SINGLE_SELECT_LIST; | |||||
import static org.sonar.api.PropertyType.STRING; | |||||
import static org.sonar.api.PropertyType.TEXT; | |||||
import static org.sonar.core.extension.PluginRiskConsent.NOT_ACCEPTED; | import static org.sonar.core.extension.PluginRiskConsent.NOT_ACCEPTED; | ||||
public class CorePropertyDefinitions { | public class CorePropertyDefinitions { | ||||
.build(), | .build(), | ||||
PropertyDefinition.builder(CoreProperties.SERVER_BASE_URL) | PropertyDefinition.builder(CoreProperties.SERVER_BASE_URL) | ||||
.name("Server base URL") | .name("Server base URL") | ||||
.description("HTTP(S) URL of this SonarQube server, such as <i>https://yourhost.yourdomain/sonar</i>. This value is used outside SonarQube itself, e.g. for PR decoration, emails, etc.") | |||||
.description( | |||||
"HTTP(S) URL of this SonarQube server, such as <i>https://yourhost.yourdomain/sonar</i>. This value is used outside SonarQube itself, e.g. for PR decoration, emails, etc.") | |||||
.category(CoreProperties.CATEGORY_GENERAL) | .category(CoreProperties.CATEGORY_GENERAL) | ||||
.build(), | .build(), | ||||
PropertyDefinition.builder(SONAR_PROJECTCREATION_MAINBRANCHNAME) | PropertyDefinition.builder(SONAR_PROJECTCREATION_MAINBRANCHNAME) | ||||
.name("Duplication Exclusions") | .name("Duplication Exclusions") | ||||
.description("Patterns used to exclude some source files from the duplication detection mechanism. " + | .description("Patterns used to exclude some source files from the duplication detection mechanism. " + | ||||
"See below to know how to use wildcards to specify this property.") | "See below to know how to use wildcards to specify this property.") | ||||
.onQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE) | |||||
.onQualifiers(Qualifiers.PROJECT) | |||||
.category(CoreProperties.CATEGORY_EXCLUSIONS) | .category(CoreProperties.CATEGORY_EXCLUSIONS) | ||||
.subCategory(CoreProperties.SUBCATEGORY_DUPLICATIONS_EXCLUSIONS) | .subCategory(CoreProperties.SUBCATEGORY_DUPLICATIONS_EXCLUSIONS) | ||||
.multiValues(true) | .multiValues(true) |
.subCategory(CoreProperties.SUBCATEGORY_COVERAGE_EXCLUSIONS) | .subCategory(CoreProperties.SUBCATEGORY_COVERAGE_EXCLUSIONS) | ||||
.type(PropertyType.STRING) | .type(PropertyType.STRING) | ||||
.multiValues(true) | .multiValues(true) | ||||
.onQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE) | |||||
.onQualifiers(Qualifiers.PROJECT) | |||||
.build(), | .build(), | ||||
// FILES | // FILES |
ResourceTypeTree tree = DefaultResourceTypes.get(); | ResourceTypeTree tree = DefaultResourceTypes.get(); | ||||
assertThat(tree.getTypes()).hasSize(5); | assertThat(tree.getTypes()).hasSize(5); | ||||
assertThat(tree.getChildren(Qualifiers.PROJECT)).containsExactly(Qualifiers.MODULE); | |||||
assertThat(tree.getChildren(Qualifiers.PROJECT)).containsExactly(Qualifiers.DIRECTORY); | |||||
} | } | ||||
} | } |
* Possible values: | * Possible values: | ||||
* <ul> | * <ul> | ||||
* <li>"projects"</li> | * <li>"projects"</li> | ||||
* <li>"moduleUuids"</li> | |||||
* <li>"fileUuids"</li> | * <li>"fileUuids"</li> | ||||
* <li>"assigned_to_me"</li> | * <li>"assigned_to_me"</li> | ||||
* <li>"severities"</li> | * <li>"severities"</li> |