diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-06-23 16:03:29 +0200 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2015-06-25 10:21:33 +0200 |
commit | 9273b7fa6ddc25715837e49d6ba083bb888b0c30 (patch) | |
tree | 9fddca3bb351e1d59d3e7b30ba356607ad7bdbfd /server | |
parent | 7ff83ed88a1240c637127e58f7df7511d6bf10df (diff) | |
download | sonarqube-9273b7fa6ddc25715837e49d6ba083bb888b0c30.tar.gz sonarqube-9273b7fa6ddc25715837e49d6ba083bb888b0c30.zip |
SONAR-6195 Implement selection of fields in api/issues/search
Diffstat (limited to 'server')
6 files changed, 162 insertions, 84 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java index ad8e534fdf2..12379d164aa 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java @@ -749,7 +749,7 @@ public class InternalRubyIssueService { projectsByComponentUuid, ImmutableMultimap.<String, DefaultIssueComment>of(), ImmutableMap.<String, ActionPlan>of(), - ImmutableList.of(IssueJsonWriter.ACTIONS_EXTRA_FIELD, IssueJsonWriter.TRANSITIONS_EXTRA_FIELD)); + ImmutableList.copyOf(IssueJsonWriter.SELECTABLE_FIELDS)); json.name("users").beginArray(); String assignee = issue.assignee(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueJsonWriter.java index 826c36abcc8..ef04b6d8f14 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueJsonWriter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueJsonWriter.java @@ -20,8 +20,11 @@ package org.sonar.server.issue.ws; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; import java.util.Collection; import java.util.Date; import java.util.List; @@ -42,15 +45,46 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.component.ComponentDto; import org.sonar.markdown.Markdown; import org.sonar.server.user.UserSession; +import org.sonar.server.ws.JsonWriterUtils; + +import static org.sonar.server.ws.JsonWriterUtils.writeIfNeeded; public class IssueJsonWriter { - public static final String ACTIONS_EXTRA_FIELD = "actions"; - public static final String TRANSITIONS_EXTRA_FIELD = "transitions"; - public static final String ACTION_PLAN_NAME_EXTRA_FIELD = "actionPlanName"; + private static final String FIELD_KEY = "key"; + private static final String FIELD_COMPONENT = "component"; + private static final String FIELD_COMPONENT_ID = "componentId"; + private static final String FIELD_PROJECT = "project"; + private static final String FIELD_SUB_PROJECT = "subProject"; + private static final String FIELD_RULE = "rule"; + private static final String FIELD_STATUS = "status"; + private static final String FIELD_RESOLUTION = "resolution"; + private static final String FIELD_AUTHOR = "author"; + private static final String FIELD_REPORTER = "reporter"; + private static final String FIELD_ASSIGNEE = "assignee"; + private static final String FIELD_DEBT = "debt"; + private static final String FIELD_LINE = "line"; + private static final String FIELD_MESSAGE = "message"; + private static final String FIELD_SEVERITY = "severity"; + private static final String FIELD_ACTION_PLAN = "actionPlan"; + private static final String FIELD_CREATION_DATE = "creationDate"; + private static final String FIELD_UPDATE_DATE = "updateDate"; + private static final String FIELD_CLOSE_DATE = "closeDate"; + private static final String FIELD_TAGS = "tags"; + private static final String FIELD_COMMENTS = "comments"; + private static final String FIELD_ATTRIBUTES = "attr"; + public static final String FIELD_ACTIONS = "actions"; + public static final String FIELD_TRANSITIONS = "transitions"; + public static final String FIELD_ACTION_PLAN_NAME = "actionPlanName"; public static final Set<String> EXTRA_FIELDS = ImmutableSet.of( - ACTIONS_EXTRA_FIELD, TRANSITIONS_EXTRA_FIELD, ACTION_PLAN_NAME_EXTRA_FIELD); + FIELD_ACTIONS, FIELD_TRANSITIONS, FIELD_ACTION_PLAN_NAME); + + public static final Set<String> SELECTABLE_FIELDS = ImmutableSet.of(FIELD_COMPONENT, FIELD_PROJECT, FIELD_SUB_PROJECT, FIELD_RULE, FIELD_STATUS, FIELD_RESOLUTION, FIELD_AUTHOR, + FIELD_REPORTER, FIELD_ASSIGNEE, FIELD_DEBT, FIELD_LINE, FIELD_MESSAGE, FIELD_SEVERITY, FIELD_ACTION_PLAN, FIELD_CREATION_DATE, FIELD_UPDATE_DATE, FIELD_CLOSE_DATE, + FIELD_COMPONENT_ID, FIELD_TAGS, FIELD_COMMENTS, FIELD_ATTRIBUTES, FIELD_ACTIONS, FIELD_TRANSITIONS, FIELD_ACTION_PLAN_NAME); + + private static final List<String> SELECTABLE_MINUS_EXTRAS = ImmutableList.copyOf(Sets.difference(SELECTABLE_FIELDS, EXTRA_FIELDS)); private final I18n i18n; private final Durations durations; @@ -65,12 +99,22 @@ public class IssueJsonWriter { } public void write(JsonWriter json, Issue issue, Map<String, User> usersByLogin, Map<String, ComponentDto> componentsByUuid, - Map<String, ComponentDto> projectsByComponentUuid, Multimap<String, DefaultIssueComment> commentsByIssues, Map<String, ActionPlan> actionPlanByKeys, List<String> extraFields) { + Map<String, ComponentDto> projectsByComponentUuid, Multimap<String, DefaultIssueComment> commentsByIssues, Map<String, ActionPlan> actionPlanByKeys, + @Nullable List<String> selectedFields) { + + List<String> fields = Lists.newArrayList(); + if (selectedFields == null || selectedFields.isEmpty()) { + fields.addAll(SELECTABLE_MINUS_EXTRAS); + } else { + fields.addAll(selectedFields); + } + json.beginObject(); String actionPlanKey = issue.actionPlanKey(); ComponentDto file = componentsByUuid.get(issue.componentUuid()); - ComponentDto project = null, subProject = null; + ComponentDto project = null; + ComponentDto subProject = null; if (file != null) { project = projectsByComponentUuid.get(file.uuid()); if (!file.projectUuid().equals(file.moduleUuid())) { @@ -80,32 +124,37 @@ public class IssueJsonWriter { Duration debt = issue.debt(); Date updateDate = issue.updateDate(); - json - .prop("key", issue.key()) - .prop("component", file != null ? file.getKey() : null) - // Only used for the compatibility with the Issues Java WS Client <= 4.4 used by Eclipse - .prop("componentId", file != null ? file.getId() : null) - .prop("project", project != null ? project.getKey() : null) - .prop("subProject", subProject != null ? subProject.getKey() : null) - .prop("rule", issue.ruleKey().toString()) - .prop("status", issue.status()) - .prop("resolution", issue.resolution()) - .prop("severity", issue.severity()) - .prop("message", issue.message()) - .prop("line", issue.line()) - .prop("debt", debt != null ? durations.encode(debt) : null) - .prop("assignee", issue.assignee()) - .prop("reporter", issue.reporter()) - .prop("author", issue.authorLogin()) - .prop("actionPlan", actionPlanKey) - .prop("creationDate", isoDate(issue.creationDate())) - .prop("updateDate", isoDate(updateDate)) - .prop("closeDate", isoDate(issue.closeDate())); - - writeTags(issue, json); - writeIssueComments(commentsByIssues.get(issue.key()), usersByLogin, json); - writeIssueAttributes(issue, json); - writeIssueExtraFields(issue, usersByLogin, actionPlanByKeys, extraFields, json); + json.prop(FIELD_KEY, issue.key()); + JsonWriterUtils.writeIfNeeded(json, file != null ? file.getKey() : null, FIELD_COMPONENT, fields); + // Only used for the compatibility with the Issues Java WS Client <= 4.4 used by Eclipse + writeIfNeeded(json, file != null ? file.getId() : null, FIELD_COMPONENT_ID, fields); + writeIfNeeded(json, project != null ? project.getKey() : null, FIELD_PROJECT, fields); + writeIfNeeded(json, subProject != null ? subProject.getKey() : null, FIELD_SUB_PROJECT, fields); + writeIfNeeded(json, issue.ruleKey().toString(), FIELD_RULE, fields); + writeIfNeeded(json, issue.status(), FIELD_STATUS, fields); + writeIfNeeded(json, issue.resolution(), FIELD_RESOLUTION, fields); + writeIfNeeded(json, issue.severity(), FIELD_SEVERITY, fields); + writeIfNeeded(json, issue.message(), FIELD_MESSAGE, fields); + writeIfNeeded(json, issue.line(), FIELD_LINE, fields); + writeIfNeeded(json, debt != null ? durations.encode(debt) : null, FIELD_DEBT, fields); + writeIfNeeded(json, issue.assignee(), FIELD_ASSIGNEE, fields); + writeIfNeeded(json, issue.reporter(), FIELD_REPORTER, fields); + writeIfNeeded(json, issue.authorLogin(), FIELD_AUTHOR, fields); + writeIfNeeded(json, actionPlanKey, FIELD_ACTION_PLAN, fields); + writeIfNeeded(json, isoDate(issue.creationDate()), FIELD_CREATION_DATE, fields); + writeIfNeeded(json, isoDate(updateDate), FIELD_UPDATE_DATE, fields); + writeIfNeeded(json, isoDate(issue.closeDate()), FIELD_CLOSE_DATE, fields); + + if (JsonWriterUtils.isFieldWanted(FIELD_TAGS, fields)) { + writeTags(issue, json); + } + if (JsonWriterUtils.isFieldWanted(FIELD_COMMENTS, fields)) { + writeIssueComments(commentsByIssues.get(issue.key()), usersByLogin, json); + } + if (JsonWriterUtils.isFieldWanted(FIELD_ATTRIBUTES, fields)) { + writeIssueAttributes(issue, json); + } + writeIssueExtraFields(issue, actionPlanByKeys, fields, json); json.endObject(); } @@ -120,7 +169,7 @@ public class IssueJsonWriter { private static void writeTags(Issue issue, JsonWriter json) { Collection<String> tags = issue.tags(); if (tags != null && !tags.isEmpty()) { - json.name("tags").beginArray(); + json.name(FIELD_TAGS).beginArray(); for (String tag : tags) { json.value(tag); } @@ -130,7 +179,7 @@ public class IssueJsonWriter { private void writeIssueComments(Collection<DefaultIssueComment> issueComments, Map<String, User> usersByLogin, JsonWriter json) { if (!issueComments.isEmpty()) { - json.name("comments").beginArray(); + json.name(FIELD_COMMENTS).beginArray(); String login = userSession.getLogin(); for (IssueComment comment : issueComments) { String userLogin = comment.userLogin(); @@ -152,7 +201,7 @@ public class IssueJsonWriter { private static void writeIssueAttributes(Issue issue, JsonWriter json) { if (!issue.attributes().isEmpty()) { - json.name("attr").beginObject(); + json.name(FIELD_ATTRIBUTES).beginObject(); for (Map.Entry<String, String> entry : issue.attributes().entrySet()) { json.prop(entry.getKey(), entry.getValue()); } @@ -160,35 +209,26 @@ public class IssueJsonWriter { } } - private void writeIssueExtraFields(Issue issue, Map<String, User> usersByLogin, Map<String, ActionPlan> actionPlanByKeys, - @Nullable List<String> extraFields, - JsonWriter json) { - if (extraFields != null) { - if (extraFields.contains(ACTIONS_EXTRA_FIELD)) { - actionsWriter.writeActions(issue, json); - } + private void writeIssueExtraFields(Issue issue, Map<String, ActionPlan> actionPlanByKeys, + @Nullable List<String> fields, JsonWriter json) { + if (JsonWriterUtils.isFieldWanted(FIELD_ACTIONS, fields)) { + actionsWriter.writeActions(issue, json); + } - if (extraFields.contains(TRANSITIONS_EXTRA_FIELD)) { - actionsWriter.writeTransitions(issue, json); - } + if (JsonWriterUtils.isFieldWanted(FIELD_TRANSITIONS, fields)) { + actionsWriter.writeTransitions(issue, json); + } - writeActionPlanIfNeeded(issue, actionPlanByKeys, extraFields, json); + if (JsonWriterUtils.isFieldWanted(FIELD_ACTION_PLAN_NAME, fields)) { + writeActionPlanName(issue, actionPlanByKeys, json); } } - private void writeActionPlanIfNeeded(Issue issue, Map<String, ActionPlan> actionPlanByKeys, List<String> extraFields, JsonWriter json) { + private void writeActionPlanName(Issue issue, Map<String, ActionPlan> actionPlanByKeys, JsonWriter json) { String actionPlanKey = issue.actionPlanKey(); - if (extraFields.contains(ACTION_PLAN_NAME_EXTRA_FIELD) && actionPlanKey != null) { + if (actionPlanKey != null) { ActionPlan actionPlan = actionPlanByKeys.get(actionPlanKey); - json.prop(ACTION_PLAN_NAME_EXTRA_FIELD, actionPlan != null ? actionPlan.name() : null); + json.prop(FIELD_ACTION_PLAN_NAME, actionPlan != null ? actionPlan.name() : null); } } - - @CheckForNull - private String formatAgeDate(@Nullable Date date) { - if (date != null) { - return i18n.ageFromNow(userSession.locale(), date); - } - return null; - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java index e3253cc3e79..512de33d3ef 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -46,6 +46,7 @@ import org.sonar.api.rule.Severity; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; +import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.user.User; import org.sonar.api.user.UserFinder; import org.sonar.api.utils.DateUtils; @@ -76,8 +77,6 @@ public class SearchAction implements IssuesWsAction { public static final String SEARCH_ACTION = "search"; - private static final String EXTRA_FIELDS_PARAM = "extra_fields"; - private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. "; private final IssueService service; @@ -128,7 +127,7 @@ public class SearchAction implements IssuesWsAction { .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") .setPossibleValues(IssueIndex.SUPPORTED_FACETS); action.addSortParams(IssueQuery.SORTS, null, true); - // TODO support param "f" + action.addFieldsParam(IssueJsonWriter.SELECTABLE_FIELDS); addComponentRelatedParams(action); action.createParam(IssueFilterParameters.ISSUES) @@ -184,9 +183,6 @@ public class SearchAction implements IssuesWsAction { action.createParam(IssueFilterParameters.LANGUAGES) .setDescription("Comma-separated list of languages. Available since 4.4") .setExampleValue("java,js"); - action.createParam(EXTRA_FIELDS_PARAM) - .setDescription("Add some extra fields on each issue. Available since 4.4") - .setPossibleValues(IssueJsonWriter.EXTRA_FIELDS); action.createParam(IssueFilterParameters.CREATED_AT) .setDescription("To retrieve issues created at a given date. Format: date or datetime ISO formats") .setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)"); @@ -347,7 +343,7 @@ public class SearchAction implements IssuesWsAction { Map<String, ActionPlan> actionPlanByKeys = getActionPlanByKeys(actionPlanKeys); writeIssues(result, commentsByIssues, usersByLogin, actionPlanByKeys, componentsByUuid, projectsByComponentUuid, - request.paramAsStrings(EXTRA_FIELDS_PARAM), json); + request.paramAsStrings(Param.FIELDS), json); writeRules(json, !request.mandatoryParamAsBoolean(IssueFilterParameters.HIDE_RULES) ? ruleService.getByKeys(ruleKeys) : Collections.<Rule>emptyList()); writeUsers(json, usersByLogin); writeActionPlans(json, actionPlanByKeys.values()); @@ -474,11 +470,11 @@ public class SearchAction implements IssuesWsAction { private void writeIssues(SearchResult<IssueDoc> result, Multimap<String, DefaultIssueComment> commentsByIssues, Map<String, User> usersByLogin, Map<String, ActionPlan> actionPlanByKeys, - Map<String, ComponentDto> componentsByUuid, Map<String, ComponentDto> projectsByComponentUuid, @Nullable List<String> extraFields, JsonWriter json) { + Map<String, ComponentDto> componentsByUuid, Map<String, ComponentDto> projectsByComponentUuid, @Nullable List<String> fields, JsonWriter json) { json.name("issues").beginArray(); for (IssueDoc issue : result.getDocs()) { - issueWriter.write(json, issue, usersByLogin, componentsByUuid, projectsByComponentUuid, commentsByIssues, actionPlanByKeys, extraFields); + issueWriter.write(json, issue, usersByLogin, componentsByUuid, projectsByComponentUuid, commentsByIssues, actionPlanByKeys, fields); } json.endArray(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java index e889435770c..0152c1b5a72 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java @@ -29,6 +29,9 @@ import org.sonar.core.permission.GlobalPermissions; import org.sonar.server.user.UserSession; import org.sonar.server.user.index.UserDoc; +import static org.sonar.server.ws.JsonWriterUtils.isFieldWanted; +import static org.sonar.server.ws.JsonWriterUtils.writeIfNeeded; + public class UserJsonWriter { private static final String FIELD_LOGIN = "login"; @@ -72,18 +75,6 @@ public class UserJsonWriter { } } - private static void writeIfNeeded(JsonWriter json, @Nullable String value, String field, Collection<String> fields) { - if (isFieldWanted(field, fields)) { - json.prop(field, value); - } - } - - private static void writeIfNeeded(JsonWriter json, @Nullable Boolean value, String field, Collection<String> fields) { - if (isFieldWanted(field, fields)) { - json.prop(field, value); - } - } - private void writeGroupsIfNeeded(JsonWriter json, Collection<String> groups, @Nullable Collection<String> fields) { if (isFieldWanted(FIELD_GROUPS, fields) && userSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN)) { json.name(FIELD_GROUPS).beginArray(); @@ -102,8 +93,4 @@ public class UserJsonWriter { .endArray(); } } - - private static boolean isFieldWanted(String field, @Nullable Collection<String> fields) { - return fields == null || fields.isEmpty() || fields.contains(field); - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java b/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java new file mode 100644 index 00000000000..2db3c921325 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/JsonWriterUtils.java @@ -0,0 +1,55 @@ +/* + * 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.ws; + +import java.util.Collection; +import javax.annotation.Nullable; +import org.sonar.api.utils.text.JsonWriter; + +public class JsonWriterUtils { + + public static void writeIfNeeded(JsonWriter json, @Nullable String value, String field, Collection<String> fields) { + if (isFieldWanted(field, fields)) { + json.prop(field, value); + } + } + + public static void writeIfNeeded(JsonWriter json, @Nullable Boolean value, String field, Collection<String> fields) { + if (isFieldWanted(field, fields)) { + json.prop(field, value); + } + } + + public static void writeIfNeeded(JsonWriter json, @Nullable Integer value, String field, Collection<String> fields) { + if (isFieldWanted(field, fields)) { + json.prop(field, value); + } + } + + public static void writeIfNeeded(JsonWriter json, @Nullable Long value, String field, Collection<String> fields) { + if (isFieldWanted(field, fields)) { + json.prop(field, value); + } + } + + public static boolean isFieldWanted(String field, @Nullable Collection<String> fields) { + return fields == null || fields.isEmpty() || fields.contains(field); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java index 48c1a3aa2f8..b921a2f7de2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java @@ -273,7 +273,7 @@ public class SearchActionMediumTest { userSessionRule.login("john"); WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) - .setParam("extra_fields", "actions,transitions,actionPlanName").execute(); + .setParam("f", "assignee,reporter,actionPlan,actions,transitions,actionPlanName").execute(); result.assertJson(this.getClass(), "issue_with_extra_fields.json"); } |