package org.sonar.server.component.ws;
import com.google.common.base.Splitter;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.commons.lang.StringUtils;
+import java.util.stream.StreamSupport;
+import javax.annotation.Nullable;
import org.sonar.api.measures.Metric.Level;
+import org.sonar.core.util.stream.Collectors;
import org.sonar.server.measure.index.ProjectMeasuresQuery;
import static com.google.common.base.Preconditions.checkArgument;
// prevent instantiation
}
- static ProjectMeasuresQuery newProjectMeasuresQuery(String filter, Set<String> favoriteProjectUuids) {
- if (StringUtils.isBlank(filter)) {
- return new ProjectMeasuresQuery();
- }
+ static List<String> toCriteria(String filter) {
+ return StreamSupport.stream(CRITERIA_SPLITTER.split(filter).spliterator(), false)
+ .filter(Objects::nonNull)
+ .filter(criterion -> !criterion.isEmpty())
+ .collect(Collectors.toList());
+ }
- ProjectMeasuresQuery query = new ProjectMeasuresQuery();
+ static boolean hasIsFavouriteCriterion(List<String> criteria) {
+ return criteria.stream().anyMatch(IS_FAVORITE_CRITERION::equalsIgnoreCase);
+ }
- CRITERIA_SPLITTER.split(filter)
- .forEach(criteria -> processCriterion(criteria, query, favoriteProjectUuids));
- return query;
+ static ProjectMeasuresQuery newProjectMeasuresQuery(List<String> criteria, @Nullable Set<String> projectUuids) {
+ ProjectMeasuresQuery res = new ProjectMeasuresQuery();
+ if (projectUuids != null) {
+ res.setProjectUuids(projectUuids);
+ }
+ criteria.forEach(criterion -> processCriterion(criterion, res));
+ return res;
}
- private static void processCriterion(String rawCriterion, ProjectMeasuresQuery query, Set<String> favoriteProjectUuids) {
+ private static void processCriterion(String rawCriterion, ProjectMeasuresQuery query) {
String criterion = rawCriterion.trim();
- try {
- if (IS_FAVORITE_CRITERION.equalsIgnoreCase(criterion)) {
- query.setProjectUuids(favoriteProjectUuids);
- return;
- }
+ if (IS_FAVORITE_CRITERION.equalsIgnoreCase(criterion)) {
+ return;
+ }
+ try {
Matcher matcher = CRITERIA_PATTERN.matcher(criterion);
checkArgument(matcher.find() && matcher.groupCount() == 3, "Criterion should be 'isFavourite' or criterion should have a metric, an operator and a value");
String metric = matcher.group(1).toLowerCase(ENGLISH);
package org.sonar.server.component.ws;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Ordering;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.String.format;
+import static org.sonar.core.util.stream.Collectors.toSet;
+import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.hasIsFavouriteCriterion;
import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
+import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.toCriteria;
import static org.sonar.server.measure.index.ProjectMeasuresIndex.SUPPORTED_FACETS;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
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.component.SearchProjectsRequest.DEFAULT_PAGE_SIZE;
import static org.sonarqube.ws.client.component.SearchProjectsRequest.MAX_PAGE_SIZE;
.setResponseExample(getClass().getResource("search_projects-example.json"))
.setHandler(this);
+ action.createParam(PARAM_ORGANIZATION)
+ .setDescription("the organization to search projects in")
+ .setRequired(false)
+ .setSince("6.3");
action.createParam(Param.FACETS)
.setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")
.setPossibleValues(SUPPORTED_FACETS);
private SearchProjectsWsResponse doHandle(SearchProjectsRequest request) {
try (DbSession dbSession = dbClient.openSession(false)) {
- SearchResults searchResults = searchData(dbSession, request);
- Set<String> organizationUuids = searchResults.projects.stream().map(ComponentDto::getOrganizationUuid).collect(Collectors.toSet());
- Map<String, OrganizationDto> organizationsByUuid = dbClient.organizationDao().selectByUuids(dbSession, organizationUuids)
- .stream()
- .collect(Collectors.uniqueIndex(OrganizationDto::getUuid));
-
- return buildResponse(request, searchResults, organizationsByUuid);
+ String organizationKey = request.getOrganization();
+ if (organizationKey == null) {
+ return handleForAnyOrganization(dbSession, request);
+ } else {
+ OrganizationDto organization = checkFoundWithOptional(
+ dbClient.organizationDao().selectByKey(dbSession, organizationKey),
+ "No organization for key '%s'", organizationKey);
+ return handleForOrganization(dbSession, request, organization);
+ }
}
}
- private SearchResults searchData(DbSession dbSession, SearchProjectsRequest request) {
- String filter = firstNonNull(request.getFilter(), "");
+ private SearchProjectsWsResponse handleForAnyOrganization(DbSession dbSession, SearchProjectsRequest request) {
+ SearchResults searchResults = searchData(dbSession, request, null);
+ Set<String> organizationUuids = searchResults.projects.stream().map(ComponentDto::getOrganizationUuid).collect(toSet());
+ Map<String, OrganizationDto> organizationsByUuid = dbClient.organizationDao().selectByUuids(dbSession, organizationUuids)
+ .stream()
+ .collect(Collectors.uniqueIndex(OrganizationDto::getUuid));
+ return buildResponse(request, searchResults, organizationsByUuid);
+ }
+
+ private SearchProjectsWsResponse handleForOrganization(DbSession dbSession, SearchProjectsRequest request, OrganizationDto organization) {
+ SearchResults searchResults = searchData(dbSession, request, organization);
+ return buildResponse(request, searchResults, ImmutableMap.of(organization.getUuid(), organization));
+ }
+
+ private SearchResults searchData(DbSession dbSession, SearchProjectsRequest request, @Nullable OrganizationDto organization) {
+ List<String> criteria = toCriteria(firstNonNull(request.getFilter(), ""));
- Set<String> favoriteProjectUuids = searchFavoriteProjects(dbSession);
+ List<ComponentDto> favoriteProjects = searchFavoriteProjects(dbSession);
+ Set<String> projectUuids = buildFilterOnProjectUuids(dbSession, criteria, favoriteProjects, organization);
- ProjectMeasuresQuery query = newProjectMeasuresQuery(filter, favoriteProjectUuids);
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(criteria, projectUuids);
queryValidator.validate(dbSession, query);
SearchIdResult<String> esResults = index.search(query, new SearchOptions()
Ordering<ComponentDto> ordering = Ordering.explicit(esResults.getIds()).onResultOf(ComponentDto::uuid);
List<ComponentDto> projects = ordering.immutableSortedCopy(dbClient.componentDao().selectByUuids(dbSession, esResults.getIds()));
- return new SearchResults(projects, favoriteProjectUuids, esResults);
+ return new SearchResults(projects, favoriteProjects.stream().map(ComponentDto::uuid).collect(toSet()), esResults);
+ }
+
+ /**
+ * Builds the set of project uuid on which the query on index measure should be filtering.
+ * <ul>
+ * <li>if neither isFavourite criterion nor an organization is specified, there is not filtering on projects at all</li>
+ * <li>if isFavourite criterion and an organization are specified, filtering is done on favourite projects of
+ * the user which belong to the specified organization</li>
+ * <li>if only isFavourite criterion is specified, filtering is done on favourite projects of the user</li>
+ * <li>if only an organization is specified, filtering is done on the projects of this organization</li>
+ * </ul>
+ */
+ @CheckForNull
+ private Set<String> buildFilterOnProjectUuids(DbSession dbSession, List<String> criteria, List<ComponentDto> favoriteProjects, @Nullable OrganizationDto organization) {
+ boolean hasIsFavouriteCriterion = hasIsFavouriteCriterion(criteria);
+ if (hasIsFavouriteCriterion && organization != null) {
+ return favoriteProjects.stream()
+ .filter(project -> project.getOrganizationUuid().equals(organization.getUuid()))
+ .map(ComponentDto::uuid)
+ .collect(toSet());
+ }
+ if (hasIsFavouriteCriterion) {
+ return favoriteProjects.stream()
+ .map(ComponentDto::uuid)
+ .collect(toSet());
+ }
+ if (organization != null) {
+ return dbClient.componentDao().selectAllRootsByOrganization(dbSession, organization.getUuid())
+ .stream()
+ .filter(componentDto -> Qualifiers.PROJECT.equals(componentDto.qualifier()))
+ .map(ComponentDto::uuid)
+ .collect(toSet());
+ }
+ return null;
}
- private Set<String> searchFavoriteProjects(DbSession dbSession) {
- List<Long> favoriteDbIds = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
- .setUserId(userSession.getUserId())
- .setKey("favourite")
- .build(), dbSession)
+ private List<ComponentDto> searchFavoriteProjects(DbSession dbSession) {
+ List<Long> favoriteDbIds = dbClient.propertiesDao().selectByQuery(
+ PropertyQuery.builder()
+ .setUserId(userSession.getUserId())
+ .setKey("favourite")
+ .build(),
+ dbSession)
.stream()
.map(PropertyDto::getResourceId)
.collect(Collectors.toList());
- return dbClient.componentDao().selectByIds(dbSession, favoriteDbIds)
- .stream()
- .filter(dbComponent -> Qualifiers.PROJECT.equals(dbComponent.qualifier()))
- .map(ComponentDto::uuid)
- .collect(Collectors.toSet());
+ return dbClient.componentDao().selectByIds(dbSession, favoriteDbIds);
}
private static SearchProjectsRequest toRequest(Request httpRequest) {
SearchProjectsRequest.Builder request = SearchProjectsRequest.builder()
+ .setOrganization(httpRequest.param(PARAM_ORGANIZATION))
.setFilter(httpRequest.param(PARAM_FILTER))
.setPage(httpRequest.mandatoryParamAsInt(Param.PAGE))
.setPageSize(httpRequest.mandatoryParamAsInt(Param.PAGE_SIZE));
package org.sonar.server.component.ws;
+import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.server.measure.index.ProjectMeasuresQuery;
import org.sonar.server.tester.UserSessionRule;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
+import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.toCriteria;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.OK;
import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion;
import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator;
@Test
public void create_query() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10 and coverage <= 80", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10 and coverage <= 80"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_having_lesser_than_operation() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc < 10", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc < 10"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_having_lesser_than_or_equals_operation() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc <= 10", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc <= 10"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_having_greater_than_operation() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc > 10", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_having_greater_than_or_equals_operation() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc >= 10", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc >= 10"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_having_equal_operation() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc = 10", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc = 10"), emptySet());
assertThat(query.getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
@Test
public void create_query_on_quality_gate() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("alert_status = OK", emptySet());
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("alert_status = OK"), emptySet());
assertThat(query.getQualityGateStatus().name()).isEqualTo(OK.name());
}
@Test
- public void query_without_favorites_by_default() {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("ncloc = 10", emptySet());
+ public void do_not_filter_on_projectUuids_if_criteria_non_empty_and_projectUuid_is_null() {
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc = 10"), null);
assertThat(query.doesFilterOnProjectUuids()).isFalse();
}
@Test
- public void create_query_with_favorites() throws Exception {
- ProjectMeasuresQuery query = newProjectMeasuresQuery("isFavorite", emptySet());
+ public void filter_on_projectUuids_if_projectUuid_is_empty_and_criteria_non_empty() throws Exception {
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10"), emptySet());
+
+ assertThat(query.doesFilterOnProjectUuids()).isTrue();
+ }
+
+ @Test
+ public void filter_on_projectUuids_if_projectUuid_is_non_empty_and_criteria_non_empty() throws Exception {
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(toCriteria("ncloc > 10"), Collections.singleton("foo"));
+
+ assertThat(query.doesFilterOnProjectUuids()).isTrue();
+ }
+
+ @Test
+ public void filter_on_projectUuids_if_projectUuid_is_empty_and_criteria_is_empty() throws Exception {
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(emptyList(), emptySet());
+
+ assertThat(query.doesFilterOnProjectUuids()).isTrue();
+ }
+
+ @Test
+ public void filter_on_projectUuids_if_projectUuid_is_non_empty_and_criteria_empty() throws Exception {
+ ProjectMeasuresQuery query = newProjectMeasuresQuery(emptyList(), Collections.singleton("foo"));
assertThat(query.doesFilterOnProjectUuids()).isTrue();
}
@Test
public void fail_to_create_query_on_quality_gate_when_operator_is_not_equal() throws Exception {
expectedException.expect(IllegalArgumentException.class);
- newProjectMeasuresQuery("alert_status > OK", emptySet());
+ newProjectMeasuresQuery(toCriteria("alert_status > OK"), emptySet());
}
@Test
public void search_is_case_insensitive() throws Exception {
- assertThat(newProjectMeasuresQuery("ncloc > 10 AnD coverage <= 80 AND debt = 10 AND issues = 20", emptySet()).getMetricCriteria()).hasSize(4);
+ assertThat(newProjectMeasuresQuery(toCriteria("ncloc > 10 AnD coverage <= 80 AND debt = 10 AND issues = 20"), emptySet()).getMetricCriteria()).hasSize(4);
}
@Test
public void convert_metric_to_lower_case() throws Exception {
- assertThat(newProjectMeasuresQuery("NCLOC > 10 AND coVERage <= 80", emptySet()).getMetricCriteria())
+ assertThat(newProjectMeasuresQuery(toCriteria("NCLOC > 10 AND coVERage <= 80"), emptySet()).getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
.containsOnly(
tuple("ncloc", Operator.GT, 10d),
@Test
public void ignore_white_spaces() throws Exception {
- assertThat(newProjectMeasuresQuery(" ncloc > 10 ", emptySet()).getMetricCriteria())
+ assertThat(newProjectMeasuresQuery(toCriteria(" ncloc > 10 "), emptySet()).getMetricCriteria())
.extracting(MetricCriterion::getMetricKey, MetricCriterion::getOperator, MetricCriterion::getValue)
.containsOnly(tuple("ncloc", Operator.GT, 10d));
}
@Test
public void accept_empty_query() throws Exception {
- ProjectMeasuresQuery result = newProjectMeasuresQuery("", emptySet());
+ ProjectMeasuresQuery result = newProjectMeasuresQuery(emptyList(), emptySet());
assertThat(result.getMetricCriteria()).isEmpty();
}
public void fail_on_invalid_criteria() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion 'ncloc ? 10'");
- newProjectMeasuresQuery("ncloc ? 10", emptySet());
+
+ newProjectMeasuresQuery(toCriteria("ncloc ? 10"), emptySet());
}
@Test
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion 'ncloc ? 10'");
- newProjectMeasuresQuery(" ncloc ? 10 ", emptySet());
+ newProjectMeasuresQuery(toCriteria(" ncloc ? 10 "), emptySet());
}
@Test
public void fail_when_not_double() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion 'ncloc > ten'");
- newProjectMeasuresQuery("ncloc > ten", emptySet());
+ newProjectMeasuresQuery(toCriteria("ncloc > ten"), emptySet());
}
@Test
public void fail_when_no_operator() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion 'ncloc 10'");
- newProjectMeasuresQuery("ncloc 10", emptySet());
+ newProjectMeasuresQuery(toCriteria("ncloc 10"), emptySet());
}
@Test
public void fail_when_no_key() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion '>= 10'");
- newProjectMeasuresQuery(">= 10", emptySet());
+ newProjectMeasuresQuery(toCriteria(">= 10"), emptySet());
}
@Test
public void fail_when_no_value() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid criterion 'ncloc >='");
- newProjectMeasuresQuery("ncloc >=", emptySet());
+ newProjectMeasuresQuery(toCriteria("ncloc >="), emptySet());
}
}
import org.sonar.db.metric.MetricDto;
import org.sonar.server.tester.UserSessionRule;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static org.sonar.api.measures.Metric.ValueType.DATA;
import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
import static org.sonar.db.metric.MetricTesting.newMetricDto;
import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.newProjectMeasuresQuery;
+import static org.sonar.server.component.ws.ProjectMeasuresQueryFactory.toCriteria;
public class ProjectMeasuresQueryValidatorTest {
@Test
public void query_with_empty_metrics_is_valid() throws Exception {
- underTest.validate(dbSession, newProjectMeasuresQuery("", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(emptyList(), emptySet()));
}
@Test
public void does_not_fail_when_metric_criteria_contains_an_existing_metric() throws Exception {
insertValidMetric("ncloc");
- underTest.validate(dbSession, newProjectMeasuresQuery("ncloc > 10", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(toCriteria("ncloc > 10"), emptySet()));
}
@Test
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Following metrics are not numeric : [data, distrib, string]");
- underTest.validate(dbSession, newProjectMeasuresQuery("data > 10 and distrib = 11 and ncloc <= 20 and debt < 30 and string = 40", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(toCriteria("data > 10 and distrib = 11 and ncloc <= 20 and debt < 30 and string = 40"), emptySet()));
}
@Test
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Following metrics are disabled : [ncloc]");
- underTest.validate(dbSession, newProjectMeasuresQuery("ncloc > 10", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(toCriteria("ncloc > 10"), emptySet()));
}
@Test
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Unknown metric(s) [unknown]");
- underTest.validate(dbSession, newProjectMeasuresQuery("unknown > 10", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(toCriteria("unknown > 10"), emptySet()));
}
@Test
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Unknown metric(s) [coverage, debt]");
- underTest.validate(dbSession, newProjectMeasuresQuery("debt > 10 AND ncloc <= 20 AND coverage > 30", emptySet()));
+ underTest.validate(dbSession, newProjectMeasuresQuery(toCriteria("debt > 10 AND ncloc <= 20 AND coverage > 30"), emptySet()));
}
private void insertValidMetric(String metricKey) {
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.sonar.server.measure.index.ProjectMeasuresIndexDefinition.TYPE_PROJECT_MEASURE;
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;
public class SearchProjectsActionTest {
private static final String NCLOC = "ncloc";
private static final String COVERAGE = "coverage";
+ private static final String IS_FAVOURITE_CRITERION = "isFavorite";
@Rule
public ExpectedException expectedException = ExpectedException.none();
private SearchProjectsRequest.Builder request = SearchProjectsRequest.builder();
+ @Test
+ public void verify_definition() {
+ WebService.Action def = ws.getDef();
+
+ assertThat(def.key()).isEqualTo("search_projects");
+ assertThat(def.since()).isEqualTo("6.2");
+ assertThat(def.isInternal()).isTrue();
+ assertThat(def.isPost()).isFalse();
+ assertThat(def.responseExampleAsString()).isNotEmpty();
+ Param organization = def.param("organization");
+ assertThat(organization.isRequired()).isFalse();
+ assertThat(organization.description()).isEqualTo("the organization to search projects in");
+ assertThat(organization.since()).isEqualTo("6.3");
+ }
+
@Test
public void json_example() {
OrganizationDto organization1Dto = db.organizations().insertForKey("my-org-key-1");
OrganizationDto organization2Dto = db.organizations().insertForKey("my-org-key-2");
- long project1Id = insertProjectInDbAndEs(newProjectDto(organization1Dto)
+ ComponentDto project1 = insertProjectInDbAndEs(newProjectDto(organization1Dto)
.setUuid(Uuids.UUID_EXAMPLE_01)
.setKey(KeyExamples.KEY_PROJECT_EXAMPLE_001)
.setName("My Project 1"));
.setKey(KeyExamples.KEY_PROJECT_EXAMPLE_003)
.setName("My Project 3"));
userSession.login().setUserId(23);
- dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(project1Id).setUserId(23L));
+ addFavourite(project1);
dbSession.commit();
String result = ws.newRequest().execute().getInput();
assertThat(result.getComponents(0).getName()).isEqualTo("Sonar Markdown");
}
+ @Test
+ public void filter_projects_with_query_within_specified_organization() {
+ OrganizationDto organization1 = db.organizations().insert();
+ OrganizationDto organization2 = db.organizations().insert();
+ insertProjectInDbAndEs(newProjectDto(organization1).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
+ insertProjectInDbAndEs(newProjectDto(organization1).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+ insertProjectInDbAndEs(newProjectDto(organization2).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+ insertMetrics(COVERAGE, NCLOC);
+
+ assertThat(call(request.setOrganization(null)).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly("Sonar Java", "Sonar Markdown", "Sonar Qube");
+ assertThat(call(request.setOrganization(organization1.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly("Sonar Java", "Sonar Markdown");
+ assertThat(call(request.setOrganization(organization2.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly("Sonar Qube");
+ }
+
+ @Test
+ public void filter_favourite_projects_with_query_with_or_without_a_specified_organization() {
+ OrganizationDto organization1 = db.organizations().insert();
+ OrganizationDto organization2 = db.organizations().insert();
+ OrganizationDto organization3 = db.organizations().insert();
+ OrganizationDto organization4 = db.organizations().insert();
+ OrganizationDto organization5 = db.organizations().insert();
+ List<Map<String, Object>> someMeasure = singletonList(newMeasure(COVERAGE, 81));
+ ComponentDto favourite1_1 = insertProjectInDbAndEs(newProjectDto(organization1), someMeasure);
+ ComponentDto favourite1_2 = insertProjectInDbAndEs(newProjectDto(organization1), someMeasure);
+ ComponentDto nonFavourite1 = insertProjectInDbAndEs(newProjectDto(organization1), someMeasure);
+ ComponentDto favourite2 = insertProjectInDbAndEs(newProjectDto(organization2), someMeasure);
+ ComponentDto nonFavourite2 = insertProjectInDbAndEs(newProjectDto(organization2), someMeasure);
+ ComponentDto favourite3 = insertProjectInDbAndEs(newProjectDto(organization3), someMeasure);
+ ComponentDto nonFavourite4 = insertProjectInDbAndEs(newProjectDto(organization4), someMeasure);
+ Stream.of(favourite1_1, favourite1_2, favourite2, favourite3)
+ .forEach(this::addFavourite);
+ insertMetrics(COVERAGE, NCLOC);
+
+ assertThat(call(request.setFilter(null).setOrganization(null)).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite1_1.name(), favourite1_2.name(), nonFavourite1.name(), favourite2.name(), nonFavourite2.name(), favourite3.name(), nonFavourite4.name());
+ assertThat(call(request.setFilter(IS_FAVOURITE_CRITERION).setOrganization(null)).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite1_1.name(), favourite1_2.name(), favourite2.name(), favourite3.name());
+ assertThat(call(request.setFilter(null).setOrganization(organization1.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite1_1.name(), favourite1_2.name(), nonFavourite1.name());
+ assertThat(call(request.setFilter(IS_FAVOURITE_CRITERION).setOrganization(organization1.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite1_1.name(), favourite1_2.name());
+ assertThat(call(request.setFilter(null).setOrganization(organization3.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite3.name());
+ assertThat(call(request.setFilter(IS_FAVOURITE_CRITERION).setOrganization(organization3.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(favourite3.name());
+ assertThat(call(request.setFilter(null).setOrganization(organization4.getKey())).getComponentsList())
+ .extracting(Component::getName)
+ .containsOnly(nonFavourite4.name());
+ assertThat(call(request.setFilter(IS_FAVOURITE_CRITERION).setOrganization(organization4.getKey())).getComponentsList())
+ .isEmpty();
+ assertThat(call(request.setFilter(null).setOrganization(organization5.getKey())).getComponentsList())
+ .isEmpty();
+ assertThat(call(request.setFilter(IS_FAVOURITE_CRITERION).setOrganization(organization5.getKey())).getComponentsList())
+ .isEmpty();
+ }
+
@Test
public void filter_projects_on_favorites() {
- long javaId = insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization(), "java-id").setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
- long markDownId = insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization(), "markdown-id").setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+ ComponentDto javaProject = insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization(), "java-id").setName("Sonar Java"),
+ newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
+ ComponentDto markDownProject = insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization(), "markdown-id").setName("Sonar Markdown"),
+ newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
insertProjectInDbAndEs(newProjectDto(db.organizations().insert()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
- dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(javaId).setUserId(Long.valueOf(userSession.getUserId())));
- dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(markDownId).setUserId(Long.valueOf(userSession.getUserId())));
+ addFavourite(javaProject);
+ addFavourite(markDownProject);
dbSession.commit();
request.setFilter("isFavorite");
@Test
public void return_nloc_facet() {
- insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization()).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
- insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization()).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
- insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization()).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
- insertProjectInDbAndEs(newProjectDto(db.getDefaultOrganization()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
+ OrganizationDto organization = db.getDefaultOrganization();
+ insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+ insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+ insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+ insertProjectInDbAndEs(newProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
insertMetrics(COVERAGE, NCLOC);
SearchProjectsWsResponse result = call(request.setFacets(singletonList(NCLOC)));
TestRequest httpRequest = ws.newRequest()
.setMediaType(MediaTypes.PROTOBUF);
+ String organization = wsRequest.getOrganization();
+ if (organization != null) {
+ httpRequest.setParam(PARAM_ORGANIZATION, organization);
+ }
httpRequest.setParam(Param.PAGE, String.valueOf(wsRequest.getPage()));
httpRequest.setParam(Param.PAGE_SIZE, String.valueOf(wsRequest.getPageSize()));
String filter = wsRequest.getFilter();
}
}
- @Test
- public void definition() {
- WebService.Action def = ws.getDef();
-
- assertThat(def.key()).isEqualTo("search_projects");
- assertThat(def.since()).isEqualTo("6.2");
- assertThat(def.isInternal()).isTrue();
- assertThat(def.isPost()).isFalse();
- assertThat(def.responseExampleAsString()).isNotEmpty();
- }
-
- private long insertProjectInDbAndEs(ComponentDto project) {
+ private ComponentDto insertProjectInDbAndEs(ComponentDto project) {
return insertProjectInDbAndEs(project, emptyList());
}
- private long insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) {
- componentDb.insertComponent(project);
+ private ComponentDto insertProjectInDbAndEs(ComponentDto project, List<Map<String, Object>> measures) {
+ ComponentDto res = componentDb.insertComponent(project);
try {
es.putDocuments(INDEX_PROJECT_MEASURES, TYPE_PROJECT_MEASURE,
new ProjectMeasuresDoc().setId(project.uuid()).setKey(project.key()).setName(project.name()).setMeasures(measures));
Throwables.propagate(e);
}
- return project.getId();
+ return res;
}
private void insertMetrics(String... metricKeys) {
private static Map<String, Object> newMeasure(String key, double value) {
return ImmutableMap.of("key", key, "value", value);
}
+
+ private void addFavourite(ComponentDto project) {
+ dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite").setResourceId(project.getId()).setUserId(Long.valueOf(userSession.getUserId())));
+ }
}
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ID;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_KEY;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_NEW_KEY;
+import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_STRATEGY;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_TO;
public SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) {
GetRequest get = new GetRequest(path(ACTION_SEARCH_PROJECTS))
+ .setParam(PARAM_ORGANIZATION, request.getOrganization())
.setParam(PARAM_FILTER, request.getFilter())
.setParam(Param.FACETS, request.getFacets())
.setParam(Param.PAGE, request.getPage())
public static final String ACTION_SUGGESTIONS = "suggestions";
// parameters
+ public static final String PARAM_ORGANIZATION = "organization";
public static final String PARAM_QUALIFIERS = "qualifiers";
public static final String PARAM_LANGUAGE = "language";
public static final String PARAM_BASE_COMPONENT_ID = "baseComponentId";
import java.util.ArrayList;
import java.util.List;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
private final int page;
private final int pageSize;
+ private final String organization;
private final String filter;
private final List<String> facets;
private SearchProjectsRequest(Builder builder) {
this.page = builder.page;
this.pageSize = builder.pageSize;
+ this.organization = builder.organization;
this.filter = builder.filter;
this.facets = builder.facets;
}
+ @CheckForNull
+ public String getOrganization() {
+ return organization;
+ }
+
@CheckForNull
public String getFilter() {
return filter;
}
public static class Builder {
+ private String organization;
private Integer page;
private Integer pageSize;
private String filter;
// enforce static factory method
}
- public Builder setFilter(String filter) {
+ public Builder setOrganization(@Nullable String organization) {
+ this.organization = organization;
+ return this;
+ }
+
+ public Builder setFilter(@Nullable String filter) {
this.filter = filter;
return this;
}