]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5904 Return directories facet in Issues search WS
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 22 Jan 2015 13:05:05 +0000 (14:05 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 22 Jan 2015 13:14:30 +0000 (14:14 +0100)
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueNormalizer.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/search/FacetValue.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json [new file with mode: 0644]

index 963afc6c05baa79e52e2e2e6110066e4ccebe7e9..4ee92aac528ba3e0624a1be5573f1c2d27a3bcc5 100644 (file)
@@ -181,7 +181,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
     setFacets(query, options, filters, esQuery, esSearch);
 
     SearchResponse response = esSearch.get();
-    return new Result<Issue>(this, response);
+    return new Result<>(this, response);
   }
 
   private BoolFilterBuilder getFilter(IssueQuery query, QueryContext options) {
@@ -196,7 +196,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
 
   public void deleteClosedIssuesOfProjectBefore(String uuid, Date beforeDate) {
     FilterBuilder projectFilter = FilterBuilders.boolFilter().must(FilterBuilders.termsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, uuid));
-    FilterBuilder dateFilter = FilterBuilders.rangeFilter(IssueNormalizer.IssueField.ISSUE_CLOSE_DATE.field()).lt(beforeDate.getTime());
+    FilterBuilder dateFilter = FilterBuilders.rangeFilter(IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT).lt(beforeDate.getTime());
     QueryBuilder queryBuilder = QueryBuilders.filteredQuery(
       QueryBuilders.matchAllQuery(),
       FilterBuilders.andFilter(projectFilter, dateFilter)
@@ -334,22 +334,24 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
       StickyFacetBuilder stickyFacetBuilder = stickyFacetBuilder(esQuery, filters);
       // Execute Term aggregations
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.SEVERITIES, IssueNormalizer.IssueField.SEVERITY.field(), Severity.ALL.toArray());
+        IssueFilterParameters.SEVERITIES, IssueIndexDefinition.FIELD_ISSUE_SEVERITY, Severity.ALL.toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.STATUSES, IssueNormalizer.IssueField.STATUS.field(), Issue.STATUSES.toArray());
+        IssueFilterParameters.STATUSES, IssueIndexDefinition.FIELD_ISSUE_STATUS, Issue.STATUSES.toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.COMPONENT_UUIDS, IssueNormalizer.IssueField.COMPONENT.field(), query.componentUuids().toArray());
+        IssueFilterParameters.COMPONENT_UUIDS, IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.PROJECT_UUIDS, IssueNormalizer.IssueField.PROJECT.field(), query.projectUuids().toArray());
+        IssueFilterParameters.PROJECT_UUIDS, IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.LANGUAGES, IssueNormalizer.IssueField.LANGUAGE.field(), query.languages().toArray());
+        IssueFilterParameters.DIRECTORIES, IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.RULES, IssueNormalizer.IssueField.RULE_KEY.field(), query.rules().toArray());
+        IssueFilterParameters.LANGUAGES, IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, query.languages().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.REPORTERS, IssueNormalizer.IssueField.REPORTER.field());
+        IssueFilterParameters.RULES, IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, query.rules().toArray());
+      addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
+        IssueFilterParameters.REPORTERS, IssueIndexDefinition.FIELD_ISSUE_REPORTER);
 
       if (options.facets().contains(IssueFilterParameters.TAGS)) {
-        esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueNormalizer.IssueField.TAGS.field(), IssueFilterParameters.TAGS, TAGS_FACET_SIZE, query.tags().toArray()));
+        esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TAGS, IssueFilterParameters.TAGS, TAGS_FACET_SIZE, query.tags().toArray()));
       }
 
       if (options.facets().contains(IssueFilterParameters.RESOLUTIONS)) {
@@ -372,7 +374,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
   }
 
   private AggregationBuilder getAssigneesFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
-    String fieldName = IssueNormalizer.IssueField.ASSIGNEE.field();
+    String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE;
     String facetName = IssueFilterParameters.ASSIGNEES;
 
     // Same as in super.stickyFacetBuilder
@@ -403,7 +405,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
   }
 
   private AggregationBuilder getResolutionFacet(Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
-    String fieldName = IssueNormalizer.IssueField.RESOLUTION.field();
+    String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION;
     String facetName = IssueFilterParameters.RESOLUTIONS;
 
     // Same as in super.stickyFacetBuilder
@@ -428,7 +430,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
   }
 
   private AggregationBuilder getActionPlansFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
-    String fieldName = IssueNormalizer.IssueField.ACTION_PLAN.field();
+    String fieldName = IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN;
     String facetName = IssueFilterParameters.ACTION_PLANS;
 
     // Same as in super.stickyFacetBuilder
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueNormalizer.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueNormalizer.java
deleted file mode 100644 (file)
index e0d8e6d..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.issue.index;
-
-import org.elasticsearch.action.update.UpdateRequest;
-import org.sonar.core.persistence.Dto;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.search.BaseNormalizer;
-import org.sonar.server.search.IndexField;
-import org.sonar.server.search.Indexable;
-
-import java.util.List;
-
-public class IssueNormalizer extends BaseNormalizer {
-
-  public IssueNormalizer(DbClient db) {
-    super(db);
-  }
-
-  @Override
-  public List<UpdateRequest> normalize(Dto dto) {
-    throw new UnsupportedOperationException();
-  }
-
-  public static final class IssueField extends Indexable {
-
-    public static final IndexField KEY = addSortable(IndexField.Type.STRING, "key");
-    public static final IndexField UPDATED_AT = add(IndexField.Type.DATE, "updatedAt");
-
-    public static final IndexField PROJECT = addSortable(IndexField.Type.STRING, "project");
-    public static final IndexField COMPONENT = add(IndexField.Type.STRING, "component");
-    public static final IndexField MODULE = add(IndexField.Type.STRING, "module");
-    public static final IndexField MODULE_PATH = add(IndexField.Type.UUID_PATH, "modulePath");
-
-    public static final IndexField ACTION_PLAN = add(IndexField.Type.STRING, "actionPlan");
-    public static final IndexField ASSIGNEE = addSortable(IndexField.Type.STRING, "assignee");
-    public static final IndexField ATTRIBUTES = add(IndexField.Type.STRING, "attributes");
-    public static final IndexField AUTHOR_LOGIN = add(IndexField.Type.STRING, "authorLogin");
-    public static final IndexField DEBT = add(IndexField.Type.LONG, "debt");
-    public static final IndexField EFFORT = add(IndexField.Type.DOUBLE, "effort");
-    public static final IndexField ISSUE_CREATED_AT = addSortable(IndexField.Type.DATE, "issueCreatedAt");
-    public static final IndexField ISSUE_UPDATED_AT = addSortable(IndexField.Type.DATE, "issueUpdatedAt");
-    public static final IndexField ISSUE_CLOSE_DATE = addSortable(IndexField.Type.DATE, "issueClosedAt");
-    public static final IndexField LINE = addSortable(IndexField.Type.INTEGER, "line");
-    public static final IndexField MESSAGE = add(IndexField.Type.STRING, "message");
-    public static final IndexField RESOLUTION = add(IndexField.Type.STRING, "resolution");
-    public static final IndexField REPORTER = add(IndexField.Type.STRING, "reporter");
-    public static final IndexField STATUS = addSortable(IndexField.Type.STRING, "status");
-    public static final IndexField SEVERITY = add(IndexField.Type.STRING, "severity");
-    public static final IndexField SEVERITY_VALUE = addSortable(IndexField.Type.INTEGER, "severityValue");
-    public static final IndexField LANGUAGE = add(IndexField.Type.STRING, "language");
-    public static final IndexField TAGS = add(IndexField.Type.STRING, "tags");
-    public static final IndexField RULE_KEY = add(IndexField.Type.STRING, "ruleKey");
-    public static final IndexField FILE_PATH = addSortable(IndexField.Type.STRING, "filePath");
-  }
-
-}
index 0f615189b8f1b43c58713b7c09c7347f18fc52c3..58138a592c616c5fd61f97bdd38e78ae08a13ad4 100644 (file)
@@ -283,6 +283,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
       IssueFilterParameters.ASSIGNEES,
       IssueFilterParameters.REPORTERS,
       IssueFilterParameters.COMPONENT_UUIDS,
+      IssueFilterParameters.DIRECTORIES,
       IssueFilterParameters.LANGUAGES,
       IssueFilterParameters.TAGS,
     });
index c0e2bfda799eacc3a2a8e79e40db13bbd05a282f..9bedf2b28f7c2fc760b11e86ba4f93c0e9e7fe8a 100644 (file)
@@ -53,13 +53,7 @@ import org.sonar.core.measure.db.MeasureFilterDao;
 import org.sonar.core.metric.DefaultMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.DaoUtils;
-import org.sonar.core.persistence.DatabaseVersion;
-import org.sonar.core.persistence.DefaultDatabase;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.persistence.PreviewDatabaseFactory;
-import org.sonar.core.persistence.SemaphoreUpdater;
-import org.sonar.core.persistence.SemaphoresImpl;
+import org.sonar.core.persistence.*;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.purge.PurgeProfiler;
@@ -85,12 +79,7 @@ import org.sonar.server.activity.index.ActivityNormalizer;
 import org.sonar.server.activity.ws.ActivitiesWebService;
 import org.sonar.server.activity.ws.ActivityMapping;
 import org.sonar.server.authentication.ws.AuthenticationWs;
-import org.sonar.server.batch.BatchIndex;
-import org.sonar.server.batch.BatchWs;
-import org.sonar.server.batch.GlobalRepositoryAction;
-import org.sonar.server.batch.IssuesAction;
-import org.sonar.server.batch.ProjectRepositoryAction;
-import org.sonar.server.batch.ProjectRepositoryLoader;
+import org.sonar.server.batch.*;
 import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.component.ComponentService;
@@ -98,20 +87,12 @@ import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.component.db.SnapshotDao;
-import org.sonar.server.component.ws.ComponentAppAction;
-import org.sonar.server.component.ws.ComponentsWs;
-import org.sonar.server.component.ws.EventsWs;
-import org.sonar.server.component.ws.ProjectsWs;
-import org.sonar.server.component.ws.ResourcesWs;
+import org.sonar.server.component.ws.*;
 import org.sonar.server.computation.AnalysisReportQueue;
 import org.sonar.server.computation.AnalysisReportQueueCleaner;
 import org.sonar.server.computation.ComputationThreadLauncher;
 import org.sonar.server.computation.db.AnalysisReportDao;
-import org.sonar.server.computation.ws.ComputationWebService;
-import org.sonar.server.computation.ws.HistoryWsAction;
-import org.sonar.server.computation.ws.IsQueueEmptyWebService;
-import org.sonar.server.computation.ws.QueueWsAction;
-import org.sonar.server.computation.ws.SubmitReportWsAction;
+import org.sonar.server.computation.ws.*;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.dashboard.db.DashboardDao;
 import org.sonar.server.dashboard.db.WidgetDao;
@@ -123,14 +104,7 @@ import org.sonar.server.db.DbClient;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
 import org.sonar.server.db.migrations.DatabaseMigrations;
 import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
-import org.sonar.server.debt.DebtModelBackup;
-import org.sonar.server.debt.DebtModelLookup;
-import org.sonar.server.debt.DebtModelOperations;
-import org.sonar.server.debt.DebtModelPluginRepository;
-import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.debt.DebtModelXMLExporter;
-import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.debt.*;
 import org.sonar.server.design.FileDesignWidget;
 import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
 import org.sonar.server.duplication.ws.DuplicationsParser;
@@ -138,22 +112,7 @@ import org.sonar.server.duplication.ws.DuplicationsWs;
 import org.sonar.server.es.EsClient;
 import org.sonar.server.es.IndexCreator;
 import org.sonar.server.es.IndexRegistry;
-import org.sonar.server.issue.ActionService;
-import org.sonar.server.issue.AddTagsAction;
-import org.sonar.server.issue.AssignAction;
-import org.sonar.server.issue.CommentAction;
-import org.sonar.server.issue.InternalRubyIssueService;
-import org.sonar.server.issue.IssueBulkChangeService;
-import org.sonar.server.issue.IssueChangelogFormatter;
-import org.sonar.server.issue.IssueChangelogService;
-import org.sonar.server.issue.IssueCommentService;
-import org.sonar.server.issue.IssueQueryService;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.issue.PlanAction;
-import org.sonar.server.issue.RemoveTagsAction;
-import org.sonar.server.issue.ServerIssueStorage;
-import org.sonar.server.issue.SetSeverityAction;
-import org.sonar.server.issue.TransitionAction;
+import org.sonar.server.issue.*;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.actionplan.ActionPlanWs;
 import org.sonar.server.issue.db.IssueDao;
@@ -164,18 +123,8 @@ import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.issue.index.IssueNormalizer;
-import org.sonar.server.issue.notification.ChangesOnMyIssueNotificationDispatcher;
-import org.sonar.server.issue.notification.IssueChangesEmailTemplate;
-import org.sonar.server.issue.notification.IssueNotifications;
-import org.sonar.server.issue.notification.NewFalsePositiveNotificationDispatcher;
-import org.sonar.server.issue.notification.NewIssuesEmailTemplate;
-import org.sonar.server.issue.notification.NewIssuesNotificationDispatcher;
-import org.sonar.server.issue.ws.ComponentTagsAction;
-import org.sonar.server.issue.ws.IssueActionsWriter;
-import org.sonar.server.issue.ws.IssueShowAction;
-import org.sonar.server.issue.ws.IssuesWs;
-import org.sonar.server.issue.ws.SetTagsAction;
+import org.sonar.server.issue.notification.*;
+import org.sonar.server.issue.ws.*;
 import org.sonar.server.language.ws.LanguageWs;
 import org.sonar.server.language.ws.ListAction;
 import org.sonar.server.measure.MeasureFilterEngine;
@@ -196,118 +145,35 @@ import org.sonar.server.platform.ws.L10nWs;
 import org.sonar.server.platform.ws.RestartHandler;
 import org.sonar.server.platform.ws.ServerWs;
 import org.sonar.server.platform.ws.SystemWs;
-import org.sonar.server.plugins.InstalledPluginReferentialFactory;
-import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerExtensionInstaller;
-import org.sonar.server.plugins.ServerPluginJarInstaller;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
-import org.sonar.server.plugins.ServerPluginRepository;
-import org.sonar.server.plugins.UpdateCenterClient;
-import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.plugins.*;
 import org.sonar.server.properties.ProjectSettingsFactory;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
 import org.sonar.server.qualitygate.RegisterQualityGates;
-import org.sonar.server.qualitygate.ws.QGatesAppAction;
-import org.sonar.server.qualitygate.ws.QGatesCopyAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeselectAction;
-import org.sonar.server.qualitygate.ws.QGatesDestroyAction;
-import org.sonar.server.qualitygate.ws.QGatesListAction;
-import org.sonar.server.qualitygate.ws.QGatesRenameAction;
-import org.sonar.server.qualitygate.ws.QGatesSearchAction;
-import org.sonar.server.qualitygate.ws.QGatesSelectAction;
-import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesShowAction;
-import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesWs;
-import org.sonar.server.qualityprofile.BuiltInProfiles;
-import org.sonar.server.qualityprofile.QProfileBackuper;
-import org.sonar.server.qualityprofile.QProfileCopier;
-import org.sonar.server.qualityprofile.QProfileExporters;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.qualityprofile.QProfileLookup;
-import org.sonar.server.qualityprofile.QProfileProjectLookup;
-import org.sonar.server.qualityprofile.QProfileProjectOperations;
-import org.sonar.server.qualityprofile.QProfileReset;
-import org.sonar.server.qualityprofile.QProfileService;
-import org.sonar.server.qualityprofile.QProfiles;
-import org.sonar.server.qualityprofile.RegisterQualityProfiles;
-import org.sonar.server.qualityprofile.RuleActivator;
-import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
+import org.sonar.server.qualitygate.ws.*;
+import org.sonar.server.qualityprofile.*;
 import org.sonar.server.qualityprofile.db.ActiveRuleDao;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions;
-import org.sonar.server.qualityprofile.ws.ProfilesWs;
-import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction;
-import org.sonar.server.qualityprofile.ws.QProfilesWs;
-import org.sonar.server.qualityprofile.ws.RuleActivationActions;
-import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.rule.DeprecatedRulesDefinitionLoader;
-import org.sonar.server.rule.RegisterRules;
-import org.sonar.server.rule.RubyRuleService;
-import org.sonar.server.rule.RuleCreator;
-import org.sonar.server.rule.RuleDefinitionsLoader;
-import org.sonar.server.rule.RuleDeleter;
-import org.sonar.server.rule.RuleOperations;
-import org.sonar.server.rule.RuleRepositories;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.rule.RuleUpdater;
+import org.sonar.server.qualityprofile.ws.*;
+import org.sonar.server.rule.*;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleNormalizer;
-import org.sonar.server.rule.ws.ActiveRuleCompleter;
-import org.sonar.server.rule.ws.AppAction;
-import org.sonar.server.rule.ws.DeleteAction;
-import org.sonar.server.rule.ws.RepositoriesAction;
-import org.sonar.server.rule.ws.RuleMapping;
-import org.sonar.server.rule.ws.RulesWebService;
+import org.sonar.server.rule.ws.*;
 import org.sonar.server.rule.ws.SearchAction;
 import org.sonar.server.rule.ws.TagsAction;
-import org.sonar.server.rule.ws.UpdateAction;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.IndexQueue;
-import org.sonar.server.search.IndexSynchronizer;
-import org.sonar.server.search.SearchClient;
-import org.sonar.server.search.SearchHealth;
+import org.sonar.server.search.*;
 import org.sonar.server.source.HtmlSourceDecorator;
 import org.sonar.server.source.SourceService;
 import org.sonar.server.source.index.SourceLineIndex;
 import org.sonar.server.source.index.SourceLineIndexDefinition;
 import org.sonar.server.source.index.SourceLineIndexer;
-import org.sonar.server.source.ws.HashAction;
-import org.sonar.server.source.ws.IndexAction;
-import org.sonar.server.source.ws.LinesAction;
-import org.sonar.server.source.ws.RawAction;
-import org.sonar.server.source.ws.ScmAction;
-import org.sonar.server.source.ws.ScmWriter;
+import org.sonar.server.source.ws.*;
 import org.sonar.server.source.ws.ShowAction;
-import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.startup.CleanPreviewAnalysisCache;
-import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules;
-import org.sonar.server.startup.GeneratePluginIndex;
-import org.sonar.server.startup.JdbcDriverDeployer;
-import org.sonar.server.startup.LogServerId;
-import org.sonar.server.startup.RegisterDashboards;
-import org.sonar.server.startup.RegisterDebtModel;
-import org.sonar.server.startup.RegisterMetrics;
-import org.sonar.server.startup.RegisterNewMeasureFilters;
-import org.sonar.server.startup.RegisterPermissionTemplates;
-import org.sonar.server.startup.RegisterServletFilters;
-import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
-import org.sonar.server.startup.ServerMetadataPersister;
+import org.sonar.server.startup.*;
 import org.sonar.server.test.CoverageService;
-import org.sonar.server.test.ws.CoverageShowAction;
-import org.sonar.server.test.ws.CoverageWs;
-import org.sonar.server.test.ws.TestsCoveredFilesAction;
-import org.sonar.server.test.ws.TestsShowAction;
-import org.sonar.server.test.ws.TestsTestCasesAction;
-import org.sonar.server.test.ws.TestsWs;
+import org.sonar.server.test.ws.*;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.text.RubyTextService;
 import org.sonar.server.ui.JRubyI18n;
@@ -315,14 +181,7 @@ import org.sonar.server.ui.JRubyProfiling;
 import org.sonar.server.ui.PageDecorations;
 import org.sonar.server.ui.Views;
 import org.sonar.server.updatecenter.ws.UpdateCenterWs;
-import org.sonar.server.user.DefaultUserService;
-import org.sonar.server.user.DoPrivileged;
-import org.sonar.server.user.GroupMembershipFinder;
-import org.sonar.server.user.GroupMembershipService;
-import org.sonar.server.user.NewUserNotifier;
-import org.sonar.server.user.SecurityRealmFactory;
-import org.sonar.server.user.UserService;
-import org.sonar.server.user.UserUpdater;
+import org.sonar.server.user.*;
 import org.sonar.server.user.db.GroupDao;
 import org.sonar.server.user.db.UserDao;
 import org.sonar.server.user.db.UserGroupDao;
@@ -332,13 +191,7 @@ import org.sonar.server.user.index.UserIndexer;
 import org.sonar.server.user.ws.FavoritesWs;
 import org.sonar.server.user.ws.UserPropertiesWs;
 import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.util.BooleanTypeValidation;
-import org.sonar.server.util.FloatTypeValidation;
-import org.sonar.server.util.IntegerTypeValidation;
-import org.sonar.server.util.StringListTypeValidation;
-import org.sonar.server.util.StringTypeValidation;
-import org.sonar.server.util.TextTypeValidation;
-import org.sonar.server.util.TypeValidations;
+import org.sonar.server.util.*;
 import org.sonar.server.ws.ListingWs;
 import org.sonar.server.ws.WebServiceEngine;
 
@@ -420,7 +273,6 @@ class ServerComponents {
       ActiveRuleDao.class,
 
       // issues
-      IssueNormalizer.class,
       IssueIndex.class,
       IssueDao.class,
 
index af2e132e7dbe5daa54228ab310e3a7ed98c32729..ad83b07c3698669972914746813c2dd10e88e5c1 100644 (file)
@@ -54,4 +54,12 @@ public class FacetValue {
   public int hashCode() {
     return key != null ? key.hashCode() : 0;
   }
+
+  @Override
+  public String toString() {
+    return "FacetValue{" +
+      "key='" + key + '\'' +
+      ", value=" + value +
+      '}';
+  }
 }
index 7dce52187eb0ad244b303a21f4d10dc7ece19752..af05cb67c1a3643b6424c7732643eb700b52e81a 100644 (file)
@@ -147,6 +147,21 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_projects() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD");
+    ComponentDto project2 = ComponentTesting.newProjectDto("EFGH");
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", ComponentTesting.newFileDto(project)),
+      IssueTesting.newDoc("ISSUE2", ComponentTesting.newFileDto(project)),
+      IssueTesting.newDoc("ISSUE3", ComponentTesting.newFileDto(project2)));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("projectUuids")));
+    assertThat(result.getFacets()).containsOnlyKeys("projectUuids");
+    assertThat(result.getFacets().get("projectUuids")).containsOnly(new FacetValue("ABCD", 2), new FacetValue("EFGH", 1));
+  }
+
   @Test
   public void filter_by_modules() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -194,6 +209,25 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_components() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto("A");
+    ComponentDto file1 = ComponentTesting.newFileDto(project, "ABCD");
+    ComponentDto file2 = ComponentTesting.newFileDto(project, "BCDE");
+    ComponentDto file3 = ComponentTesting.newFileDto(project, "CDEF");
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", project),
+      IssueTesting.newDoc("ISSUE2", file1),
+      IssueTesting.newDoc("ISSUE3", file2),
+      IssueTesting.newDoc("ISSUE4", file2),
+      IssueTesting.newDoc("ISSUE5", file3));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("componentUuids")));
+    assertThat(result.getFacets()).containsOnlyKeys("componentUuids");
+    assertThat(result.getFacets().get("componentUuids")).containsOnly(new FacetValue("A", 1), new FacetValue("ABCD", 1), new FacetValue("BCDE", 2), new FacetValue("CDEF", 1));
+  }
+
   @Test
   public void filter_by_directories() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -209,6 +243,21 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().directories(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_directories() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file1 = ComponentTesting.newFileDto(project).setPath("src/main/xoo/F1.xoo");
+    ComponentDto file2 = ComponentTesting.newFileDto(project).setPath("F2.xoo");
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file1).setDirectoryPath("/src/main/xoo"),
+      IssueTesting.newDoc("ISSUE2", file2).setDirectoryPath("/"));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("directories")));
+    assertThat(result.getFacets()).containsOnlyKeys("directories");
+    assertThat(result.getFacets().get("directories")).containsOnly(new FacetValue("/src/main/xoo", 1), new FacetValue("/", 1));
+  }
+
   @Test
   public void filter_by_severities() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -223,6 +272,21 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.BLOCKER)).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_severities() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file).setSeverity(Severity.INFO),
+      IssueTesting.newDoc("ISSUE2", file).setSeverity(Severity.INFO),
+      IssueTesting.newDoc("ISSUE3", file).setSeverity(Severity.MAJOR));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("severities")));
+    assertThat(result.getFacets()).containsOnlyKeys("severities");
+    assertThat(result.getFacets().get("severities")).containsOnly(new FacetValue("INFO", 2), new FacetValue("MAJOR", 1));
+  }
+
   @Test
   public void filter_by_statuses() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -237,6 +301,21 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CONFIRMED)).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_statuses() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file).setStatus(Issue.STATUS_CLOSED),
+      IssueTesting.newDoc("ISSUE2", file).setStatus(Issue.STATUS_CLOSED),
+      IssueTesting.newDoc("ISSUE3", file).setStatus(Issue.STATUS_OPEN));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("statuses")));
+    assertThat(result.getFacets()).containsOnlyKeys("statuses");
+    assertThat(result.getFacets().get("statuses")).containsOnly(new FacetValue("CLOSED", 2), new FacetValue("OPEN", 1));
+  }
+
   @Test
   public void filter_by_resolutions() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -252,6 +331,21 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_REMOVED)).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_resolutions() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file).setResolution(Issue.RESOLUTION_FALSE_POSITIVE),
+      IssueTesting.newDoc("ISSUE2", file).setResolution(Issue.RESOLUTION_FALSE_POSITIVE),
+      IssueTesting.newDoc("ISSUE3", file).setResolution(Issue.RESOLUTION_FIXED));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("resolutions")));
+    assertThat(result.getFacets()).containsOnlyKeys("resolutions");
+    assertThat(result.getFacets().get("resolutions")).containsOnly(new FacetValue("FALSE-POSITIVE", 2), new FacetValue("FIXED", 1));
+  }
+
   @Test
   public void filter_by_resolved() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -282,6 +376,20 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_action_plans() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file).setActionPlanKey("plan1"),
+      IssueTesting.newDoc("ISSUE2", file).setActionPlanKey("plan2"));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("actionPlans")));
+    assertThat(result.getFacets()).containsOnlyKeys("actionPlans");
+    assertThat(result.getFacets().get("actionPlans")).containsOnly(new FacetValue("plan1", 1), new FacetValue("plan2", 1));
+  }
+
   @Test
   public void filter_by_planned() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -322,6 +430,19 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().languages(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_languages() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+    RuleKey ruleKey = RuleKey.of("repo", "X1");
+
+    indexIssues(IssueTesting.newDoc("ISSUE1", file).setRuleKey(ruleKey.toString()).setLanguage("xoo"));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("languages")));
+    assertThat(result.getFacets()).containsOnlyKeys("languages");
+    assertThat(result.getFacets().get("languages")).containsOnly(new FacetValue("xoo", 1));
+  }
+
   @Test
   public void filter_by_assignees() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
@@ -337,6 +458,22 @@ public class IssueIndexMediumTest {
     assertThat(index.search(IssueQuery.builder().assignees(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
+  @Test
+  public void facets_on_assignees() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+
+    indexIssues(
+      IssueTesting.newDoc("ISSUE1", file).setAssignee("steph"),
+      IssueTesting.newDoc("ISSUE2", file).setAssignee("simon"),
+      IssueTesting.newDoc("ISSUE3", file).setAssignee("simon"),
+      IssueTesting.newDoc("ISSUE4", file).setAssignee(null));
+
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("assignees")));
+    assertThat(result.getFacets()).containsOnlyKeys("assignees");
+    assertThat(result.getFacets().get("assignees")).containsOnly(new FacetValue("steph", 1), new FacetValue("simon", 2), new FacetValue("", 1));
+  }
+
   @Test
   public void filter_by_assigned() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto();
index b8b7022cb3442ca756eed150fe4d99168c04576f..e0820eed055ad1296e13d1efe5d6e8b8345723a2 100644 (file)
@@ -493,6 +493,25 @@ public class SearchActionMediumTest {
     result.assertJson(this.getClass(), "display_zero_facets.json", false);
   }
 
+  @Test
+  public void display_directory_facet() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir"));
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java"));
+    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    MockUserSession.set().setLogin("john");
+    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam("resolved", "false")
+      .setParam(SearchAction.PARAM_FACETS, "directories")
+      .execute();
+    result.assertJson(this.getClass(), "display_directory_facet.json", false);
+  }
+
   @Test
   public void hide_rules() throws Exception {
     ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json
new file mode 100644 (file)
index 0000000..53f0673
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "facets": [
+    {
+      "property": "directories",
+      "values": [
+        {
+          "val": "/src/main/java/dir",
+          "count": 1
+        }
+      ]
+    }
+  ]
+}