]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11950 add revision to response of WS api/projects/search
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 6 May 2019 15:06:30 +0000 (17:06 +0200)
committerSonarTech <sonartech@sonarsource.com>
Wed, 22 May 2019 18:21:17 +0000 (20:21 +0200)
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java
server/sonar-server/src/main/resources/org/sonar/server/project/ws/search-example.json
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
sonar-ws/src/main/protobuf/ws-projects.proto

index 10499c5e313c2127d9b8935e2700230e5d79e32c..5968fb30f64a91a7a3003da2276debfc8dabcda2 100644 (file)
@@ -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<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize());
-      Map<String, Long> 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<String> componentUuids = components.stream().map(ComponentDto::uuid).collect(MoreCollectors.toHashSet(components.size()));
+      Map<String, SnapshotDto> 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<ComponentDto> components, OrganizationDto organization, Map<String, Long> analysisDateByComponentUuid, Paging paging) {
+  private static SearchWsResponse buildResponse(List<ComponentDto> components, OrganizationDto organization, Map<String, SnapshotDto> 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();
   }
index e6b292f0760eef92fb1bcac1f4c0c17e26a5761f..9667bbf367163945734a3a21048334bbb12033b6 100644 (file)
@@ -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<ComponentDto> 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<Long> componentIds = dbClient.roleDao().selectComponentIdsByPermissionAndUserId(dbSession, UserRole.ADMIN, userId);
index dc5d028ceed1cd7eaa8131e8935499d51c82cd58..d484a04897565338f08630418f0f6ce554ee1db6 100644 (file)
@@ -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<ComponentDto> projects;
   private final ListMultimap<String, ProjectLinkDto> projectLinksByProjectUuid;
-  private final Map<String, String> lastAnalysisDates;
+  private final Map<String, SnapshotDto> snapshotsByComponentUuid;
   private final Map<String, String> 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<String> lastAnalysisDateFor(String componentUuid) {
-    return Optional.ofNullable(lastAnalysisDates.get(componentUuid));
+  Optional<SnapshotDto> lastSnapshot(String componentUuid) {
+    return Optional.ofNullable(snapshotsByComponentUuid.get(componentUuid));
   }
 
   Optional<String> qualityGateStatusFor(String componentUuid) {
@@ -80,12 +81,6 @@ class SearchMyProjectsData {
     return projectLinks.build();
   }
 
-  private static Map<String, String> buildAnalysisDates(List<SnapshotDto> snapshots) {
-    return ImmutableMap.copyOf(snapshots.stream().collect(Collectors.toMap(
-      SnapshotDto::getComponentUuid,
-      snapshot -> formatDateTime(snapshot.getCreatedAt()))));
-  }
-
   private static Map<String, String> buildQualityGateStatuses(List<LiveMeasureDto> measures) {
     return ImmutableMap.copyOf(measures.stream()
       .collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString)));
index ac6accbe924773294b639efd6838e1156685bc1f..88924e41bb039aedfafc36e38a3b4479e07f5e0d 100644 (file)
@@ -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"
     }
   ]
 }
index eeebc375368bfcc7ffe2b70819be1faa4b39b61f..9ed6e2dfde30ed6c32680b7e8508a03a7f181ccc 100644 (file)
@@ -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()
index 2f5372f1305ed3f820c59fc85c80e8882a95db07..be060144e48dc7c051bc4309c0fbd7dea41b6a7d 100644 (file)
@@ -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;
   }
 }