@@ -370,4 +370,8 @@ public class IssueService implements ServerComponent { | |||
session.close(); | |||
} | |||
} | |||
public Map<String, Long> listTagsForComponent(String componentUuid, int pageSize) { | |||
return indexClient.get(IssueIndex.class).listTagsForComponent(componentUuid, pageSize); | |||
} | |||
} |
@@ -61,6 +61,7 @@ import org.sonar.server.user.UserSession; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Date; | |||
import java.util.List; | |||
@@ -272,32 +273,38 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> { | |||
} | |||
private void addComponentRelatedFilters(IssueQuery query, Map<String, FilterBuilder> filters) { | |||
Collection<String> componentUuids = query.componentUuids(); | |||
if (BooleanUtils.isTrue(query.onComponentOnly())) { | |||
Set<String> allComponents = Sets.newHashSet(); | |||
allComponents.addAll(query.projectUuids()); | |||
allComponents.addAll(query.moduleUuids()); | |||
allComponents.addAll(query.componentUuids()); | |||
allComponents.addAll(componentUuids); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, allComponents)); | |||
} else { | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids())); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids())); | |||
FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids()); | |||
FilterBuilder modulePathFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, query.componentUuids()); | |||
FilterBuilder compositeFilter = null; | |||
if (componentFilter != null) { | |||
if (modulePathFilter != null) { | |||
compositeFilter = FilterBuilders.orFilter(componentFilter, modulePathFilter); | |||
} else { | |||
compositeFilter = componentFilter; | |||
} | |||
} else if (modulePathFilter != null) { | |||
compositeFilter = modulePathFilter; | |||
} | |||
FilterBuilder compositeFilter = componentFilter(componentUuids); | |||
filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, compositeFilter); | |||
} | |||
} | |||
private FilterBuilder componentFilter(Collection<String> componentUuids) { | |||
FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentUuids); | |||
FilterBuilder modulePathFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, componentUuids); | |||
FilterBuilder compositeFilter = null; | |||
if (componentFilter != null) { | |||
if (modulePathFilter != null) { | |||
compositeFilter = FilterBuilders.orFilter(componentFilter, modulePathFilter); | |||
} else { | |||
compositeFilter = componentFilter; | |||
} | |||
} else if (modulePathFilter != null) { | |||
compositeFilter = modulePathFilter; | |||
} | |||
return compositeFilter; | |||
} | |||
private FilterBuilder getAuthorizationFilter(QueryContext options) { | |||
String user = options.getUserLogin(); | |||
Set<String> groups = options.getUserGroups(); | |||
@@ -504,4 +511,25 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> { | |||
} | |||
}); | |||
} | |||
public Map<String, Long> listTagsForComponent(String componentUuid, int pageSize) { | |||
SearchRequestBuilder count = getClient().prepareSearch(IssueIndexDefinition.INDEX) | |||
.setTypes(IssueIndexDefinition.TYPE_ISSUE) | |||
.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), | |||
FilterBuilders.boolFilter() | |||
.must(getAuthorizationFilter(new QueryContext())) | |||
.must(componentFilter(Arrays.asList(componentUuid))))); | |||
TermsBuilder aggreg = AggregationBuilders.terms("_ref") | |||
.field(IssueIndexDefinition.FIELD_ISSUE_TAGS) | |||
.size(pageSize) | |||
.order(Order.count(false)) | |||
.minDocCount(1L); | |||
Terms result = count.addAggregation(aggreg).get().getAggregations().get("_ref"); | |||
Map<String, Long> map = Maps.newHashMap(); | |||
for (Bucket bucket: result.getBuckets()) { | |||
map.put(bucket.getKey(), bucket.getDocCount()); | |||
} | |||
return map; | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
/* | |||
* 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.ws; | |||
import com.google.common.io.Resources; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.RequestHandler; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.server.ws.WebService.NewAction; | |||
import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.server.issue.IssueService; | |||
import java.util.Map; | |||
/** | |||
* List issue tags matching a given query. | |||
* @since 5.1 | |||
*/ | |||
public class ComponentTagsAction implements RequestHandler { | |||
private final IssueService service; | |||
public ComponentTagsAction(IssueService service) { | |||
this.service = service; | |||
} | |||
void define(WebService.NewController controller) { | |||
NewAction action = controller.createAction("component_tags") | |||
.setHandler(this) | |||
.setSince("5.1") | |||
.setInternal(true) | |||
.setDescription("List tags for the issues under a given component (including issues on the descendants of the component)") | |||
.setResponseExample(Resources.getResource(getClass(), "example-component-tags.json")); | |||
action.createParam("componentUuid") | |||
.setDescription("A component UUID") | |||
.setRequired(true) | |||
.setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92"); | |||
action.createParam("ps") | |||
.setDescription("The maximum size of the list to return") | |||
.setExampleValue("25") | |||
.setDefaultValue("10"); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
String componentUuid = request.mandatoryParam("componentUuid"); | |||
int pageSize = request.mandatoryParamAsInt("ps"); | |||
JsonWriter json = response.newJsonWriter().beginObject().name("tags").beginArray(); | |||
for (Map.Entry<String, Long> tag : service.listTagsForComponent(componentUuid, pageSize).entrySet()) { | |||
json.beginObject() | |||
.prop("key", tag.getKey()) | |||
.prop("value", tag.getValue()) | |||
.endObject(); | |||
} | |||
json.endArray() | |||
.endObject() | |||
.close(); | |||
} | |||
} |
@@ -46,12 +46,14 @@ public class IssuesWs implements WebService { | |||
private final SearchAction esSearchAction; | |||
private final TagsAction tagsAction; | |||
private final SetTagsAction setTagsAction; | |||
private final ComponentTagsAction componentTagsAction; | |||
public IssuesWs(IssueShowAction showAction, SearchAction searchAction, TagsAction tagsAction, SetTagsAction setTagsAction) { | |||
public IssuesWs(IssueShowAction showAction, SearchAction searchAction, TagsAction tagsAction, SetTagsAction setTagsAction, ComponentTagsAction componentTagsAction) { | |||
this.showAction = showAction; | |||
this.esSearchAction = searchAction; | |||
this.tagsAction = tagsAction; | |||
this.setTagsAction = setTagsAction; | |||
this.componentTagsAction = componentTagsAction; | |||
} | |||
@Override | |||
@@ -64,6 +66,7 @@ public class IssuesWs implements WebService { | |||
esSearchAction.define(controller); | |||
tagsAction.define(controller); | |||
setTagsAction.define(controller); | |||
componentTagsAction.define(controller); | |||
defineChangelogAction(controller); | |||
defineAssignAction(controller); |
@@ -54,7 +54,13 @@ 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.*; | |||
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.preview.PreviewCache; | |||
import org.sonar.core.profiling.Profiling; | |||
import org.sonar.core.purge.PurgeProfiler; | |||
@@ -80,7 +86,11 @@ 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.*; | |||
import org.sonar.server.batch.BatchIndex; | |||
import org.sonar.server.batch.BatchWs; | |||
import org.sonar.server.batch.GlobalReferentialsAction; | |||
import org.sonar.server.batch.ProjectReferentialsAction; | |||
import org.sonar.server.batch.ProjectReferentialsLoader; | |||
import org.sonar.server.charts.ChartFactory; | |||
import org.sonar.server.component.ComponentCleanerService; | |||
import org.sonar.server.component.ComponentService; | |||
@@ -88,14 +98,31 @@ 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.*; | |||
import org.sonar.server.computation.*; | |||
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.computation.AnalysisReportQueue; | |||
import org.sonar.server.computation.AnalysisReportService; | |||
import org.sonar.server.computation.AnalysisReportTaskCleaner; | |||
import org.sonar.server.computation.AnalysisReportTaskLauncher; | |||
import org.sonar.server.computation.ComputationService; | |||
import org.sonar.server.computation.ComputeEngineIssueStorageFactory; | |||
import org.sonar.server.computation.db.AnalysisReportDao; | |||
import org.sonar.server.computation.step.*; | |||
import org.sonar.server.computation.ws.QueueWsAction; | |||
import org.sonar.server.computation.ws.HistoryWsAction; | |||
import org.sonar.server.computation.step.CleanReportStep; | |||
import org.sonar.server.computation.step.ComponentIndexationInDatabaseStep; | |||
import org.sonar.server.computation.step.ComputationStepRegistry; | |||
import org.sonar.server.computation.step.DataCleanerStep; | |||
import org.sonar.server.computation.step.DigestReportStep; | |||
import org.sonar.server.computation.step.IndexProjectIssuesStep; | |||
import org.sonar.server.computation.step.InvalidatePreviewCacheStep; | |||
import org.sonar.server.computation.step.SwitchSnapshotStep; | |||
import org.sonar.server.computation.step.SynchronizeProjectPermissionsStep; | |||
import org.sonar.server.computation.ws.ComputationWebService; | |||
import org.sonar.server.computation.ws.HistoryWsAction; | |||
import org.sonar.server.computation.ws.IsQueueEmptyWsAction; | |||
import org.sonar.server.computation.ws.QueueWsAction; | |||
import org.sonar.server.computation.ws.SubmitReportWsAction; | |||
import org.sonar.server.config.ws.PropertiesWs; | |||
import org.sonar.server.dashboard.db.DashboardDao; | |||
@@ -108,7 +135,14 @@ 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.*; | |||
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.design.FileDesignWidget; | |||
import org.sonar.server.duplication.ws.DuplicationsJsonWriter; | |||
import org.sonar.server.duplication.ws.DuplicationsParser; | |||
@@ -116,14 +150,34 @@ 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.*; | |||
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.actionplan.ActionPlanService; | |||
import org.sonar.server.issue.actionplan.ActionPlanWs; | |||
import org.sonar.server.issue.db.IssueDao; | |||
import org.sonar.server.issue.filter.IssueFilterService; | |||
import org.sonar.server.issue.filter.IssueFilterWriter; | |||
import org.sonar.server.issue.filter.IssueFilterWs; | |||
import org.sonar.server.issue.index.*; | |||
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.ws.ComponentTagsAction; | |||
import org.sonar.server.issue.ws.IssueActionsWriter; | |||
import org.sonar.server.issue.ws.IssueShowAction; | |||
import org.sonar.server.issue.ws.IssuesWs; | |||
@@ -146,34 +200,118 @@ 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.*; | |||
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.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.*; | |||
import org.sonar.server.qualityprofile.*; | |||
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.qualityprofile.db.ActiveRuleDao; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndex; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer; | |||
import org.sonar.server.qualityprofile.ws.*; | |||
import org.sonar.server.rule.*; | |||
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.rule.db.RuleDao; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
import org.sonar.server.rule.index.RuleNormalizer; | |||
import org.sonar.server.rule.ws.*; | |||
import org.sonar.server.search.*; | |||
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.RuleMapping; | |||
import org.sonar.server.rule.ws.RulesWebService; | |||
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.source.HtmlSourceDecorator; | |||
import org.sonar.server.source.IndexSourceLinesStep; | |||
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.*; | |||
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.ShowAction; | |||
import org.sonar.server.startup.*; | |||
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.test.CoverageService; | |||
import org.sonar.server.test.ws.*; | |||
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.text.MacroInterpreter; | |||
import org.sonar.server.text.RubyTextService; | |||
import org.sonar.server.ui.JRubyI18n; | |||
@@ -181,7 +319,14 @@ 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.*; | |||
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.db.GroupDao; | |||
import org.sonar.server.user.db.UserDao; | |||
import org.sonar.server.user.db.UserGroupDao; | |||
@@ -191,7 +336,13 @@ 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.*; | |||
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.ws.ListingWs; | |||
import org.sonar.server.ws.WebServiceEngine; | |||
@@ -525,6 +676,7 @@ class ServerComponents { | |||
pico.addSingleton(org.sonar.server.issue.ws.SearchAction.class); | |||
pico.addSingleton(org.sonar.server.issue.ws.TagsAction.class); | |||
pico.addSingleton(SetTagsAction.class); | |||
pico.addSingleton(ComponentTagsAction.class); | |||
pico.addSingleton(IssueService.class); | |||
pico.addSingleton(IssueActionsWriter.class); | |||
pico.addSingleton(IssueQueryService.class); |
@@ -0,0 +1,7 @@ | |||
{ | |||
"tags": [ | |||
{ key: "convention", value: 42 }, | |||
{ key: "cwe", value: 12 }, | |||
{ key: "security", value: 5 } | |||
] | |||
} |
@@ -68,6 +68,7 @@ import java.util.Map; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.fest.assertions.Fail.fail; | |||
import static org.fest.assertions.MapAssert.entry; | |||
public class IssueServiceMediumTest { | |||
@@ -488,4 +489,19 @@ public class IssueServiceMediumTest { | |||
service.setTags(issue.getKey(), ImmutableSet.<String>of()); | |||
assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).isEmpty(); | |||
} | |||
@Test | |||
public void list_component_tags() { | |||
db.issueDao().insert(session, | |||
IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention", "java8", "bug")), | |||
IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention", "bug")), | |||
IssueTesting.newDto(rule, file, project), | |||
IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention"))); | |||
session.commit(); | |||
index(); | |||
assertThat(service.listTagsForComponent(project.uuid(), 5)).includes(entry("convention", 3L), entry("bug", 2L), entry("java8", 1L)); | |||
assertThat(service.listTagsForComponent(project.uuid(), 2)).includes(entry("convention", 3L), entry("bug", 2L)).excludes(entry("java8", 1L)); | |||
assertThat(service.listTagsForComponent("other", 10)).isEmpty(); | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
/* | |||
* 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.ws; | |||
import com.google.common.collect.ImmutableMap; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.Mock; | |||
import org.mockito.runners.MockitoJUnitRunner; | |||
import org.sonar.api.server.ws.WebService.Action; | |||
import org.sonar.api.server.ws.WebService.Param; | |||
import org.sonar.server.issue.IssueService; | |||
import org.sonar.server.ws.WsTester; | |||
import java.util.Map; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
@RunWith(MockitoJUnitRunner.class) | |||
public class ComponentTagsActionTest { | |||
@Mock | |||
private IssueService service; | |||
private ComponentTagsAction componentTagsAction; | |||
private WsTester tester; | |||
@Before | |||
public void setUp() { | |||
componentTagsAction = new ComponentTagsAction(service); | |||
tester = new WsTester( | |||
new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null), | |||
new SearchAction(null, null, null, null, null, null, null, null, null, null,null), | |||
new TagsAction(null), new SetTagsAction(null), componentTagsAction)); | |||
} | |||
@Test | |||
public void should_define() throws Exception { | |||
Action action = tester.controller("api/issues").action("component_tags"); | |||
assertThat(action.description()).isNotEmpty(); | |||
assertThat(action.responseExampleAsString()).isNotEmpty(); | |||
assertThat(action.isPost()).isFalse(); | |||
assertThat(action.isInternal()).isTrue(); | |||
assertThat(action.handler()).isEqualTo(componentTagsAction); | |||
assertThat(action.params()).hasSize(2); | |||
Param query = action.param("componentUuid"); | |||
assertThat(query.isRequired()).isTrue(); | |||
assertThat(query.description()).isNotEmpty(); | |||
assertThat(query.exampleValue()).isNotEmpty(); | |||
Param pageSize = action.param("ps"); | |||
assertThat(pageSize.isRequired()).isFalse(); | |||
assertThat(pageSize.defaultValue()).isEqualTo("10"); | |||
assertThat(pageSize.description()).isNotEmpty(); | |||
assertThat(pageSize.exampleValue()).isNotEmpty(); | |||
} | |||
@Test | |||
public void should_return_empty_list() throws Exception { | |||
tester.newGetRequest("api/issues", "component_tags").setParam("componentUuid", "polop").execute().assertJson("{tags:[]}"); | |||
} | |||
@Test | |||
public void should_return_tag_list() throws Exception { | |||
Map<String, Long> tags = ImmutableMap.<String, Long>builder() | |||
.put("convention", 2771L) | |||
.put("brain-overload", 998L) | |||
.put("cwe", 89L) | |||
.put("bug", 32L) | |||
.put("cert", 2L) | |||
.build(); | |||
when(service.listTagsForComponent("polop", 5)).thenReturn(tags); | |||
tester.newGetRequest("api/issues", "component_tags").setParam("componentUuid", "polop").setParam("ps", "5").execute() | |||
.assertJson(getClass(), "component-tags.json"); | |||
verify(service).listTagsForComponent("polop", 5); | |||
} | |||
} |
@@ -150,7 +150,7 @@ public class IssueShowActionTest { | |||
new SearchAction(mock(DbClient.class), mock(IssueChangeDao.class), mock(IssueService.class), mock(IssueActionsWriter.class), mock(IssueQueryService.class), | |||
mock(RuleService.class), | |||
mock(ActionPlanService.class), mock(UserFinder.class), mock(I18n.class), mock(Durations.class), mock(Languages.class)), | |||
new TagsAction(null), new SetTagsAction(null) | |||
new TagsAction(null), new SetTagsAction(null), new ComponentTagsAction(null) | |||
)); | |||
} | |||
@@ -50,7 +50,7 @@ public class IssueTagsActionTest { | |||
tester = new WsTester( | |||
new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null), | |||
new SearchAction(null, null, null, null, null, null, null, null, null, null,null), | |||
tagsAction, new SetTagsAction(null))); | |||
tagsAction, new SetTagsAction(null), new ComponentTagsAction(null))); | |||
} | |||
@Test |
@@ -61,7 +61,7 @@ public class IssuesWsTest { | |||
SearchAction searchAction = new SearchAction(mock(DbClient.class), mock(IssueChangeDao.class), mock(IssueService.class), mock(IssueActionsWriter.class), | |||
mock(IssueQueryService.class), mock(RuleService.class), | |||
mock(ActionPlanService.class), mock(UserFinder.class), mock(I18n.class), mock(Durations.class), mock(Languages.class)); | |||
tester = new WsTester(new IssuesWs(showAction, searchAction, new TagsAction(null), new SetTagsAction(null))); | |||
tester = new WsTester(new IssuesWs(showAction, searchAction, new TagsAction(null), new SetTagsAction(null), new ComponentTagsAction(null))); | |||
} | |||
@Test | |||
@@ -70,7 +70,7 @@ public class IssuesWsTest { | |||
assertThat(controller).isNotNull(); | |||
assertThat(controller.description()).isNotEmpty(); | |||
assertThat(controller.since()).isEqualTo("3.6"); | |||
assertThat(controller.actions()).hasSize(16); | |||
assertThat(controller.actions()).hasSize(17); | |||
} | |||
@Test |
@@ -50,7 +50,7 @@ public class SetTagsActionTest { | |||
tester = new WsTester( | |||
new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null), | |||
new SearchAction(null, null, null, null, null, null, null, null, null, null,null), | |||
new TagsAction(null), setTagsAction)); | |||
new TagsAction(null), setTagsAction, new ComponentTagsAction(null))); | |||
} | |||
@Test |
@@ -0,0 +1,9 @@ | |||
{ | |||
tags: [ | |||
{ key: "convention", value: 2771 }, | |||
{ key: "brain-overload", value: 998 }, | |||
{ key: "cwe", value: 89 }, | |||
{ key: "bug", value: 32 }, | |||
{ key: "cert", value: 2 } | |||
] | |||
} |