Browse Source

SONAR-8231 Return language distribution facet

tags/6.4-RC1
Julien Lancelot 7 years ago
parent
commit
da3f423847

+ 27
- 32
server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java View File

@@ -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);
}

}

+ 33
- 2
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java View File

@@ -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 {

@@ -384,6 +387,29 @@ public class SearchProjectsActionTest {
tuple("500000.0-*", 1L));
}

@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();
@@ -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);
}


+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java View File

@@ -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");

+ 2
- 0
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java View File

@@ -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
}

Loading…
Cancel
Save