diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-02-17 17:33:07 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-02-22 08:15:35 +0100 |
commit | da3f4238479d89173c3cbc9ebbd669c1990abb53 (patch) | |
tree | 41dc2619e9cd15bac44fb8a8e608cb34bc69f408 | |
parent | eb3a5e9ecb555ea838b28e2d0d27ae95922470e7 (diff) | |
download | sonarqube-da3f4238479d89173c3cbc9ebbd669c1990abb53.tar.gz sonarqube-da3f4238479d89173c3cbc9ebbd669c1990abb53.zip |
SONAR-8231 Return language distribution facet
4 files changed, 63 insertions, 35 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java index 5ff762cf0f6..e687404d592 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java @@ -21,6 +21,7 @@ package org.sonar.server.measure.index; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import java.util.HashMap; import java.util.List; @@ -56,7 +57,6 @@ import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY; import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY_KEY; import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; -import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY; import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY; import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY; import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY; @@ -69,6 +69,7 @@ import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.FIEL import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.INDEX_PROJECT_MEASURES; import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURE; import static org.sonar.server.measure.index.ProjectMeasuresQuery.SORT_BY_NAME; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.FILTER_LANGUAGE; public class ProjectMeasuresIndex extends BaseIndex { @@ -79,7 +80,8 @@ public class ProjectMeasuresIndex extends BaseIndex { SQALE_RATING_KEY, RELIABILITY_RATING_KEY, SECURITY_RATING_KEY, - ALERT_STATUS_KEY); + ALERT_STATUS_KEY, + FILTER_LANGUAGE); private static final String FIELD_MEASURES_KEY = FIELD_MEASURES + "." + ProjectMeasuresIndexDefinition.FIELD_MEASURES_KEY; private static final String FIELD_MEASURES_VALUE = FIELD_MEASURES + "." + ProjectMeasuresIndexDefinition.FIELD_MEASURES_VALUE; @@ -87,6 +89,17 @@ public class ProjectMeasuresIndex extends BaseIndex { private static final String FIELD_LANGUAGES_KEY = FIELD_LANGUAGES + "." + ProjectMeasuresIndexDefinition.FIELD_LANGUAGES_KEY; private static final String FIELD_LANGUAGES_VALUE = FIELD_LANGUAGES + "." + ProjectMeasuresIndexDefinition.FIELD_LANGUAGES_VALUE; + private static final Map<String, FacetSetter> FACET_FACTORIES = ImmutableMap.<String, FacetSetter>builder() + .put(NCLOC_KEY, (esSearch, filters) -> addRangeFacet(esSearch, NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d), filters)) + .put(DUPLICATED_LINES_DENSITY_KEY, (esSearch, filters) -> addRangeFacet(esSearch, DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d), filters)) + .put(COVERAGE_KEY, (esSearch, filters) -> addRangeFacet(esSearch, COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d), filters)) + .put(SQALE_RATING_KEY, (esSearch, filters) -> addRatingFacet(esSearch, SQALE_RATING_KEY, filters)) + .put(RELIABILITY_RATING_KEY, (esSearch, filters) -> addRatingFacet(esSearch, RELIABILITY_RATING_KEY, filters)) + .put(SECURITY_RATING_KEY, (esSearch, filters) -> addRatingFacet(esSearch, SECURITY_RATING_KEY, filters)) + .put(ALERT_STATUS_KEY, (esSearch, filters) -> esSearch.addAggregation(createStickyFacet(ALERT_STATUS_KEY, filters, createQualityGateFacet()))) + .put(FILTER_LANGUAGE, (esSearch, filters) -> esSearch.addAggregation(createStickyFacet(FILTER_LANGUAGE, filters, createLanguagesFacet()))) + .build(); + private final AuthorizationTypeSupport authorizationTypeSupport; public ProjectMeasuresIndex(EsClient client, AuthorizationTypeSupport authorizationTypeSupport) { @@ -133,33 +146,10 @@ public class ProjectMeasuresIndex extends BaseIndex { } private static void addFacets(SearchRequestBuilder esSearch, SearchOptions options, Map<String, QueryBuilder> filters) { - if (options.getFacets().isEmpty()) { - return; - } - if (options.getFacets().contains(NCLOC_KEY)) { - addRangeFacet(esSearch, NCLOC_KEY, ImmutableList.of(1_000d, 10_000d, 100_000d, 500_000d), filters); - } - if (options.getFacets().contains(DUPLICATED_LINES_DENSITY_KEY)) { - addRangeFacet(esSearch, DUPLICATED_LINES_DENSITY_KEY, ImmutableList.of(3d, 5d, 10d, 20d), filters); - } - if (options.getFacets().contains(COVERAGE_KEY)) { - addRangeFacet(esSearch, COVERAGE_KEY, ImmutableList.of(30d, 50d, 70d, 80d), filters); - } - if (options.getFacets().contains(SQALE_RATING_KEY)) { - addRatingFacet(esSearch, SQALE_RATING_KEY, filters); - } - if (options.getFacets().contains(RELIABILITY_RATING_KEY)) { - addRatingFacet(esSearch, RELIABILITY_RATING_KEY, filters); - } - if (options.getFacets().contains(SECURITY_RATING_KEY)) { - addRatingFacet(esSearch, SECURITY_RATING_KEY, filters); - } - if (options.getFacets().contains(ALERT_STATUS_KEY)) { - esSearch.addAggregation(createStickyFacet(ALERT_STATUS_KEY, filters, createQualityGateFacet())); - } - if (options.getFacets().contains(NCLOC_LANGUAGE_DISTRIBUTION_KEY)) { - esSearch.addAggregation(createStickyFacet(NCLOC_LANGUAGE_DISTRIBUTION_KEY, filters, createLanguagesFacet())); - } + options.getFacets().stream() + .filter(FACET_FACTORIES::containsKey) + .map(FACET_FACTORIES::get) + .forEach(factory -> factory.addFacet(esSearch, filters)); } private static void addRangeFacet(SearchRequestBuilder esSearch, String metricKey, List<Double> thresholds, Map<String, QueryBuilder> filters) { @@ -226,12 +216,12 @@ public class ProjectMeasuresIndex extends BaseIndex { } private static AbstractAggregationBuilder createLanguagesFacet() { - return AggregationBuilders.nested("nested_" + NCLOC_LANGUAGE_DISTRIBUTION_KEY) + return AggregationBuilders.nested("nested_" + FILTER_LANGUAGE) .path(FIELD_LANGUAGES) .subAggregation( - AggregationBuilders.terms(NCLOC_LANGUAGE_DISTRIBUTION_KEY) + AggregationBuilders.terms(FILTER_LANGUAGE) .field(FIELD_LANGUAGES_KEY) - .subAggregation(AggregationBuilders.sum("size_" + NCLOC_LANGUAGE_DISTRIBUTION_KEY) + .subAggregation(AggregationBuilders.sum("size_" + FILTER_LANGUAGE) .field(FIELD_LANGUAGES_VALUE))); } @@ -282,4 +272,9 @@ public class ProjectMeasuresIndex extends BaseIndex { } } + @FunctionalInterface + private interface FacetSetter { + void addFacet(SearchRequestBuilder esSearch, Map<String, QueryBuilder> filters); + } + } 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 0e3a9b87f40..1106791b797 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 @@ -61,10 +61,12 @@ import org.sonarqube.ws.client.component.SearchProjectsRequest; import static com.google.common.collect.Lists.newArrayList; import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Optional.ofNullable; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; +import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY; import static org.sonar.api.measures.Metric.ValueType.INT; import static org.sonar.api.server.ws.WebService.Param.ASCENDING; import static org.sonar.api.server.ws.WebService.Param.FACETS; @@ -84,6 +86,7 @@ import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE 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; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.FILTER_LANGUAGE; public class SearchProjectsActionTest { @@ -385,6 +388,29 @@ public class SearchProjectsActionTest { } @Test + public void return_languages_facet() { + OrganizationDto organization = db.getDefaultOrganization(); + insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), ImmutableMap.of("<null>", 2, "java", 6, "xoo", 18)); + insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), ImmutableMap.of("java", 4, "xoo", 5)); + insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d)), ImmutableMap.of("xoo", 3)); + insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d)), ImmutableMap.of("<null>", 5, "java", 16, "xoo", 9)); + insertMetrics(COVERAGE, NCLOC_LANGUAGE_DISTRIBUTION_KEY); + + SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_LANGUAGE))); + + Common.Facet facet = result.getFacets().getFacetsList().stream() + .filter(oneFacet -> FILTER_LANGUAGE.equals(oneFacet.getProperty())) + .findFirst().orElseThrow(IllegalStateException::new); + assertThat(facet.getProperty()).isEqualTo(FILTER_LANGUAGE); + assertThat(facet.getValuesList()) + .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) + .containsExactly( + tuple("xoo", 35L), + tuple("java", 26L), + tuple("<null>", 7L)); + } + + @Test public void default_sort_is_by_ascending_name() throws Exception { OrganizationDto organization = db.getDefaultOrganization(); insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d))); @@ -466,6 +492,10 @@ public class SearchProjectsActionTest { } private ComponentDto insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) { + return insertProjectInDbAndEs(project, measures, emptyMap()); + } + + private ComponentDto insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures, Map<String, Integer> languagesDistribution) { ComponentDto res = componentDb.insertComponent(project); try { es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURE, @@ -474,7 +504,8 @@ public class SearchProjectsActionTest { .setId(project.uuid()) .setKey(project.key()) .setName(project.name()) - .setMeasures(measures)); + .setMeasures(measures) + .setLanguages(languagesDistribution)); authorizationIndexerTester.allowOnlyAnyone(project); } catch (Exception e) { Throwables.propagate(e); @@ -490,7 +521,7 @@ public class SearchProjectsActionTest { dbSession.commit(); } - private static Map<String, Object> newMeasure(String key, double value) { + private static Map<String, Object> newMeasure(String key, Object value) { return ImmutableMap.of("key", key, "value", value); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java index de317b41563..abbd8c49ac2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java @@ -69,7 +69,7 @@ public class ProjectMeasuresIndexTest { private static final String COVERAGE = "coverage"; private static final String DUPLICATION = "duplicated_lines_density"; private static final String NCLOC = "ncloc"; - private static final String LANGUAGES = "ncloc_language_distribution"; + private static final String LANGUAGES = "languages"; private static final OrganizationDto ORG = OrganizationTesting.newOrganizationDto(); private static final ComponentDto PROJECT1 = newProjectDto(ORG).setUuid("Project-1").setName("Project 1").setKey("key-1"); diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java index b735334df8f..fe4371a341f 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java @@ -36,6 +36,8 @@ public class ProjectsWsParameters { public static final String PARAM_ORGANIZATION = "organization"; public static final String PARAM_QUALIFIERS = "qualifiers"; + public static final String FILTER_LANGUAGE = "language"; + private ProjectsWsParameters() { // static utils only } |