From 986f94e0e94b78698874bb5eeca6a392090c19ca Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Mon, 6 May 2019 17:06:30 +0200 Subject: [PATCH] SONAR-11950 add revision to response of WS api/projects/search --- .../sonar/server/project/ws/SearchAction.java | 23 ++++++++++++------- .../project/ws/SearchMyProjectsAction.java | 12 ++++++---- .../project/ws/SearchMyProjectsData.java | 17 +++++--------- .../server/project/ws/search-example.json | 6 +++-- .../server/project/ws/SearchActionTest.java | 8 +++++-- sonar-ws/src/main/protobuf/ws-projects.proto | 2 ++ 6 files changed, 40 insertions(+), 28 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java index 10499c5e313..5968fb30f64 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java @@ -22,6 +22,7 @@ package org.sonar.server.project.ws; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.Nullable; import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Request; @@ -45,6 +46,7 @@ import org.sonarqube.ws.Projects.SearchWsResponse; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; import static java.util.Optional.ofNullable; +import static java.util.function.Function.identity; import static org.sonar.api.resources.Qualifiers.APP; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.resources.Qualifiers.VIEW; @@ -179,10 +181,11 @@ public class SearchAction implements ProjectsWsAction { ComponentQuery query = buildDbQuery(request); Paging paging = buildPaging(dbSession, request, organization, query); List components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize()); - Map analysisDateByComponentUuid = dbClient.snapshotDao() - .selectLastAnalysesByRootComponentUuids(dbSession, components.stream().map(ComponentDto::uuid).collect(MoreCollectors.toList())).stream() - .collect(MoreCollectors.uniqueIndex(SnapshotDto::getComponentUuid, SnapshotDto::getCreatedAt)); - return buildResponse(components, organization, analysisDateByComponentUuid, paging); + Set componentUuids = components.stream().map(ComponentDto::uuid).collect(MoreCollectors.toHashSet(components.size())); + Map snapshotsByComponentUuid = dbClient.snapshotDao() + .selectLastAnalysesByRootComponentUuids(dbSession, componentUuids).stream() + .collect(MoreCollectors.uniqueIndex(SnapshotDto::getComponentUuid, identity())); + return buildResponse(components, organization, snapshotsByComponentUuid, paging); } } @@ -211,7 +214,7 @@ public class SearchAction implements ProjectsWsAction { .andTotal(total); } - private static SearchWsResponse buildResponse(List components, OrganizationDto organization, Map analysisDateByComponentUuid, Paging paging) { + private static SearchWsResponse buildResponse(List components, OrganizationDto organization, Map snapshotsByComponentUuid, Paging paging) { SearchWsResponse.Builder responseBuilder = newBuilder(); responseBuilder.getPagingBuilder() .setPageIndex(paging.pageIndex()) @@ -220,12 +223,12 @@ public class SearchAction implements ProjectsWsAction { .build(); components.stream() - .map(dto -> dtoToProject(organization, dto, analysisDateByComponentUuid.get(dto.uuid()))) + .map(dto -> dtoToProject(organization, dto, snapshotsByComponentUuid.get(dto.uuid()))) .forEach(responseBuilder::addComponents); return responseBuilder.build(); } - private static Component dtoToProject(OrganizationDto organization, ComponentDto dto, @Nullable Long analysisDate) { + private static Component dtoToProject(OrganizationDto organization, ComponentDto dto, @Nullable SnapshotDto snapshot) { checkArgument( organization.getUuid().equals(dto.getOrganizationUuid()), "No Organization found for uuid '%s'", @@ -238,7 +241,11 @@ public class SearchAction implements ProjectsWsAction { .setName(dto.name()) .setQualifier(dto.qualifier()) .setVisibility(dto.isPrivate() ? PRIVATE.getLabel() : PUBLIC.getLabel()); - ofNullable(analysisDate).ifPresent(d -> builder.setLastAnalysisDate(formatDateTime(d))); + if (snapshot != null) { + // FIXME created_at should not be nullable + ofNullable(snapshot.getCreatedAt()).ifPresent(d -> builder.setLastAnalysisDate(formatDateTime(d))); + ofNullable(snapshot.getRevision()).ifPresent(builder::setRevision); + } return builder.build(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java index e6b292f0760..9667bbf3671 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java @@ -19,7 +19,6 @@ */ package org.sonar.server.project.ws; -import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import java.util.List; @@ -52,6 +51,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.Optional.ofNullable; +import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.Paging.offset; import static org.sonar.server.project.ws.SearchMyProjectsData.builder; import static org.sonar.server.ws.WsUtils.writeProtobuf; @@ -137,7 +137,10 @@ public class SearchMyProjectsAction implements ProjectsWsAction { .setId(dto.uuid()) .setKey(dto.getDbKey()) .setName(dto.name()); - data.lastAnalysisDateFor(dto.uuid()).ifPresent(project::setLastAnalysisDate); + data.lastSnapshot(dto.uuid()).ifPresent(s -> { + project.setLastAnalysisDate(formatDateTime(s.getCreatedAt())); + ofNullable(s.getRevision()).ifPresent(project::setRevision); + }); data.qualityGateStatusFor(dto.uuid()).ifPresent(project::setQualityGate); ofNullable(emptyToNull(dto.description())).ifPresent(project::setDescription); @@ -168,7 +171,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction { } } - SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request) { + private SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request) { SearchMyProjectsData.Builder data = builder(); ProjectsResult searchResult = searchProjects(dbSession, request); List projects = searchResult.projects; @@ -187,8 +190,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction { return data.build(); } - @VisibleForTesting - ProjectsResult searchProjects(DbSession dbSession, SearchMyProjectsRequest request) { + private ProjectsResult searchProjects(DbSession dbSession, SearchMyProjectsRequest request) { int userId = requireNonNull(userSession.getUserId(), "Current user must be authenticated"); List componentIds = dbClient.roleDao().selectComponentIdsByPermissionAndUserId(dbSession, UserRole.ADMIN, userId); diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java index dc5d028ceed..d484a048975 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java @@ -33,19 +33,20 @@ import org.sonar.db.measure.LiveMeasureDto; import static com.google.common.collect.ImmutableList.copyOf; import static java.util.Objects.requireNonNull; -import static org.sonar.api.utils.DateUtils.formatDateTime; +import static java.util.function.Function.identity; +import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; class SearchMyProjectsData { private final List projects; private final ListMultimap projectLinksByProjectUuid; - private final Map lastAnalysisDates; + private final Map snapshotsByComponentUuid; private final Map qualityGateStatuses; private final int totalNbOfProject; private SearchMyProjectsData(Builder builder) { this.projects = copyOf(builder.projects); this.projectLinksByProjectUuid = buildProjectLinks(builder.projectLinks); - this.lastAnalysisDates = buildAnalysisDates(builder.snapshots); + this.snapshotsByComponentUuid =builder.snapshots.stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, identity())); this.qualityGateStatuses = buildQualityGateStatuses(builder.qualityGates); this.totalNbOfProject = builder.totalNbOfProjects; } @@ -62,8 +63,8 @@ class SearchMyProjectsData { return projectLinksByProjectUuid.get(projectUuid); } - Optional lastAnalysisDateFor(String componentUuid) { - return Optional.ofNullable(lastAnalysisDates.get(componentUuid)); + Optional lastSnapshot(String componentUuid) { + return Optional.ofNullable(snapshotsByComponentUuid.get(componentUuid)); } Optional qualityGateStatusFor(String componentUuid) { @@ -80,12 +81,6 @@ class SearchMyProjectsData { return projectLinks.build(); } - private static Map buildAnalysisDates(List snapshots) { - return ImmutableMap.copyOf(snapshots.stream().collect(Collectors.toMap( - SnapshotDto::getComponentUuid, - snapshot -> formatDateTime(snapshot.getCreatedAt())))); - } - private static Map buildQualityGateStatuses(List measures) { return ImmutableMap.copyOf(measures.stream() .collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString))); diff --git a/server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json index ac6accbe924..88924e41bb0 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json @@ -12,7 +12,8 @@ "name": "Project Name 1", "qualifier": "TRK", "visibility": "public", - "lastAnalysisDate": "2017-03-01T11:39:03+0300" + "lastAnalysisDate": "2017-03-01T11:39:03+0300", + "revision": "cfb82f55c6ef32e61828c4cb3db2da12795fd767" }, { "organization": "my-org-1", @@ -21,7 +22,8 @@ "name": "Project Name 1", "qualifier": "TRK", "visibility": "private", - "lastAnalysisDate": "2017-03-02T15:21:47+0300" + "lastAnalysisDate": "2017-03-02T15:21:47+0300", + "revision": "7be96a94ac0c95a61ee6ee0ef9c6f808d386a355" } ] } diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java index eeebc375368..9ed6e2dfde3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java @@ -413,8 +413,12 @@ public class SearchActionTest { db.components().insertComponents( publicProject, privateProject); - db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(publicProject).setCreatedAt(parseDateTime("2017-03-01T11:39:03+0300").getTime())); - db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(privateProject).setCreatedAt(parseDateTime("2017-03-02T15:21:47+0300").getTime())); + db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(publicProject) + .setCreatedAt(parseDateTime("2017-03-01T11:39:03+0300").getTime()) + .setRevision("cfb82f55c6ef32e61828c4cb3db2da12795fd767")); + db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(privateProject) + .setCreatedAt(parseDateTime("2017-03-02T15:21:47+0300").getTime()) + .setRevision("7be96a94ac0c95a61ee6ee0ef9c6f808d386a355")); db.commit(); String response = ws.newRequest() diff --git a/sonar-ws/src/main/protobuf/ws-projects.proto b/sonar-ws/src/main/protobuf/ws-projects.proto index 2f5372f1305..be060144e48 100644 --- a/sonar-ws/src/main/protobuf/ws-projects.proto +++ b/sonar-ws/src/main/protobuf/ws-projects.proto @@ -35,6 +35,7 @@ message SearchMyProjectsWsResponse { optional string lastAnalysisDate = 6; optional string qualityGate = 7; repeated Link links = 8; + optional string revision = 9; } message Link { @@ -71,6 +72,7 @@ message SearchWsResponse { optional string qualifier = 5; optional string visibility = 6; optional string lastAnalysisDate = 7; + optional string revision = 8; } } -- 2.39.5