diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2023-03-27 15:44:00 -0500 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-04-04 20:03:16 +0000 |
commit | 3f602a70548d285d61d0295b704aa18a3b8314b8 (patch) | |
tree | 3a59c6ee1f0898c12af24bc12bf94b869b6feed6 /server/sonar-webserver-webapi | |
parent | 02f358bec4d5636d8c23bf34d4d086b0405f65cf (diff) | |
download | sonarqube-3f602a70548d285d61d0295b704aa18a3b8314b8.tar.gz sonarqube-3f602a70548d285d61d0295b704aa18a3b8314b8.zip |
SONAR-18860 Refactor usage of main_branch_project_uuid to use branch is_main flag in webserver-webapi module
Diffstat (limited to 'server/sonar-webserver-webapi')
21 files changed, 205 insertions, 171 deletions
diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java index 51fca49833f..8a27c0aca4a 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/component/ComponentCleanerServiceIT.java @@ -86,33 +86,26 @@ public class ComponentCleanerServiceIT { } @Test - public void delete_list_of_components_from_db() { + public void delete_component_from_db() { ComponentDto componentDto1 = db.components().insertPublicProject(); ComponentDto componentDto2 = db.components().insertPublicProject(); - ComponentDto componentDto3 = db.components().insertPublicProject(); mockResourceTypeAsValidProject(); - underTest.deleteComponents(dbSession, asList(componentDto1, componentDto2)); + underTest.deleteComponent(dbSession, componentDto1); dbSession.commit(); assertNotExists(componentDto1); - assertNotExists(componentDto2); - assertExists(componentDto3); + assertExists(componentDto2); } @Test public void fail_with_IAE_if_project_non_deletable() { ComponentDto componentDto1 = db.components().insertPublicProject(); - ComponentDto componentDto2 = db.components().insertPublicProject(); - mockResourceTypeAsNonDeletable(); - dbSession.commit(); - List<ComponentDto> componentDtos = asList(componentDto1, componentDto2); - - assertThatThrownBy(() -> underTest.deleteComponents(dbSession, componentDtos)) + assertThatThrownBy(() -> underTest.deleteComponent(dbSession, componentDto1)) .withFailMessage("Only projects can be deleted") .isInstanceOf(IllegalArgumentException.class); } @@ -187,7 +180,7 @@ public class ComponentCleanerServiceIT { dbClient.componentDao().insertOnMainBranch(dbSession, file); dbSession.commit(); - assertThatThrownBy(() -> underTest.delete(dbSession, file)) + assertThatThrownBy(() -> underTest.deleteComponent(dbSession, file)) .isInstanceOf(IllegalArgumentException.class); } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionIT.java index 7201714ab10..96933397589 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionIT.java @@ -337,7 +337,7 @@ public class SearchActionIT { assertThatThrownBy(request::execute) .isInstanceOf(NotFoundException.class) - .hasMessage("Component key '%s' not found", key); + .hasMessage("Project '%s' not found", key); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java index 099d3fd16ae..be5985198c8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java @@ -230,7 +230,7 @@ public class BulkDeleteActionIT { .setParam("projects", StringUtils.join(keys, ",")) .execute(); - verify(componentCleanerService, times(1_000)).delete(any(DbSession.class), any(ComponentDto.class)); + verify(componentCleanerService, times(1_000)).deleteComponent(any(DbSession.class), any(ComponentDto.class)); ArgumentCaptor<Set<Project>> projectsCaptor = ArgumentCaptor.forClass(Set.class); verify(projectLifeCycleListeners).onProjectsDeleted(projectsCaptor.capture()); assertThat(projectsCaptor.getValue()).hasSize(1_000); @@ -306,7 +306,7 @@ public class BulkDeleteActionIT { private void verifyComponentDeleted(ComponentDto... projects) { ArgumentCaptor<ComponentDto> argument = ArgumentCaptor.forClass(ComponentDto.class); - verify(componentCleanerService, times(projects.length)).delete(any(DbSession.class), argument.capture()); + verify(componentCleanerService, times(projects.length)).deleteComponent(any(DbSession.class), argument.capture()); for (ComponentDto project : projects) { assertThat(argument.getAllValues()).extracting(ComponentDto::uuid).contains(project.uuid()); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java index d80a7117d52..1906ad4bde8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/setting/ws/ValuesActionIT.java @@ -335,28 +335,28 @@ public class ValuesActionIT { } @Test - public void return_inherited_values_on_module() { + public void return_inherited_values_on_component() { logInAsProjectUser(); ComponentDto file = db.components().insertComponent(newFileDto(project)); definitions.addComponents(asList( PropertyDefinition.builder("defaultProperty").defaultValue("default").onQualifiers(PROJECT).build(), PropertyDefinition.builder("globalProperty").onQualifiers(PROJECT).build(), PropertyDefinition.builder("projectProperty").onQualifiers(PROJECT).build(), - PropertyDefinition.builder("moduleProperty").onQualifiers(PROJECT).build())); + PropertyDefinition.builder("componentProperty").onQualifiers(PROJECT).build())); db.properties().insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("globalProperty").setValue("global")); db.properties().insertProperties(null, project.getKey(), project.name(), project.qualifier(), newComponentPropertyDto(project).setKey("projectProperty").setValue("project")); db.properties().insertProperties(null, file.getKey(), file.name(), file.qualifier(), - newComponentPropertyDto(file).setKey("moduleProperty").setValue("module")); + newComponentPropertyDto(file).setKey("componentProperty").setValue("component")); - ValuesWsResponse result = executeRequestForComponentProperties(file, "defaultProperty", "globalProperty", "projectProperty", "moduleProperty"); + ValuesWsResponse result = executeRequestForComponentProperties(file, "defaultProperty", "globalProperty", "projectProperty", "componentProperty"); assertThat(result.getSettingsList()).hasSize(4); assertSetting(result.getSettings(0), "defaultProperty", "default", true); assertSetting(result.getSettings(1), "globalProperty", "global", true); assertSetting(result.getSettings(2), "projectProperty", "project", true); - assertSetting(result.getSettings(3), "moduleProperty", "module", false); + assertSetting(result.getSettings(3), "componentProperty", "component", false); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/source/ws/ShowActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/source/ws/ShowActionIT.java index ee50e82fe5e..efbbffdfaf6 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/source/ws/ShowActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/source/ws/ShowActionIT.java @@ -27,6 +27,7 @@ import org.sonar.api.resources.Qualifiers; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDao; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; @@ -54,6 +55,7 @@ public class ShowActionIT { private DbClient dbClient = mock(DbClient.class); private DbSession session = mock(DbSession.class); private ComponentDao componentDao = mock(ComponentDao.class); + private BranchDao branchDao = mock(BranchDao.class); private ComponentDto project = ComponentTesting.newPrivateProjectDto(); private ComponentDto file = ComponentTesting.newFileDto(project); private ShowAction underTest = new ShowAction(sourceService, dbClient, userSessionRule, @@ -63,6 +65,7 @@ public class ShowActionIT { @Before public void setUp() { when(dbClient.componentDao()).thenReturn(componentDao); + when(dbClient.branchDao()).thenReturn(branchDao); when(dbClient.openSession(false)).thenReturn(session); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java index 7557eaaa0df..435bd6dc4e8 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -54,12 +54,6 @@ public class ComponentCleanerService { } } - public void deleteComponents(DbSession dbSession, List<ComponentDto> components) { - for (ComponentDto component : components) { - delete(dbSession, component); - } - } - public void deleteBranch(DbSession dbSession, BranchDto branch) { dbClient.purgeDao().deleteBranch(dbSession, branch.getUuid()); projectIndexers.commitAndIndexBranches(dbSession, singletonList(branch), PROJECT_DELETION); @@ -78,12 +72,12 @@ public class ComponentCleanerService { projectIndexers.commitAndIndexProjects(dbSession, singletonList(application), PROJECT_DELETION); } - public void delete(DbSession dbSession, ComponentDto project) { - checkArgument(hasProjectScope(project) && isDeletable(project) && project.getMainBranchProjectUuid() == null, "Only projects can be deleted"); - dbClient.purgeDao().deleteProject(dbSession, project.uuid(), project.qualifier(), project.name(), project.getKey()); - dbClient.userDao().cleanHomepage(dbSession, project); - dbClient.userTokenDao().deleteByProjectKey(dbSession, project.getKey()); - projectIndexers.commitAndIndexComponents(dbSession, singletonList(project), PROJECT_DELETION); + public void deleteComponent(DbSession dbSession, ComponentDto component) { + checkArgument(hasProjectScope(component) && isDeletable(component), "Only projects can be deleted"); + dbClient.purgeDao().deleteProject(dbSession, component.uuid(), component.qualifier(), component.name(), component.getKey()); + dbClient.userDao().cleanHomepage(dbSession, component); + dbClient.userTokenDao().deleteByProjectKey(dbSession, component.getKey()); + projectIndexers.commitAndIndexComponents(dbSession, singletonList(component), PROJECT_DELETION); } private static boolean hasProjectScope(ComponentDto project) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentFinder.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentFinder.java index 3ed37818c31..ef9394061c1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentFinder.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentFinder.java @@ -113,6 +113,30 @@ public class ComponentFinder { return getBranchOrPullRequest(dbSession, project.getUuid(), project.getKey(), branchKey, pullRequestKey); } + public ProjectAndBranch getAppOrProjectAndBranch(DbSession dbSession, String projectKey, @Nullable String branchKey, @Nullable String pullRequestKey) { + ProjectDto projectOrApp = getProjectOrApplicationByKey(dbSession, projectKey); + BranchDto branch = getBranchOrPullRequest(dbSession, projectOrApp, branchKey, pullRequestKey); + return new ProjectAndBranch(projectOrApp, branch); + } + + public static class ProjectAndBranch { + private final ProjectDto project; + private final BranchDto branch; + + public ProjectAndBranch(ProjectDto project, BranchDto branch) { + this.project = project; + this.branch = branch; + } + + public ProjectDto getProject() { + return project; + } + + public BranchDto getBranch() { + return branch; + } + } + public BranchDto getBranchOrPullRequest(DbSession dbSession, String projectUuid, String projectKey, @Nullable String branchKey, @Nullable String pullRequestKey) { if (branchKey != null) { return dbClient.branchDao().selectByBranchKey(dbSession, projectUuid, branchKey) @@ -139,23 +163,22 @@ public class ComponentFinder { } private ComponentDto getByKey(DbSession dbSession, String key, String label) { - return checkComponent(dbClient.componentDao().selectByKey(dbSession, key), "%s key '%s' not found", label, key); + return checkComponent(dbSession, dbClient.componentDao().selectByKey(dbSession, key), "%s key '%s' not found", label, key); } - /** - * This method only returns components in main branches. - */ public ComponentDto getByUuidFromMainBranch(DbSession dbSession, String uuid) { return getByUuidFromMainBranch(dbSession, uuid, LABEL_COMPONENT); } private ComponentDto getByUuidFromMainBranch(DbSession dbSession, String uuid, String label) { - return checkComponent(dbClient.componentDao().selectByUuid(dbSession, uuid), "%s id '%s' not found", label, uuid); + return checkComponent(dbSession, dbClient.componentDao().selectByUuid(dbSession, uuid), "%s id '%s' not found", label, uuid); } - private static ComponentDto checkComponent(Optional<ComponentDto> componentDto, String message, Object... messageArguments) { - if (componentDto.isPresent() && componentDto.get().isEnabled() && componentDto.get().getMainBranchProjectUuid() == null) { - return componentDto.get(); + private ComponentDto checkComponent(DbSession session, Optional<ComponentDto> componentDto, String message, Object... messageArguments) { + if (componentDto.isPresent() && componentDto.get().isEnabled()) { + if (dbClient.branchDao().selectByUuid(session, componentDto.get().branchUuid()).map(BranchDto::isMain).orElse(true)) { + return componentDto.get(); + } } throw new NotFoundException(format(message, messageArguments)); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ComponentDtoToWsComponent.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ComponentDtoToWsComponent.java index 45a3b0c4285..8054a7745d0 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ComponentDtoToWsComponent.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ComponentDtoToWsComponent.java @@ -66,7 +66,7 @@ class ComponentDtoToWsComponent { } public static Components.Component.Builder componentDtoToWsComponent(ComponentDto dto, @Nullable ProjectDto parentProjectDto, - @Nullable SnapshotDto lastAnalysis, @Nullable String branch, @Nullable String pullRequest) { + @Nullable SnapshotDto lastAnalysis, boolean isMainBranch, @Nullable String branch, @Nullable String pullRequest) { Components.Component.Builder wsComponent = Components.Component.newBuilder() .setKey(ComponentDto.removeBranchAndPullRequestFromKey(dto.getKey())) .setName(dto.name()) @@ -84,7 +84,7 @@ class ComponentDtoToWsComponent { }); if (QUALIFIERS_WITH_VISIBILITY.contains(dto.qualifier())) { wsComponent.setVisibility(Visibility.getLabel(dto.isPrivate())); - if (Arrays.asList(Qualifiers.PROJECT, Qualifiers.APP).contains(dto.qualifier()) && dto.getMainBranchProjectUuid() != null && parentProjectDto != null) { + if (Arrays.asList(Qualifiers.PROJECT, Qualifiers.APP).contains(dto.qualifier()) && parentProjectDto != null && isMainBranch) { wsComponent.getTagsBuilder().addAllTags(parentProjectDto.getTags()); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java index fa8b9de4696..277718f66ef 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/ShowAction.java @@ -43,7 +43,6 @@ import org.sonar.server.user.UserSession; import org.sonarqube.ws.Components; import org.sonarqube.ws.Components.ShowWsResponse; -import static java.util.Optional.ofNullable; import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentDtoToWsComponent; import static org.sonar.server.component.ws.ComponentDtoToWsComponent.projectOrAppToWsComponent; import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH; @@ -143,30 +142,37 @@ public class ShowAction implements ComponentsWsAction { private Components.Component.Builder toWsComponent(DbSession dbSession, ComponentDto component, @Nullable SnapshotDto lastAnalysis, Request request) { + + // project or application if (isProjectOrApp(component)) { ProjectDto project = dbClient.projectDao().selectProjectOrAppByKey(dbSession, component.getKey()) .orElseThrow(() -> new IllegalStateException("Project is in invalid state.")); boolean needIssueSync = needIssueSync(dbSession, component, project); - return projectOrAppToWsComponent(project, lastAnalysis) + return projectOrAppToWsComponent(project, lastAnalysis).setNeedIssueSync(needIssueSync); + } + + // parent project can an application. For components in portfolios, it will be null + ProjectDto parentProject = dbClient.projectDao().selectByBranchUuid(dbSession, component.branchUuid()).orElse(null); + boolean needIssueSync = needIssueSync(dbSession, component, parentProject); + + // if this is a project calculated in a portfolio or app, we need to include the original branch name (if any) + if (component.getCopyComponentUuid() != null) { + String branch = dbClient.branchDao().selectByUuid(dbSession, component.getCopyComponentUuid()) + .filter(b -> !b.isMain()) + .map(BranchDto::getKey) + .orElse(null); + return componentDtoToWsComponent(component, parentProject, lastAnalysis, true, branch, null) + .setNeedIssueSync(needIssueSync); + } + + // branch won't exist for portfolios + Optional<BranchDto> branchDto = dbClient.branchDao().selectByUuid(dbSession, component.branchUuid()); + if (branchDto.isPresent() && !branchDto.get().isMain()) { + return componentDtoToWsComponent(component, parentProject, lastAnalysis, false, request.branch, request.pullRequest) .setNeedIssueSync(needIssueSync); } else { - Optional<ProjectDto> parentProject = dbClient.projectDao().selectByUuid(dbSession, - ofNullable(component.getMainBranchProjectUuid()).orElse(component.branchUuid())); - boolean needIssueSync = needIssueSync(dbSession, component, parentProject.orElse(null)); - if (component.getCopyComponentUuid() != null) { - String branch = dbClient.branchDao().selectByUuid(dbSession, component.getCopyComponentUuid()) - .filter(b -> !b.isMain()) - .map(BranchDto::getKey) - .orElse(null); - return componentDtoToWsComponent(component, parentProject.orElse(null), lastAnalysis, branch, null) - .setNeedIssueSync(needIssueSync); - } else if (component.getMainBranchProjectUuid() != null) { - return componentDtoToWsComponent(component, parentProject.orElse(null), lastAnalysis, request.branch, request.pullRequest) - .setNeedIssueSync(needIssueSync); - } else { - return componentDtoToWsComponent(component, parentProject.orElse(null), lastAnalysis, null, null) - .setNeedIssueSync(needIssueSync); - } + return componentDtoToWsComponent(component, parentProject, lastAnalysis, true, null, null) + .setNeedIssueSync(needIssueSync); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/TreeAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/TreeAction.java index 1cbba6819d9..1f786a346cb 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/TreeAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/TreeAction.java @@ -233,33 +233,33 @@ public class TreeAction implements ComponentsWsAction { .filter(b -> !b.isMain()) .collect(Collectors.toMap(BranchDto::getUuid, BranchDto::getBranchKey)); - response.setBaseComponent(toWsComponent(dbSession, baseComponent, referenceComponentsByUuid, branchKeyByReferenceUuid, request)); + boolean isMainBranch = dbClient.branchDao().selectByUuid(dbSession, baseComponent.branchUuid()).map(BranchDto::isMain).orElse(true); + response.setBaseComponent(toWsComponent(dbSession, baseComponent, isMainBranch, referenceComponentsByUuid, branchKeyByReferenceUuid, request)); for (ComponentDto dto : components) { - response.addComponents(toWsComponent(dbSession, dto, referenceComponentsByUuid, branchKeyByReferenceUuid, request)); + response.addComponents(toWsComponent(dbSession, dto, isMainBranch, referenceComponentsByUuid, branchKeyByReferenceUuid, request)); } return response.build(); } - private Components.Component.Builder toWsComponent(DbSession dbSession, ComponentDto component, + private Components.Component.Builder toWsComponent(DbSession dbSession, ComponentDto component, boolean isMainBranch, Map<String, ComponentDto> referenceComponentsByUuid, Map<String, String> branchKeyByReferenceUuid, Request request) { ComponentDto referenceComponent = referenceComponentsByUuid.get(component.getCopyComponentUuid()); Components.Component.Builder wsComponent; - if (component.getMainBranchProjectUuid() == null && component.isRootProject() && PROJECT_OR_APP_QUALIFIERS.contains(component.qualifier())) { + if (isMainBranch && component.isRootProject() && PROJECT_OR_APP_QUALIFIERS.contains(component.qualifier())) { ProjectDto projectDto = componentFinder.getProjectOrApplicationByKey(dbSession, component.getKey()); wsComponent = projectOrAppToWsComponent(projectDto, null); } else { - Optional<ProjectDto> parentProject = dbClient.projectDao().selectByUuid(dbSession, - ofNullable(component.getMainBranchProjectUuid()).orElse(component.branchUuid())); + ProjectDto parentProject = dbClient.projectDao().selectByBranchUuid(dbSession, component.branchUuid()).orElse(null); if (referenceComponent != null) { - wsComponent = componentDtoToWsComponent(component, parentProject.orElse(null), null, branchKeyByReferenceUuid.get(referenceComponent.uuid()), null); - } else if (component.getMainBranchProjectUuid() != null) { - wsComponent = componentDtoToWsComponent(component, parentProject.orElse(null), null, request.branch, request.pullRequest); + wsComponent = componentDtoToWsComponent(component, parentProject, null, false, branchKeyByReferenceUuid.get(referenceComponent.uuid()), null); + } else if (!isMainBranch) { + wsComponent = componentDtoToWsComponent(component, parentProject, null, false, request.branch, request.pullRequest); } else { - wsComponent = componentDtoToWsComponent(component, parentProject.orElse(null), null, null, null); + wsComponent = componentDtoToWsComponent(component, parentProject, null, true, null, null); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java index 5ec0692777a..31b961e38e0 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/AssignAction.java @@ -30,8 +30,8 @@ import org.sonar.core.issue.IssueChangeContext; import org.sonar.core.util.Uuids; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; import org.sonar.db.issue.IssueDto; +import org.sonar.db.project.ProjectDto; import org.sonar.db.user.UserDto; import org.sonar.server.issue.IssueFieldsSetter; import org.sonar.server.issue.ws.IssueUpdater; @@ -135,11 +135,11 @@ public class AssignAction implements HotspotsWsAction { return checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, assignee), "Unknown user: %s", assignee); } - private void checkAssigneeProjectPermission(DbSession dbSession, UserDto assignee, String issueProjectUuid) { - ComponentDto componentDto = checkFoundWithOptional(dbClient.componentDao().selectByUuid(dbSession, issueProjectUuid), - "Could not find project for issue"); - String mainProjectUuid = componentDto.getMainBranchProjectUuid() == null ? componentDto.uuid() : componentDto.getMainBranchProjectUuid(); - if (componentDto.isPrivate() && !hasProjectPermission(dbSession, assignee.getUuid(), mainProjectUuid)) { + private void checkAssigneeProjectPermission(DbSession dbSession, UserDto assignee, String issueBranchUuid) { + ProjectDto project = checkFoundWithOptional(dbClient.projectDao().selectByBranchUuid(dbSession, issueBranchUuid), + "Could not find branch for issue"); + + if (project.isPrivate() && !hasProjectPermission(dbSession, assignee.getUuid(), project.getUuid())) { throw new IllegalArgumentException(String.format("Provided user with login '%s' does not have 'Browse' permission to project", assignee.getLogin())); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java index 590d9bd5ce0..e7edae1e7f7 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java @@ -38,7 +38,6 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.search.SearchHit; import org.jetbrains.annotations.NotNull; import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleType; import org.sonar.api.server.ws.Change; @@ -57,6 +56,7 @@ import org.sonar.db.project.ProjectDto; import org.sonar.db.protobuf.DbIssues; import org.sonar.db.rule.RuleDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.component.ComponentFinder.ProjectAndBranch; import org.sonar.server.es.SearchOptions; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.TextRangeResponseFormatter; @@ -70,7 +70,6 @@ import org.sonarqube.ws.Common; import org.sonarqube.ws.Hotspots; import org.sonarqube.ws.Hotspots.SearchWsResponse; -import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; @@ -179,7 +178,7 @@ public class SearchAction implements HotspotsWsAction { validateParameters(wsRequest); try (DbSession dbSession = dbClient.openSession(false)) { checkIfNeedIssueSync(dbSession, wsRequest); - Optional<ComponentDto> project = getAndValidateProjectOrApplication(dbSession, wsRequest); + Optional<ProjectAndBranch> project = getAndValidateProjectOrApplication(dbSession, wsRequest); SearchResponseData searchResponseData = searchHotspots(wsRequest, dbSession, project.orElse(null)); loadComponents(dbSession, searchResponseData); loadRules(dbSession, searchResponseData); @@ -327,24 +326,22 @@ public class SearchAction implements HotspotsWsAction { action.setResponseExample(getClass().getResource("search-example.json")); } - private Optional<ComponentDto> getAndValidateProjectOrApplication(DbSession dbSession, WsRequest wsRequest) { + private Optional<ProjectAndBranch> getAndValidateProjectOrApplication(DbSession dbSession, WsRequest wsRequest) { return wsRequest.getProjectKey().map(projectKey -> { - ComponentDto project = getProject(dbSession, projectKey, wsRequest.getBranch().orElse(null), wsRequest.getPullRequest().orElse(null)); - if (!Scopes.PROJECT.equals(project.scope()) || !SUPPORTED_QUALIFIERS.contains(project.qualifier()) || !project.isEnabled()) { + ProjectAndBranch appOrProjectAndBranch = componentFinder.getAppOrProjectAndBranch(dbSession, projectKey, wsRequest.getBranch().orElse(null), + wsRequest.getPullRequest().orElse(null)); + + if (!SUPPORTED_QUALIFIERS.contains(appOrProjectAndBranch.getProject().getQualifier())) { throw new NotFoundException(format("Project '%s' not found", projectKey)); } - userSession.checkComponentPermission(USER, project); - userSession.checkChildProjectsPermission(USER, project); - return project; + userSession.checkProjectPermission(USER, appOrProjectAndBranch.getProject()); + userSession.checkChildProjectsPermission(USER, appOrProjectAndBranch.getProject()); + return appOrProjectAndBranch; }); } - private ComponentDto getProject(DbSession dbSession, String projectKey, @Nullable String branch, @Nullable String pullRequest) { - return componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, projectKey, branch, pullRequest); - } - - private SearchResponseData searchHotspots(WsRequest wsRequest, DbSession dbSession, @Nullable ComponentDto project) { - SearchResponse result = doIndexSearch(wsRequest, dbSession, project); + private SearchResponseData searchHotspots(WsRequest wsRequest, DbSession dbSession, @Nullable ProjectAndBranch projectorApp) { + SearchResponse result = doIndexSearch(wsRequest, dbSession, projectorApp); List<String> issueKeys = Arrays.stream(result.getHits().getHits()) .map(SearchHit::getId) .collect(toList(result.getHits().getHits().length)); @@ -371,28 +368,29 @@ public class SearchAction implements HotspotsWsAction { .toList(); } - private SearchResponse doIndexSearch(WsRequest wsRequest, DbSession dbSession, @Nullable ComponentDto project) { + private SearchResponse doIndexSearch(WsRequest wsRequest, DbSession dbSession, @Nullable ProjectAndBranch projectOrAppAndBranch) { var builder = IssueQuery.builder() .types(singleton(RuleType.SECURITY_HOTSPOT.name())) .sort(IssueQuery.SORT_HOTSPOTS) .asc(true) .statuses(wsRequest.getStatus().map(Collections::singletonList).orElse(STATUSES)); - if (project != null) { - String projectUuid = firstNonNull(project.getMainBranchProjectUuid(), project.uuid()); - if (Qualifiers.APP.equals(project.qualifier())) { - builder.viewUuids(singletonList(projectUuid)); + if (projectOrAppAndBranch != null) { + ProjectDto projectOrApp = projectOrAppAndBranch.getProject(); + + if (Qualifiers.APP.equals(projectOrApp.getQualifier())) { + builder.viewUuids(singletonList(projectOrApp.getUuid())); if (wsRequest.isInNewCodePeriod() && wsRequest.getPullRequest().isEmpty()) { - addInNewCodePeriodFilterByProjects(builder, dbSession, project); + addInNewCodePeriodFilterByProjects(builder, dbSession, projectOrAppAndBranch.getBranch()); } } else { - builder.projectUuids(singletonList(projectUuid)); + builder.projectUuids(singletonList(projectOrApp.getUuid())); if (wsRequest.isInNewCodePeriod() && wsRequest.getPullRequest().isEmpty()) { - addInNewCodePeriodFilter(dbSession, project, builder); + addInNewCodePeriodFilter(dbSession, projectOrApp, builder); } } - addMainBranchFilter(project, builder); + addMainBranchFilter(projectOrAppAndBranch.getBranch(), builder); } if (!wsRequest.getHotspotKeys().isEmpty()) { @@ -458,17 +456,17 @@ public class SearchAction implements HotspotsWsAction { } } - private static void addMainBranchFilter(@NotNull ComponentDto project, IssueQuery.Builder builder) { - if (project.getMainBranchProjectUuid() == null) { + private static void addMainBranchFilter(@NotNull BranchDto branch, IssueQuery.Builder builder) { + if (branch.isMain()) { builder.mainBranch(true); } else { - builder.branchUuid(project.uuid()); + builder.branchUuid(branch.getUuid()); builder.mainBranch(false); } } - private void addInNewCodePeriodFilter(DbSession dbSession, @NotNull ComponentDto project, IssueQuery.Builder builder) { - Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, project.uuid()); + private void addInNewCodePeriodFilter(DbSession dbSession, @NotNull ProjectDto project, IssueQuery.Builder builder) { + Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, project.getUuid()); boolean isLastAnalysisUsingReferenceBranch = snapshot.map(SnapshotDto::getPeriodMode) .orElse("").equals(REFERENCE_BRANCH.name()); @@ -484,21 +482,23 @@ public class SearchAction implements HotspotsWsAction { } } - private void addInNewCodePeriodFilterByProjects(IssueQuery.Builder builder, DbSession dbSession, ComponentDto application) { - Set<String> projectUuids; - if (application.getMainBranchProjectUuid() == null) { - projectUuids = dbClient.applicationProjectsDao().selectProjects(dbSession, application.uuid()).stream() + private void addInNewCodePeriodFilterByProjects(IssueQuery.Builder builder, DbSession dbSession, BranchDto appBranch) { + Set<String> branchUuids; + + if (appBranch.isMain()) { + // TODO assuming project uuid matches main branch uuid + branchUuids = dbClient.applicationProjectsDao().selectProjects(dbSession, appBranch.getProjectUuid()).stream() .map(ProjectDto::getUuid) .collect(Collectors.toSet()); } else { - projectUuids = dbClient.applicationProjectsDao().selectProjectBranchesFromAppBranchUuid(dbSession, application.uuid()).stream() + branchUuids = dbClient.applicationProjectsDao().selectProjectBranchesFromAppBranchUuid(dbSession, appBranch.getUuid()).stream() .map(BranchDto::getUuid) .collect(Collectors.toSet()); } long now = system2.now(); - List<SnapshotDto> snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids); + List<SnapshotDto> snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, branchUuids); Set<String> newCodeReferenceByProjects = snapshots .stream() diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java index d284e60e318..96c6a7a3968 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/live/LiveMeasureComputerImpl.java @@ -97,8 +97,8 @@ public class LiveMeasureComputerImpl implements LiveMeasureComputer { } BranchDto branch = loadBranch(dbSession, branchComponent); - Configuration config = projectConfigurationLoader.loadProjectConfiguration(dbSession, branch); ProjectDto project = loadProject(dbSession, branch.getProjectUuid()); + Configuration config = projectConfigurationLoader.loadBranchConfiguration(dbSession, branch); QualityGate qualityGate = qGateComputer.loadQualityGate(dbSession, project, branch); MeasureMatrix matrix = loadMeasureMatrix(dbSession, components.getAllUuids(), qualityGate); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentAction.java index c4129a81e7f..8f325fd6553 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentAction.java @@ -165,7 +165,7 @@ public class ComponentAction implements MeasuresWsAction { Optional<Measures.Period> period = snapshotToWsPeriods(analysis); Optional<RefComponent> reference = getReference(dbSession, component); - return buildResponse(request, component, reference, measuresByMetric, metrics, period); + return buildResponse(dbSession, request, component, reference, measuresByMetric, metrics, period); } } @@ -246,10 +246,9 @@ public class ComponentAction implements MeasuresWsAction { return refBranch.map(rb -> new RefComponent(rb, refComponent.get())); } - private static ComponentWsResponse buildResponse(ComponentRequest request, ComponentDto component, Optional<RefComponent> reference, + private ComponentWsResponse buildResponse(DbSession dbSession, ComponentRequest request, ComponentDto component, Optional<RefComponent> reference, Map<MetricDto, LiveMeasureDto> measuresByMetric, Collection<MetricDto> metrics, Optional<Measures.Period> period) { ComponentWsResponse.Builder response = ComponentWsResponse.newBuilder(); - boolean isMainBranch = component.getMainBranchProjectUuid() == null; if (reference.isPresent()) { BranchDto refBranch = reference.get().getRefBranch(); @@ -257,6 +256,7 @@ public class ComponentAction implements MeasuresWsAction { response.setComponent(componentDtoToWsComponent(component, measuresByMetric, singletonMap(refComponent.uuid(), refComponent), refBranch.isMain() ? null : refBranch.getBranchKey(), null)); } else { + boolean isMainBranch = dbClient.branchDao().selectByUuid(dbSession, component.branchUuid()).map(BranchDto::isMain).orElse(true); response.setComponent(componentDtoToWsComponent(component, measuresByMetric, emptyMap(), isMainBranch ? null : request.getBranch(), request.getPullRequest())); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java index da343f45723..35dfde3e2f1 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java @@ -270,7 +270,7 @@ public class ComponentTreeAction implements MeasuresWsAction { private ComponentTreeWsResponse doHandle(ComponentTreeRequest request) { ComponentTreeData data = load(request); if (data.getComponents() == null) { - return emptyResponse(data.getBaseComponent(), request); + return emptyResponse(data.getBaseComponent(), data.getBranch(), request); } return buildResponse( @@ -290,7 +290,7 @@ public class ComponentTreeAction implements MeasuresWsAction { .setTotal(paging.total()) .build(); - boolean isMainBranch = data.getBaseComponent().getMainBranchProjectUuid() == null; + boolean isMainBranch = data.getBranch() == null || data.getBranch().isMain(); response.setBaseComponent( toWsComponent( data.getBaseComponent(), @@ -333,14 +333,14 @@ public class ComponentTreeAction implements MeasuresWsAction { return additionalFields != null && additionalFields.contains(ADDITIONAL_METRICS); } - private static ComponentTreeWsResponse emptyResponse(@Nullable ComponentDto baseComponent, ComponentTreeRequest request) { + private static ComponentTreeWsResponse emptyResponse(@Nullable ComponentDto baseComponent, @Nullable BranchDto branch, ComponentTreeRequest request) { ComponentTreeWsResponse.Builder response = ComponentTreeWsResponse.newBuilder(); response.getPagingBuilder() .setPageIndex(request.getPage()) .setPageSize(request.getPageSize()) .setTotal(0); if (baseComponent != null) { - boolean isMainBranch = baseComponent.getMainBranchProjectUuid() == null; + boolean isMainBranch = branch == null || branch.isMain(); response.setBaseComponent(componentDtoToWsComponent(baseComponent, isMainBranch ? null : request.getBranch(), request.getPullRequest())); } return response.build(); @@ -415,9 +415,13 @@ public class ComponentTreeAction implements MeasuresWsAction { try (DbSession dbSession = dbClient.openSession(false)) { ComponentDto baseComponent = loadComponent(dbSession, wsRequest); checkPermissions(baseComponent); + // portfolios don't have branches + BranchDto branchDto = dbClient.branchDao().selectByUuid(dbSession, baseComponent.branchUuid()).orElse(null); + Optional<SnapshotDto> baseSnapshot = dbClient.snapshotDao().selectLastAnalysisByRootComponentUuid(dbSession, baseComponent.branchUuid()); if (baseSnapshot.isEmpty()) { return ComponentTreeData.builder() + .setBranch(branchDto) .setBaseComponent(baseComponent) .build(); } @@ -455,6 +459,7 @@ public class ComponentTreeAction implements MeasuresWsAction { return ComponentTreeData.builder() .setBaseComponent(baseComponent) + .setBranch(branchDto) .setComponentsFromDb(components) .setComponentCount(componentCount) .setBranchByReferenceUuid(branchByReferenceUuid) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java index 4c86e9f6668..7ddd4bafb9f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/measure/ws/ComponentTreeData.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.measure.LiveMeasureDto; import org.sonar.db.metric.MetricDto; @@ -35,6 +36,7 @@ import static java.util.Objects.requireNonNull; class ComponentTreeData { private final ComponentDto baseComponent; + private final BranchDto branch; private final List<ComponentDto> components; private final int componentCount; private final Map<String, ComponentDto> referenceComponentsByUuid; @@ -47,6 +49,7 @@ class ComponentTreeData { this.baseComponent = builder.baseComponent; this.components = builder.componentsFromDb; this.componentCount = builder.componentCount; + this.branch = builder.branch; this.referenceComponentsByUuid = builder.referenceComponentsByUuid; this.branchByReferenceUuid = builder.branchByReferenceUuid; this.metrics = builder.metrics; @@ -63,6 +66,11 @@ class ComponentTreeData { } @CheckForNull + public BranchDto getBranch() { + return branch; + } + + @CheckForNull List<ComponentDto> getComponents() { return components; } @@ -102,6 +110,8 @@ class ComponentTreeData { private int componentCount; private List<MetricDto> metrics; private Measures.Period period; + private BranchDto branch; + private Table<String, MetricDto, Measure> measuresByComponentUuidAndMetric; private Builder() { @@ -128,6 +138,11 @@ class ComponentTreeData { return this; } + public Builder setBranch(@Nullable BranchDto branch) { + this.branch = branch; + return this; + } + public Builder setMetrics(List<MetricDto> metrics) { this.metrics = metrics; return this; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java index e431283145c..a38add5920c 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java @@ -94,7 +94,7 @@ public class BulkDeleteAction implements ProjectsWsAction { .setChangelog( new Change("7.8", parameterRequiredMessage), new Change("9.1", "The parameter '" + PARAM_ANALYZED_BEFORE + "' " - + "takes into account the analysis of all branches and pull requests, not only the main branch.")); + + "takes into account the analysis of all branches and pull requests, not only the main branch.")); action .createParam(PARAM_PROJECTS) @@ -115,7 +115,7 @@ public class BulkDeleteAction implements ProjectsWsAction { action.createParam(PARAM_VISIBILITY) .setDescription("Filter the projects that should be visible to everyone (%s), or only specific user/groups (%s).<br/>" + - "If no visibility is specified, the default project visibility will be used.", + "If no visibility is specified, the default project visibility will be used.", Visibility.PUBLIC.getLabel(), Visibility.PRIVATE.getLabel()) .setRequired(false) .setInternal(true) @@ -148,7 +148,7 @@ public class BulkDeleteAction implements ProjectsWsAction { Set<ComponentDto> componentDtos = new HashSet<>(dbClient.componentDao().selectByQuery(dbSession, query, 0, Integer.MAX_VALUE)); try { - componentDtos.forEach(p -> componentCleanerService.delete(dbSession, p)); + componentDtos.forEach(p -> componentCleanerService.deleteComponent(dbSession, p)); } finally { projectLifeCycleListeners.onProjectsDeleted(componentDtos.stream().map(Project::from).collect(MoreCollectors.toSet(componentDtos.size()))); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java index ab2002a6941..deb01610b6e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/ValuesAction.java @@ -25,6 +25,7 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Ordering; import com.google.common.collect.TreeMultimap; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -124,11 +125,9 @@ public class ValuesAction implements SettingsWsAction { try (DbSession dbSession = dbClient.openSession(true)) { ValuesRequest valuesRequest = ValuesRequest.from(request); Optional<ComponentDto> component = loadComponent(dbSession, valuesRequest); - BranchDto branchDto = component.map(c -> componentFinder.getBranchByUuid(dbSession, c.branchUuid())).orElse(null); - Set<String> keys = loadKeys(valuesRequest); Map<String, String> keysToDisplayMap = getKeysToDisplayMap(keys); - List<Setting> settings = loadSettings(dbSession, component, keysToDisplayMap.keySet(), branchDto); + List<Setting> settings = loadSettings(dbSession, component, keysToDisplayMap.keySet()); return new ValuesResponseBuilder(settings, component, keysToDisplayMap).build(); } } @@ -160,28 +159,33 @@ public class ValuesAction implements SettingsWsAction { return Optional.of(component); } - private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys, @Nullable BranchDto branchDto) { + private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys) { // List of settings must be kept in the following orders : default -> global -> component -> branch List<Setting> settings = new ArrayList<>(); settings.addAll(loadDefaultValues(keys)); settings.addAll(loadGlobalSettings(dbSession, keys)); - String branch = getBranchKeySafely(branchDto); - if (component.isPresent() && branch != null && component.get().getMainBranchProjectUuid() != null) { - ComponentDto project = componentFinder.getByUuidFromMainBranch(dbSession, component.get().getMainBranchProjectUuid()); - settings.addAll(loadComponentSettings(dbSession, keys, project).values()); - } - component.ifPresent(componentDto -> settings.addAll(loadComponentSettings(dbSession, keys, componentDto).values())); + component.ifPresent(c -> settings.addAll(loadComponentSettings(dbSession, c, keys))); return settings.stream() .filter(s -> settingsWsSupport.isVisible(s.getKey(), component)) .toList(); } - @CheckForNull - private static String getBranchKeySafely(@Nullable BranchDto branchDto) { - if (branchDto != null) { - return branchDto.isMain() ? null : branchDto.getBranchKey(); + private Collection<Setting> loadComponentSettings(DbSession dbSession, ComponentDto componentDto, Set<String> keys) { + BranchDto branchDto = componentFinder.getBranchByUuid(dbSession, componentDto.branchUuid()); + + List<String> componentUuids = new LinkedList<>(); + if (!branchDto.isMain()) { + ComponentDto mainBranchComponent = componentFinder.getByKey(dbSession, componentDto.getKey()); + if (!mainBranchComponent.isRoot()) { + componentUuids.add(mainBranchComponent.branchUuid()); + } + componentUuids.add(mainBranchComponent.uuid()); + } + if (!componentDto.isRoot()) { + componentUuids.add(componentDto.branchUuid()); } - return null; + componentUuids.add(componentDto.uuid()); + return loadComponentsSettings(dbSession, keys, componentUuids); } private List<Setting> loadDefaultValues(Set<String> keys) { @@ -209,14 +213,9 @@ public class ValuesAction implements SettingsWsAction { } /** - * Return list of settings by component uuid + * Return list of settings by component uuids */ - private Multimap<String, Setting> loadComponentSettings(DbSession dbSession, Set<String> keys, ComponentDto component) { - List<String> componentUuids = new LinkedList<>(); - if (!component.uuid().equals(component.branchUuid())) { - componentUuids.add(component.branchUuid()); - } - componentUuids.add(component.uuid()); + private Collection<Setting> loadComponentsSettings(DbSession dbSession, Set<String> keys, List<String> componentUuids) { List<PropertyDto> properties = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, keys, componentUuids); List<PropertyDto> propertySets = dbClient.propertiesDao().selectPropertiesByKeysAndComponentUuids(dbSession, getPropertySetKeys(properties), componentUuids); @@ -227,7 +226,7 @@ public class ValuesAction implements SettingsWsAction { settingsByUuid.put(componentUuid, Setting.createFromDto(propertyDto, getPropertySets(propertyKey, propertySets, componentUuid), propertyDefinitions.get(propertyKey))); } - return settingsByUuid; + return settingsByUuid.values(); } private Set<String> getPropertySetKeys(List<PropertyDto> properties) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/source/ws/LinesAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/source/ws/LinesAction.java index be693c44f8e..d24aec74705 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/source/ws/LinesAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/source/ws/LinesAction.java @@ -158,13 +158,13 @@ public class LinesAction implements SourcesWsAction { private ComponentDto loadComponent(DbSession dbSession, Request wsRequest) { String componentKey = wsRequest.param(PARAM_KEY); - String componentId = wsRequest.param(PARAM_UUID); + String componentUuid = wsRequest.param(PARAM_UUID); String branch = wsRequest.param(PARAM_BRANCH); String pullRequest = wsRequest.param(PARAM_PULL_REQUEST); - checkArgument(componentId == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", + checkArgument(componentUuid == null || (branch == null && pullRequest == null), "Parameter '%s' cannot be used at the same time as '%s' or '%s'", PARAM_UUID, PARAM_BRANCH, PARAM_PULL_REQUEST); if (branch == null && pullRequest == null) { - return componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, UUID_AND_KEY); + return componentFinder.getByUuidOrKey(dbSession, componentUuid, componentKey, UUID_AND_KEY); } checkRequest(componentKey != null, "The '%s' parameter is missing", PARAM_KEY); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/ComponentAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/ComponentAction.java index 8c8de6fcf66..58e63b6f858 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/ComponentAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/ui/ws/ComponentAction.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Predicate; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.config.Configuration; import org.sonar.api.resources.Qualifiers; @@ -43,6 +42,7 @@ import org.sonar.api.web.UserRole; import org.sonar.api.web.page.Page; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.measure.LiveMeasureDto; @@ -149,9 +149,10 @@ public class ComponentAction implements NavigationWsAction { String pullRequest = request.param(PARAM_PULL_REQUEST); ComponentDto component = componentFinder.getByKeyAndOptionalBranchOrPullRequest(session, componentKey, branch, pullRequest); checkComponentNotAModuleAndNotADirectory(component); - ComponentDto rootProjectOrBranch = getRootProjectOrBranch(component, session); - ComponentDto rootProject = rootProjectOrBranch.getMainBranchProjectUuid() == null ? rootProjectOrBranch - : componentFinder.getByUuidFromMainBranch(session, rootProjectOrBranch.getMainBranchProjectUuid()); + ComponentDto rootComponent = getRootProjectOrBranch(component, session); + // will be empty for portfolios + Optional<BranchDto> branchDto = dbClient.branchDao().selectByUuid(session, rootComponent.branchUuid()); + String projectOrPortfolioUuid = branchDto.map(BranchDto::getProjectUuid).orElse(rootComponent.branchUuid()); if (!userSession.hasComponentPermission(USER, component) && !userSession.hasComponentPermission(ADMIN, component) && !userSession.isSystemAdministrator()) { @@ -161,11 +162,10 @@ public class ComponentAction implements NavigationWsAction { try (JsonWriter json = response.newJsonWriter()) { json.beginObject(); - boolean isFavourite = isFavourite(session, rootProject, component); - String branchKey = getBranchKey(session, component); - writeComponent(json, component, analysis.orElse(null), isFavourite, branchKey); + boolean isFavourite = isFavourite(session, projectOrPortfolioUuid, component); + writeComponent(json, component, analysis.orElse(null), isFavourite, branchDto.map(BranchDto::getBranchKey).orElse(null)); writeProfiles(json, session, component); - writeQualityGate(json, session, rootProject); + writeQualityGate(json, session, projectOrPortfolioUuid); if (userSession.hasComponentPermission(ADMIN, component) || userSession.hasPermission(ADMINISTER_QUALITY_PROFILES) || userSession.hasPermission(ADMINISTER_QUALITY_GATES)) { @@ -177,14 +177,6 @@ public class ComponentAction implements NavigationWsAction { } } - @CheckForNull - private String getBranchKey(DbSession session, ComponentDto component) { - // TODO portfolios may have no branch, so we shouldn't faul? - return dbClient.branchDao().selectByUuid(session, component.branchUuid()) - .map(b -> b.isMain() ? null : b.getBranchKey()) - .orElse(null); - } - private static void checkComponentNotAModuleAndNotADirectory(ComponentDto component) { BadRequestException.checkRequest(!MODULE_OR_DIR_QUALIFIERS.contains(component.qualifier()), "Operation not supported for module or directory components"); } @@ -239,11 +231,11 @@ public class ComponentAction implements NavigationWsAction { } } - private boolean isFavourite(DbSession session, ComponentDto rootComponent, ComponentDto component) { + private boolean isFavourite(DbSession session, String projectOrPortfolioUuid, ComponentDto component) { PropertyQuery propertyQuery = PropertyQuery.builder() .setUserUuid(userSession.getUuid()) .setKey("favourite") - .setComponentUuid(isSubview(component) ? component.uuid() : rootComponent.uuid()) + .setComponentUuid(isSubview(component) ? component.uuid() : projectOrPortfolioUuid) .build(); List<PropertyDto> componentFavourites = dbClient.propertiesDao().selectByQuery(propertyQuery, session); return componentFavourites.size() == 1; @@ -266,8 +258,8 @@ public class ComponentAction implements NavigationWsAction { json.endArray(); } - private void writeQualityGate(JsonWriter json, DbSession session, ComponentDto component) { - var qualityGateData = qualityGateFinder.getEffectiveQualityGate(session, component.uuid()); + private void writeQualityGate(JsonWriter json, DbSession session, String projectOrPortfolioUuid) { + var qualityGateData = qualityGateFinder.getEffectiveQualityGate(session, projectOrPortfolioUuid); json.name("qualityGate").beginObject() .prop("key", qualityGateData.getUuid()) .prop("name", qualityGateData.getName()) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/TestProjectConfigurationLoader.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/TestProjectConfigurationLoader.java index 36813971f4f..4984ab3dd8d 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/TestProjectConfigurationLoader.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/setting/TestProjectConfigurationLoader.java @@ -22,7 +22,6 @@ package org.sonar.server.setting; import org.sonar.api.config.Configuration; import org.sonar.db.DbSession; import org.sonar.db.component.BranchDto; -import org.sonar.db.component.ComponentDto; public class TestProjectConfigurationLoader implements ProjectConfigurationLoader { @@ -33,7 +32,12 @@ public class TestProjectConfigurationLoader implements ProjectConfigurationLoade } @Override - public Configuration loadProjectConfiguration(DbSession dbSession, BranchDto branch) { + public Configuration loadBranchConfiguration(DbSession dbSession, BranchDto branch) { + return config; + } + + @Override + public Configuration loadProjectConfiguration(DbSession dbSession, String projectUuid) { return config; } } |