diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-08-28 14:58:12 +0200 |
---|---|---|
committer | Janos Gyerik <janos.gyerik@sonarsource.com> | 2017-09-12 11:34:54 +0200 |
commit | 8767617b9d142cd617a22933089947796c97090c (patch) | |
tree | 379b9266940869d73d234cac5fecbb32acbe82ab /server | |
parent | b135ed4ad8922c03bc882d64ad7d5d9e0e89c22c (diff) | |
download | sonarqube-8767617b9d142cd617a22933089947796c97090c.tar.gz sonarqube-8767617b9d142cd617a22933089947796c97090c.zip |
SONAR-9616 Use ES to get issues in api/project_branches/list
Diffstat (limited to 'server')
3 files changed, 98 insertions, 117 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java deleted file mode 100644 index 06ff510630e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/BranchDtoToWsBranch.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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.server.projectbranch.ws; - -import java.util.Map; -import java.util.Optional; -import org.sonar.db.component.BranchDto; -import org.sonar.db.measure.MeasureDto; -import org.sonarqube.ws.Common; -import org.sonarqube.ws.WsBranches; - -import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.CoreMetrics.BUGS_KEY; -import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY; -import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; -import static org.sonar.core.util.Protobuf.setNullable; -import static org.sonar.db.component.BranchType.LONG; -import static org.sonar.db.component.BranchType.SHORT; - -public class BranchDtoToWsBranch { - - private BranchDtoToWsBranch() { - // static methods only - } - - static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, Optional<BranchDto> mergeBranch, Map<String, MeasureDto> measuresByMetricKey) { - WsBranches.Branch.Builder builder = WsBranches.Branch.newBuilder(); - String branchKey = branch.getKey(); - setNullable(branchKey, builder::setName); - builder.setIsMain(branch.isMain()); - builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); - if (branch.getBranchType().equals(SHORT)) { - if (mergeBranch.isPresent()) { - String mergeBranchKey = mergeBranch.get().getKey(); - builder.setMergeBranch(mergeBranchKey); - } else { - builder.setIsOrphan(true); - } - } - - if (branch.getBranchType().equals(LONG)) { - WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); - MeasureDto measure = measuresByMetricKey.get(ALERT_STATUS_KEY); - setNullable(measure, m -> builder.setStatus(statusBuilder.setQualityGateStatus(m.getData()))); - } - - if (branch.getBranchType().equals(SHORT)) { - WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); - MeasureDto bugs = measuresByMetricKey.get(BUGS_KEY); - setNullable(bugs, m -> builder.setStatus(statusBuilder.setBugs(m.getValue().intValue()))); - - MeasureDto vulnerabilities = measuresByMetricKey.get(VULNERABILITIES_KEY); - setNullable(vulnerabilities, m -> builder.setStatus(statusBuilder.setVulnerabilities(m.getValue().intValue()))); - - MeasureDto codeSmells = measuresByMetricKey.get(CODE_SMELLS_KEY); - setNullable(codeSmells, m -> builder.setStatus(statusBuilder.setCodeSmells(m.getValue().intValue()))); - builder.setStatus(statusBuilder); - } - return builder; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java index 3237961ea26..05595f72c00 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java @@ -19,14 +19,13 @@ */ package org.sonar.server.projectbranch.ws; -import com.google.common.collect.Multimap; import com.google.common.io.Resources; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; +import javax.annotation.Nullable; +import org.elasticsearch.action.search.SearchResponse; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -35,26 +34,34 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchKeyType; +import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.measure.MeasureDto; import org.sonar.db.metric.MetricDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.es.Facets; +import org.sonar.server.es.SearchOptions; +import org.sonar.server.issue.IssueQuery; +import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.user.UserSession; import org.sonar.server.ws.WsUtils; +import org.sonarqube.ws.Common; import org.sonarqube.ws.WsBranches; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.CoreMetrics.BUGS_KEY; -import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY; -import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; import static org.sonar.api.resources.Qualifiers.PROJECT; -import static org.sonar.core.util.stream.MoreCollectors.index; +import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.core.util.stream.MoreCollectors.toList; import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; -import static org.sonar.server.projectbranch.ws.BranchDtoToWsBranch.toBranchBuilder; +import static org.sonar.db.component.BranchType.LONG; +import static org.sonar.db.component.BranchType.SHORT; +import static org.sonar.server.rule.index.RuleIndex.FACET_TYPES; import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonarqube.ws.Common.RuleType.BUG; +import static org.sonarqube.ws.Common.RuleType.CODE_SMELL; +import static org.sonarqube.ws.Common.RuleType.VULNERABILITY; import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.ACTION_LIST; import static org.sonarqube.ws.client.projectbranches.ProjectBranchesParameters.PARAM_PROJECT; @@ -63,11 +70,13 @@ public class ListAction implements BranchWsAction { private final DbClient dbClient; private final UserSession userSession; private final ComponentFinder componentFinder; + private final IssueIndex issueIndex; - public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) { + public ListAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder, IssueIndex issueIndex) { this.dbClient = dbClient; this.userSession = userSession; this.componentFinder = componentFinder; + this.issueIndex = issueIndex; } @Override @@ -95,30 +104,69 @@ public class ListAction implements BranchWsAction { userSession.checkComponentPermission(UserRole.USER, project); checkArgument(project.isEnabled() && PROJECT.equals(project.qualifier()), "Invalid project key"); - List<MetricDto> metrics = dbClient.metricDao().selectByKeys(dbSession, asList(ALERT_STATUS_KEY, BUGS_KEY, VULNERABILITIES_KEY, CODE_SMELLS_KEY)); - Map<Integer, MetricDto> metricsById = metrics.stream().collect(uniqueIndex(MetricDto::getId)); - Collection<BranchDto> branches = dbClient.branchDao().selectByComponent(dbSession, project); + MetricDto qualityGateMetric = dbClient.metricDao().selectOrFailByKey(dbSession, ALERT_STATUS_KEY); Map<String, BranchDto> mergeBranchesByUuid = dbClient.branchDao() .selectByUuids(dbSession, branches.stream().map(BranchDto::getMergeBranchUuid).filter(Objects::nonNull).collect(toList())) .stream().collect(uniqueIndex(BranchDto::getUuid)); - Multimap<String, MeasureDto> measuresByComponentUuids = dbClient.measureDao() - .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), metricsById.keySet()) - .stream().collect(index(MeasureDto::getComponentUuid)); + Map<String, MeasureDto> qualityGateMeasuresByComponentUuids = dbClient.measureDao() + .selectByComponentsAndMetrics(dbSession, branches.stream().map(BranchDto::getUuid).collect(toList()), singletonList(qualityGateMetric.getId())) + .stream().collect(uniqueIndex(MeasureDto::getComponentUuid)); WsBranches.ListWsResponse.Builder protobufResponse = WsBranches.ListWsResponse.newBuilder(); branches.stream() .filter(b -> b.getKeeType().equals(BranchKeyType.BRANCH)) - .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, metricsById, measuresByComponentUuids.get(b.getUuid()))); + .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()))); WsUtils.writeProtobuf(protobufResponse.build(), request, response); } } - private static void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, - Map<Integer, MetricDto> metricsById, Collection<MeasureDto> measures) { - response.addBranches( - toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())), - measures.stream().collect(uniqueIndex(m -> metricsById.get(m.getMetricId()).getKey(), Function.identity())))); + private void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, @Nullable MeasureDto qualityGateMeasure) { + WsBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()))); + setLongLivingBranchStatus(builder, branch, qualityGateMeasure); + setShortLivingBranchStatus(builder, branch); + response.addBranches(builder); + } + + private static WsBranches.Branch.Builder toBranchBuilder(BranchDto branch, Optional<BranchDto> mergeBranch) { + WsBranches.Branch.Builder builder = WsBranches.Branch.newBuilder(); + String branchKey = branch.getKey(); + setNullable(branchKey, builder::setName); + builder.setIsMain(branch.isMain()); + builder.setType(Common.BranchType.valueOf(branch.getBranchType().name())); + if (branch.getBranchType().equals(SHORT)) { + if (mergeBranch.isPresent()) { + String mergeBranchKey = mergeBranch.get().getKey(); + builder.setMergeBranch(mergeBranchKey); + } else { + builder.setIsOrphan(true); + } + } + return builder; + } + + private static void setLongLivingBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch, @Nullable MeasureDto qualityGateMeasure) { + if (branch.getBranchType().equals(LONG) && qualityGateMeasure != null) { + WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); + statusBuilder.setQualityGateStatus(qualityGateMeasure.getData()); + builder.setStatus(statusBuilder); + } + } + + private void setShortLivingBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch) { + if (!branch.getBranchType().equals(BranchType.SHORT)) { + return; + } + SearchResponse searchResponse = issueIndex.search(IssueQuery.builder().branchUuid(branch.getUuid()).build(), new SearchOptions() + .setLimit(0) + .addFacets(FACET_TYPES)); + Facets facets = new Facets(searchResponse); + Map<String, Long> typesFacet = Objects.requireNonNull(facets.get(FACET_TYPES), "Facet types does not exists"); + WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder(); + setNullable(typesFacet.get(BUG.name()), v -> statusBuilder.setBugs(v.intValue())); + setNullable(typesFacet.get(VULNERABILITY.name()), v -> statusBuilder.setVulnerabilities(v.intValue())); + setNullable(typesFacet.get(CODE_SMELL.name()), v -> statusBuilder.setCodeSmells(v.intValue())); + builder.setStatus(statusBuilder); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java index 15ddf4440b6..ba6722e6247 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.MapSettings; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; @@ -35,8 +36,16 @@ import org.sonar.db.component.ResourceTypesRule; import org.sonar.db.component.SnapshotDto; import org.sonar.db.metric.MetricDto; import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.issue.index.IssueIndex; +import org.sonar.server.issue.index.IssueIndexDefinition; +import org.sonar.server.issue.index.IssueIndexer; +import org.sonar.server.issue.index.IssueIteratorFactory; +import org.sonar.server.permission.index.AuthorizationTypeSupport; +import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Common; @@ -46,13 +55,14 @@ import org.sonarqube.ws.WsBranches.Branch; import org.sonarqube.ws.WsBranches.ListWsResponse; import static java.lang.String.format; +import static java.util.Collections.emptySet; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.api.measures.CoreMetrics.BUGS_KEY; -import static org.sonar.api.measures.CoreMetrics.CODE_SMELLS_KEY; -import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; import static org.sonar.api.resources.Qualifiers.PROJECT; +import static org.sonar.api.rules.RuleType.BUG; +import static org.sonar.api.rules.RuleType.CODE_SMELL; +import static org.sonar.api.rules.RuleType.VULNERABILITY; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.WsBranches.Branch.Status; @@ -60,28 +70,25 @@ public class ListActionTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - @Rule public DbTester db = DbTester.create(System2.INSTANCE); - + @Rule + public EsTester es = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig())); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); + private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient())); + private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession)); + private PermissionIndexerTester permissionIndexerTester = new PermissionIndexerTester(es, issueIndexer); private MetricDto qualityGateStatus; - private MetricDto bugs; - private MetricDto vulnerabilities; - private MetricDto codeSmells; - public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes))); + public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes), issueIndex)); @Before public void setUp() throws Exception { qualityGateStatus = db.measures().insertMetric(m -> m.setKey(ALERT_STATUS_KEY)); - bugs = db.measures().insertMetric(m -> m.setKey(BUGS_KEY)); - vulnerabilities = db.measures().insertMetric(m -> m.setKey(VULNERABILITIES_KEY)); - codeSmells = db.measures().insertMetric(m -> m.setKey(CODE_SMELLS_KEY)); } @Test @@ -252,10 +259,15 @@ public class ListActionTest { ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG)); ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid())); - SnapshotDto branchAnalysis = db.components().insertSnapshot(shortLivingBranch); - db.measures().insertMeasure(shortLivingBranch, branchAnalysis, bugs, m -> m.setValue(1d)); - db.measures().insertMeasure(shortLivingBranch, branchAnalysis, vulnerabilities, m -> m.setValue(2d)); - db.measures().insertMeasure(shortLivingBranch, branchAnalysis, codeSmells, m -> m.setValue(3d)); + RuleDefinitionDto rule = db.rules().insert(); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(BUG)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(VULNERABILITY)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL)); + db.issues().insert(rule, shortLivingBranch, shortLivingBranch, i -> i.setType(CODE_SMELL)); + issueIndexer.indexOnStartup(emptySet()); + permissionIndexerTester.allowOnlyAnyone(project); ListWsResponse response = ws.newRequest() .setParam("project", project.getKey()) |