diff options
author | Benjamin Campomenosi <109955405+benjamin-campomenosi-sonarsource@users.noreply.github.com> | 2023-11-02 14:52:28 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-11-08 20:02:52 +0000 |
commit | 0bc3c36c61a82eb18a66e2433164d06d548d127a (patch) | |
tree | 30efe10e56cf79ffbf8e56f6672ebe4669ab3ad4 /server/sonar-webserver-es | |
parent | a1be2cd1286ff3a24fc27d9c9a387069f5eafb91 (diff) | |
download | sonarqube-0bc3c36c61a82eb18a66e2433164d06d548d127a.tar.gz sonarqube-0bc3c36c61a82eb18a66e2433164d06d548d127a.zip |
SONAR-20871 Add simple status to the issue index
Diffstat (limited to 'server/sonar-webserver-es')
5 files changed, 80 insertions, 8 deletions
diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 08cf93e12a4..e9da3ec2e45 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -77,6 +77,7 @@ import org.sonar.api.server.rule.RulesDefinition.OwaspTop10Version; import org.sonar.api.server.rule.RulesDefinition.PciDssVersion; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; +import org.sonar.core.issue.status.SimpleStatus; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsUtils; import org.sonar.server.es.SearchOptions; @@ -144,6 +145,7 @@ import static org.sonar.server.issue.index.IssueIndex.Facet.RULES; import static org.sonar.server.issue.index.IssueIndex.Facet.SANS_TOP_25; import static org.sonar.server.issue.index.IssueIndex.Facet.SCOPES; import static org.sonar.server.issue.index.IssueIndex.Facet.SEVERITIES; +import static org.sonar.server.issue.index.IssueIndex.Facet.SIMPLE_STATUSES; import static org.sonar.server.issue.index.IssueIndex.Facet.SONARSOURCE_SECURITY; import static org.sonar.server.issue.index.IssueIndex.Facet.STATUSES; import static org.sonar.server.issue.index.IssueIndex.Facet.TAGS; @@ -181,6 +183,7 @@ import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SANS import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SCOPE; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE; +import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SIMPLE_STATUS; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_SQ_SECURITY_CATEGORY; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_STATUS; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_TAGS; @@ -214,6 +217,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SCOPES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES; +import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SIMPLE_STATUSES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SONARSOURCE_SECURITY; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS; @@ -263,6 +267,7 @@ public class IssueIndex { STATUSES(PARAM_STATUSES, FIELD_ISSUE_STATUS, STICKY, Issue.STATUSES.size()), // Resolutions facet returns one more element than the number of resolutions to take into account unresolved issues RESOLUTIONS(PARAM_RESOLUTIONS, FIELD_ISSUE_RESOLUTION, STICKY, Issue.RESOLUTIONS.size() + 1), + SIMPLE_STATUSES(PARAM_SIMPLE_STATUSES, FIELD_ISSUE_SIMPLE_STATUS, STICKY, SimpleStatus.values().length), TYPES(PARAM_TYPES, FIELD_ISSUE_TYPE, STICKY, RuleType.values().length), SCOPES(PARAM_SCOPES, FIELD_ISSUE_SCOPE, STICKY, MAX_FACET_SIZE), LANGUAGES(PARAM_LANGUAGES, FIELD_ISSUE_LANGUAGE, STICKY, MAX_FACET_SIZE), @@ -481,6 +486,7 @@ public class IssueIndex { FIELD_ISSUE_RULE_UUID, query.ruleUuids())); filters.addFilter(FIELD_ISSUE_STATUS, STATUSES.getFilterScope(), createTermsFilter(FIELD_ISSUE_STATUS, query.statuses())); + filters.addFilter(FIELD_ISSUE_SIMPLE_STATUS, SIMPLE_STATUSES.getFilterScope(), createTermsFilter(FIELD_ISSUE_SIMPLE_STATUS, query.simpleStatuses())); filters.addFilter(FIELD_ISSUE_CODE_VARIANTS, CODE_VARIANTS.getFilterScope(), createTermsFilter(FIELD_ISSUE_CODE_VARIANTS, query.codeVariants())); // security category @@ -839,6 +845,7 @@ public class IssueIndex { private void configureTopAggregations(TopAggregationHelper aggregationHelper, IssueQuery query, SearchOptions options, AllFilters queryFilters, SearchSourceBuilder esRequest) { addFacetIfNeeded(options, aggregationHelper, esRequest, STATUSES, NO_SELECTED_VALUES); + addFacetIfNeeded(options, aggregationHelper, esRequest, SIMPLE_STATUSES, query.simpleStatuses().toArray()); addFacetIfNeeded(options, aggregationHelper, esRequest, PROJECT_UUIDS, query.projectUuids().toArray()); addFacetIfNeeded(options, aggregationHelper, esRequest, DIRECTORIES, query.directories().toArray()); addFacetIfNeeded(options, aggregationHelper, esRequest, FILES, query.files().toArray()); @@ -924,7 +931,7 @@ public class IssueIndex { .map(softwareQuality -> new FiltersAggregator.KeyedFilter(softwareQuality.name(), query.impactSeverities().isEmpty() ? mainQuery.apply(softwareQuality) : mainQuery.apply(softwareQuality) - .filter(termsQuery(FIELD_ISSUE_IMPACT_SEVERITY, query.impactSeverities())))) + .filter(termsQuery(FIELD_ISSUE_IMPACT_SEVERITY, query.impactSeverities())))) .toArray(FiltersAggregator.KeyedFilter[]::new); AggregationBuilder aggregation = aggregationHelper.buildTopAggregation( @@ -948,7 +955,7 @@ public class IssueIndex { .map(severity -> new FiltersAggregator.KeyedFilter(severity.name(), query.impactSoftwareQualities().isEmpty() ? mainQuery.apply(severity) : mainQuery.apply(severity) - .filter(termsQuery(FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY, query.impactSoftwareQualities())))) + .filter(termsQuery(FIELD_ISSUE_IMPACT_SOFTWARE_QUALITY, query.impactSoftwareQualities())))) .toArray(FiltersAggregator.KeyedFilter[]::new); AggregationBuilder aggregation = aggregationHelper.buildTopAggregation( diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQuery.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQuery.java index 33eefc1e188..291ba957330 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQuery.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQuery.java @@ -62,6 +62,7 @@ public class IssueQuery { private final Collection<String> impactSeverities; private final Collection<String> impactSoftwareQualities; private final Collection<String> statuses; + private final Collection<String> simpleStatuses; private final Collection<String> resolutions; private final Collection<String> components; private final Collection<String> projects; @@ -110,6 +111,7 @@ public class IssueQuery { this.impactSoftwareQualities = defaultCollection(builder.impactSoftwareQualities); this.statuses = defaultCollection(builder.statuses); this.resolutions = defaultCollection(builder.resolutions); + this.simpleStatuses = defaultCollection(builder.simpleStatuses); this.components = defaultCollection(builder.components); this.projects = defaultCollection(builder.projects); this.directories = defaultCollection(builder.directories); @@ -171,6 +173,10 @@ public class IssueQuery { return statuses; } + public Collection<String> simpleStatuses() { + return simpleStatuses; + } + public Collection<String> resolutions() { return resolutions; } @@ -179,7 +185,6 @@ public class IssueQuery { return components; } - public Collection<String> projectUuids() { return projects; } @@ -363,6 +368,7 @@ public class IssueQuery { private Collection<String> impactSoftwareQualities; private Collection<String> statuses; private Collection<String> resolutions; + private Collection<String> simpleStatuses; private Collection<String> components; private Collection<String> projects; private Collection<String> directories; @@ -427,6 +433,11 @@ public class IssueQuery { return this; } + public Builder simpleStatuses(@Nullable Collection<String> l) { + this.simpleStatuses = l; + return this; + } + public Builder componentUuids(@Nullable Collection<String> l) { this.components = l; return this; diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java index 27562572a1a..6412996c006 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java @@ -129,6 +129,7 @@ public class IssueQueryFactory { .impactSeverities(request.getImpactSeverities()) .statuses(request.getStatuses()) .resolutions(request.getResolutions()) + .simpleStatuses(request.getSimpleStatuses()) .resolved(request.getResolved()) .rules(ruleDtos) .ruleUuids(ruleUuids) diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java index 2f15ebbde63..a2bd2f309ca 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFacetsTest.java @@ -29,6 +29,7 @@ import org.junit.Test; import org.sonar.api.issue.impact.Severity; import org.sonar.api.rules.RuleType; import org.sonar.api.server.rule.RulesDefinition.OwaspAsvsVersion; +import org.sonar.core.issue.status.SimpleStatus; import org.sonar.db.component.ComponentDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.es.Facets; @@ -371,6 +372,31 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { } @Test + public void search_shouldReturnSimpleStatusesFacet() { + ComponentDto mainBranch = newPrivateProjectDto(); + ComponentDto file = newFileDto(mainBranch); + + indexIssues( + newDoc("I1", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.CONFIRMED.name()), + newDoc("I2", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.FIXED.name()), + newDoc("I3", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()), + newDoc("I4", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()), + newDoc("I5", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I6", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I7", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I8", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name()), + newDoc("I9", mainBranch.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name())); + + assertThatFacetHasSize(IssueQuery.builder().build(), "simpleStatuses", 5); + assertThatFacetHasOnly(IssueQuery.builder(), "simpleStatuses", + entry("OPEN", 2L), + entry("CONFIRMED", 1L), + entry("FALSE_POSITIVE", 2L), + entry("ACCEPTED", 3L), + entry("FIXED", 1L)); + } + + @Test public void facets_on_resolutions_return_5_entries_max() { ComponentDto project = newPrivateProjectDto(); ComponentDto file = newFileDto(project); @@ -869,7 +895,7 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { } @SafeVarargs - private final void assertThatFacetHasExactly(IssueQuery.Builder query, String facet, Map.Entry<String, Long>... expectedEntries) { + private void assertThatFacetHasExactly(IssueQuery.Builder query, String facet, Map.Entry<String, Long>... expectedEntries) { SearchResponse result = underTest.search(query.build(), new SearchOptions().addFacets(singletonList(facet))); Facets facets = new Facets(result, system2.getDefaultTimeZone().toZoneId()); assertThat(facets.getNames()).containsOnly(facet, "effort"); @@ -877,7 +903,7 @@ public class IssueIndexFacetsTest extends IssueIndexTestCommon { } @SafeVarargs - private final void assertThatFacetHasOnly(IssueQuery.Builder query, String facet, Map.Entry<String, Long>... expectedEntries) { + private void assertThatFacetHasOnly(IssueQuery.Builder query, String facet, Map.Entry<String, Long>... expectedEntries) { SearchResponse result = underTest.search(query.build(), new SearchOptions().addFacets(singletonList(facet))); Facets facets = new Facets(result, system2.getDefaultTimeZone().toZoneId()); assertThat(facets.getNames()).containsOnly(facet, "effort"); diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java index d6f0c5a7519..8292c9caac8 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexFiltersTest.java @@ -28,6 +28,7 @@ import org.junit.Test; import org.sonar.api.issue.Issue; import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; +import org.sonar.core.issue.status.SimpleStatus; import org.sonar.db.component.ComponentDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.es.SearchOptions; @@ -672,7 +673,7 @@ public class IssueIndexFiltersTest extends IssueIndexTestCommon { assertThatThrownBy(() -> underTest.search(IssueQuery.builder() .createdAfter(parseDate("2014-09-20")).createdBefore(parseDate("2014-09-20")) .build(), new SearchOptions())) - .isInstanceOf(IllegalArgumentException.class); + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -705,8 +706,8 @@ public class IssueIndexFiltersTest extends IssueIndexTestCommon { public void fail_if_created_before_equals_created_after() { assertThatThrownBy(() -> underTest.search(IssueQuery.builder().createdAfter(parseDate("2014-09-20")) .createdBefore(parseDate("2014-09-20")).build(), new SearchOptions())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Start bound cannot be larger or equal to end bound"); + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Start bound cannot be larger or equal to end bound"); } @Test @@ -923,6 +924,32 @@ public class IssueIndexFiltersTest extends IssueIndexTestCommon { "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8"); } + @Test + public void search_whenFilteringBySimpleStatus_shouldReturnRelevantIssues() { + ComponentDto project = newPrivateProjectDto(); + ComponentDto file = newFileDto(project); + + indexIssues( + newDoc("I1", project.uuid(), file).setSimpleStatus(SimpleStatus.CONFIRMED.name()), + newDoc("I2", project.uuid(), file).setSimpleStatus(SimpleStatus.FIXED.name()), + newDoc("I3", project.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()), + newDoc("I4", project.uuid(), file).setSimpleStatus(SimpleStatus.OPEN.name()), + newDoc("I5", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I6", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I7", project.uuid(), file).setSimpleStatus(SimpleStatus.ACCEPTED.name()), + newDoc("I8", project.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name()), + newDoc("I9", project.uuid(), file).setSimpleStatus(SimpleStatus.FALSE_POSITIVE.name())); + + assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.CONFIRMED.name(), SimpleStatus.OPEN.name())), + "I1", "I3", "I4"); + + assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.FALSE_POSITIVE.name(), SimpleStatus.ACCEPTED.name())), + "I5", "I6", "I7", "I8", "I9"); + + assertThatSearchReturnsOnly(IssueQuery.builder().simpleStatuses(Set.of(SimpleStatus.FIXED.name())), + "I2"); + } + private void indexView(String viewUuid, List<String> projectBranchUuids) { viewIndexer.index(new ViewDoc().setUuid(viewUuid).setProjectBranchUuids(projectBranchUuids)); } |