Skip to content

Commit

Permalink
SONAR-11950 add revision to response of WS api/projects/search
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Brandhof authored and SonarTech committed May 22, 2019
1 parent ad48aec commit 986f94e
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 28 deletions.
Expand Up @@ -22,6 +22,7 @@
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.server.ws.Change; import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
Expand All @@ -45,6 +46,7 @@
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format; import static java.lang.String.format;
import static java.util.Optional.ofNullable; 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.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW; import static org.sonar.api.resources.Qualifiers.VIEW;
Expand Down Expand Up @@ -179,10 +181,11 @@ private SearchWsResponse doHandle(SearchRequest request) {
ComponentQuery query = buildDbQuery(request); ComponentQuery query = buildDbQuery(request);
Paging paging = buildPaging(dbSession, request, organization, query); Paging paging = buildPaging(dbSession, request, organization, query);
List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize()); List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize());
Map<String, Long> analysisDateByComponentUuid = dbClient.snapshotDao() Set<String> componentUuids = components.stream().map(ComponentDto::uuid).collect(MoreCollectors.toHashSet(components.size()));
.selectLastAnalysesByRootComponentUuids(dbSession, components.stream().map(ComponentDto::uuid).collect(MoreCollectors.toList())).stream() Map<String, SnapshotDto> snapshotsByComponentUuid = dbClient.snapshotDao()
.collect(MoreCollectors.uniqueIndex(SnapshotDto::getComponentUuid, SnapshotDto::getCreatedAt)); .selectLastAnalysesByRootComponentUuids(dbSession, componentUuids).stream()
return buildResponse(components, organization, analysisDateByComponentUuid, paging); .collect(MoreCollectors.uniqueIndex(SnapshotDto::getComponentUuid, identity()));
return buildResponse(components, organization, snapshotsByComponentUuid, paging);
} }
} }


Expand Down Expand Up @@ -211,7 +214,7 @@ private Paging buildPaging(DbSession dbSession, SearchRequest request, Organizat
.andTotal(total); .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(); SearchWsResponse.Builder responseBuilder = newBuilder();
responseBuilder.getPagingBuilder() responseBuilder.getPagingBuilder()
.setPageIndex(paging.pageIndex()) .setPageIndex(paging.pageIndex())
Expand All @@ -220,12 +223,12 @@ private static SearchWsResponse buildResponse(List<ComponentDto> components, Org
.build(); .build();


components.stream() components.stream()
.map(dto -> dtoToProject(organization, dto, analysisDateByComponentUuid.get(dto.uuid()))) .map(dto -> dtoToProject(organization, dto, snapshotsByComponentUuid.get(dto.uuid())))
.forEach(responseBuilder::addComponents); .forEach(responseBuilder::addComponents);
return responseBuilder.build(); 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( checkArgument(
organization.getUuid().equals(dto.getOrganizationUuid()), organization.getUuid().equals(dto.getOrganizationUuid()),
"No Organization found for uuid '%s'", "No Organization found for uuid '%s'",
Expand All @@ -238,7 +241,11 @@ private static Component dtoToProject(OrganizationDto organization, ComponentDto
.setName(dto.name()) .setName(dto.name())
.setQualifier(dto.qualifier()) .setQualifier(dto.qualifier())
.setVisibility(dto.isPrivate() ? PRIVATE.getLabel() : PUBLIC.getLabel()); .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(); return builder.build();
} }
Expand Down
Expand Up @@ -19,7 +19,6 @@
*/ */
package org.sonar.server.project.ws; package org.sonar.server.project.ws;


import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -52,6 +51,7 @@
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable; 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.api.utils.Paging.offset;
import static org.sonar.server.project.ws.SearchMyProjectsData.builder; import static org.sonar.server.project.ws.SearchMyProjectsData.builder;
import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonar.server.ws.WsUtils.writeProtobuf;
Expand Down Expand Up @@ -137,7 +137,10 @@ public Project apply(ComponentDto dto) {
.setId(dto.uuid()) .setId(dto.uuid())
.setKey(dto.getDbKey()) .setKey(dto.getDbKey())
.setName(dto.name()); .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); data.qualityGateStatusFor(dto.uuid()).ifPresent(project::setQualityGate);
ofNullable(emptyToNull(dto.description())).ifPresent(project::setDescription); ofNullable(emptyToNull(dto.description())).ifPresent(project::setDescription);


Expand Down Expand Up @@ -168,7 +171,7 @@ public Link apply(ProjectLinkDto dto) {
} }
} }


SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request) { private SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request) {
SearchMyProjectsData.Builder data = builder(); SearchMyProjectsData.Builder data = builder();
ProjectsResult searchResult = searchProjects(dbSession, request); ProjectsResult searchResult = searchProjects(dbSession, request);
List<ComponentDto> projects = searchResult.projects; List<ComponentDto> projects = searchResult.projects;
Expand All @@ -187,8 +190,7 @@ SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request)
return data.build(); return data.build();
} }


@VisibleForTesting private ProjectsResult searchProjects(DbSession dbSession, SearchMyProjectsRequest request) {
ProjectsResult searchProjects(DbSession dbSession, SearchMyProjectsRequest request) {
int userId = requireNonNull(userSession.getUserId(), "Current user must be authenticated"); int userId = requireNonNull(userSession.getUserId(), "Current user must be authenticated");


List<Long> componentIds = dbClient.roleDao().selectComponentIdsByPermissionAndUserId(dbSession, UserRole.ADMIN, userId); List<Long> componentIds = dbClient.roleDao().selectComponentIdsByPermissionAndUserId(dbSession, UserRole.ADMIN, userId);
Expand Down
Expand Up @@ -33,19 +33,20 @@


import static com.google.common.collect.ImmutableList.copyOf; import static com.google.common.collect.ImmutableList.copyOf;
import static java.util.Objects.requireNonNull; 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 { class SearchMyProjectsData {
private final List<ComponentDto> projects; private final List<ComponentDto> projects;
private final ListMultimap<String, ProjectLinkDto> projectLinksByProjectUuid; 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 Map<String, String> qualityGateStatuses;
private final int totalNbOfProject; private final int totalNbOfProject;


private SearchMyProjectsData(Builder builder) { private SearchMyProjectsData(Builder builder) {
this.projects = copyOf(builder.projects); this.projects = copyOf(builder.projects);
this.projectLinksByProjectUuid = buildProjectLinks(builder.projectLinks); 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.qualityGateStatuses = buildQualityGateStatuses(builder.qualityGates);
this.totalNbOfProject = builder.totalNbOfProjects; this.totalNbOfProject = builder.totalNbOfProjects;
} }
Expand All @@ -62,8 +63,8 @@ List<ProjectLinkDto> projectLinksFor(String projectUuid) {
return projectLinksByProjectUuid.get(projectUuid); return projectLinksByProjectUuid.get(projectUuid);
} }


Optional<String> lastAnalysisDateFor(String componentUuid) { Optional<SnapshotDto> lastSnapshot(String componentUuid) {
return Optional.ofNullable(lastAnalysisDates.get(componentUuid)); return Optional.ofNullable(snapshotsByComponentUuid.get(componentUuid));
} }


Optional<String> qualityGateStatusFor(String componentUuid) { Optional<String> qualityGateStatusFor(String componentUuid) {
Expand All @@ -80,12 +81,6 @@ private static ListMultimap<String, ProjectLinkDto> buildProjectLinks(List<Proje
return projectLinks.build(); 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) { private static Map<String, String> buildQualityGateStatuses(List<LiveMeasureDto> measures) {
return ImmutableMap.copyOf(measures.stream() return ImmutableMap.copyOf(measures.stream()
.collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString))); .collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString)));
Expand Down
Expand Up @@ -12,7 +12,8 @@
"name": "Project Name 1", "name": "Project Name 1",
"qualifier": "TRK", "qualifier": "TRK",
"visibility": "public", "visibility": "public",
"lastAnalysisDate": "2017-03-01T11:39:03+0300" "lastAnalysisDate": "2017-03-01T11:39:03+0300",
"revision": "cfb82f55c6ef32e61828c4cb3db2da12795fd767"
}, },
{ {
"organization": "my-org-1", "organization": "my-org-1",
Expand All @@ -21,7 +22,8 @@
"name": "Project Name 1", "name": "Project Name 1",
"qualifier": "TRK", "qualifier": "TRK",
"visibility": "private", "visibility": "private",
"lastAnalysisDate": "2017-03-02T15:21:47+0300" "lastAnalysisDate": "2017-03-02T15:21:47+0300",
"revision": "7be96a94ac0c95a61ee6ee0ef9c6f808d386a355"
} }
] ]
} }
Expand Up @@ -413,8 +413,12 @@ public void json_example() {
db.components().insertComponents( db.components().insertComponents(
publicProject, publicProject,
privateProject); 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(publicProject)
db.getDbClient().snapshotDao().insert(db.getSession(), newAnalysis(privateProject).setCreatedAt(parseDateTime("2017-03-02T15:21:47+0300").getTime())); .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(); db.commit();


String response = ws.newRequest() String response = ws.newRequest()
Expand Down
2 changes: 2 additions & 0 deletions sonar-ws/src/main/protobuf/ws-projects.proto
Expand Up @@ -35,6 +35,7 @@ message SearchMyProjectsWsResponse {
optional string lastAnalysisDate = 6; optional string lastAnalysisDate = 6;
optional string qualityGate = 7; optional string qualityGate = 7;
repeated Link links = 8; repeated Link links = 8;
optional string revision = 9;
} }


message Link { message Link {
Expand Down Expand Up @@ -71,6 +72,7 @@ message SearchWsResponse {
optional string qualifier = 5; optional string qualifier = 5;
optional string visibility = 6; optional string visibility = 6;
optional string lastAnalysisDate = 7; optional string lastAnalysisDate = 7;
optional string revision = 8;
} }
} }


Expand Down

0 comments on commit 986f94e

Please sign in to comment.