session.close();
}
}
+
+ public Map<String, Long> listTagsForComponent(String componentUuid, int pageSize) {
+ return indexClient.get(IssueIndex.class).listTagsForComponent(componentUuid, pageSize);
+ }
}
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
}
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();
}
});
}
+
+ 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;
+ }
}
--- /dev/null
+/*
+ * 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();
+ }
+
+}
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
esSearchAction.define(controller);
tagsAction.define(controller);
setTagsAction.define(controller);
+ componentTagsAction.define(controller);
defineChangelogAction(controller);
defineAssignAction(controller);
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;
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;
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;
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;
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;
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;
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;
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;
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);
--- /dev/null
+{
+ "tags": [
+ { key: "convention", value: 42 },
+ { key: "cwe", value: 12 },
+ { key: "security", value: 5 }
+ ]
+}
\ No newline at end of file
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
+import static org.fest.assertions.MapAssert.entry;
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();
+ }
}
--- /dev/null
+/*
+ * 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);
+ }
+}
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)
));
}
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
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
assertThat(controller).isNotNull();
assertThat(controller.description()).isNotEmpty();
assertThat(controller.since()).isEqualTo("3.6");
- assertThat(controller.actions()).hasSize(16);
+ assertThat(controller.actions()).hasSize(17);
}
@Test
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
--- /dev/null
+{
+ tags: [
+ { key: "convention", value: 2771 },
+ { key: "brain-overload", value: 998 },
+ { key: "cwe", value: 89 },
+ { key: "bug", value: 32 },
+ { key: "cert", value: 2 }
+ ]
+}
\ No newline at end of file