diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java index c6d63a10cfe2..a3ec277faa34 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/pr/ws/ListAction.java @@ -34,6 +34,7 @@ import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; +import org.sonar.db.measure.LiveMeasureDto; import org.sonar.db.protobuf.DbProjectBranches; import org.sonar.server.component.ComponentFinder; import org.sonar.server.issue.index.BranchStatistics; @@ -42,7 +43,9 @@ import org.sonarqube.ws.ProjectPullRequests; import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; +import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.core.util.Protobuf.setNullable; @@ -98,19 +101,22 @@ public void handle(Request request, Response response) throws Exception { .stream().collect(uniqueIndex(BranchDto::getUuid)); Map branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), pullRequestUuids).stream() .collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); + Map qualityGateMeasuresByComponentUuids = dbClient.liveMeasureDao() + .selectByComponentUuidsAndMetricKeys(dbSession, pullRequestUuids, singletonList(ALERT_STATUS_KEY)).stream() + .collect(uniqueIndex(LiveMeasureDto::getComponentUuid)); Map analysisDateByBranchUuid = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, pullRequestUuids).stream() .collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); ProjectPullRequests.ListWsResponse.Builder protobufResponse = ProjectPullRequests.ListWsResponse.newBuilder(); pullRequests - .forEach(b -> addPullRequest(protobufResponse, b, mergeBranchesByUuid, branchStatisticsByBranchUuid.get(b.getUuid()), + .forEach(b -> addPullRequest(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()), analysisDateByBranchUuid.get(b.getUuid()))); writeProtobuf(protobufResponse.build(), request, response); } } private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder response, BranchDto branch, Map mergeBranchesByUuid, - BranchStatistics branchStatistics, @Nullable String analysisDate) { + @Nullable LiveMeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) { Optional mergeBranch = Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())); ProjectPullRequests.PullRequest.Builder builder = ProjectPullRequests.PullRequest.newBuilder(); @@ -128,12 +134,15 @@ private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder re builder.setIsOrphan(true); } setNullable(analysisDate, builder::setAnalysisDate); - setBranchStatus(builder, branchStatistics); + setQualityGate(builder, qualityGateMeasure, branchStatistics); response.addPullRequests(builder); } - private static void setBranchStatus(ProjectPullRequests.PullRequest.Builder builder, @Nullable BranchStatistics branchStatistics) { + private static void setQualityGate(ProjectPullRequests.PullRequest.Builder builder, @Nullable LiveMeasureDto qualityGateMeasure, @Nullable BranchStatistics branchStatistics) { ProjectPullRequests.Status.Builder statusBuilder = ProjectPullRequests.Status.newBuilder(); + if (qualityGateMeasure != null) { + setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); + } statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java index 3d375c879a04..74e2bc0f828a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/branch/ws/ListAction.java @@ -30,7 +30,6 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; -import org.sonar.core.util.Protobuf; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -157,15 +156,15 @@ private static void setBranchStatus(ProjectBranches.Branch.Builder builder, Bran @Nullable BranchStatistics branchStatistics) { ProjectBranches.Status.Builder statusBuilder = ProjectBranches.Status.newBuilder(); if (qualityGateMeasure != null) { - Protobuf.setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); - builder.setStatus(statusBuilder); + setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); } if (branch.getBranchType() == BranchType.SHORT) { statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); - builder.setStatus(statusBuilder); } + + builder.setStatus(statusBuilder); } private void checkPermission(ComponentDto component) { diff --git a/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json index a925c1f901a5..4fef887dc826 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/branch/pr/ws/list-example.json @@ -6,6 +6,7 @@ "branch": "feature/bar", "base": "feature/foo", "status": { + "qualityGateStatus": "OK", "bugs": 0, "vulnerabilities": 0, "codeSmells": 0 diff --git a/server/sonar-server/src/test/java/org/sonar/server/branch/pr/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/branch/pr/ws/ListActionTest.java index e8715b90bae4..3ab729c882a6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/branch/pr/ws/ListActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/branch/pr/ws/ListActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.branch.pr.ws; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -33,7 +34,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ResourceTypesRule; -import org.sonar.db.component.SnapshotTesting; +import org.sonar.db.metric.MetricDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.protobuf.DbProjectBranches; import org.sonar.db.rule.RuleDefinitionDto; @@ -58,6 +59,7 @@ import static org.assertj.core.api.Assertions.tuple; import static org.sonar.api.issue.Issue.RESOLUTION_FALSE_POSITIVE; import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; +import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_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; @@ -66,6 +68,8 @@ import static org.sonar.api.utils.DateUtils.parseDateTime; import static org.sonar.db.component.BranchType.LONG; import static org.sonar.db.component.BranchType.PULL_REQUEST; +import static org.sonar.db.component.SnapshotTesting.newAnalysis; +import static org.sonar.server.branch.pr.ws.PullRequestsWsParameters.PARAM_PROJECT; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.ProjectPullRequests.Status; @@ -80,6 +84,8 @@ public class ListActionTest { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); + private MetricDto qualityGateStatus; + 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)); @@ -87,6 +93,11 @@ public class ListActionTest { public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes), issueIndex)); + @Before + public void setUp() { + qualityGateStatus = db.measures().insertMetric(m -> m.setKey(ALERT_STATUS_KEY)); + } + @Test public void definition() { WebService.Action definition = ws.getDef(); @@ -110,18 +121,19 @@ public void json_example() { .setTitle("Add feature X") .setUrl("https://github.com/SonarSource/sonar-core-plugins/pull/32") .build())); + db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(pullRequest).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-01T01:15:42+0100").getTime())); + db.measures().insertLiveMeasure(pullRequest, qualityGateStatus, m -> m.setData("OK")); userSession.logIn().addProjectPermission(UserRole.USER, project); - db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(pullRequest).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-01T01:15:42+0100").getTime())); db.commit(); String json = ws.newRequest() - .setParam("project", project.getDbKey()) + .setParam(PARAM_PROJECT, project.getKey()) .execute() .getInput(); assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); + assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(json); } @Test @@ -235,6 +247,7 @@ public void status_on_pull_requests() { .setBranchType(PULL_REQUEST) .setMergeBranchUuid(longLivingBranch.uuid()) .setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/bar").build())); + db.measures().insertLiveMeasure(pullRequest, qualityGateStatus, m -> m.setData("ERROR")); RuleDefinitionDto rule = db.rules().insert(); db.issues().insert(rule, pullRequest, pullRequest, i -> i.setType(BUG).setResolution(null)); db.issues().insert(rule, pullRequest, pullRequest, i -> i.setType(BUG).setResolution(RESOLUTION_FIXED)); @@ -252,8 +265,8 @@ public void status_on_pull_requests() { .executeProtobuf(ListWsResponse.class); assertThat(response.getPullRequestsList().stream().map(PullRequest::getStatus)) - .extracting(Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells) - .containsExactlyInAnyOrder(tuple(true, 1L, true, 2L, true, 3L)); + .extracting(Status::getQualityGateStatus, Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells) + .containsExactlyInAnyOrder(tuple("ERROR", true, 1L, true, 2L, true, 3L)); } @Test @@ -302,11 +315,11 @@ public void response_contains_date_of_last_analysis() { .setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/pr2").build())); db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch)); + newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch)); db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(pullRequest2).setCreatedAt(previousAnalysisPullRequest).setLast(false)); + newAnalysis(pullRequest2).setCreatedAt(previousAnalysisPullRequest).setLast(false)); db.getDbClient().snapshotDao().insert(db.getSession(), - SnapshotTesting.newAnalysis(pullRequest2).setCreatedAt(lastAnalysisPullRequest)); + newAnalysis(pullRequest2).setCreatedAt(lastAnalysisPullRequest)); db.commit(); issueIndexer.indexOnStartup(emptySet()); permissionIndexerTester.allowOnlyAnyone(project); diff --git a/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto b/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto index e6bc03009539..242031214961 100644 --- a/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto +++ b/sonar-ws/src/main/protobuf/ws-projectpullrequests.proto @@ -43,6 +43,7 @@ message PullRequest { } message Status { + optional string qualityGateStatus = 1; optional int64 bugs = 2; optional int64 vulnerabilities = 3; optional int64 codeSmells = 4;