diff options
author | Cody Simms <141657208+cody-simms-sonarsource@users.noreply.github.com> | 2024-12-18 09:58:49 -0600 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-12-18 20:03:11 +0000 |
commit | ab3125728559f0d37ae3210610335c210dac02ba (patch) | |
tree | 9e10fdb801ba57c5f931fef505722dc5201fba4f | |
parent | ec0d8ad9cdb8097ddee68ceada41abd0b2632032 (diff) | |
download | sonarqube-ab3125728559f0d37ae3210610335c210dac02ba.tar.gz sonarqube-ab3125728559f0d37ae3210610335c210dac02ba.zip |
SONAR-23936 Query all portfolio projects at once rather than recursively
Co-authored-by: Duarte Meneses <duarte.meneses@sonarsource.com>
4 files changed, 62 insertions, 74 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java index 437961a5470..59dcb3ede0c 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java @@ -61,7 +61,8 @@ public class ComponentDao implements Dao { } public ComponentDto selectOrFailByUuid(DbSession session, String uuid) { - return selectByUuid(session, uuid).orElseThrow(() -> new RowNotFoundException(String.format("Component with uuid '%s' not found", uuid))); + return selectByUuid(session, uuid).orElseThrow(() -> new RowNotFoundException(String.format("Component with uuid '%s' not found", + uuid))); } public List<ComponentDto> selectByUuids(DbSession session, Collection<String> uuids) { @@ -99,18 +100,24 @@ public class ComponentDao implements Dao { */ /** - * @throws IllegalArgumentException if parameter query#getComponentIds() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values - * @throws IllegalArgumentException if parameter query#getComponentKeys() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values - * @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getComponentIds() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getComponentKeys() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values */ public List<ComponentDto> selectByQuery(DbSession dbSession, ComponentQuery query, Pagination pagination) { return selectByQueryImpl(dbSession, query, pagination); } /** - * @throws IllegalArgumentException if parameter query#getComponentIds() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values - * @throws IllegalArgumentException if parameter query#getComponentKeys() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values - * @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getComponentIds() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getComponentKeys() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values + * @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than + * {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values */ public int countByQuery(DbSession session, ComponentQuery query) { return countByQueryImpl(session, query); @@ -158,7 +165,8 @@ public class ComponentDao implements Dao { /** * If no branch or pull request is provided, returns components in the main branch */ - public List<ComponentDto> selectByKeys(DbSession session, Collection<String> keys, @Nullable String branch, @Nullable String pullRequest) { + public List<ComponentDto> selectByKeys(DbSession session, Collection<String> keys, @Nullable String branch, + @Nullable String pullRequest) { checkState(branch == null || pullRequest == null, "Can't set both branch and pull request"); return executeLargeInputs(keys, subKeys -> mapper(session).selectByKeysAndBranchOrPr(subKeys, branch, pullRequest)); } @@ -250,8 +258,10 @@ public class ComponentDao implements Dao { * Returns components with open issues from P/Rs that use a certain branch as reference (reference branch). * Excludes components from the current branch. */ - public List<KeyWithUuidDto> selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(DbSession dbSession, String referenceBranchUuid, String currentBranchUuid) { - return mapper(dbSession).selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(referenceBranchUuid, currentBranchUuid); + public List<KeyWithUuidDto> selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(DbSession dbSession, + String referenceBranchUuid, String currentBranchUuid) { + return mapper(dbSession).selectComponentsFromPullRequestsTargetingCurrentBranchThatHaveOpenIssues(referenceBranchUuid, + currentBranchUuid); } /** @@ -329,7 +339,8 @@ public class ComponentDao implements Dao { mapper(session).setPrivateForBranchUuid(branchUuid, isPrivate); } - public void setPrivateForBranchUuid(DbSession session, String branchUuid, boolean isPrivate, String qualifier, String componentKey, String componentName) { + public void setPrivateForBranchUuid(DbSession session, String branchUuid, boolean isPrivate, String qualifier, String componentKey, + String componentName) { ComponentNewValue componentNewValue = new ComponentNewValue(branchUuid, componentName, componentKey, isPrivate, qualifier); //TODO we should log change to the visibility in EntityDao, not ComponentDao auditPersister.updateComponentVisibility(session, componentNewValue); @@ -351,5 +362,4 @@ public class ComponentDao implements Dao { checkThatNotTooManyConditions(query.getComponentKeys(), "Too many component keys in query"); checkThatNotTooManyConditions(query.getComponentUuids(), "Too many component UUIDs in query"); } - } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java index 7b61364c650..7d26dc3d09f 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java @@ -33,7 +33,8 @@ public interface ComponentMapper { List<ComponentDto> selectByKeyCaseInsensitive(@Param("key") String key); @CheckForNull - ComponentDto selectByKeyAndBranchOrPr(@Param("key") String key, @Nullable @Param("branch") String branch, @Nullable @Param("pullRequest") String pullRequest); + ComponentDto selectByKeyAndBranchOrPr(@Param("key") String key, @Nullable @Param("branch") String branch, @Nullable @Param("pullRequest" + ) String pullRequest); @CheckForNull ComponentDto selectByUuid(@Param("uuid") String uuid); @@ -58,7 +59,8 @@ public interface ComponentMapper { int countByQuery(@Param("query") ComponentQuery query); - List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuid") String baseUuid, @Param("baseUuidPath") String baseUuidPath); + List<ComponentDto> selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuid") String baseUuid, @Param("baseUuidPath" + ) String baseUuidPath); List<ComponentDto> selectChildren(@Param("branchUuid") String branchUuid, @Param("uuidPaths") Set<String> uuidPaths); @@ -111,5 +113,7 @@ public interface ComponentMapper { List<KeyWithUuidDto> selectComponentsFromBranchesThatHaveOpenIssues(@Param("branchUuids") List<String> branchUuids); - short checkIfAnyOfComponentsWithQualifiers(@Param("componentKeys") Collection<String> componentKeys, @Param("qualifiers") Set<String> qualifiers); + short checkIfAnyOfComponentsWithQualifiers(@Param("componentKeys") Collection<String> componentKeys, + @Param("qualifiers") Set<String> qualifiers); + } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml index d0be1f8bcfa..0d340aa7046 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml @@ -162,9 +162,10 @@ and gr.group_uuid = gu.group_uuid ) ) - and <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=" or "> - gr.entity_uuid=#{element, jdbcType=VARCHAR} - </foreach> + and gr.entity_uuid in + <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=","> + #{element, jdbcType=VARCHAR} + </foreach> union @@ -177,8 +178,9 @@ where ur.role=#{role, jdbcType=VARCHAR} and ur.user_uuid=#{userUuid, jdbcType=INTEGER} - and <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=" or "> - entity.uuid=#{element, jdbcType=VARCHAR} + and entity.uuid in + <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=","> + #{element, jdbcType=VARCHAR} </foreach> union @@ -191,9 +193,9 @@ entity.uuid from (<include refid="org.sonar.db.entity.EntityMapper.selectAll"/>) entity - where - <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=" or "> - entity.uuid=#{element ,jdbcType=VARCHAR} + where entity.uuid in + <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=","> + #{element ,jdbcType=VARCHAR} </foreach> and entity.isPrivate = ${_false} and #{role, jdbcType=VARCHAR} in ('user','codeviewer') @@ -207,9 +209,10 @@ where gr.role=#{role, jdbcType=VARCHAR} and gr.group_uuid is null - and <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=" or "> - gr.entity_uuid=#{element, jdbcType=VARCHAR} - </foreach> + and gr.entity_uuid in + <foreach collection="entityUuids" open="(" close=")" item="element" index="index" separator=","> + #{element, jdbcType=VARCHAR} + </foreach> union diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java index d4c20ff8bc9..4f973599cc7 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/user/ServerUserSession.java @@ -32,12 +32,12 @@ import java.util.Set; import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import org.sonar.db.component.ComponentQualifiers; -import org.sonar.db.component.ComponentScopes; 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.ComponentQualifiers; +import org.sonar.db.component.ComponentScopes; import org.sonar.db.component.ComponentTreeQuery; import org.sonar.db.component.ComponentTreeQuery.Strategy; import org.sonar.db.entity.EntityDto; @@ -49,9 +49,9 @@ import static java.util.Collections.singleton; import static java.util.Optional.of; import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toSet; +import static org.sonar.api.web.UserRole.PUBLIC_PERMISSIONS; import static org.sonar.db.component.ComponentQualifiers.SUBVIEW; import static org.sonar.db.component.ComponentQualifiers.VIEW; -import static org.sonar.api.web.UserRole.PUBLIC_PERMISSIONS; /** * Implementation of {@link UserSession} used in web server @@ -178,9 +178,8 @@ public class ServerUserSession extends AbstractUserSession { @Override protected boolean hasPortfolioChildProjectsPermission(String permission, String portfolioUuid) { - Set<ComponentDto> portfolioHierarchyComponents = resolvePortfolioHierarchyComponents(portfolioUuid); - Set<String> branchUuids = findBranchUuids(portfolioHierarchyComponents); - Set<String> projectUuids = findProjectUuids(branchUuids); + // portfolioUuid might be the UUID of a sub portfolio + Set<String> projectUuids = findProjectUuids(portfolioUuid); Set<String> projectsWithPermission = keepEntitiesUuidsByPermission(permission, projectUuids); return projectsWithPermission.containsAll(projectUuids); @@ -204,16 +203,21 @@ public class ServerUserSession extends AbstractUserSession { } } - private static Set<String> findBranchUuids(Set<ComponentDto> portfolioHierarchyComponents) { - return portfolioHierarchyComponents.stream() - .map(ComponentDto::getCopyComponentUuid) - .collect(toSet()); - } - - private Set<String> findProjectUuids(Set<String> branchesComponentsUuid) { + private Set<String> findProjectUuids(String portfolioUuid) { try (DbSession dbSession = dbClient.openSession(false)) { - List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, branchesComponentsUuid); - return getProjectUuids(dbSession, componentDtos); + List<ComponentDto> portfolioLeaves = dbClient.componentDao().selectDescendants(dbSession, ComponentTreeQuery.builder() + .setBaseUuid(portfolioUuid) + .setQualifiers(List.of(ComponentQualifiers.PROJECT)) + .setStrategy(Strategy.LEAVES).build()); + + Set<String> projectBranchUuids = portfolioLeaves.stream() + .map(ComponentDto::getCopyComponentUuid) + .filter(Objects::nonNull) + .collect(toSet()); + + return dbClient.branchDao().selectByUuids(dbSession, projectBranchUuids).stream() + .map(BranchDto::getProjectUuid) + .collect(toSet()); } } @@ -297,39 +301,6 @@ public class ServerUserSession extends AbstractUserSession { } } - private List<ComponentDto> getDirectChildComponents(String portfolioUuid) { - try (DbSession dbSession = dbClient.openSession(false)) { - return dbClient.componentDao().selectDescendants(dbSession, ComponentTreeQuery.builder() - .setBaseUuid(portfolioUuid) - .setQualifiers(Arrays.asList(ComponentQualifiers.PROJECT, ComponentQualifiers.SUBVIEW)) - .setStrategy(Strategy.CHILDREN).build()); - } - } - - private Set<ComponentDto> resolvePortfolioHierarchyComponents(String parentComponentUuid) { - Set<ComponentDto> portfolioHierarchyProjects = new HashSet<>(); - resolvePortfolioHierarchyComponents(parentComponentUuid, portfolioHierarchyProjects); - return portfolioHierarchyProjects; - } - - private void resolvePortfolioHierarchyComponents(String parentComponentUuid, Set<ComponentDto> hierarchyChildComponents) { - List<ComponentDto> childComponents = getDirectChildComponents(parentComponentUuid); - - if (childComponents.isEmpty()) { - return; - } - - childComponents.forEach(c -> { - if (c.getCopyComponentUuid() != null) { - hierarchyChildComponents.add(c); - } - - if (ComponentQualifiers.SUBVIEW.equals(c.qualifier())) { - resolvePortfolioHierarchyComponents(c.uuid(), hierarchyChildComponents); - } - }); - } - private Set<GlobalPermission> loadGlobalPermissions() { Set<String> permissionKeys; try (DbSession dbSession = dbClient.openSession(false)) { |