From: Guillaume Jambet Date: Thu, 8 Mar 2018 11:17:35 +0000 (+0100) Subject: SONAR-9206 Enhance /api/components/search_projects response with organizations X-Git-Tag: 7.5~1523 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d651bd4c8f834d1a14fa87a7557e834c86c9df56;p=sonarqube.git SONAR-9206 Enhance /api/components/search_projects response with organizations --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java index 3e6fdee58ea..b936d79a242 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchProjectsAction.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Ordering; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -58,16 +59,19 @@ import org.sonar.server.measure.index.ProjectMeasuresQuery; import org.sonar.server.project.Visibility; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Common; +import org.sonarqube.ws.Components; import org.sonarqube.ws.Components.Component; import org.sonarqube.ws.Components.SearchProjectsWsResponse; import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.collect.ImmutableList.of; import static com.google.common.collect.Sets.newHashSet; import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.Objects.requireNonNull; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.api.server.ws.WebService.Param.FACETS; import static org.sonar.api.server.ws.WebService.Param.FIELDS; import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.core.util.Protobuf.setNullable; @@ -92,9 +96,11 @@ public class SearchProjectsAction implements ComponentsWsAction { public static final int MAX_PAGE_SIZE = 500; public static final int DEFAULT_PAGE_SIZE = 100; + private static final String ALL = "_all"; + private static final String ORGANIZATIONS = "organizations"; private static final String ANALYSIS_DATE = "analysisDate"; private static final String LEAK_PERIOD_DATE = "leakPeriodDate"; - private static final Set POSSIBLE_FIELDS = newHashSet(ANALYSIS_DATE, LEAK_PERIOD_DATE); + private static final Set POSSIBLE_FIELDS = newHashSet(ALL, ORGANIZATIONS, ANALYSIS_DATE, LEAK_PERIOD_DATE); private final DbClient dbClient; private final ProjectMeasuresIndex index; @@ -130,7 +136,7 @@ public class SearchProjectsAction implements ComponentsWsAction { .setRequired(false) .setInternal(true) .setSince("6.3"); - action.createParam(Param.FACETS) + action.createParam(FACETS) .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") .setPossibleValues(SUPPORTED_FACETS.stream().sorted().collect(MoreCollectors.toList(SUPPORTED_FACETS.size()))); action @@ -299,11 +305,16 @@ public class SearchProjectsAction implements ComponentsWsAction { .setAsc(httpRequest.mandatoryParamAsBoolean(Param.ASCENDING)) .setPage(httpRequest.mandatoryParamAsInt(Param.PAGE)) .setPageSize(httpRequest.mandatoryParamAsInt(Param.PAGE_SIZE)); - if (httpRequest.hasParam(Param.FACETS)) { - request.setFacets(httpRequest.paramAsStrings(Param.FACETS)); + if (httpRequest.hasParam(FACETS)) { + request.setFacets(httpRequest.mandatoryParamAsStrings(FACETS)); } if (httpRequest.hasParam(FIELDS)) { - request.setAdditionalFields(httpRequest.paramAsStrings(FIELDS)); + List paramsAsString = httpRequest.mandatoryParamAsStrings(FIELDS); + if (paramsAsString.contains(ALL)) { + request.setAdditionalFields(of(ORGANIZATIONS, ANALYSIS_DATE, LEAK_PERIOD_DATE)); + } else { + request.setAdditionalFields(paramsAsString); + } } return request.build(); } @@ -312,6 +323,11 @@ public class SearchProjectsAction implements ComponentsWsAction { Function dbToWsComponent = new DbToWsComponent(request, organizationsByUuid, searchResults.favoriteProjectUuids, searchResults.analysisByProjectUuid, userSession.isLoggedIn()); + Map organizationsByUuidForAdditionalInfo = new HashMap<>(); + if (request.additionalFields.contains(ORGANIZATIONS)) { + organizationsByUuidForAdditionalInfo.putAll(organizationsByUuid); + } + return Stream.of(SearchProjectsWsResponse.newBuilder()) .map(response -> response.setPaging(Common.Paging.newBuilder() .setPageIndex(request.getPage()) @@ -323,6 +339,15 @@ public class SearchProjectsAction implements ComponentsWsAction { .forEach(response::addComponents); return response; }) + .map(response -> { + organizationsByUuidForAdditionalInfo.values().stream().forEach( + dto -> response.addOrganizations( + Components.Organization.newBuilder() + .setKey(dto.getKey()) + .setName(dto.getName()) + .build())); + return response; + }) .map(response -> addFacets(searchResults, response)) .map(SearchProjectsWsResponse.Builder::build) .findFirst() @@ -532,6 +557,7 @@ public class SearchProjectsAction implements ComponentsWsAction { public static RequestBuilder builder() { return new RequestBuilder(); } + } static class RequestBuilder { diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java index 3593bac8a49..6436512c13f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SuggestionsAction.java @@ -72,7 +72,7 @@ import static org.sonar.core.util.stream.MoreCollectors.toSet; import static org.sonar.server.component.index.SuggestionQuery.DEFAULT_LIMIT; import static org.sonar.server.es.DefaultIndexSettings.MINIMUM_NGRAM_LENGTH; import static org.sonar.server.ws.WsUtils.writeProtobuf; -import static org.sonarqube.ws.Components.SuggestionsWsResponse.Organization; +import static org.sonarqube.ws.Components.Organization; import static org.sonarqube.ws.Components.SuggestionsWsResponse.newBuilder; import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SUGGESTIONS; diff --git a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search_projects-example.json b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search_projects-example.json index 41d9cfa4c75..942f218e1c5 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search_projects-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search_projects-example.json @@ -4,6 +4,16 @@ "pageSize": 100, "total": 3 }, + "organizations": [ + { + "key": "my-org-key-1", + "name": "Foo" + }, + { + "key": "my-org-key-2", + "name": "Bar" + } + ], "components": [ { "organization": "my-org-key-1", diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java index e1774f31f65..72b33112397 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java @@ -54,7 +54,6 @@ import org.sonar.server.measure.index.ProjectMeasuresIndexer; import org.sonar.server.permission.index.AuthorizationTypeSupport; import org.sonar.server.permission.index.PermissionIndexerTester; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.KeyExamples; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Common; @@ -89,6 +88,9 @@ import static org.sonar.core.util.stream.MoreCollectors.toList; import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.DATA; import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.PERCENT; import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.RATING; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_003; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; @@ -183,9 +185,9 @@ public class SearchProjectsActionTest { assertThat(asc.defaultValue()).isEqualTo("true"); assertThat(asc.possibleValues()).containsOnly("true", "false", "yes", "no"); - Param additionalFields = def.param("f"); - assertThat(additionalFields.defaultValue()).isNull(); - assertThat(additionalFields.possibleValues()).containsOnly("analysisDate", "leakPeriodDate"); + Param f = def.param("f"); + assertThat(f.defaultValue()).isNull(); + assertThat(f.possibleValues()).containsOnly("_all", "organizations", "analysisDate", "leakPeriodDate"); Param facets = def.param("facets"); assertThat(facets.defaultValue()).isNull(); @@ -196,31 +198,40 @@ public class SearchProjectsActionTest { @Test public void json_example() { userSession.logIn(); - OrganizationDto organization1Dto = db.organizations().insertForKey("my-org-key-1"); - OrganizationDto organization2Dto = db.organizations().insertForKey("my-org-key-2"); + OrganizationDto organization2Dto = db.organizations().insert(dto-> dto.setKey("my-org-key-2").setName("Bar")); + OrganizationDto organization1Dto = db.organizations().insert(dto-> dto.setKey("my-org-key-1").setName("Foo")); + MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType(PERCENT.name())); ComponentDto project1 = insertProject(organization1Dto, c -> c - .setDbKey(KeyExamples.KEY_PROJECT_EXAMPLE_001) + .setDbKey(KEY_PROJECT_EXAMPLE_001) .setName("My Project 1") .setTagsString("finance, java"), new Measure(coverage, c -> c.setValue(80d))); ComponentDto project2 = insertProject(organization1Dto, c -> c - .setDbKey(KeyExamples.KEY_PROJECT_EXAMPLE_002) + .setDbKey(KEY_PROJECT_EXAMPLE_002) .setName("My Project 2"), new Measure(coverage, c -> c.setValue(90d))); ComponentDto project3 = insertProject(organization2Dto, c -> c - .setDbKey(KeyExamples.KEY_PROJECT_EXAMPLE_003) + .setDbKey(KEY_PROJECT_EXAMPLE_003) .setName("My Project 3") .setTagsString("sales, offshore, java"), new Measure(coverage, c -> c.setValue(20d))); addFavourite(project1); - String jsonResult = ws.newRequest().setParam(Param.FACETS, COVERAGE).execute().getInput(); - SearchProjectsWsResponse protobufResult = ws.newRequest().setParam(Param.FACETS, COVERAGE).executeProtobuf(SearchProjectsWsResponse.class); + String jsonResult = ws.newRequest() + .setParam(FACETS, COVERAGE) + .setParam(FIELDS, "_all") + .execute().getInput(); assertJson(jsonResult).withStrictArrayOrder().ignoreFields("id").isSimilarTo(ws.getDef().responseExampleAsString()); assertJson(ws.getDef().responseExampleAsString()).ignoreFields("id").withStrictArrayOrder().isSimilarTo(jsonResult); - assertThat(protobufResult.getComponentsList()).extracting(Component::getId).containsExactly(project1.uuid(), project2.uuid(), project3.uuid()); + + SearchProjectsWsResponse protobufResult = ws.newRequest() + .setParam(FACETS, COVERAGE) + .executeProtobuf(SearchProjectsWsResponse.class); + + assertThat(protobufResult.getComponentsList()).extracting(Component::getId) + .containsExactly(project1.uuid(), project2.uuid(), project3.uuid()); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java index 24b26f4ce15..5d8c55557c0 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SuggestionsActionTest.java @@ -49,12 +49,12 @@ import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; -import org.sonarqube.ws.MediaTypes; +import org.sonarqube.ws.Components.Organization; import org.sonarqube.ws.Components.SuggestionsWsResponse; import org.sonarqube.ws.Components.SuggestionsWsResponse.Category; -import org.sonarqube.ws.Components.SuggestionsWsResponse.Organization; import org.sonarqube.ws.Components.SuggestionsWsResponse.Project; import org.sonarqube.ws.Components.SuggestionsWsResponse.Suggestion; +import org.sonarqube.ws.MediaTypes; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; diff --git a/sonar-ws/src/main/protobuf/ws-components.proto b/sonar-ws/src/main/protobuf/ws-components.proto index a995eb42cbc..0218de0edee 100644 --- a/sonar-ws/src/main/protobuf/ws-components.proto +++ b/sonar-ws/src/main/protobuf/ws-components.proto @@ -69,11 +69,6 @@ message SuggestionsWsResponse { optional bool isFavorite = 7; } - message Organization { - optional string key = 1; - optional string name = 2; - } - message Project { optional string key = 1; optional string name = 2; @@ -83,8 +78,9 @@ message SuggestionsWsResponse { // WS api/components/search_projects message SearchProjectsWsResponse { optional sonarqube.ws.commons.Paging paging = 1; - repeated Component components = 2; - optional sonarqube.ws.commons.Facets facets = 3; + repeated Organization organizations = 2; + repeated Component components = 3; + optional sonarqube.ws.commons.Facets facets = 4; } // WS api/components/provisioned @@ -129,3 +125,10 @@ message Component { } } +message Organization { + optional string key = 1; + optional string name = 2; +} + + +