Browse Source

SONAR-5341 In /issues/search WS, add parameter 'extra_fields'

tags/4.4-RC1
Julien Lancelot 10 years ago
parent
commit
19397ac0aa
25 changed files with 1478 additions and 325 deletions
  1. 15
    5
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/Request.java
  2. 9
    0
      sonar-plugin-api/src/test/java/org/sonar/api/server/ws/RequestTest.java
  3. 90
    0
      sonar-server/src/main/java/org/sonar/server/issue/ws/IssueActionsWriter.java
  4. 420
    0
      sonar-server/src/main/java/org/sonar/server/issue/ws/IssueSearchAction.java
  5. 9
    57
      sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java
  6. 8
    80
      sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
  7. 5
    1
      sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
  8. 3
    0
      sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json
  9. 209
    0
      sonar-server/src/test/java/org/sonar/server/issue/ws/IssueActionsWriterTest.java
  10. 377
    0
      sonar-server/src/test/java/org/sonar/server/issue/ws/IssueSearchActionTest.java
  11. 12
    65
      sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java
  12. 14
    7
      sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java
  13. 32
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues.json
  14. 24
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_action_plan.json
  15. 26
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_attributes.json
  16. 58
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_components.json
  17. 26
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_dates.json
  18. 24
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_debt.json
  19. 39
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_extra_fields.json
  20. 39
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_rules.json
  21. 39
    0
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_users.json
  22. 0
    27
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_actions_defined_by_plugins.json
  23. 0
    27
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_assign_to_me_action.json
  24. 0
    27
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_set_severity_action.json
  25. 0
    29
      sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_without_assign_to_me_action.json

+ 15
- 5
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/Request.java View File

@@ -22,9 +22,11 @@ package org.sonar.api.server.ws;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.DateUtils;

import javax.annotation.CheckForNull;

import java.util.Date;
import java.util.List;

/**
@@ -93,6 +95,7 @@ public abstract class Request {
return values;
}

@CheckForNull
public List<String> paramAsStrings(String key) {
String value = param(key);
if (value == null) {
@@ -182,9 +185,16 @@ public abstract class Request {
return result;
}

// @CheckForNull
// public Date paramAsDate(String key) {
// String s = param(key);
// return s == null ? null : Long.parseLong(s);
// }
@CheckForNull
public Date paramAsDate(String key) {
String s = param(key);
if (s != null) {
Date date = DateUtils.parseDateTimeQuietly(s);
if (date != null) {
return date;
}
return DateUtils.parseDate(s);
}
return null;
}
}

+ 9
- 0
sonar-plugin-api/src/test/java/org/sonar/api/server/ws/RequestTest.java View File

@@ -24,8 +24,10 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.server.ws.internal.ValidatingRequest;
import org.sonar.api.utils.DateUtils;

import javax.annotation.Nullable;

import java.util.Map;

import static org.fest.assertions.Assertions.assertThat;
@@ -71,6 +73,7 @@ public class RequestTest {
action.createParam("a_boolean");
action.createParam("a_number");
action.createParam("a_enum");
action.createParam("a_date");

action.createParam("a_required_string").setRequired(true);
action.createParam("a_required_boolean").setRequired(true);
@@ -177,6 +180,12 @@ public class RequestTest {
RuleStatus.BETA, RuleStatus.READY);
}

@Test
public void param_as_date() throws Exception {
assertThat(request.setParam("a_date", "2014-05-27").paramAsDate("a_date")).isEqualTo(DateUtils.parseDate("2014-05-27"));
assertThat(request.setParam("a_date", "2014-05-27T15:50:45+0100").paramAsDate("a_date")).isEqualTo(DateUtils.parseDateTime("2014-05-27T15:50:45+0100"));
}

@Test
public void param_as_strings() throws Exception {
assertThat(request.paramAsStrings("a_string")).isNull();

+ 90
- 0
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueActionsWriter.java View File

@@ -0,0 +1,90 @@
/*
* 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 org.sonar.api.ServerComponent;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.user.UserSession;

import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

public class IssueActionsWriter implements ServerComponent {

private final IssueService issueService;
private final ActionService actionService;

public IssueActionsWriter(IssueService issueService, ActionService actionService) {
this.issueService = issueService;
this.actionService = actionService;
}

public void writeTransitions(Issue issue, JsonWriter json) {
json.name("transitions").beginArray();
if (UserSession.get().isLoggedIn()) {
List<Transition> transitions = issueService.listTransitions(issue, UserSession.get());
for (Transition transition : transitions) {
json.value(transition.key());
}
}
json.endArray();
}

public void writeActions(Issue issue, JsonWriter json) {
json.name("actions").beginArray();
for (String action : actions((DefaultIssue) issue)) {
json.value(action);
}
json.endArray();
}

private List<String> actions(DefaultIssue issue) {
List<String> actions = newArrayList();
String login = UserSession.get().login();
if (login != null) {
actions.add("comment");
if (issue.resolution() == null) {
actions.add("assign");
if (!login.equals(issue.assignee())) {
actions.add("assign_to_me");
}
actions.add("plan");
String projectKey = issue.projectKey();
if (projectKey != null && UserSession.get().hasProjectPermission(UserRole.ISSUE_ADMIN, projectKey)) {
actions.add("set_severity");
}
for (Action action : actionService.listAvailableActions(issue)) {
actions.add(action.key());
}
}
}
return actions;
}

}

+ 420
- 0
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueSearchAction.java View File

@@ -0,0 +1,420 @@
/*
* 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.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.io.Resources;
import org.sonar.api.component.Component;
import org.sonar.api.i18n.I18n;
import org.sonar.api.issue.*;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
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.user.User;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.server.issue.filter.IssueFilterParameters;
import org.sonar.server.user.UserSession;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.google.common.collect.Lists.newArrayList;

public class IssueSearchAction implements RequestHandler {

private static final String EXTRA_FIELDS_PARAM = "extra_fields";

private final IssueFinder issueFinder;
private final IssueActionsWriter actionsWriter;
private final I18n i18n;
private final Durations durations;

public IssueSearchAction(IssueFinder issueFinder, IssueActionsWriter actionsWriter, I18n i18n, Durations durations) {
this.issueFinder = issueFinder;
this.actionsWriter = actionsWriter;
this.i18n = i18n;
this.durations = durations;
}

void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("search")
.setDescription("Get a list of issues. If the number of issues is greater than 10,000, only the first 10,000 ones are returned by the web service. " +
"Requires Browse permission on project(s)")
.setSince("3.6")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "example-search.json"));

action.createParam(IssueFilterParameters.ISSUES)
.setDescription("Comma-separated list of issue keys")
.setExampleValue("5bccd6e8-f525-43a2-8d76-fcb13dde79ef");
action.createParam(IssueFilterParameters.SEVERITIES)
.setDescription("Comma-separated list of severities")
.setExampleValue(Severity.BLOCKER + "," + Severity.CRITICAL)
.setPossibleValues(Severity.ALL);
action.createParam(IssueFilterParameters.STATUSES)
.setDescription("Comma-separated list of statuses")
.setExampleValue(Issue.STATUS_OPEN + "," + Issue.STATUS_REOPENED)
.setPossibleValues(Issue.STATUSES);
action.createParam(IssueFilterParameters.RESOLUTIONS)
.setDescription("Comma-separated list of resolutions")
.setExampleValue(Issue.RESOLUTION_FIXED + "," + Issue.RESOLUTION_REMOVED)
.setPossibleValues(Issue.RESOLUTIONS);
action.createParam(IssueFilterParameters.RESOLVED)
.setDescription("To match resolved or unresolved issues")
.setBooleanPossibleValues();
action.createParam(IssueFilterParameters.COMPONENTS)
.setDescription("To retrieve issues associated to a specific list of components (comma-separated list of component keys). " +
"Note that if you set the value to a project key, only issues associated to this project are retrieved. " +
"Issues associated to its sub-components (such as files, packages, etc.) are not retrieved. See also componentRoots")
.setExampleValue("org.apache.struts:struts:org.apache.struts.Action");
action.createParam(IssueFilterParameters.COMPONENT_ROOTS)
.setDescription("To retrieve issues associated to a specific list of components and their sub-components (comma-separated list of component keys). " +
"Views are not supported")
.setExampleValue("org.apache.struts:struts");
action.createParam(IssueFilterParameters.RULES)
.setDescription("Comma-separated list of coding rule keys. Format is <repository>:<rule>")
.setExampleValue("squid:AvoidCycles");
action.createParam(IssueFilterParameters.HIDE_RULES)
.setDescription("To not return rules")
.setBooleanPossibleValues();
action.createParam(IssueFilterParameters.ACTION_PLANS)
.setDescription("Comma-separated list of action plan keys (not names)")
.setExampleValue("3f19de90-1521-4482-a737-a311758ff513");
action.createParam(IssueFilterParameters.PLANNED)
.setDescription("To retrieve issues associated to an action plan or not")
.setBooleanPossibleValues();
action.createParam(IssueFilterParameters.REPORTERS)
.setDescription("Comma-separated list of reporter logins")
.setExampleValue("admin");
action.createParam(IssueFilterParameters.ASSIGNEES)
.setDescription("Comma-separated list of assignee logins")
.setExampleValue("admin,usera");
action.createParam(IssueFilterParameters.ASSIGNED)
.setDescription("To retrieve assigned or unassigned issues")
.setBooleanPossibleValues();
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("actions", "transitions", "assigneeName", "actionPlanName");
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)");
action.createParam(IssueFilterParameters.CREATED_AFTER)
.setDescription("To retrieve issues created after the given date (inclusive). Format: date or datetime ISO formats")
.setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)");
action.createParam(IssueFilterParameters.CREATED_BEFORE)
.setDescription("To retrieve issues created before the given date (exclusive). Format: date or datetime ISO formats")
.setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)");
action.createParam(IssueFilterParameters.PAGE_SIZE)
.setDescription("Maximum number of results per page. " +
"Default value: 100 (except when the 'components' parameter is set, value is set to \"-1\" in this case). " +
"If set to \"-1\", the max possible value is used")
.setExampleValue("50");
action.createParam(IssueFilterParameters.PAGE_INDEX)
.setDescription("Index of the selected page")
.setDefaultValue("1")
.setExampleValue("2");
action.createParam(IssueFilterParameters.SORT)
.setDescription("Sort field")
.setPossibleValues(IssueQuery.SORTS);
action.createParam(IssueFilterParameters.ASC)
.setDescription("Ascending sort")
.setBooleanPossibleValues();
}

@Override
public void handle(Request request, Response response) {
IssueQueryResult queryResult = issueFinder.find(createQuery(request));

JsonWriter json = response.newJsonWriter();
json.beginObject();

writePaging(queryResult, json);
writeIssues(queryResult, request.paramAsStrings(EXTRA_FIELDS_PARAM), json);
writeComponents(queryResult, json);
writeProjects(queryResult, json);
writeRules(queryResult, json);
writeUsers(queryResult, json);

json.endObject().close();
}

private void writePaging(IssueQueryResult result, JsonWriter json) {
json.prop("maxResultsReached", result.maxResultsReached());
json.name("paging").beginObject()
.prop("pageIndex", result.paging().pageIndex())
.prop("pageSize", result.paging().pageSize())
.prop("total", result.paging().total())
.prop("fTotal", i18n.formatInteger(UserSession.get().locale(), result.paging().total()))
.prop("pages", result.paging().pages())
.endObject();
}

private void writeIssues(IssueQueryResult result, @Nullable List<String> extraFields, JsonWriter json) {
json.name("issues").beginArray();

for (Issue i : result.issues()) {
json.beginObject();

DefaultIssue issue = (DefaultIssue) i;
String actionPlanKey = issue.actionPlanKey();
Duration debt = issue.debt();
Date updateDate = issue.updateDate();
Date closeDate = issue.closeDate();

json
.prop("key", issue.key())
.prop("component", issue.componentKey())
.prop("project", issue.projectKey())
.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.format(UserSession.get().locale(), debt, Durations.DurationFormat.SHORT) : null)
.prop("reporter", issue.reporter())
.prop("assignee", issue.assignee())
.prop("author", issue.authorLogin())
.prop("actionPlan", actionPlanKey)
.prop("creationDate", DateUtils.formatDateTime(issue.creationDate()))
.prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null)
.prop("fUpdateAge", formatAgeDate(updateDate))
.prop("closeDate", closeDate != null ? DateUtils.formatDateTime(closeDate) : null);

writeIssueAttributes(issue, json);
writeIssueExtraFields(result, issue, extraFields, json);
json.endObject();
}

json.endArray();
}

private void writeIssueAttributes(Issue issue, JsonWriter json) {
if (!issue.attributes().isEmpty()) {
json.name("attr").beginObject();
for (Map.Entry<String, String> entry : issue.attributes().entrySet()) {
json.prop(entry.getKey(), entry.getValue());
}
json.endObject();
}
}

private void writeIssueExtraFields(IssueQueryResult result, Issue issue, @Nullable List<String> extraFields, JsonWriter json) {
if (extraFields != null) {
if (extraFields.contains("actions")) {
actionsWriter.writeActions(issue, json);
}
if (extraFields.contains("transitions")) {
actionsWriter.writeTransitions(issue, json);
}
String assignee = issue.assignee();
if (extraFields.contains("assigneeName") && assignee != null) {
User user = result.user(assignee);
json.prop("assigneeName", user != null ? user.name() : null);
}
String actionPlanKey = issue.actionPlanKey();
if (extraFields.contains("actionPlanName") && actionPlanKey != null) {
ActionPlan actionPlan = result.actionPlan(issue);
json.prop("actionPlanName", actionPlan != null ? actionPlan.name() : null);
}
}
}

private void writeComponents(IssueQueryResult result, JsonWriter json) {
json.name("components").beginArray();
for (Component component : result.components()) {
ComponentDto componentDto = (ComponentDto) component;
json.beginObject()
.prop("key", component.key())
.prop("id", componentDto.getId())
.prop("qualifier", component.qualifier())
.prop("name", component.name())
.prop("longName", component.longName())
.prop("path", component.path())
// On a root project, subProjectId is null but projectId is equal to itself, which make no sense.
.prop("projectId", (componentDto.projectId() != null && componentDto.subProjectId() != null) ? componentDto.projectId() : null)
.prop("subProjectId", componentDto.subProjectId())
.endObject();
}
json.endArray();
}

private void writeProjects(IssueQueryResult result, JsonWriter json) {
json.name("projects").beginArray();
for (Component project : result.projects()) {
ComponentDto componentDto = (ComponentDto) project;
json.beginObject()
.prop("key", project.key())
.prop("id", componentDto.getId())
.prop("qualifier", project.qualifier())
.prop("name", project.name())
.prop("longName", project.longName())
.endObject();
}
json.endArray();
}

private void writeRules(IssueQueryResult result, JsonWriter json) {
json.name("rules").beginArray();
for (Rule rule : result.rules()) {
json.beginObject()
.prop("key", rule.ruleKey().toString())
.prop("name", rule.getName())
.prop("desc", rule.getDescription())
.prop("status", rule.getStatus())
.endObject();
}
json.endArray();
}

private void writeUsers(IssueQueryResult result, JsonWriter json) {
json.name("users").beginArray();
for (User user : result.users()) {
json.beginObject()
.prop("login", user.login())
.prop("name", user.name())
.prop("active", user.active())
.prop("email", user.email())
.endObject();
}
json.endArray();
}


//
// private void writeTransitions(Issue issue, JsonWriter json) {
// json.name("transitions").beginArray();
// if (UserSession.get().isLoggedIn()) {
// List<Transition> transitions = issueService.listTransitions(issue, UserSession.get());
// for (Transition transition : transitions) {
// json.value(transition.key());
// }
// }
// json.endArray();
// }
//
// private void writeActions(DefaultIssue issue, JsonWriter json) {
// json.name("actions").beginArray();
// for (String action : actions(issue)) {
// json.value(action);
// }
// json.endArray();
// }
//
// private List<String> actions(DefaultIssue issue) {
// List<String> actions = newArrayList();
// String login = UserSession.get().login();
// if (login != null) {
// actions.add("comment");
// if (issue.resolution() == null) {
// actions.add("assign");
// if (!login.equals(issue.assignee())) {
// actions.add("assign_to_me");
// }
// actions.add("plan");
// String projectKey = issue.projectKey();
// if (projectKey != null && UserSession.get().hasProjectPermission(UserRole.ISSUE_ADMIN, projectKey)) {
// actions.add("set_severity");
// }
// for (Action action : actionService.listAvailableActions(issue)) {
// actions.add(action.key());
// }
// }
// }
// return actions;
// }
//

@CheckForNull
private String formatAgeDate(@Nullable Date date) {
if (date != null) {
return i18n.ageFromNow(UserSession.get().locale(), date);
}
return null;
}

@CheckForNull
private static Collection<RuleKey> stringsToRules(@Nullable Collection<String> rules) {
if (rules != null) {
return newArrayList(Iterables.transform(rules, new Function<String, RuleKey>() {
@Override
public RuleKey apply(@Nullable String s) {
return s != null ? RuleKey.parse(s) : null;
}
}));
}
return null;
}

@VisibleForTesting
static IssueQuery createQuery(Request request) {
IssueQuery.Builder builder = IssueQuery.builder()
.requiredRole(UserRole.USER)
.issueKeys(request.paramAsStrings(IssueFilterParameters.ISSUES))
.severities(request.paramAsStrings(IssueFilterParameters.SEVERITIES))
.statuses(request.paramAsStrings(IssueFilterParameters.STATUSES))
.resolutions(request.paramAsStrings(IssueFilterParameters.RESOLUTIONS))
.resolved(request.paramAsBoolean(IssueFilterParameters.RESOLVED))
.components(request.paramAsStrings(IssueFilterParameters.COMPONENTS))
.componentRoots(request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOTS))
.rules(stringsToRules(request.paramAsStrings(IssueFilterParameters.RULES)))
.actionPlans(request.paramAsStrings(IssueFilterParameters.ACTION_PLANS))
.reporters(request.paramAsStrings(IssueFilterParameters.REPORTERS))
.assignees(request.paramAsStrings(IssueFilterParameters.ASSIGNEES))
.languages(request.paramAsStrings(IssueFilterParameters.LANGUAGES))
.assigned(request.paramAsBoolean(IssueFilterParameters.ASSIGNED))
.planned(request.paramAsBoolean(IssueFilterParameters.PLANNED))
.hideRules(request.paramAsBoolean(IssueFilterParameters.HIDE_RULES))
.createdAt(request.paramAsDate(IssueFilterParameters.CREATED_AT))
.createdAfter(request.paramAsDate(IssueFilterParameters.CREATED_AFTER))
.createdBefore(request.paramAsDate(IssueFilterParameters.CREATED_BEFORE))
.pageSize(request.paramAsInt(IssueFilterParameters.PAGE_SIZE))
.pageIndex(request.paramAsInt(IssueFilterParameters.PAGE_INDEX));
String sort = request.param(IssueFilterParameters.SORT);
if (!Strings.isNullOrEmpty(sort)) {
builder.sort(sort);
builder.asc(request.paramAsBoolean(IssueFilterParameters.ASC));
}
return builder.build();
}

}

+ 9
- 57
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java View File

@@ -25,7 +25,6 @@ import com.google.common.io.Resources;
import org.sonar.api.component.Component;
import org.sonar.api.i18n.I18n;
import org.sonar.api.issue.*;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.server.debt.DebtCharacteristic;
@@ -41,14 +40,11 @@ import org.sonar.api.utils.Durations;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.markdown.Markdown;
import org.sonar.server.debt.DebtModelService;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueChangelog;
import org.sonar.server.issue.IssueChangelogService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.user.UserSession;

import javax.annotation.CheckForNull;
@@ -58,24 +54,20 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

public class IssueShowAction implements RequestHandler {

private final IssueFinder issueFinder;
private final IssueService issueService;
private final IssueChangelogService issueChangelogService;
private final ActionService actionService;
private final IssueActionsWriter actionsWriter;
private final DebtModelService debtModel;
private final I18n i18n;
private final Durations durations;

public IssueShowAction(IssueFinder issueFinder, IssueService issueService, IssueChangelogService issueChangelogService, ActionService actionService,
public IssueShowAction(IssueFinder issueFinder, IssueChangelogService issueChangelogService, IssueActionsWriter actionsWriter,
DebtModelService debtModel, I18n i18n, Durations durations) {
this.issueFinder = issueFinder;
this.issueService = issueService;
this.issueChangelogService = issueChangelogService;
this.actionService = actionService;
this.actionsWriter = actionsWriter;
this.debtModel = debtModel;
this.i18n = i18n;
this.durations = durations;
@@ -96,7 +88,9 @@ public class IssueShowAction implements RequestHandler {
@Override
public void handle(Request request, Response response) {
String issueKey = request.mandatoryParam("key");
IssueQueryResult queryResult = issueFinder.find(IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).build());
IssueQueryResult queryResult = issueFinder.find(IssueQuery.builder()
.requiredRole(UserRole.USER)
.issueKeys(Arrays.asList(issueKey)).build());
if (queryResult.issues().size() != 1) {
throw new NotFoundException("Issue not found: " + issueKey);
}
@@ -106,8 +100,8 @@ public class IssueShowAction implements RequestHandler {
json.beginObject().name("issue").beginObject();

writeIssue(queryResult, issue, json);
writeTransitions(issue, json);
writeActions(issue, json);
actionsWriter.writeActions(issue, json);
actionsWriter.writeTransitions(issue, json);
writeComments(queryResult, issue, json);
writeChangelog(issue, json);

@@ -220,48 +214,6 @@ public class IssueShowAction implements RequestHandler {
return null;
}

private void writeTransitions(Issue issue, JsonWriter json) {
json.name("transitions").beginArray();
if (UserSession.get().isLoggedIn()) {
List<Transition> transitions = issueService.listTransitions(issue, UserSession.get());
for (Transition transition : transitions) {
json.value(transition.key());
}
}
json.endArray();
}

private void writeActions(DefaultIssue issue, JsonWriter json) {
json.name("actions").beginArray();
for (String action : actions(issue)) {
json.value(action);
}
json.endArray();
}

private List<String> actions(DefaultIssue issue) {
List<String> actions = newArrayList();
String login = UserSession.get().login();
if (login != null) {
actions.add("comment");
if (issue.resolution() == null) {
actions.add("assign");
if (!login.equals(issue.assignee())) {
actions.add("assign_to_me");
}
actions.add("plan");
String projectKey = issue.projectKey();
if (projectKey != null && UserSession.get().hasProjectPermission(UserRole.ISSUE_ADMIN, projectKey)) {
actions.add("set_severity");
}
for (Action action : actionService.listAvailableActions(issue)) {
actions.add(action.key());
}
}
}
return actions;
}

private void writeComments(IssueQueryResult queryResult, Issue issue, JsonWriter json) {
json.name("comments").beginArray();
String login = UserSession.get().login();
@@ -311,7 +263,7 @@ public class IssueShowAction implements RequestHandler {
json.endArray();
}

private void addUserWithLabel(IssueQueryResult result, @Nullable String value, String field, JsonWriter json) {
private static void addUserWithLabel(IssueQueryResult result, @Nullable String value, String field, JsonWriter json) {
if (value != null) {
User user = result.user(value);
json

+ 8
- 80
sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java View File

@@ -21,17 +21,18 @@ package org.sonar.server.issue.ws;

import com.google.common.io.Resources;
import org.sonar.api.issue.DefaultTransitions;
import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.server.ws.WebService;

public class IssuesWs implements WebService {

private final IssueShowAction showHandler;
private final IssueShowAction showAction;
private final IssueSearchAction searchAction;

public IssuesWs(IssueShowAction showHandler) {
this.showHandler = showHandler;
public IssuesWs(IssueShowAction showAction, IssueSearchAction searchAction) {
this.showAction = showAction;
this.searchAction = searchAction;
}

@Override
@@ -40,8 +41,9 @@ public class IssuesWs implements WebService {
controller.setDescription("Coding rule issues");
controller.setSince("3.6");

showHandler.define(controller);
defineSearchAction(controller);
showAction.define(controller);
searchAction.define(controller);

defineChangelogAction(controller);
defineAssignAction(controller);
defineAddCommentAction(controller);
@@ -58,80 +60,6 @@ public class IssuesWs implements WebService {
controller.done();
}

private void defineSearchAction(NewController controller) {
WebService.NewAction action = controller.createAction("search")
.setDescription("Get a list of issues. If the number of issues is greater than 10,000, only the first 10,000 ones are returned by the web service. " +
"Requires Browse permission on project(s)")
.setSince("3.6")
.setHandler(RailsHandler.INSTANCE)
.setResponseExample(Resources.getResource(this.getClass(), "example-search.json"));

action.createParam("issues")
.setDescription("Comma-separated list of issue keys")
.setExampleValue("5bccd6e8-f525-43a2-8d76-fcb13dde79ef");
action.createParam("severities")
.setDescription("Comma-separated list of severities")
.setExampleValue(Severity.BLOCKER + "," + Severity.CRITICAL)
.setPossibleValues(Severity.ALL);
action.createParam("statuses")
.setDescription("Comma-separated list of statuses")
.setExampleValue(Issue.STATUS_OPEN + "," + Issue.STATUS_REOPENED)
.setPossibleValues(Issue.STATUSES);
action.createParam("resolutions")
.setDescription("Comma-separated list of resolutions")
.setExampleValue(Issue.RESOLUTION_FIXED + "," + Issue.RESOLUTION_REMOVED)
.setPossibleValues(Issue.RESOLUTIONS);
action.createParam("resolved")
.setDescription("To match resolved or unresolved issues")
.setBooleanPossibleValues();
action.createParam("components")
.setDescription("To retrieve issues associated to a specific list of components (comma-separated list of component keys). " +
"Note that if you set the value to a project key, only issues associated to this project are retrieved. " +
"Issues associated to its sub-components (such as files, packages, etc.) are not retrieved. See also componentRoots")
.setExampleValue("org.apache.struts:struts:org.apache.struts.Action");
action.createParam("componentRoots")
.setDescription("To retrieve issues associated to a specific list of components and their sub-components (comma-separated list of component keys). " +
"Views are not supported")
.setExampleValue("org.apache.struts:struts");
action.createParam("rules")
.setDescription("Comma-separated list of coding rule keys. Format is <repository>:<rule>")
.setExampleValue("squid:AvoidCycles");
action.createParam("actionPlans")
.setDescription("Comma-separated list of action plan keys (not names)")
.setExampleValue("3f19de90-1521-4482-a737-a311758ff513");
action.createParam("planned")
.setDescription("To retrieve issues associated to an action plan or not")
.setBooleanPossibleValues();
action.createParam("reporters")
.setDescription("Comma-separated list of reporter logins")
.setExampleValue("admin");
action.createParam("assignees")
.setDescription("Comma-separated list of assignee logins")
.setExampleValue("admin,usera");
action.createParam("assigned")
.setDescription("To retrieve assigned or unassigned issues")
.setBooleanPossibleValues();
action.createParam("extra_fields")
.setDescription("Add some extra fields on each issue. Available since 4.4")
.setPossibleValues("actions", "transitions");
action.createParam("createdAfter")
.setDescription("To retrieve issues created after the given date (inclusive). Format: date or datetime ISO formats")
.setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)");
action.createParam("createdBefore")
.setDescription("To retrieve issues created before the given date (exclusive). Format: date or datetime ISO formats")
.setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)");
action.createParam("pageSize")
.setDescription("Maximum number of results per page. " +
"Default value: 100 (except when the 'components' parameter is set, value is set to \"-1\" in this case). " +
"If set to \"-1\", the max possible value is used")
.setExampleValue("50");
action.createParam("pageIndex")
.setDescription("Index of the selected page")
.setDefaultValue("1")
.setExampleValue("2");
RailsHandler.addFormatParam(action);
}

private void defineChangelogAction(NewController controller) {
WebService.NewAction action = controller.createAction("changelog")
.setDescription("Display changelog of an issue")

+ 5
- 1
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java View File

@@ -96,6 +96,8 @@ import org.sonar.server.issue.actionplan.ActionPlanWs;
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.ws.IssueActionsWriter;
import org.sonar.server.issue.ws.IssueSearchAction;
import org.sonar.server.issue.ws.IssueShowAction;
import org.sonar.server.issue.ws.IssuesWs;
import org.sonar.server.measure.MeasureFilterEngine;
@@ -421,8 +423,10 @@ class ServerComponents {
pico.addSingleton(Actions.class);
pico.addSingleton(IssueBulkChangeService.class);
pico.addSingleton(IssueChangelogFormatter.class);
pico.addSingleton(IssueShowAction.class);
pico.addSingleton(IssuesWs.class);
pico.addSingleton(IssueShowAction.class);
pico.addSingleton(IssueSearchAction.class);
pico.addSingleton(IssueActionsWriter.class);

// issue filters
pico.addSingleton(IssueFilterService.class);

+ 3
- 0
sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json View File

@@ -29,6 +29,9 @@
"createdAt": "2013-05-13T18:08:34+0200"
}
],
"attr": {
"jira-issue-key": "SONAR-1234"
},
"actions": ["link-to-jira"],
"transitions": [
"unconfirm",

+ 209
- 0
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueActionsWriterTest.java View File

@@ -0,0 +1,209 @@
/*
* 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 org.json.JSONException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.skyscreamer.jsonassert.JSONAssert;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.user.UserSession;

import java.io.StringWriter;

import static com.google.common.collect.Lists.newArrayList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class IssueActionsWriterTest {

@Mock
IssueService issueService;

@Mock
ActionService actionService;

IssueActionsWriter writer;

@Before
public void setUp() throws Exception {
writer = new IssueActionsWriter(issueService, actionService);
}

@Test
public void write_all_standard_actions() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"));

MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ISSUE_ADMIN, "sample");

testActions(issue,
"{\"actions\": " +
"[" +
"\"comment\", \"assign\", \"assign_to_me\", \"plan\", \"set_severity\"\n" +
"]}"
);
}

@Test
public void write_plugin_actions() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"));

MockUserSession.set().setLogin("john");
Action action = mock(Action.class);
when(action.key()).thenReturn("link-to-jira");
when(actionService.listAvailableActions(eq(issue))).thenReturn(newArrayList(action));

testActions(issue,
"{\"actions\": " +
"[" +
"\"comment\", \"assign\", \"assign_to_me\", \"plan\", \"link-to-jira\"\n" +
"]}"
);
}

@Test
public void write_only_comment_action() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setResolution("CLOSED");

MockUserSession.set().setLogin("john");

testActions(issue,
"{\"actions\": " +
"[" +
"\"comment\"" +
"]}"
);
}

@Test
public void write_no_action_if_not_logged() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"));

MockUserSession.set();

testActions(issue,
"{\"actions\": []}"
);
}

@Test
public void write_actions_without_assign_to_me() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setAssignee("john");

MockUserSession.set().setLogin("john");

testActions(issue,
"{\"actions\": " +
"[" +
"\"comment\", \"assign\", \"plan\"\n" +
"]}"
);
}

@Test
public void write_transitions() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"));

when(issueService.listTransitions(eq(issue), any(UserSession.class))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
MockUserSession.set().setLogin("john");

testTransitions(issue,
"{\"transitions\": [\n" +
" \"reopen\"\n" +
" ]}"
);
}

@Test
public void write_no_transitions() throws Exception {
Issue issue = new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"));

MockUserSession.set().setLogin("john");

testTransitions(issue,
"{\"transitions\": []}"
);
}

private void testActions(Issue issue, String expected) throws JSONException {
StringWriter output = new StringWriter();
JsonWriter jsonWriter = JsonWriter.of(output);
jsonWriter.beginObject();
writer.writeActions(issue, jsonWriter);
jsonWriter.endObject();
JSONAssert.assertEquals(output.toString(), expected, true);
}

private void testTransitions(Issue issue, String expected) throws JSONException {
StringWriter output = new StringWriter();
JsonWriter jsonWriter = JsonWriter.of(output);
jsonWriter.beginObject();
writer.writeTransitions(issue, jsonWriter);
jsonWriter.endObject();
JSONAssert.assertEquals(output.toString(), expected, true);
}

}

+ 377
- 0
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueSearchActionTest.java View File

@@ -0,0 +1,377 @@
/*
* 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.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.component.Component;
import org.sonar.api.i18n.I18n;
import org.sonar.api.issue.ActionPlan;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueFinder;
import org.sonar.api.issue.IssueQuery;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.user.User;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.Paging;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssueQueryResult;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.user.DefaultUser;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsTester;

import java.util.*;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class IssueSearchActionTest {

@Mock
IssueFinder issueFinder;

@Mock
IssueService issueService;

@Mock
ActionService actionService;

@Mock
I18n i18n;

@Mock
Durations durations;

List<Issue> issues;
DefaultIssueQueryResult result;

Date issueCreationDate;

WsTester tester;

@Before
public void setUp() throws Exception {
issues = new ArrayList<Issue>();
result = new DefaultIssueQueryResult(issues);
when(issueFinder.find(any(IssueQuery.class))).thenReturn(result);

issueCreationDate = DateUtils.parseDateTime("2014-01-22T19:10:03+0100");
when(i18n.formatDateTime(any(Locale.class), eq(issueCreationDate))).thenReturn("Jan 22, 2014 10:03 AM");

result.setMaxResultsReached(true);
result.setPaging(Paging.create(100, 1, 2));
when(i18n.formatInteger(any(Locale.class), eq(2))).thenReturn("2");

tester = new WsTester(new IssuesWs(mock(IssueShowAction.class), new IssueSearchAction(issueFinder, new IssueActionsWriter(issueService, actionService), i18n, durations)));
}

@Test
public void issues() throws Exception {
String issueKey = "ABCD";
Issue issue = new DefaultIssue()
.setKey(issueKey)
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setActionPlanKey("AP-ABCD")
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setAssignee("john")
.setReporter("steven")
.setAuthorLogin("Henry")
.setCreationDate(issueCreationDate);
issues.add(issue);

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues.json");
}

@Test
public void issues_with_components() throws Exception {
String issueKey = "ABCD";
Issue issue = new DefaultIssue()
.setKey(issueKey)
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setActionPlanKey("AP-ABCD")
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setAssignee("john")
.setReporter("steven")
.setAuthorLogin("Henry")
.setCreationDate(issueCreationDate);
issues.add(issue);

ComponentDto component = new ComponentDto()
.setId(10L)
.setKey("sample:src/main/xoo/sample/Sample.xoo")
.setLongName("src/main/xoo/sample/Sample.xoo")
.setName("Sample.xoo")
.setQualifier("FIL")
.setPath("src/main/xoo/sample/Sample.xoo")
.setSubProjectId(7L)
.setProjectId(7L);

ComponentDto project = new ComponentDto()
.setId(7L)
.setKey("sample")
.setLongName("Sample")
.setName("Sample")
.setQualifier("TRK")
.setProjectId(7L);

result.addComponents(Lists.<Component>newArrayList(component, project));
result.addProjects(Lists.<Component>newArrayList(project));

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_components.json");
}

@Test
public void issues_with_rules() throws Exception {
String issueKey = "ABCD";
Issue issue = new DefaultIssue()
.setKey(issueKey)
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setActionPlanKey("AP-ABCD")
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setAssignee("john")
.setReporter("steven")
.setAuthorLogin("Henry")
.setCreationDate(issueCreationDate);
issues.add(issue);

result.addRules(newArrayList(
Rule.create("squid", "AvoidCycle").setName("Avoid cycle").setDescription("Avoid cycle description")
));

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_rules.json");
}

@Test
public void issues_with_users() throws Exception {
String issueKey = "ABCD";
Issue issue = new DefaultIssue()
.setKey(issueKey)
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setActionPlanKey("AP-ABCD")
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setAssignee("john")
.setReporter("steven")
.setAuthorLogin("Henry")
.setCreationDate(issueCreationDate);
issues.add(issue);

result.addUsers(Lists.<User>newArrayList(
new DefaultUser().setName("John").setLogin("john").setActive(true).setEmail("john@email.com")
));

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_users.json");
}

@Test
public void issues_with_dates() throws Exception {
Date creationDate = DateUtils.parseDateTime("2014-01-22T19:10:03+0100");
Date updateDate = DateUtils.parseDateTime("2014-01-23T19:10:03+0100");
Date closedDate = DateUtils.parseDateTime("2014-01-24T19:10:03+0100");

Issue issue = createStandardIssue()
.setCreationDate(creationDate)
.setUpdateDate(updateDate)
.setCloseDate(closedDate);
issues.add(issue);

when(i18n.formatDateTime(any(Locale.class), eq(creationDate))).thenReturn("Jan 22, 2014 10:03 AM");
when(i18n.formatDateTime(any(Locale.class), eq(updateDate))).thenReturn("Jan 23, 2014 10:03 AM");
when(i18n.ageFromNow(any(Locale.class), eq(updateDate))).thenReturn("9 days");
when(i18n.formatDateTime(any(Locale.class), eq(closedDate))).thenReturn("Jan 24, 2014 10:03 AM");

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_dates.json");
}

@Test
public void issues_with_debt() throws Exception {
Duration debt = (Duration.create(7260L));
Issue issue = createStandardIssue().setDebt(debt);
issues.add(issue);

when(durations.format(any(Locale.class), eq(debt), eq(Durations.DurationFormat.SHORT))).thenReturn("2 hours 1 minutes");

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_debt.json");
}

@Test
public void issues_with_action_plan() throws Exception {
Issue issue = createStandardIssue()
.setActionPlanKey("AP-ABCD");
issues.add(issue);

MockUserSession.set();
WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_action_plan.json");
}

@Test
public void issues_with_attributes() throws Exception {
Issue issue = createStandardIssue()
.setAttribute("jira-issue-key", "SONAR-1234");
issues.add(issue);

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search");
request.execute().assertJson(getClass(), "issues_with_attributes.json");
}

@Test
public void issues_with_extra_fields() throws Exception {
Issue issue = createStandardIssue()
.setActionPlanKey("AP-ABCD")
.setAssignee("john");
issues.add(issue);

MockUserSession.set().setLogin("john");
when(issueService.listTransitions(eq(issue), any(UserSession.class))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));

result.addActionPlans(newArrayList((ActionPlan) new DefaultActionPlan().setKey("AP-ABCD").setName("1.0")));

result.addUsers(Lists.<User>newArrayList(
new DefaultUser().setName("John").setLogin("john")
));

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search").setParam("extra_fields", "actions,transitions,assigneeName,actionPlanName");
request.execute().assertJson(getClass(), "issues_with_extra_fields.json");
}

@Test
public void verify_issue_query_parameters() throws Exception {
Map<String, String> map = newHashMap();
map.put("issues", "ABCDE1234");
map.put("severities", "MAJOR,MINOR");
map.put("statuses", "CLOSED");
map.put("resolutions", "FALSE-POSITIVE");
map.put("resolved", "true");
map.put("components", "org.apache");
map.put("componentRoots", "org.sonar");
map.put("reporters", "marilyn");
map.put("assignees", "joanna");
map.put("languages", "xoo");
map.put("assigned", "true");
map.put("planned", "true");
map.put("hideRules", "true");
map.put("createdAt", "2013-04-15T09:08:24+0200");
map.put("createdAfter", "2013-04-16T09:08:24+0200");
map.put("createdBefore", "2013-04-17T09:08:24+0200");
map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
map.put("pageSize", "10");
map.put("pageIndex", "50");
map.put("sort", "CREATION_DATE");
map.put("asc", "true");

WsTester.TestRequest request = tester.newGetRequest("api/issues", "search").setParams(map);
request.execute();

ArgumentCaptor<IssueQuery> captor = ArgumentCaptor.forClass(IssueQuery.class);
verify(issueFinder).find(captor.capture());

IssueQuery query = captor.getValue();
assertThat(query.requiredRole()).isEqualTo("user");
assertThat(query.issueKeys()).containsOnly("ABCDE1234");
assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
assertThat(query.statuses()).containsOnly("CLOSED");
assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
assertThat(query.resolved()).isTrue();
assertThat(query.components()).containsOnly("org.apache");
assertThat(query.componentRoots()).containsOnly("org.sonar");
assertThat(query.reporters()).containsOnly("marilyn");
assertThat(query.assignees()).containsOnly("joanna");
assertThat(query.languages()).containsOnly("xoo");
assertThat(query.assigned()).isTrue();
assertThat(query.planned()).isTrue();
assertThat(query.hideRules()).isTrue();
assertThat(query.createdAt()).isEqualTo(DateUtils.parseDateTime("2013-04-15T09:08:24+0200"));
assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullReference"));
assertThat(query.pageSize()).isEqualTo(10);
assertThat(query.pageIndex()).isEqualTo(50);
assertThat(query.sort()).isEqualTo("CREATION_DATE");
assertThat(query.asc()).isTrue();
}

private DefaultIssue createStandardIssue() {
return createIssue();
}

private DefaultIssue createIssue() {
return new DefaultIssue()
.setKey("ABCD")
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo")
.setProjectKey("sample")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setCreationDate(issueCreationDate);
}

}

+ 12
- 65
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java View File

@@ -17,6 +17,7 @@
* 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.Lists;
@@ -31,7 +32,6 @@ import org.sonar.api.issue.ActionPlan;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueFinder;
import org.sonar.api.issue.IssueQuery;
import org.sonar.api.issue.action.Action;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.DefaultIssueComment;
import org.sonar.api.issue.internal.FieldDiffs;
@@ -42,7 +42,6 @@ import org.sonar.api.user.User;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssueQueryResult;
@@ -95,7 +94,7 @@ public class IssueShowActionTest {
List<Issue> issues;
DefaultIssueQueryResult result;

private Date issue_creation_date;
Date issueCreationDate;

WsTester tester;

@@ -108,12 +107,13 @@ public class IssueShowActionTest {

when(issueChangelogService.changelog(any(Issue.class))).thenReturn(mock(IssueChangelog.class));

issue_creation_date = DateUtils.parseDateTime("2014-01-22T19:10:03+0100");
when(i18n.formatDateTime(any(Locale.class), eq(issue_creation_date))).thenReturn("Jan 22, 2014 10:03 AM");
issueCreationDate = DateUtils.parseDateTime("2014-01-22T19:10:03+0100");
when(i18n.formatDateTime(any(Locale.class), eq(issueCreationDate))).thenReturn("Jan 22, 2014 10:03 AM");

when(i18n.message(any(Locale.class), eq("created"), eq((String) null))).thenReturn("Created");

tester = new WsTester(new IssuesWs(new IssueShowAction(issueFinder, issueService, issueChangelogService, actionService, debtModel, i18n, durations)));
tester = new WsTester(new IssuesWs(new IssueShowAction(issueFinder, issueChangelogService, new IssueActionsWriter(issueService, actionService), debtModel, i18n, durations),
mock(IssueSearchAction.class)));
}

@Test
@@ -125,18 +125,18 @@ public class IssueShowActionTest {
.setProjectKey("org.sonar.Sonar")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setCreationDate(issue_creation_date);
.setCreationDate(issueCreationDate);
issues.add(issue);

result.addComponents(Lists.<Component>newArrayList(new ComponentDto()
.setId(10L)
.setKey("org.sonar.server.issue.IssueClient")
.setLongName("SonarQube :: Issue Client")
.setName("SonarQube :: Issue Client")
.setQualifier("FIL")
.setSubProjectId(1L)
.setProjectId(1L)
@@ -146,6 +146,7 @@ public class IssueShowActionTest {
.setId(1L)
.setKey("org.sonar.Sonar")
.setLongName("SonarQube")
.setName("SonarQube")
.setProjectId(1L)
));

@@ -163,12 +164,11 @@ public class IssueShowActionTest {
.setProjectKey("org.sonar.Sonar")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setLine(12)
.setEffortToFix(2.0)
.setMessage("Fix it")
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setCreationDate(issue_creation_date);
.setCreationDate(issueCreationDate);
issues.add(issue);

// File
@@ -214,7 +214,7 @@ public class IssueShowActionTest {
.setResolution("FIXED")
.setStatus("CLOSED")
.setSeverity("MAJOR")
.setCreationDate(issue_creation_date);
.setCreationDate(issueCreationDate);
issues.add(issue);

// File
@@ -444,59 +444,6 @@ public class IssueShowActionTest {
request.execute().assertJson(getClass(), "show_issue_with_actions.json");
}

@Test
public void show_issue_with_set_severity_action() throws Exception {
DefaultIssue issue = createStandardIssue()
.setStatus("OPEN");
issues.add(issue);

MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ISSUE_ADMIN, issue.projectKey());
WsTester.TestRequest request = tester.newGetRequest("api/issues", "show").setParam("key", issue.key());
request.execute().assertJson(getClass(), "show_issue_with_set_severity_action.json");
}

@Test
public void show_issue_with_assign_to_me_action() throws Exception {
DefaultIssue issue = createStandardIssue()
.setStatus("OPEN");
issues.add(issue);

MockUserSession.set().setLogin("john");
WsTester.TestRequest request = tester.newGetRequest("api/issues", "show").setParam("key", issue.key());
request.execute().assertJson(getClass(), "show_issue_with_assign_to_me_action.json");
}

@Test
public void show_issue_without_assign_to_me_action() throws Exception {
DefaultIssue issue = createStandardIssue()
.setStatus("OPEN")
.setAssignee("john");
issues.add(issue);

result.addUsers(Lists.<User>newArrayList(
new DefaultUser().setLogin("john").setName("John")
));

MockUserSession.set().setLogin("john");
WsTester.TestRequest request = tester.newGetRequest("api/issues", "show").setParam("key", issue.key());
request.execute().assertJson(getClass(), "show_issue_without_assign_to_me_action.json");
}

@Test
public void show_issue_with_actions_defined_by_plugins() throws Exception {
Issue issue = createStandardIssue()
.setStatus("OPEN");
issues.add(issue);

Action action = mock(Action.class);
when(action.key()).thenReturn("link-to-jira");
when(actionService.listAvailableActions(issue)).thenReturn(newArrayList(action));

MockUserSession.set().setLogin("john");
WsTester.TestRequest request = tester.newGetRequest("api/issues", "show").setParam("key", issue.key());
request.execute().assertJson(getClass(), "show_issue_with_actions_defined_by_plugins.json");
}

@Test
public void show_issue_with_changelog() throws Exception {
Issue issue = createStandardIssue();
@@ -538,7 +485,7 @@ public class IssueShowActionTest {
.setComponentKey("org.sonar.server.issue.IssueClient")
.setProjectKey("org.sonar.Sonar")
.setRuleKey(RuleKey.of("squid", "AvoidCycle"))
.setCreationDate(issue_creation_date);
.setCreationDate(issueCreationDate);
}

private void addComponentAndProject() {

+ 14
- 7
sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java View File

@@ -27,9 +27,7 @@ import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.Durations;
import org.sonar.server.debt.DebtModelService;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueChangelogService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.ws.WsTester;

import static org.fest.assertions.Assertions.assertThat;
@@ -39,13 +37,22 @@ public class IssuesWsTest {

IssueShowAction showAction;

IssueSearchAction searchAction;

WsTester tester;

@Before
public void setUp() throws Exception {
showAction = new IssueShowAction(mock(IssueFinder.class), mock(IssueService.class), mock(IssueChangelogService.class), mock(ActionService.class),
mock(DebtModelService.class), mock(I18n.class), mock(Durations.class));
tester = new WsTester(new IssuesWs(showAction));
IssueFinder issueFinder = mock(IssueFinder.class);
IssueChangelogService issueChangelogService = mock(IssueChangelogService.class);
IssueActionsWriter actionsWriter = mock(IssueActionsWriter.class);
DebtModelService debtModelService = mock(DebtModelService.class);
I18n i18n = mock(I18n.class);
Durations durations = mock(Durations.class);

showAction = new IssueShowAction(issueFinder, issueChangelogService, actionsWriter, debtModelService, i18n, durations);
searchAction = new IssueSearchAction(issueFinder, actionsWriter, i18n, durations);
tester = new WsTester(new IssuesWs(showAction, searchAction));
}

@Test
@@ -87,9 +94,9 @@ public class IssuesWsTest {
assertThat(show.since()).isEqualTo("3.6");
assertThat(show.isPost()).isFalse();
assertThat(show.isInternal()).isFalse();
assertThat(show.handler()).isInstanceOf(RailsHandler.class);
assertThat(show.handler()).isSameAs(searchAction);
assertThat(show.responseExampleAsString()).isNotEmpty();
assertThat(show.params()).hasSize(19);
assertThat(show.params()).hasSize(23);
}

@Test

+ 32
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues.json View File

@@ -0,0 +1,32 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"resolution": "FIXED",
"status": "CLOSED",
"severity": "MAJOR",
"message": "Fix it",
"line": 12,
"reporter": "steven",
"assignee": "john",
"author": "Henry",
"actionPlan": "AP-ABCD",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [],
"users": []
}

+ 24
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_action_plan.json View File

@@ -0,0 +1,24 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"actionPlan" : "AP-ABCD",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [],
"users": []
}

+ 26
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_attributes.json View File

@@ -0,0 +1,26 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"creationDate": "2014-01-22T19:10:03+0100",
"attr": {
"jira-issue-key": "SONAR-1234"
}
}
],
"components": [],
"projects": [],
"rules": [],
"users": []
}

+ 58
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_components.json View File

@@ -0,0 +1,58 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"resolution": "FIXED",
"status": "CLOSED",
"severity": "MAJOR",
"message": "Fix it",
"line": 12,
"reporter": "steven",
"assignee": "john",
"author": "Henry",
"actionPlan": "AP-ABCD",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [
{
"key": "sample:src/main/xoo/sample/Sample.xoo",
"id": 10,
"qualifier": "FIL",
"name": "Sample.xoo",
"longName": "src/main/xoo/sample/Sample.xoo",
"path": "src/main/xoo/sample/Sample.xoo",
"projectId": 7,
"subProjectId": 7
},
{
"key": "sample",
"id": 7,
"qualifier": "TRK",
"name": "Sample",
"longName": "Sample"
}
],
"projects": [
{
"key": "sample",
"id": 7,
"qualifier": "TRK",
"name": "Sample",
"longName": "Sample"
}
],
"rules": [],
"users": []
}

+ 26
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_dates.json View File

@@ -0,0 +1,26 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"creationDate": "2014-01-22T19:10:03+0100",
"updateDate": "2014-01-23T19:10:03+0100",
"fUpdateAge": "9 days",
"closeDate": "2014-01-24T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [],
"users": []
}

+ 24
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_debt.json View File

@@ -0,0 +1,24 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"debt": "2 hours 1 minutes",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [],
"users": []
}

+ 39
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_extra_fields.json View File

@@ -0,0 +1,39 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"creationDate": "2014-01-22T19:10:03+0100",
"assignee": "john",
"assigneeName" : "John",
"actionPlan" : "AP-ABCD",
"actionPlanName" : "1.0",
"actions": [
"comment", "assign", "plan"
],
"transitions": [
"reopen"
]
}
],
"components": [],
"projects": [],
"rules": [],
"users": [
{
"login": "john",
"name": "John",
"active": false
}
]
}

+ 39
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_rules.json View File

@@ -0,0 +1,39 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"resolution": "FIXED",
"status": "CLOSED",
"severity": "MAJOR",
"message": "Fix it",
"line": 12,
"reporter": "steven",
"assignee": "john",
"author": "Henry",
"actionPlan": "AP-ABCD",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [
{
"key": "squid:AvoidCycle",
"name": "Avoid cycle",
"desc": "Avoid cycle description",
"status": "READY"
}
],
"users": []
}

+ 39
- 0
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueSearchActionTest/issues_with_users.json View File

@@ -0,0 +1,39 @@
{
"maxResultsReached": true,
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2,
"fTotal": "2",
"pages": 1
},
"issues": [
{
"key": "ABCD",
"component": "sample:src/main/xoo/sample/Sample.xoo",
"project": "sample",
"rule": "squid:AvoidCycle",
"resolution": "FIXED",
"status": "CLOSED",
"severity": "MAJOR",
"message": "Fix it",
"line": 12,
"reporter": "steven",
"assignee": "john",
"author": "Henry",
"actionPlan": "AP-ABCD",
"creationDate": "2014-01-22T19:10:03+0100"
}
],
"components": [],
"projects": [],
"rules": [],
"users": [
{
"login": "john",
"name": "John",
"active": true,
"email": "john@email.com"
}
]
}

+ 0
- 27
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_actions_defined_by_plugins.json View File

@@ -1,27 +0,0 @@
{
"issue": {
"key": "ABCD",
"component": "org.sonar.server.issue.IssueClient",
"componentLongName": "SonarQube :: Issue Client",
"componentQualifier": "FIL",
"project": "org.sonar.Sonar",
"projectName": "SonarQube",
"rule": "squid:AvoidCycle",
"ruleName": "Avoid cycle",
"status": "OPEN",
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"transitions": [],
"actions": [
"comment", "assign", "assign_to_me", "plan", "link-to-jira"
],
"comments": [],
"changelog": [
{
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"diffs": ["Created"]
}
]
}
}

+ 0
- 27
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_assign_to_me_action.json View File

@@ -1,27 +0,0 @@
{
"issue": {
"key": "ABCD",
"component": "org.sonar.server.issue.IssueClient",
"componentLongName": "SonarQube :: Issue Client",
"componentQualifier": "FIL",
"project": "org.sonar.Sonar",
"projectName": "SonarQube",
"rule": "squid:AvoidCycle",
"ruleName": "Avoid cycle",
"status": "OPEN",
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"transitions": [],
"actions": [
"comment", "assign", "assign_to_me", "plan"
],
"comments": [],
"changelog": [
{
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"diffs": ["Created"]
}
]
}
}

+ 0
- 27
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_with_set_severity_action.json View File

@@ -1,27 +0,0 @@
{
"issue": {
"key": "ABCD",
"component": "org.sonar.server.issue.IssueClient",
"componentLongName": "SonarQube :: Issue Client",
"componentQualifier": "FIL",
"project": "org.sonar.Sonar",
"projectName": "SonarQube",
"rule": "squid:AvoidCycle",
"ruleName": "Avoid cycle",
"status": "OPEN",
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"transitions": [],
"actions": [
"comment", "assign", "assign_to_me", "plan", "set_severity"
],
"comments": [],
"changelog": [
{
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"diffs": ["Created"]
}
]
}
}

+ 0
- 29
sonar-server/src/test/resources/org/sonar/server/issue/ws/IssueShowActionTest/show_issue_without_assign_to_me_action.json View File

@@ -1,29 +0,0 @@
{
"issue": {
"key": "ABCD",
"component": "org.sonar.server.issue.IssueClient",
"componentLongName": "SonarQube :: Issue Client",
"componentQualifier": "FIL",
"project": "org.sonar.Sonar",
"projectName": "SonarQube",
"rule": "squid:AvoidCycle",
"ruleName": "Avoid cycle",
"assignee": "john",
"assigneeName": "John",
"status": "OPEN",
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"transitions": [],
"actions": [
"comment", "assign", "plan"
],
"comments": [],
"changelog": [
{
"creationDate": "2014-01-22T19:10:03+0100",
"fCreationDate": "Jan 22, 2014 10:03 AM",
"diffs": ["Created"]
}
]
}
}

Loading…
Cancel
Save