Skip to content

Commit

Permalink
SONAR-10474 Confirming all remaining issues in a PR should make it pa…
Browse files Browse the repository at this point in the history
…ss the QG
  • Loading branch information
teryk authored and SonarTech committed Mar 22, 2018
1 parent 3f0ffe9 commit 3cef0ae
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 17 deletions.
Expand Up @@ -34,6 +34,7 @@
import org.sonar.db.component.BranchDto; import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotDto;
import org.sonar.db.measure.LiveMeasureDto;
import org.sonar.db.protobuf.DbProjectBranches; import org.sonar.db.protobuf.DbProjectBranches;
import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentFinder;
import org.sonar.server.issue.index.BranchStatistics; import org.sonar.server.issue.index.BranchStatistics;
Expand All @@ -42,7 +43,9 @@
import org.sonarqube.ws.ProjectPullRequests; import org.sonarqube.ws.ProjectPullRequests;


import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull; 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.resources.Qualifiers.PROJECT;
import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.formatDateTime;
import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.core.util.Protobuf.setNullable;
Expand Down Expand Up @@ -98,19 +101,22 @@ public void handle(Request request, Response response) throws Exception {
.stream().collect(uniqueIndex(BranchDto::getUuid)); .stream().collect(uniqueIndex(BranchDto::getUuid));
Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), pullRequestUuids).stream() Map<String, BranchStatistics> branchStatisticsByBranchUuid = issueIndex.searchBranchStatistics(project.uuid(), pullRequestUuids).stream()
.collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity())); .collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity()));
Map<String, LiveMeasureDto> qualityGateMeasuresByComponentUuids = dbClient.liveMeasureDao()
.selectByComponentUuidsAndMetricKeys(dbSession, pullRequestUuids, singletonList(ALERT_STATUS_KEY)).stream()
.collect(uniqueIndex(LiveMeasureDto::getComponentUuid));
Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, pullRequestUuids).stream() Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, pullRequestUuids).stream()
.collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt()))); .collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt())));


ProjectPullRequests.ListWsResponse.Builder protobufResponse = ProjectPullRequests.ListWsResponse.newBuilder(); ProjectPullRequests.ListWsResponse.Builder protobufResponse = ProjectPullRequests.ListWsResponse.newBuilder();
pullRequests 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()))); analysisDateByBranchUuid.get(b.getUuid())));
writeProtobuf(protobufResponse.build(), request, response); writeProtobuf(protobufResponse.build(), request, response);
} }
} }


private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid,
BranchStatistics branchStatistics, @Nullable String analysisDate) { @Nullable LiveMeasureDto qualityGateMeasure, BranchStatistics branchStatistics, @Nullable String analysisDate) {
Optional<BranchDto> mergeBranch = Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())); Optional<BranchDto> mergeBranch = Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid()));


ProjectPullRequests.PullRequest.Builder builder = ProjectPullRequests.PullRequest.newBuilder(); ProjectPullRequests.PullRequest.Builder builder = ProjectPullRequests.PullRequest.newBuilder();
Expand All @@ -128,12 +134,15 @@ private static void addPullRequest(ProjectPullRequests.ListWsResponse.Builder re
builder.setIsOrphan(true); builder.setIsOrphan(true);
} }
setNullable(analysisDate, builder::setAnalysisDate); setNullable(analysisDate, builder::setAnalysisDate);
setBranchStatus(builder, branchStatistics); setQualityGate(builder, qualityGateMeasure, branchStatistics);
response.addPullRequests(builder); 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(); ProjectPullRequests.Status.Builder statusBuilder = ProjectPullRequests.Status.newBuilder();
if (qualityGateMeasure != null) {
setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus);
}
statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs());
statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities());
statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells());
Expand Down
Expand Up @@ -30,7 +30,6 @@
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.Protobuf;
import org.sonar.core.util.stream.MoreCollectors; import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
Expand Down Expand Up @@ -157,15 +156,15 @@ private static void setBranchStatus(ProjectBranches.Branch.Builder builder, Bran
@Nullable BranchStatistics branchStatistics) { @Nullable BranchStatistics branchStatistics) {
ProjectBranches.Status.Builder statusBuilder = ProjectBranches.Status.newBuilder(); ProjectBranches.Status.Builder statusBuilder = ProjectBranches.Status.newBuilder();
if (qualityGateMeasure != null) { if (qualityGateMeasure != null) {
Protobuf.setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus); setNullable(qualityGateMeasure.getDataAsString(), statusBuilder::setQualityGateStatus);
builder.setStatus(statusBuilder);
} }
if (branch.getBranchType() == BranchType.SHORT) { if (branch.getBranchType() == BranchType.SHORT) {
statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs()); statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs());
statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities()); statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities());
statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells()); statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells());
builder.setStatus(statusBuilder);
} }

builder.setStatus(statusBuilder);
} }


private void checkPermission(ComponentDto component) { private void checkPermission(ComponentDto component) {
Expand Down
Expand Up @@ -6,6 +6,7 @@
"branch": "feature/bar", "branch": "feature/bar",
"base": "feature/foo", "base": "feature/foo",
"status": { "status": {
"qualityGateStatus": "OK",
"bugs": 0, "bugs": 0,
"vulnerabilities": 0, "vulnerabilities": 0,
"codeSmells": 0 "codeSmells": 0
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.sonar.server.branch.pr.ws; package org.sonar.server.branch.pr.ws;


import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
Expand All @@ -33,7 +34,7 @@
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ResourceTypesRule; 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.organization.OrganizationDto;
import org.sonar.db.protobuf.DbProjectBranches; import org.sonar.db.protobuf.DbProjectBranches;
import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleDefinitionDto;
Expand All @@ -58,6 +59,7 @@
import static org.assertj.core.api.Assertions.tuple; 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_FALSE_POSITIVE;
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; 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.resources.Qualifiers.PROJECT;
import static org.sonar.api.rules.RuleType.BUG; import static org.sonar.api.rules.RuleType.BUG;
import static org.sonar.api.rules.RuleType.CODE_SMELL; import static org.sonar.api.rules.RuleType.CODE_SMELL;
Expand All @@ -66,6 +68,8 @@
import static org.sonar.api.utils.DateUtils.parseDateTime; import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.db.component.BranchType.LONG; import static org.sonar.db.component.BranchType.LONG;
import static org.sonar.db.component.BranchType.PULL_REQUEST; 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.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.ProjectPullRequests.Status; import static org.sonarqube.ws.ProjectPullRequests.Status;


Expand All @@ -80,13 +84,20 @@ public class ListActionTest {
@Rule @Rule
public UserSessionRule userSession = UserSessionRule.standalone(); public UserSessionRule userSession = UserSessionRule.standalone();


private MetricDto qualityGateStatus;

private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT); private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT);
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient())); 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 IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession));
private PermissionIndexerTester permissionIndexerTester = new PermissionIndexerTester(es, issueIndexer); private PermissionIndexerTester permissionIndexerTester = new PermissionIndexerTester(es, issueIndexer);


public WsActionTester ws = new WsActionTester(new ListAction(db.getDbClient(), userSession, new ComponentFinder(db.getDbClient(), resourceTypes), issueIndex)); 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 @Test
public void definition() { public void definition() {
WebService.Action definition = ws.getDef(); WebService.Action definition = ws.getDef();
Expand All @@ -110,18 +121,19 @@ public void json_example() {
.setTitle("Add feature X") .setTitle("Add feature X")
.setUrl("https://github.com/SonarSource/sonar-core-plugins/pull/32") .setUrl("https://github.com/SonarSource/sonar-core-plugins/pull/32")
.build())); .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); 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(); db.commit();


String json = ws.newRequest() String json = ws.newRequest()
.setParam("project", project.getDbKey()) .setParam(PARAM_PROJECT, project.getKey())
.execute() .execute()
.getInput(); .getInput();


assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString());
assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(json);
} }


@Test @Test
Expand Down Expand Up @@ -235,6 +247,7 @@ public void status_on_pull_requests() {
.setBranchType(PULL_REQUEST) .setBranchType(PULL_REQUEST)
.setMergeBranchUuid(longLivingBranch.uuid()) .setMergeBranchUuid(longLivingBranch.uuid())
.setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/bar").build())); .setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/bar").build()));
db.measures().insertLiveMeasure(pullRequest, qualityGateStatus, m -> m.setData("ERROR"));
RuleDefinitionDto rule = db.rules().insert(); 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(null));
db.issues().insert(rule, pullRequest, pullRequest, i -> i.setType(BUG).setResolution(RESOLUTION_FIXED)); db.issues().insert(rule, pullRequest, pullRequest, i -> i.setType(BUG).setResolution(RESOLUTION_FIXED));
Expand All @@ -252,8 +265,8 @@ public void status_on_pull_requests() {
.executeProtobuf(ListWsResponse.class); .executeProtobuf(ListWsResponse.class);


assertThat(response.getPullRequestsList().stream().map(PullRequest::getStatus)) assertThat(response.getPullRequestsList().stream().map(PullRequest::getStatus))
.extracting(Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells) .extracting(Status::getQualityGateStatus, Status::hasBugs, Status::getBugs, Status::hasVulnerabilities, Status::getVulnerabilities, Status::hasCodeSmells, Status::getCodeSmells)
.containsExactlyInAnyOrder(tuple(true, 1L, true, 2L, true, 3L)); .containsExactlyInAnyOrder(tuple("ERROR", true, 1L, true, 2L, true, 3L));
} }


@Test @Test
Expand Down Expand Up @@ -302,11 +315,11 @@ public void response_contains_date_of_last_analysis() {
.setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/pr2").build())); .setPullRequestData(DbProjectBranches.PullRequestData.newBuilder().setBranch("feature/pr2").build()));


db.getDbClient().snapshotDao().insert(db.getSession(), db.getDbClient().snapshotDao().insert(db.getSession(),
SnapshotTesting.newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch)); newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch));
db.getDbClient().snapshotDao().insert(db.getSession(), 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(), db.getDbClient().snapshotDao().insert(db.getSession(),
SnapshotTesting.newAnalysis(pullRequest2).setCreatedAt(lastAnalysisPullRequest)); newAnalysis(pullRequest2).setCreatedAt(lastAnalysisPullRequest));
db.commit(); db.commit();
issueIndexer.indexOnStartup(emptySet()); issueIndexer.indexOnStartup(emptySet());
permissionIndexerTester.allowOnlyAnyone(project); permissionIndexerTester.allowOnlyAnyone(project);
Expand Down
1 change: 1 addition & 0 deletions sonar-ws/src/main/protobuf/ws-projectpullrequests.proto
Expand Up @@ -43,6 +43,7 @@ message PullRequest {
} }


message Status { message Status {
optional string qualityGateStatus = 1;
optional int64 bugs = 2; optional int64 bugs = 2;
optional int64 vulnerabilities = 3; optional int64 vulnerabilities = 3;
optional int64 codeSmells = 4; optional int64 codeSmells = 4;
Expand Down

0 comments on commit 3cef0ae

Please sign in to comment.