aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/projectbranch/ws/ListAction.java38
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/projectbranch/ws/ListActionTest.java45
-rw-r--r--sonar-ws/src/main/protobuf/ws-projectbranches.proto1
4 files changed, 69 insertions, 21 deletions
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 aeae39e6a64..9ed81f2a73f 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
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
@@ -36,6 +37,7 @@ 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.component.SnapshotDto;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.server.component.ComponentFinder;
@@ -50,6 +52,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Collections.singletonList;
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;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
@@ -110,20 +113,26 @@ public class ListAction implements BranchWsAction {
.filter(b -> b.getBranchType().equals(SHORT))
.map(BranchDto::getUuid).collect(toList()))
.stream().collect(uniqueIndex(BranchStatistics::getBranchUuid, Function.identity()));
+ Map<String, String> analysisDateByBranchUuid = dbClient.snapshotDao()
+ .selectLastAnalysesByRootComponentUuids(dbSession, branches.stream().map(BranchDto::getUuid).collect(Collectors.toList()))
+ .stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, s -> formatDateTime(s.getCreatedAt())));
WsBranches.ListWsResponse.Builder protobufResponse = WsBranches.ListWsResponse.newBuilder();
branches.stream()
.filter(b -> b.getKeeType().equals(BranchKeyType.BRANCH))
- .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid())));
+ .forEach(b -> addBranch(protobufResponse, b, mergeBranchesByUuid, qualityGateMeasuresByComponentUuids.get(b.getUuid()), branchStatisticsByBranchUuid.get(b.getUuid()),
+ analysisDateByBranchUuid.get(b.getUuid())));
WsUtils.writeProtobuf(protobufResponse.build(), request, response);
}
}
private static void addBranch(WsBranches.ListWsResponse.Builder response, BranchDto branch, Map<String, BranchDto> mergeBranchesByUuid, @Nullable MeasureDto qualityGateMeasure,
- BranchStatistics branchStatistics) {
+ BranchStatistics branchStatistics, @Nullable String analysisDate) {
WsBranches.Branch.Builder builder = toBranchBuilder(branch, Optional.ofNullable(mergeBranchesByUuid.get(branch.getMergeBranchUuid())));
- setLongLivingBranchStatus(builder, branch, qualityGateMeasure);
- setShortLivingBranchStatus(builder, branch, branchStatistics);
+ setBranchStatus(builder, branch, qualityGateMeasure, branchStatistics);
+ if (analysisDate != null) {
+ builder.setAnalysisDate(analysisDate);
+ }
response.addBranches(builder);
}
@@ -144,23 +153,16 @@ public class ListAction implements BranchWsAction {
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();
+ private static void setBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch, @Nullable MeasureDto qualityGateMeasure, @Nullable BranchStatistics branchStatistics) {
+ WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder();
+ if (branch.getBranchType() == LONG && qualityGateMeasure != null) {
statusBuilder.setQualityGateStatus(qualityGateMeasure.getData());
- builder.setStatus(statusBuilder);
}
- }
-
- private static void setShortLivingBranchStatus(WsBranches.Branch.Builder builder, BranchDto branch, @Nullable BranchStatistics branchStatistics) {
- if (!branch.getBranchType().equals(BranchType.SHORT)) {
- return;
+ 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());
}
- WsBranches.Branch.Status.Builder statusBuilder = WsBranches.Branch.Status.newBuilder();
- statusBuilder.setBugs(branchStatistics == null ? 0L : branchStatistics.getBugs());
- statusBuilder.setVulnerabilities(branchStatistics == null ? 0L : branchStatistics.getVulnerabilities());
- statusBuilder.setCodeSmells(branchStatistics == null ? 0L : branchStatistics.getCodeSmells());
builder.setStatus(statusBuilder);
}
-
}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json b/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json
index 0078ef5f40b..9d285888732 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/projectbranch/ws/list-example.json
@@ -3,13 +3,15 @@
{
"name": "feature/bar",
"isMain": false,
- "type": "LONG"
+ "type": "LONG",
+ "analysisDate": "2017-04-01T01:15:42+0100"
},
{
"name": "feature/foo",
"isMain": false,
"type": "SHORT",
- "mergeBranch": "feature/bar"
+ "mergeBranch": "feature/bar",
+ "analysisDate": "2017-04-03T13:37:00+0100"
}
]
}
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 c712694835a..229936f100c 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
@@ -26,6 +26,7 @@ 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.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbTester;
@@ -34,6 +35,7 @@ import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.component.SnapshotTesting;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDefinitionDto;
@@ -65,6 +67,8 @@ 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.api.utils.DateUtils.dateToLong;
+import static org.sonar.api.utils.DateUtils.parseDateTime;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonarqube.ws.WsBranches.Branch.Status;
@@ -107,9 +111,13 @@ public class ListActionTest {
public void test_example() {
ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("sonarqube"));
ComponentDto longLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/bar").setBranchType(BranchType.LONG));
- db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid()));
+ ComponentDto shortLivingBranch = db.components().insertProjectBranch(project, b -> b.setKey("feature/foo").setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch.uuid()));
userSession.logIn().addProjectPermission(UserRole.USER, project);
+ db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(longLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-01T01:15:42+0100").getTime()));
+ db.getDbClient().snapshotDao().insert(db.getSession(), SnapshotTesting.newAnalysis(shortLivingBranch).setLast(true).setCreatedAt(DateUtils.parseDateTime("2017-04-03T13:37:00+0100").getTime()));
+ db.commit();
+
String json = ws.newRequest()
.setParam("project", project.getDbKey())
.execute()
@@ -304,6 +312,41 @@ public class ListActionTest {
}
@Test
+ public void response_contains_date_of_last_analysis() {
+ Long lastAnalysisLongLivingBranch = dateToLong(parseDateTime("2017-04-01T00:00:00+0100"));
+ Long previousAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-02T00:00:00+0100"));
+ Long lastAnalysisShortLivingBranch = dateToLong(parseDateTime("2017-04-03T00:00:00+0100"));
+
+ ComponentDto project = db.components().insertMainBranch();
+ userSession.logIn().addProjectPermission(UserRole.USER, project);
+ ComponentDto shortLivingBranch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(project.uuid()));
+ ComponentDto longLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.LONG));
+ ComponentDto shortLivingBranch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT).setMergeBranchUuid(longLivingBranch2.uuid()));
+ db.getDbClient().snapshotDao().insert(db.getSession(),
+ SnapshotTesting.newAnalysis(longLivingBranch2).setCreatedAt(lastAnalysisLongLivingBranch));
+ db.getDbClient().snapshotDao().insert(db.getSession(),
+ SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(previousAnalysisShortLivingBranch).setLast(false));
+ db.getDbClient().snapshotDao().insert(db.getSession(),
+ SnapshotTesting.newAnalysis(shortLivingBranch2).setCreatedAt(lastAnalysisShortLivingBranch));
+ db.commit();
+ issueIndexer.indexOnStartup(emptySet());
+ permissionIndexerTester.allowOnlyAnyone(project);
+
+ ListWsResponse response = ws.newRequest()
+ .setParam("project", project.getKey())
+ .executeProtobuf(ListWsResponse.class);
+
+ assertThat(response.getBranchesList())
+ .extracting(WsBranches.Branch::getType, WsBranches.Branch::hasAnalysisDate, b -> "".equals(b.getAnalysisDate()) ? null : dateToLong(parseDateTime(b.getAnalysisDate())))
+ .containsExactlyInAnyOrder(
+ tuple(Common.BranchType.LONG, false, null),
+ tuple(Common.BranchType.SHORT, false, null),
+ tuple(Common.BranchType.LONG, true, lastAnalysisLongLivingBranch),
+ tuple(Common.BranchType.SHORT, true, lastAnalysisShortLivingBranch)
+ );
+ }
+
+ @Test
public void fail_when_using_branch_db_key() throws Exception {
OrganizationDto organization = db.organizations().insert();
ComponentDto project = db.components().insertMainBranch(organization);
diff --git a/sonar-ws/src/main/protobuf/ws-projectbranches.proto b/sonar-ws/src/main/protobuf/ws-projectbranches.proto
index bfeb635b5ea..d4b2a183e4e 100644
--- a/sonar-ws/src/main/protobuf/ws-projectbranches.proto
+++ b/sonar-ws/src/main/protobuf/ws-projectbranches.proto
@@ -44,6 +44,7 @@ message Branch {
optional string mergeBranch = 4;
optional Status status = 5;
optional bool isOrphan = 6;
+ optional string analysisDate = 7;
message Status {
// Quality gate status is only present for long living branch