@@ -34,7 +34,6 @@ import org.elasticsearch.action.search.SearchResponse; | |||
import org.elasticsearch.search.SearchHit; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.server.ws.Change; | |||
@@ -67,6 +66,15 @@ import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static java.util.Optional.ofNullable; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.sonar.api.issue.Issue.RESOLUTIONS; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_REMOVED; | |||
import static org.sonar.api.issue.Issue.STATUSES; | |||
import static org.sonar.api.issue.Issue.STATUS_IN_REVIEW; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_REOPENED; | |||
import static org.sonar.api.issue.Issue.STATUS_REVIEWED; | |||
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW; | |||
import static org.sonar.api.server.ws.WebService.Param.FACETS; | |||
import static org.sonar.api.utils.Paging.forPageIndex; | |||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | |||
@@ -189,6 +197,7 @@ public class SearchAction implements IssuesWsAction, Startable { | |||
PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS) | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("7.8", format("added new Security Hotspots statuses : %s, %s and %s", STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)), | |||
new Change("7.8", "Security hotspots are returned by default"), | |||
new Change("7.7", format("Value '%s' in parameter '%s' is deprecated, please use '%s' instead", DEPRECATED_PARAM_AUTHORS, FACETS, PARAM_AUTHOR)), | |||
new Change("7.6", format("The use of module keys in parameter '%s' is deprecated", PARAM_COMPONENT_KEYS)), | |||
@@ -229,12 +238,12 @@ public class SearchAction implements IssuesWsAction, Startable { | |||
.setPossibleValues(Severity.ALL); | |||
action.createParam(PARAM_STATUSES) | |||
.setDescription("Comma-separated list of statuses") | |||
.setExampleValue(Issue.STATUS_OPEN + "," + Issue.STATUS_REOPENED) | |||
.setPossibleValues(Issue.STATUSES); | |||
.setExampleValue(STATUS_OPEN + "," + STATUS_REOPENED) | |||
.setPossibleValues(STATUSES); | |||
action.createParam(PARAM_RESOLUTIONS) | |||
.setDescription("Comma-separated list of resolutions") | |||
.setExampleValue(Issue.RESOLUTION_FIXED + "," + Issue.RESOLUTION_REMOVED) | |||
.setPossibleValues(Issue.RESOLUTIONS); | |||
.setExampleValue(RESOLUTION_FIXED + "," + RESOLUTION_REMOVED) | |||
.setPossibleValues(RESOLUTIONS); | |||
action.createParam(PARAM_RESOLVED) | |||
.setDescription("To match resolved or unresolved issues") | |||
.setBooleanPossibleValues(); | |||
@@ -453,8 +462,8 @@ public class SearchAction implements IssuesWsAction, Startable { | |||
private void completeFacets(Facets facets, SearchRequest request, IssueQuery query) { | |||
addMandatoryValuesToFacet(facets, PARAM_SEVERITIES, Severity.ALL); | |||
addMandatoryValuesToFacet(facets, PARAM_STATUSES, Issue.STATUSES); | |||
addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), Issue.RESOLUTIONS)); | |||
addMandatoryValuesToFacet(facets, PARAM_STATUSES, STATUSES); | |||
addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), RESOLUTIONS)); | |||
addMandatoryValuesToFacet(facets, FACET_PROJECTS, query.projectUuids()); | |||
addMandatoryValuesToFacet(facets, PARAM_MODULE_UUIDS, query.moduleUuids()); | |||
addMandatoryValuesToFacet(facets, PARAM_FILE_UUIDS, query.fileUuids()); |
@@ -19,7 +19,9 @@ | |||
*/ | |||
package org.sonar.server.issue.ws; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.time.Clock; | |||
import java.util.Map; | |||
import java.util.stream.IntStream; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -112,11 +114,14 @@ public class SearchActionFacetsTest { | |||
.setParam(FACETS, "severities,statuses,resolutions,rules,types,languages,projects,moduleUuids,fileUuids,assignees") | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("INREVIEW", 0L).put("TOREVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
.containsExactlyInAnyOrder( | |||
tuple("severities", of("INFO", 0L, "MINOR", 0L, "MAJOR", 1L, "CRITICAL", 0L, "BLOCKER", 0L)), | |||
tuple("statuses", of("OPEN", 1L, "CONFIRMED", 0L, "REOPENED", 0L, "RESOLVED", 0L, "CLOSED", 0L)), | |||
tuple("statuses", expectedStatuses), | |||
tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)), | |||
tuple("rules", of(rule.getKey().toString(), 1L)), | |||
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)), | |||
@@ -147,11 +152,14 @@ public class SearchActionFacetsTest { | |||
.setParam("facetMode", FACET_MODE_EFFORT) | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 10L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("INREVIEW", 0L).put("TOREVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
.containsExactlyInAnyOrder( | |||
tuple("severities", of("INFO", 0L, "MINOR", 0L, "MAJOR", 10L, "CRITICAL", 0L, "BLOCKER", 0L)), | |||
tuple("statuses", of("OPEN", 10L, "CONFIRMED", 0L, "REOPENED", 0L, "RESOLVED", 0L, "CLOSED", 0L)), | |||
tuple("statuses", expectedStatuses), | |||
tuple("resolutions", of("", 10L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)), | |||
tuple("rules", of(rule.getKey().toString(), 10L)), | |||
tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)), | |||
@@ -440,7 +448,7 @@ public class SearchActionFacetsTest { | |||
// Assignees contains one additional element : it's the empty string that will return number of unassigned issues | |||
tuple("assignees", 101), | |||
// Following facets returned fixed number of elements | |||
tuple("statuses", 5), | |||
tuple("statuses", 8), | |||
tuple("resolutions", 5), | |||
tuple("severities", 5), | |||
tuple("types", 4)); | |||
@@ -498,11 +506,14 @@ public class SearchActionFacetsTest { | |||
.setParam(FACETS, "severities,statuses,resolutions,rules,types,languages,projects,moduleUuids,fileUuids,assignees") | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("INREVIEW", 0L).put("TOREVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
.containsExactlyInAnyOrder( | |||
tuple("severities", of("INFO", 0L, "MINOR", 0L, "MAJOR", 1L, "CRITICAL", 0L, "BLOCKER", 0L)), | |||
tuple("statuses", of("OPEN", 1L, "CONFIRMED", 0L, "REOPENED", 0L, "RESOLVED", 0L, "CLOSED", 0L)), | |||
tuple("statuses", expectedStatuses), | |||
tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)), | |||
tuple("rules", of(rule1.getKey().toString(), 1L, rule2.getKey().toString(), 0L)), | |||
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)), |
@@ -29,6 +29,7 @@ import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.utils.Duration; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.unmodifiableList; | |||
/** | |||
* @since 3.6 | |||
@@ -73,7 +74,7 @@ public interface Issue extends Serializable { | |||
*/ | |||
String RESOLUTION_WONT_FIX = "WONTFIX"; | |||
List<String> RESOLUTIONS = asList(RESOLUTION_FALSE_POSITIVE, RESOLUTION_WONT_FIX, RESOLUTION_FIXED, RESOLUTION_REMOVED); | |||
List<String> RESOLUTIONS = unmodifiableList(asList(RESOLUTION_FALSE_POSITIVE, RESOLUTION_WONT_FIX, RESOLUTION_FIXED, RESOLUTION_REMOVED)); | |||
/** | |||
* @since 7.8 | |||
@@ -95,7 +96,8 @@ public interface Issue extends Serializable { | |||
* | |||
* @since 4.4 | |||
*/ | |||
List<String> STATUSES = asList(STATUS_OPEN, STATUS_CONFIRMED, STATUS_REOPENED, STATUS_RESOLVED, STATUS_CLOSED); | |||
List<String> STATUSES = unmodifiableList(asList(STATUS_OPEN, STATUS_CONFIRMED, STATUS_REOPENED, STATUS_RESOLVED, STATUS_CLOSED, | |||
STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)); | |||
/** | |||
* Unique generated key. It looks like "d2de809c-1512-4ae2-9f34-f5345c9f1a13". |