From: Julien Lancelot Date: Thu, 29 Jan 2015 07:20:35 +0000 (+0100) Subject: SONAR-6089 Allow to search Issues by Views / Sub-Views X-Git-Tag: latest-silver-master-#65~17 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2f85f918b25f9fd3e3f3155095f3c994f745ed90;p=sonarqube.git SONAR-6089 Allow to search Issues by Views / Sub-Views --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java index dea020a2f41..5116a2054a5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java @@ -63,6 +63,7 @@ public class IssueQuery { private final Collection projects; private final Collection directories; private final Collection files; + private final Collection views; private final Collection rules; private final Collection actionPlans; private final Collection reporters; @@ -93,6 +94,7 @@ public class IssueQuery { this.projects = defaultCollection(builder.projects); this.directories = defaultCollection(builder.directories); this.files = defaultCollection(builder.files); + this.views = defaultCollection(builder.views); this.rules = defaultCollection(builder.rules); this.actionPlans = defaultCollection(builder.actionPlans); this.reporters = defaultCollection(builder.reporters); @@ -153,6 +155,10 @@ public class IssueQuery { return files; } + public Collection viewUuids() { + return views; + } + public Collection rules() { return rules; } @@ -260,6 +266,7 @@ public class IssueQuery { private Collection projects; private Collection directories; private Collection files; + private Collection views; private Collection rules; private Collection actionPlans; private Collection reporters; @@ -332,6 +339,11 @@ public class IssueQuery { return this; } + public Builder viewUuids(@Nullable Collection l) { + this.views = l; + return this; + } + public Builder rules(@Nullable Collection rules) { this.rules = rules; return this; diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 11603bf01d6..42414efe6db 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -45,6 +45,7 @@ import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.filter.IssueFilterParameters; import org.sonar.server.search.*; import org.sonar.server.user.UserSession; +import org.sonar.server.view.index.ViewIndexDefinition; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -258,7 +259,6 @@ public class IssueIndex extends BaseIndex { } private void addComponentRelatedFilters(IssueQuery query, Map filters) { - FilterBuilder projectFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids()); FilterBuilder moduleRootFilter = moduleRootFilter(query.moduleRootUuids()); FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids()); @@ -266,6 +266,7 @@ public class IssueIndex extends BaseIndex { FilterBuilder directoryFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories()); FilterBuilder fileFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids()); FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids()); + FilterBuilder viewFilter = viewFilter(query.viewUuids()); if (BooleanUtils.isTrue(query.isContextualized())) { if (projectFilter != null) { @@ -292,14 +293,15 @@ public class IssueIndex extends BaseIndex { filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter); filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter); filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter); + filters.put("view", viewFilter); } } + @CheckForNull private FilterBuilder moduleRootFilter(Collection componentUuids) { - if (componentUuids == null || componentUuids.isEmpty()) { + if (componentUuids.isEmpty()) { return null; } - FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentUuids); FilterBuilder modulePathFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, componentUuids); FilterBuilder compositeFilter = null; @@ -315,6 +317,7 @@ public class IssueIndex extends BaseIndex { return compositeFilter; } + @CheckForNull private FilterBuilder directoryFilter(Collection moduleUuids, Collection directoryPaths) { BoolFilterBuilder directoryTop = null; FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleUuids); @@ -332,6 +335,23 @@ public class IssueIndex extends BaseIndex { return directoryTop; } + @CheckForNull + private FilterBuilder viewFilter(Collection viewUuids) { + if (viewUuids.isEmpty()) { + return null; + } + + OrFilterBuilder viewsFilter = FilterBuilders.orFilter(); + for (String viewUuid : viewUuids) { + viewsFilter.add(FilterBuilders.termsLookupFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID) + .lookupIndex(ViewIndexDefinition.INDEX) + .lookupType(ViewIndexDefinition.TYPE_VIEW) + .lookupId(viewUuid) + .lookupPath(ViewIndexDefinition.FIELD_PROJECTS)); + } + return viewsFilter; + } + private FilterBuilder getAuthorizationFilter(QueryContext options) { String user = options.getUserLogin(); Set groups = options.getUserGroups(); @@ -513,8 +533,8 @@ public class IssueIndex extends BaseIndex { } @CheckForNull - private FilterBuilder matchFilter(String field, @Nullable Collection values) { - if (values != null && !values.isEmpty()) { + private FilterBuilder matchFilter(String field, Collection values) { + if (!values.isEmpty()) { return FilterBuilders.termsFilter(field, values); } else { return null; diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java index a5f007bee05..5d6091370cd 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java @@ -34,7 +34,7 @@ public class ComponentTesting { } public static ComponentDto newFileDto(ComponentDto module, String fileUuid) { - return newComponent(module, fileUuid) + return newComponent(fileUuid, module) .setKey("KEY_" + fileUuid) .setName("NAME_" + fileUuid) .setLongName("LONG_NAME_" + fileUuid) @@ -46,7 +46,7 @@ public class ComponentTesting { public static ComponentDto newDirectory(ComponentDto module, String path) { String uuid = Uuids.create(); - return newComponent(module, uuid) + return newComponent(uuid, module) .setKey(!path.equals("/") ? module.getKey() + ":" + path : module.getKey() + ":/") .setName(path) .setLongName(path) @@ -55,12 +55,8 @@ public class ComponentTesting { .setQualifier(Qualifiers.DIRECTORY); } - public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) { - return newModuleDto(subProjectOrProject, Uuids.create()); - } - - public static ComponentDto newModuleDto(ComponentDto subProjectOrProject, String uuid) { - return newComponent(subProjectOrProject, uuid) + public static ComponentDto newModuleDto(String uuid, ComponentDto subProjectOrProject) { + return newComponent(uuid, subProjectOrProject) .setKey("KEY_" + uuid) .setName("NAME_" + uuid) .setLongName("LONG_NAME_" + uuid) @@ -70,6 +66,10 @@ public class ComponentTesting { .setLanguage(null); } + public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) { + return newModuleDto(Uuids.create(), subProjectOrProject); + } + public static ComponentDto newProjectDto() { return newProjectDto(Uuids.create()); } @@ -90,7 +90,7 @@ public class ComponentTesting { .setEnabled(true); } - private static ComponentDto newComponent(ComponentDto module, String uuid) { + private static ComponentDto newComponent(String uuid, ComponentDto module) { return new ComponentDto() .setUuid(uuid) .setProjectUuid(module.projectUuid()) diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java index 0f1de03316e..ed96ecb547d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java @@ -85,7 +85,7 @@ public class PurgeRemovedViewsStepTest { new ViewDoc().setUuid("CDEF").getFields()); ComponentDto view = ComponentTesting.newProjectDto("ABCD").setQualifier(Qualifiers.VIEW); - ComponentDto subView = ComponentTesting.newModuleDto(view, "BCDE").setQualifier(Qualifiers.SUBVIEW); + ComponentDto subView = ComponentTesting.newModuleDto("BCDE", view).setQualifier(Qualifiers.SUBVIEW); dbClient.componentDao().insert(session, view, subView); session.commit(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java index 0fc89a0186d..1f5f1b6eb00 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java @@ -21,6 +21,8 @@ package org.sonar.server.issue.index; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterators; +import org.elasticsearch.action.bulk.BulkRequestBuilder; +import org.elasticsearch.action.index.IndexRequest; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; @@ -32,6 +34,7 @@ import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.KeyValueFormat; import org.sonar.core.component.ComponentDto; import org.sonar.server.component.ComponentTesting; +import org.sonar.server.es.EsClient; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueTesting; @@ -40,6 +43,8 @@ import org.sonar.server.search.QueryContext; import org.sonar.server.search.Result; import org.sonar.server.tester.ServerTester; import org.sonar.server.user.MockUserSession; +import org.sonar.server.view.index.ViewDoc; +import org.sonar.server.view.index.ViewIndexDefinition; import javax.annotation.Nullable; @@ -290,6 +295,32 @@ public class IssueIndexMediumTest { assertThat(result.getFacets().get("directories")).containsOnly(new FacetValue("/src/main/xoo", 1), new FacetValue("/", 1)); } + @Test + public void filter_by_views() throws Exception { + ComponentDto project1 = ComponentTesting.newProjectDto(); + ComponentDto file1 = ComponentTesting.newFileDto(project1); + ComponentDto project2 = ComponentTesting.newProjectDto(); + indexIssues( + // Project1 has 2 issues (one on a file and one on the project itself) + IssueTesting.newDoc("ISSUE1", project1), + IssueTesting.newDoc("ISSUE2", file1), + // Project2 has 1 issue + IssueTesting.newDoc("ISSUE3", project2)); + + // The view1 is containing 2 issues from project1 + String view1 = "ABCD"; + indexView(view1, newArrayList(project1.uuid())); + + // The view2 is containing 1 issue from project2 + String view2 = "CDEF"; + indexView(view2, newArrayList(project2.uuid())); + + assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1)).build(), new QueryContext()).getHits()).hasSize(2); + assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view2)).build(), new QueryContext()).getHits()).hasSize(1); + assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1, view2)).build(), new QueryContext()).getHits()).hasSize(3); + assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty(); + } + @Test public void filter_by_severities() throws Exception { ComponentDto project = ComponentTesting.newProjectDto(); @@ -952,4 +983,10 @@ public class IssueIndexMediumTest { tester.get(IssueAuthorizationIndexer.class).index(newArrayList(new IssueAuthorizationDao.Dto(projectUuid, 1).addGroup(group).addUser(user))); } + private void indexView(String viewUuid, List projects) { + EsClient client = tester.get(EsClient.class); + BulkRequestBuilder bulk = client.prepareBulk().setRefresh(true); + bulk.add(new IndexRequest(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW).source(new ViewDoc().setUuid(viewUuid).setProjects(projects).getFields())); + bulk.get(); + } }