- protobuf specification of response - do not rely on ES docs to return data (will allow to remove _source from ES index) - sanitize response format - sanitize request parameters (no more 'hideXXX' and 'f')tags/5.2-RC1
@@ -28,6 +28,7 @@ import org.apache.commons.lang.builder.ReflectionToStringBuilder; | |||
import org.apache.commons.lang.builder.ToStringStyle; | |||
import org.elasticsearch.action.search.SearchResponse; | |||
import org.elasticsearch.search.aggregations.Aggregation; | |||
import org.elasticsearch.search.aggregations.Aggregations; | |||
import org.elasticsearch.search.aggregations.HasAggregations; | |||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram; | |||
import org.elasticsearch.search.aggregations.bucket.missing.Missing; | |||
@@ -38,20 +39,22 @@ public class Facets { | |||
public static final String TOTAL = "total"; | |||
private final Map<String, LinkedHashMap<String, Long>> facetsByName = new LinkedHashMap<>(); | |||
private final LinkedHashMap<String, LinkedHashMap<String, Long>> facetsByName; | |||
public Facets(LinkedHashMap<String, LinkedHashMap<String, Long>> facetsByName) { | |||
this.facetsByName = facetsByName; | |||
} | |||
public Facets(SearchResponse response) { | |||
if (response.getAggregations() != null) { | |||
for (Aggregation facet : response.getAggregations()) { | |||
this.facetsByName = new LinkedHashMap<>(); | |||
Aggregations aggregations = response.getAggregations(); | |||
if (aggregations != null) { | |||
for (Aggregation facet : aggregations) { | |||
processAggregation(facet); | |||
} | |||
} | |||
} | |||
public Facets(Terms terms) { | |||
processTermsAggregation(terms); | |||
} | |||
private void processAggregation(Aggregation aggregation) { | |||
if (Missing.class.isAssignableFrom(aggregation.getClass())) { | |||
processMissingAggregation((Missing) aggregation); |
@@ -20,29 +20,10 @@ | |||
package org.sonar.server.issue; | |||
import com.google.common.base.Preconditions; | |||
import com.google.common.base.Predicate; | |||
import com.google.common.base.Strings; | |||
import com.google.common.collect.Iterables; | |||
import java.util.Date; | |||
import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.component.Component; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.action.Action; | |||
import org.sonar.api.issue.action.Actions; | |||
import org.sonar.api.issue.action.Function; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.core.issue.IssueChangeContext; | |||
import org.sonar.core.issue.IssueUpdater; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.property.PropertiesDao; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.server.user.UserSession; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
@@ -53,144 +34,30 @@ import static com.google.common.collect.Lists.newArrayList; | |||
@ServerSide | |||
public class ActionService { | |||
private final DbClient dbClient; | |||
private final IssueService issueService; | |||
private final IssueStorage issueStorage; | |||
private final IssueUpdater updater; | |||
private final Settings settings; | |||
private final PropertiesDao propertiesDao; | |||
private final Actions actions; | |||
public ActionService(DbClient dbClient, IssueService issueService, IssueStorage issueStorage, IssueUpdater updater, Settings settings, PropertiesDao propertiesDao, | |||
Actions actions) { | |||
this.dbClient = dbClient; | |||
this.issueService = issueService; | |||
this.issueStorage = issueStorage; | |||
this.updater = updater; | |||
this.settings = settings; | |||
this.propertiesDao = propertiesDao; | |||
this.actions = actions; | |||
} | |||
public List<Action> listAllActions() { | |||
return actions.list(); | |||
} | |||
public List<Action> listAvailableActions(String issueKey) { | |||
DbSession session = dbClient.openSession(false); | |||
try { | |||
return listAvailableActions(issueService.getByKeyForUpdate(session, issueKey).toDefaultIssue()); | |||
} finally { | |||
session.close(); | |||
} | |||
} | |||
public List<Action> listAvailableActions(Issue issue) { | |||
return newArrayList(Iterables.filter(actions.list(), new SupportIssue(issue))); | |||
} | |||
public Issue execute(String issueKey, String actionKey, UserSession userSession) { | |||
Preconditions.checkArgument(!Strings.isNullOrEmpty(actionKey), "Missing action"); | |||
DbSession session = dbClient.openSession(false); | |||
try { | |||
DefaultIssue issue = issueService.getByKeyForUpdate(session, issueKey).toDefaultIssue(); | |||
Action action = getAction(actionKey); | |||
if (action == null) { | |||
throw new IllegalArgumentException("Action is not found : " + actionKey); | |||
private final UserSession userSession; | |||
public ActionService(UserSession userSession) { | |||
this.userSession = userSession; | |||
} | |||
public List<String> listAvailableActions(IssueDto issue) { | |||
List<String> actions = newArrayList(); | |||
String login = userSession.getLogin(); | |||
if (login != null) { | |||
actions.add("comment"); | |||
if (issue.getResolution() == null) { | |||
actions.add("assign"); | |||
actions.add("set_tags"); | |||
if (!login.equals(issue.getAssignee())) { | |||
actions.add("assign_to_me"); | |||
} | |||
actions.add("plan"); | |||
String projectUuid = issue.getProjectUuid(); | |||
if (projectUuid != null && userSession.hasProjectPermissionByUuid(UserRole.ISSUE_ADMIN, projectUuid)) { | |||
actions.add("set_severity"); | |||
} | |||
} | |||
if (!action.supports(issue)) { | |||
throw new IllegalStateException("A condition is not respected"); | |||
} | |||
IssueChangeContext changeContext = IssueChangeContext.createUser(new Date(), userSession.getLogin()); | |||
Component project = dbClient.componentDao().selectOrFailByKey(session, issue.projectKey()); | |||
FunctionContext functionContext = new FunctionContext(issue, updater, changeContext, getProjectSettings(project)); | |||
for (Function function : action.functions()) { | |||
function.execute(functionContext); | |||
} | |||
issueStorage.save(issue); | |||
return issue; | |||
} finally { | |||
session.close(); | |||
} | |||
} | |||
@CheckForNull | |||
private Action getAction(final String actionKey) { | |||
return Iterables.find(actions.list(), new ActionMatchKey(actionKey), null); | |||
} | |||
// TODO org.sonar.server.properties.ProjectSettings should be used instead | |||
public Settings getProjectSettings(Component project) { | |||
Settings projectSettings = new Settings(settings); | |||
List<PropertyDto> properties = propertiesDao.selectProjectProperties(project.key()); | |||
for (PropertyDto dto : properties) { | |||
projectSettings.setProperty(dto.getKey(), dto.getValue()); | |||
} | |||
return projectSettings; | |||
} | |||
static class FunctionContext implements Function.Context { | |||
private final DefaultIssue issue; | |||
private final IssueUpdater updater; | |||
private final IssueChangeContext changeContext; | |||
private final Settings projectSettings; | |||
FunctionContext(DefaultIssue issue, IssueUpdater updater, IssueChangeContext changeContext, Settings projectSettings) { | |||
this.updater = updater; | |||
this.issue = issue; | |||
this.changeContext = changeContext; | |||
this.projectSettings = projectSettings; | |||
} | |||
@Override | |||
public Issue issue() { | |||
return issue; | |||
} | |||
@Override | |||
public Settings projectSettings() { | |||
return projectSettings; | |||
} | |||
@Override | |||
public Function.Context setAttribute(String key, @Nullable String value) { | |||
updater.setAttribute(issue, key, value, changeContext); | |||
return this; | |||
} | |||
@Override | |||
public Function.Context addComment(String text) { | |||
updater.addComment(issue, text, changeContext); | |||
return this; | |||
} | |||
} | |||
private static class SupportIssue implements Predicate<Action> { | |||
private final Issue issue; | |||
public SupportIssue(Issue issue) { | |||
this.issue = issue; | |||
} | |||
@Override | |||
public boolean apply(@Nonnull Action action) { | |||
return action.supports(issue); | |||
} | |||
} | |||
private static class ActionMatchKey implements Predicate<Action> { | |||
private final String key; | |||
public ActionMatchKey(String key) { | |||
this.key = key; | |||
} | |||
@Override | |||
public boolean apply(@Nonnull Action action) { | |||
return action.key().equals(key); | |||
} | |||
return actions; | |||
} | |||
} |
@@ -27,7 +27,6 @@ import com.google.common.collect.ImmutableList; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.ImmutableMultimap; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Iterables; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.collect.Maps; | |||
import com.google.common.collect.Sets; | |||
@@ -81,7 +80,6 @@ import org.sonar.server.user.ws.UserJsonWriter; | |||
import org.sonar.server.util.RubyUtils; | |||
import org.sonar.server.util.Validation; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static com.google.common.collect.Maps.newHashMap; | |||
/** | |||
@@ -176,10 +174,6 @@ public class InternalRubyIssueService { | |||
return changelogService.formatDiffs(diffs); | |||
} | |||
public List<String> listPluginActions() { | |||
return newArrayList(Iterables.transform(actionService.listAllActions(), ActionToKey.INSTANCE)); | |||
} | |||
public List<DefaultIssueComment> findComments(String issueKey) { | |||
return commentService.findComments(issueKey); | |||
} | |||
@@ -231,7 +225,7 @@ public class InternalRubyIssueService { | |||
public Result<IssueComment> addComment(String issueKey, String text) { | |||
Result<IssueComment> result = Result.of(); | |||
try { | |||
result.set(commentService.addComment(issueKey, text, userSession)); | |||
result.set(commentService.addComment(issueKey, text)); | |||
} catch (Exception e) { | |||
result.addError(e.getMessage()); | |||
} | |||
@@ -239,13 +233,13 @@ public class InternalRubyIssueService { | |||
} | |||
public IssueComment deleteComment(String commentKey) { | |||
return commentService.deleteComment(commentKey, userSession); | |||
return commentService.deleteComment(commentKey); | |||
} | |||
public Result<IssueComment> editComment(String commentKey, String newText) { | |||
Result<IssueComment> result = Result.of(); | |||
try { | |||
result.set(commentService.editComment(commentKey, newText, userSession)); | |||
result.set(commentService.editComment(commentKey, newText)); | |||
} catch (Exception e) { | |||
result.addError(e.getMessage()); | |||
} | |||
@@ -434,24 +428,6 @@ public class InternalRubyIssueService { | |||
return result; | |||
} | |||
public Result<Issue> executeAction(String issueKey, String actionKey) { | |||
Result<Issue> result = Result.of(); | |||
try { | |||
result.set(actionService.execute(issueKey, actionKey, userSession)); | |||
} catch (Exception e) { | |||
result.addError(e.getMessage()); | |||
} | |||
return result; | |||
} | |||
public List<Action> listActions(String issueKey) { | |||
return actionService.listAvailableActions(issueKey); | |||
} | |||
public List<Action> listActions(Issue issue) { | |||
return actionService.listAvailableActions(issue); | |||
} | |||
public IssueQuery emptyIssueQuery() { | |||
return issueQueryService.createFromMap(Maps.<String, Object>newHashMap()); | |||
} |
@@ -44,28 +44,26 @@ import java.util.List; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
/** | |||
* @since 3.6 | |||
*/ | |||
@ServerSide | |||
public class IssueCommentService { | |||
private final DbClient dbClient; | |||
private final IssueService issueService; | |||
private final IssueUpdater updater; | |||
private final UserSession userSession; | |||
public IssueCommentService(DbClient dbClient, IssueService issueService, IssueUpdater updater) { | |||
public IssueCommentService(DbClient dbClient, IssueService issueService, IssueUpdater updater, UserSession userSession) { | |||
this.dbClient = dbClient; | |||
this.issueService = issueService; | |||
this.updater = updater; | |||
this.userSession = userSession; | |||
} | |||
public List<DefaultIssueComment> findComments(String issueKey) { | |||
return findComments(newArrayList(issueKey)); | |||
} | |||
public List<DefaultIssueComment> findComments(DbSession session, String issueKey) { | |||
return findComments(session, newArrayList(issueKey)); | |||
public List<DefaultIssueComment> findComments(DbSession dbSession, String issueKey) { | |||
return findComments(dbSession, newArrayList(issueKey)); | |||
} | |||
public List<DefaultIssueComment> findComments(Collection<String> issueKeys) { | |||
@@ -85,7 +83,7 @@ public class IssueCommentService { | |||
return dbClient.issueChangeDao().selectCommentByKey(commentKey); | |||
} | |||
public IssueComment addComment(String issueKey, String text, UserSession userSession) { | |||
public IssueComment addComment(String issueKey, String text) { | |||
verifyLoggedIn(userSession); | |||
if (StringUtils.isBlank(text)) { | |||
throw new BadRequestException("Cannot add empty comments to an issue"); | |||
@@ -110,7 +108,7 @@ public class IssueCommentService { | |||
} | |||
} | |||
public IssueComment deleteComment(String commentKey, UserSession userSession) { | |||
public IssueComment deleteComment(String commentKey) { | |||
DefaultIssueComment comment = dbClient.issueChangeDao().selectCommentByKey(commentKey); | |||
if (comment == null) { | |||
throw new NotFoundException("Comment not found: " + commentKey); | |||
@@ -126,7 +124,7 @@ public class IssueCommentService { | |||
return comment; | |||
} | |||
public IssueComment editComment(String commentKey, String text, UserSession userSession) { | |||
public IssueComment editComment(String commentKey, String text) { | |||
DefaultIssueComment comment = dbClient.issueChangeDao().selectCommentByKey(commentKey); | |||
if (StringUtils.isBlank(text)) { | |||
throw new BadRequestException("Cannot add empty comments to an issue"); | |||
@@ -149,6 +147,10 @@ public class IssueCommentService { | |||
return comment; | |||
} | |||
public boolean canEditOrDelete(IssueChangeDto dto) { | |||
return userSession.isLoggedIn() && userSession.getLogin().equals(dto.getUserLogin()); | |||
} | |||
private void verifyLoggedIn(UserSession userSession) { | |||
if (!userSession.isLoggedIn()) { | |||
throw new UnauthorizedException("User is not logged in"); |
@@ -135,7 +135,7 @@ public class IssueService { | |||
List<Transition> allowedTransitions = new ArrayList<>(); | |||
for (Transition transition : outTransitions) { | |||
String projectUuid = issue.projectUuid(); | |||
if (StringUtils.isBlank(transition.requiredProjectPermission()) || | |||
if (userSession.isLoggedIn() && StringUtils.isBlank(transition.requiredProjectPermission()) || | |||
(projectUuid != null && userSession.hasProjectPermissionByUuid(transition.requiredProjectPermission(), projectUuid))) { | |||
allowedTransitions.add(transition); | |||
} |
@@ -80,9 +80,6 @@ public class IssueActionsWriter { | |||
if (projectUuid != null && userSession.hasProjectPermissionByUuid(UserRole.ISSUE_ADMIN, projectUuid)) { | |||
actions.add("set_severity"); | |||
} | |||
for (Action action : actionService.listAvailableActions(issue)) { | |||
actions.add(action.key()); | |||
} | |||
} | |||
} | |||
return actions; |
@@ -0,0 +1,369 @@ | |||
/* | |||
* 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.base.Function; | |||
import com.google.common.collect.Lists; | |||
import com.google.common.io.Resources; | |||
import java.util.Collection; | |||
import java.util.EnumSet; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.issue.Issue; | |||
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.utils.Paging; | |||
import org.sonar.core.rule.RuleKeyFunctions; | |||
import org.sonar.server.es.Facets; | |||
import org.sonar.server.es.SearchOptions; | |||
import org.sonar.server.es.SearchResult; | |||
import org.sonar.server.issue.IssueQuery; | |||
import org.sonar.server.issue.IssueQueryService; | |||
import org.sonar.server.issue.IssueService; | |||
import org.sonar.server.issue.filter.IssueFilterParameters; | |||
import org.sonar.server.issue.index.IssueDoc; | |||
import org.sonar.server.issue.index.IssueIndex; | |||
import org.sonar.server.user.UserSession; | |||
import org.sonar.server.ws.WsUtils; | |||
import org.sonarqube.ws.Issues; | |||
import static com.google.common.collect.FluentIterable.from; | |||
import static com.google.common.collect.Iterables.concat; | |||
import static java.util.Collections.singletonList; | |||
public class Search2Action implements IssuesWsAction { | |||
private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. "; | |||
public static final String ADDITIONAL_FIELDS = "additionalFields"; | |||
public static final String SEARCH_ACTION = "search2"; | |||
private final UserSession userSession; | |||
private final IssueService service; | |||
private final IssueQueryService issueQueryService; | |||
private final SearchResponseLoader searchResponseLoader; | |||
private final SearchResponseFormat searchResponseFormat; | |||
public Search2Action(UserSession userSession, IssueService service, IssueQueryService issueQueryService, | |||
SearchResponseLoader searchResponseLoader, SearchResponseFormat searchResponseFormat) { | |||
this.userSession = userSession; | |||
this.service = service; | |||
this.issueQueryService = issueQueryService; | |||
this.searchResponseLoader = searchResponseLoader; | |||
this.searchResponseFormat = searchResponseFormat; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller | |||
.createAction(SEARCH_ACTION) | |||
.setHandler(this) | |||
.setDescription( | |||
"Search for issues. Requires Browse permission on project(s)") | |||
.setSince("3.6") | |||
.setResponseExample(Resources.getResource(this.getClass(), "example-search.json")); | |||
action.addPagingParams(100); | |||
action.createParam(Param.FACETS) | |||
.setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") | |||
.setPossibleValues(IssueIndex.SUPPORTED_FACETS); | |||
action.createParam(IssueFilterParameters.FACET_MODE) | |||
.setDefaultValue(IssueFilterParameters.FACET_MODE_COUNT) | |||
.setDescription("Choose the returned value for facet items, either count of issues or sum of debt.") | |||
.setPossibleValues(IssueFilterParameters.FACET_MODE_COUNT, IssueFilterParameters.FACET_MODE_DEBT); | |||
action.addSortParams(IssueQuery.SORTS, null, true); | |||
action.createParam(ADDITIONAL_FIELDS) | |||
.setDescription("Comma-separated list of the optional fields to be returned in response.") | |||
.setPossibleValues(SearchAdditionalField.possibleValues()); | |||
addComponentRelatedParams(action); | |||
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.RULES) | |||
.setDescription("Comma-separated list of coding rule keys. Format is <repository>:<rule>") | |||
.setExampleValue("squid:AvoidCycles"); | |||
action.createParam(IssueFilterParameters.TAGS) | |||
.setDescription("Comma-separated list of tags.") | |||
.setExampleValue("security,convention"); | |||
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.AUTHORS) | |||
.setDescription("Comma-separated list of SCM accounts") | |||
.setExampleValue("torvalds@linux-foundation.org"); | |||
action.createParam(IssueFilterParameters.ASSIGNEES) | |||
.setDescription("Comma-separated list of assignee logins. The value '__me__' can be used as a placeholder for user who performs the request") | |||
.setExampleValue("admin,usera,__me__"); | |||
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(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 (exclusive). Format: date or datetime ISO formats. If this parameter is set, createdSince must not be set") | |||
.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.CREATED_IN_LAST) | |||
.setDescription("To retrieve issues created during a time span before the current time (exclusive). " + | |||
"Accepted units are 'y' for year, 'm' for month, 'w' for week and 'd' for day. " + | |||
"If this parameter is set, createdAfter must not be set") | |||
.setExampleValue("1m2w (1 month 2 weeks)"); | |||
} | |||
private static void addComponentRelatedParams(WebService.NewAction action) { | |||
action.createParam(IssueFilterParameters.ON_COMPONENT_ONLY) | |||
.setDescription("Return only issues at a component's level, not on its descendants (modules, directories, files, etc). " + | |||
"This parameter is only considered when componentKeys or componentUuids is set. " + | |||
"Using the deprecated componentRoots or componentRootUuids parameters will set this parameter to false. " + | |||
"Using the deprecated components parameter will set this parameter to true.") | |||
.setBooleanPossibleValues() | |||
.setDefaultValue("false"); | |||
action.createParam(IssueFilterParameters.COMPONENT_KEYS) | |||
.setDescription("To retrieve issues associated to a specific list of components sub-components (comma-separated list of component keys). " + | |||
"A component can be a view, developer, project, module, directory or file. " + | |||
"If this parameter is set, componentUuids must not be set.") | |||
.setExampleValue("org.apache.struts:struts:org.apache.struts.Action"); | |||
action.createParam(IssueFilterParameters.COMPONENTS) | |||
.setDescription("Deprecated since 5.1. If used, will have the same meaning as componentKeys AND onComponentOnly=true."); | |||
action.createParam(IssueFilterParameters.COMPONENT_UUIDS) | |||
.setDescription("To retrieve issues associated to a specific list of components their sub-components (comma-separated list of component UUIDs). " + | |||
INTERNAL_PARAMETER_DISCLAIMER + | |||
"A component can be a project, module, directory or file. " + | |||
"If this parameter is set, componentKeys must not be set.") | |||
.setExampleValue("584a89f2-8037-4f7b-b82c-8b45d2d63fb2"); | |||
action.createParam(IssueFilterParameters.COMPONENT_ROOTS) | |||
.setDescription("Deprecated since 5.1. If used, will have the same meaning as componentKeys AND onComponentOnly=false."); | |||
action.createParam(IssueFilterParameters.COMPONENT_ROOT_UUIDS) | |||
.setDescription("Deprecated since 5.1. If used, will have the same meaning as componentUuids AND onComponentOnly=false."); | |||
action.createParam(IssueFilterParameters.PROJECTS) | |||
.setDescription("Deprecated since 5.1. See projectKeys"); | |||
action.createParam(IssueFilterParameters.PROJECT_KEYS) | |||
.setDescription("To retrieve issues associated to a specific list of projects (comma-separated list of project keys). " + | |||
INTERNAL_PARAMETER_DISCLAIMER + | |||
"If this parameter is set, projectUuids must not be set.") | |||
.setDeprecatedKey(IssueFilterParameters.PROJECTS) | |||
.setExampleValue("org.apache.struts:struts:org.apache.struts.Action"); | |||
action.createParam(IssueFilterParameters.PROJECT_UUIDS) | |||
.setDescription("To retrieve issues associated to a specific list of projects (comma-separated list of project UUIDs). " + | |||
INTERNAL_PARAMETER_DISCLAIMER + | |||
"Views are not supported. If this parameter is set, projectKeys must not be set.") | |||
.setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92"); | |||
action.createParam(IssueFilterParameters.MODULE_UUIDS) | |||
.setDescription("To retrieve issues associated to a specific list of modules (comma-separated list of module UUIDs). " + | |||
INTERNAL_PARAMETER_DISCLAIMER + | |||
"Views are not supported. If this parameter is set, moduleKeys must not be set.") | |||
.setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92"); | |||
action.createParam(IssueFilterParameters.DIRECTORIES) | |||
.setDescription("Since 5.1. To retrieve issues associated to a specific list of directories (comma-separated list of directory paths). " + | |||
"This parameter is only meaningful when a module is selected. " + | |||
INTERNAL_PARAMETER_DISCLAIMER) | |||
.setExampleValue("src/main/java/org/sonar/server/"); | |||
action.createParam(IssueFilterParameters.FILE_UUIDS) | |||
.setDescription("To retrieve issues associated to a specific list of files (comma-separated list of file UUIDs). " + | |||
INTERNAL_PARAMETER_DISCLAIMER) | |||
.setExampleValue("bdd82933-3070-4903-9188-7d8749e8bb92"); | |||
} | |||
@Override | |||
public final void handle(Request request, Response response) throws Exception { | |||
// prepare the Elasticsearch request | |||
SearchOptions options = new SearchOptions(); | |||
options.setPage(request.mandatoryParamAsInt(Param.PAGE), request.mandatoryParamAsInt(Param.PAGE_SIZE)); | |||
options.addFacets(request.paramAsStrings(Param.FACETS)); | |||
EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request); | |||
IssueQuery query = issueQueryService.createFromRequest(request); | |||
// execute request | |||
SearchResult<IssueDoc> result = service.search(query, options); | |||
List<String> issueKeys = from(result.getDocs()).transform(IssueDocToKey.INSTANCE).toList(); | |||
// load the additional information to be returned in response | |||
SearchResponseLoader.Collector collector = new SearchResponseLoader.Collector(additionalFields, issueKeys); | |||
collectLoggedInUser(collector); | |||
collectRequestParams(collector, request); | |||
Facets facets = null; | |||
if (!options.getFacets().isEmpty()) { | |||
facets = result.getFacets(); | |||
// add missing values to facets. For example if assignee "john" and facet on "assignees" are requested, then | |||
// "john" should always be listed in the facet. If it is not present, then it is added with value zero. | |||
// This is a constraint from webapp UX. | |||
completeFacets(facets, options, request); | |||
collectFacets(collector, facets); | |||
} | |||
SearchResponseData data = searchResponseLoader.load(collector, facets); | |||
// format response | |||
// Filter and reorder facets according to the requested ordered names. | |||
// Must be done after loading of data as the "hidden" facet "debt" | |||
// can be used to get total debt. | |||
facets = reorderFacets(facets, options.getFacets()); | |||
// FIXME allow long in Paging | |||
Paging paging = Paging.create(options.getLimit(), options.getPage(), (int) result.getTotal()); | |||
Issues.Search responseBody = searchResponseFormat.format(additionalFields, data, paging, facets); | |||
WsUtils.writeProtobuf(responseBody, request, response); | |||
} | |||
private Facets reorderFacets(@Nullable Facets facets, Collection<String> orderedNames) { | |||
if (facets == null) { | |||
return null; | |||
} | |||
LinkedHashMap<String, LinkedHashMap<String, Long>> orderedFacets = new LinkedHashMap<>(); | |||
for (String facetName : orderedNames) { | |||
LinkedHashMap<String, Long> facet = facets.get(facetName); | |||
if (facet != null) { | |||
orderedFacets.put(facetName, facet); | |||
} | |||
} | |||
return new Facets(orderedFacets); | |||
} | |||
private void completeFacets(Facets facets, SearchOptions options, Request request) { | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.SEVERITIES, Severity.ALL); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.STATUSES, Issue.STATUSES); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.RESOLUTIONS, concat(singletonList(""), Issue.RESOLUTIONS)); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.PROJECT_UUIDS, request.paramAsStrings(IssueFilterParameters.PROJECT_UUIDS)); | |||
List<String> assignees = Lists.newArrayList(""); | |||
List<String> assigneesFromRequest = request.paramAsStrings(IssueFilterParameters.ASSIGNEES); | |||
if (assigneesFromRequest != null) { | |||
assignees.addAll(assigneesFromRequest); | |||
assignees.remove(IssueQueryService.LOGIN_MYSELF); | |||
} | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.ASSIGNEES, assignees); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.FACET_ASSIGNED_TO_ME, singletonList(userSession.getLogin())); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.REPORTERS, request.paramAsStrings(IssueFilterParameters.REPORTERS)); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.RULES, request.paramAsStrings(IssueFilterParameters.RULES)); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.LANGUAGES, request.paramAsStrings(IssueFilterParameters.LANGUAGES)); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.TAGS, request.paramAsStrings(IssueFilterParameters.TAGS)); | |||
List<String> actionPlans = Lists.newArrayList(""); | |||
List<String> actionPlansFromRequest = request.paramAsStrings(IssueFilterParameters.ACTION_PLANS); | |||
if (actionPlansFromRequest != null) { | |||
actionPlans.addAll(actionPlansFromRequest); | |||
} | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.ACTION_PLANS, actionPlans); | |||
addMandatoryValuesToFacet(facets, IssueFilterParameters.COMPONENT_UUIDS, request.paramAsStrings(IssueFilterParameters.COMPONENT_UUIDS)); | |||
for (String facetName : options.getFacets()) { | |||
LinkedHashMap<String, Long> buckets = facets.get(facetName); | |||
if (!IssueFilterParameters.FACET_ASSIGNED_TO_ME.equals(facetName)) { | |||
if (buckets != null) { | |||
List<String> requestParams = request.paramAsStrings(facetName); | |||
if (requestParams != null) { | |||
for (String param : requestParams) { | |||
if (!buckets.containsKey(param) && !IssueQueryService.LOGIN_MYSELF.equals(param)) { | |||
// Prevent appearance of a glitch value due to dedicated parameter for this facet | |||
buckets.put(param, 0L); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
private void addMandatoryValuesToFacet(Facets facets, String facetName, @Nullable Iterable<String> mandatoryValues) { | |||
Map<String, Long> buckets = facets.get(facetName); | |||
if (buckets != null && mandatoryValues != null) { | |||
for (String mandatoryValue : mandatoryValues) { | |||
if (!buckets.containsKey(mandatoryValue)) { | |||
buckets.put(mandatoryValue, 0L); | |||
} | |||
} | |||
} | |||
} | |||
private void collectLoggedInUser(SearchResponseLoader.Collector collector) { | |||
if (userSession.isLoggedIn()) { | |||
collector.add(SearchAdditionalField.USERS, userSession.getLogin()); | |||
} | |||
} | |||
private void collectFacets(SearchResponseLoader.Collector collector, Facets facets) { | |||
Set<String> facetRules = facets.getBucketKeys(IssueFilterParameters.RULES); | |||
if (facetRules != null) { | |||
collector.addAll(SearchAdditionalField.RULES, from(facetRules).transform(RuleKeyFunctions.stringToRuleKey())); | |||
} | |||
collector.addProjectUuids(facets.getBucketKeys(IssueFilterParameters.PROJECT_UUIDS)); | |||
collector.addComponentUuids(facets.getBucketKeys(IssueFilterParameters.COMPONENT_UUIDS)); | |||
collector.addComponentUuids(facets.getBucketKeys(IssueFilterParameters.FILE_UUIDS)); | |||
collector.addComponentUuids(facets.getBucketKeys(IssueFilterParameters.MODULE_UUIDS)); | |||
collector.addAll(SearchAdditionalField.USERS, facets.getBucketKeys(IssueFilterParameters.ASSIGNEES)); | |||
collector.addAll(SearchAdditionalField.USERS, facets.getBucketKeys(IssueFilterParameters.REPORTERS)); | |||
collector.addAll(SearchAdditionalField.ACTION_PLANS, facets.getBucketKeys(IssueFilterParameters.ACTION_PLANS)); | |||
} | |||
private void collectRequestParams(SearchResponseLoader.Collector collector, Request request) { | |||
collector.addProjectUuids(request.paramAsStrings(IssueFilterParameters.PROJECT_UUIDS)); | |||
collector.addComponentUuids(request.paramAsStrings(IssueFilterParameters.FILE_UUIDS)); | |||
collector.addComponentUuids(request.paramAsStrings(IssueFilterParameters.MODULE_UUIDS)); | |||
collector.addComponentUuids(request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOT_UUIDS)); | |||
collector.addAll(SearchAdditionalField.USERS, request.paramAsStrings(IssueFilterParameters.ASSIGNEES)); | |||
collector.addAll(SearchAdditionalField.USERS, request.paramAsStrings(IssueFilterParameters.REPORTERS)); | |||
collector.addAll(SearchAdditionalField.ACTION_PLANS, request.paramAsStrings(IssueFilterParameters.ACTION_PLANS)); | |||
} | |||
private enum IssueDocToKey implements Function<IssueDoc, String> { | |||
INSTANCE; | |||
@Override | |||
public String apply(IssueDoc input) { | |||
return input.key(); | |||
} | |||
} | |||
} |
@@ -273,7 +273,7 @@ public class SearchAction implements IssuesWsAction { | |||
options.addFacets(request.paramAsStrings(WebService.Param.FACETS)); | |||
IssueQuery query = issueQueryService.createFromRequest(request); | |||
SearchResult<IssueDoc> result = execute(query, options); | |||
SearchResult<IssueDoc> result = service.search(query, options); | |||
JsonWriter json = response.newJsonWriter().beginObject(); | |||
options.writeJson(json, result.getTotal()); | |||
@@ -286,10 +286,6 @@ public class SearchAction implements IssuesWsAction { | |||
json.endObject().close(); | |||
} | |||
private SearchResult<IssueDoc> execute(IssueQuery query, SearchOptions options) { | |||
return service.search(query, options); | |||
} | |||
private void writeResponse(Request request, SearchResult<IssueDoc> result, JsonWriter json) { | |||
Map<String, Long> debtFacet = result.getFacets().get(IssueIndex.DEBT_AGGREGATION_NAME); | |||
if (debtFacet != null) { |
@@ -0,0 +1,83 @@ | |||
/* | |||
* 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 java.util.Collection; | |||
import java.util.EnumSet; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.server.ws.Request; | |||
public enum SearchAdditionalField { | |||
ACTIONS("actions"), | |||
ACTION_PLANS("actionPlans"), | |||
COMMENTS("comments"), | |||
LANGUAGES("languages"), | |||
RULES("rules"), | |||
TRANSITIONS("transitions"), | |||
USERS("users"); | |||
public static final String ALL_ALIAS = "_all"; | |||
public static final EnumSet<SearchAdditionalField> ALL_ADDITIONAL_FIELDS = EnumSet.allOf(SearchAdditionalField.class); | |||
private final String label; | |||
SearchAdditionalField(String label) { | |||
this.label = label; | |||
} | |||
private static final Map<String, SearchAdditionalField> BY_LABELS = new HashMap<>(); | |||
static { | |||
for (SearchAdditionalField f : values()) { | |||
BY_LABELS.put(f.label, f); | |||
} | |||
} | |||
@CheckForNull | |||
public static SearchAdditionalField findByLabel(String label) { | |||
return BY_LABELS.get(label); | |||
} | |||
public static Collection<String> possibleValues() { | |||
List<String> possibles = Lists.newArrayList(ALL_ALIAS); | |||
possibles.addAll(BY_LABELS.keySet()); | |||
return possibles; | |||
} | |||
public static EnumSet<SearchAdditionalField> getFromRequest(Request request) { | |||
List<String> labels = request.paramAsStrings(Search2Action.ADDITIONAL_FIELDS); | |||
if (labels == null) { | |||
return EnumSet.noneOf(SearchAdditionalField.class); | |||
} | |||
EnumSet<SearchAdditionalField> fields = EnumSet.noneOf(SearchAdditionalField.class); | |||
for (String label : labels) { | |||
if (label.equals(ALL_ALIAS)) { | |||
return EnumSet.allOf(SearchAdditionalField.class); | |||
} | |||
fields.add(findByLabel(label)); | |||
} | |||
return fields; | |||
} | |||
} |
@@ -0,0 +1,167 @@ | |||
/* | |||
* 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.ArrayListMultimap; | |||
import com.google.common.collect.ListMultimap; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.core.issue.workflow.Transition; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.ActionPlanDto; | |||
import org.sonar.db.issue.IssueChangeDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.user.UserDto; | |||
import static com.google.common.base.Preconditions.checkNotNull; | |||
/** | |||
* All the data required to write response of api/issues/search | |||
*/ | |||
public class SearchResponseData { | |||
private final List<IssueDto> issues; | |||
private Long debtTotal = null; | |||
private List<UserDto> users = null; | |||
private List<RuleDto> rules = null; | |||
private List<ActionPlanDto> actionPlans = null; | |||
private final Map<String, ComponentDto> componentsByUuid = new HashMap<>(); | |||
private final ListMultimap<String, IssueChangeDto> commentsByIssueKey = ArrayListMultimap.create(); | |||
private final ListMultimap<String, String> actionsByIssueKey = ArrayListMultimap.create(); | |||
private final ListMultimap<String, Transition> transitionsByIssueKey = ArrayListMultimap.create(); | |||
private final Set<String> updatableComments = new HashSet<>(); | |||
public SearchResponseData(List<IssueDto> issues) { | |||
checkNotNull(issues); | |||
this.issues = issues; | |||
} | |||
public List<IssueDto> getIssues() { | |||
return issues; | |||
} | |||
@CheckForNull | |||
public Collection<ComponentDto> getComponents() { | |||
return componentsByUuid.values(); | |||
} | |||
@CheckForNull | |||
public ComponentDto getComponentByUuid(String uuid) { | |||
return componentsByUuid.get(uuid); | |||
} | |||
@CheckForNull | |||
public List<UserDto> getUsers() { | |||
return users; | |||
} | |||
@CheckForNull | |||
public List<RuleDto> getRules() { | |||
return rules; | |||
} | |||
@CheckForNull | |||
public List<ActionPlanDto> getActionPlans() { | |||
return actionPlans; | |||
} | |||
@CheckForNull | |||
public List<IssueChangeDto> getCommentsForIssueKey(String issueKey) { | |||
if (commentsByIssueKey.containsKey(issueKey)) { | |||
return commentsByIssueKey.get(issueKey); | |||
} | |||
return null; | |||
} | |||
@CheckForNull | |||
public List<String> getActionsForIssueKey(String issueKey) { | |||
if (actionsByIssueKey.containsKey(issueKey)) { | |||
return actionsByIssueKey.get(issueKey); | |||
} | |||
return null; | |||
} | |||
@CheckForNull | |||
public List<Transition> getTransitionsForIssueKey(String issueKey) { | |||
if (transitionsByIssueKey.containsKey(issueKey)) { | |||
return transitionsByIssueKey.get(issueKey); | |||
} | |||
return null; | |||
} | |||
public void setUsers(@Nullable List<UserDto> users) { | |||
this.users = users; | |||
} | |||
public void setRules(@Nullable List<RuleDto> rules) { | |||
this.rules = rules; | |||
} | |||
public void setActionPlans(@Nullable List<ActionPlanDto> actionPlans) { | |||
this.actionPlans = actionPlans; | |||
} | |||
public void setComments(@Nullable List<IssueChangeDto> comments) { | |||
for (IssueChangeDto comment : comments) { | |||
commentsByIssueKey.put(comment.getIssueKey(), comment); | |||
} | |||
} | |||
public void addComponents(@Nullable Collection<ComponentDto> dtos) { | |||
if (dtos != null) { | |||
for (ComponentDto dto : dtos) { | |||
componentsByUuid.put(dto.uuid(), dto); | |||
} | |||
} | |||
} | |||
public void addActions(String issueKey, List<String> actions) { | |||
actionsByIssueKey.putAll(issueKey, actions); | |||
} | |||
public void addTransitions(String issueKey, List<Transition> transitions) { | |||
transitionsByIssueKey.putAll(issueKey, transitions); | |||
} | |||
public void addUpdatableComment(String commentKey) { | |||
updatableComments.add(commentKey); | |||
} | |||
public boolean isUpdatableComment(String commentKey) { | |||
return updatableComments.contains(commentKey); | |||
} | |||
@CheckForNull | |||
public Long getDebtTotal() { | |||
return debtTotal; | |||
} | |||
public void setDebtTotal(@Nullable Long debtTotal) { | |||
this.debtTotal = debtTotal; | |||
} | |||
} |
@@ -0,0 +1,291 @@ | |||
/* | |||
* 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 java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.resources.Language; | |||
import org.sonar.api.resources.Languages; | |||
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.issue.workflow.Transition; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.ActionPlanDto; | |||
import org.sonar.db.issue.IssueChangeDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.markdown.Markdown; | |||
import org.sonar.server.es.Facets; | |||
import org.sonar.server.ws.WsResponseCommonFormat; | |||
import org.sonarqube.ws.Common; | |||
import org.sonarqube.ws.Issues; | |||
import static com.google.common.base.Strings.nullToEmpty; | |||
public class SearchResponseFormat { | |||
private final Durations durations; | |||
private final WsResponseCommonFormat commonFormat; | |||
private final Languages languages; | |||
public SearchResponseFormat(Durations durations, WsResponseCommonFormat commonFormat, Languages languages) { | |||
this.durations = durations; | |||
this.commonFormat = commonFormat; | |||
this.languages = languages; | |||
} | |||
public Issues.Search format(Set<SearchAdditionalField> fields, SearchResponseData data, | |||
@Nullable Paging paging, @Nullable Facets facets) { | |||
Issues.Search.Builder response = Issues.Search.newBuilder(); | |||
if (paging != null) { | |||
formatPaging(paging, response); | |||
} | |||
formatDebtTotal(data, response); | |||
formatIssues(fields, data, response); | |||
formatComponents(data, response); | |||
if (facets != null) { | |||
formatFacets(facets, response); | |||
} | |||
if (fields.contains(SearchAdditionalField.RULES)) { | |||
formatRules(data, response); | |||
} | |||
if (fields.contains(SearchAdditionalField.USERS)) { | |||
formatUsers(data, response); | |||
} | |||
if (fields.contains(SearchAdditionalField.ACTION_PLANS)) { | |||
formatActionPlans(data, response); | |||
} | |||
if (fields.contains(SearchAdditionalField.LANGUAGES)) { | |||
formatLanguages(response); | |||
} | |||
return response.build(); | |||
} | |||
private void formatDebtTotal(SearchResponseData data, Issues.Search.Builder response) { | |||
Long debt = data.getDebtTotal(); | |||
if (debt != null) { | |||
response.setDebtTotal(debt); | |||
} | |||
} | |||
private void formatPaging(Paging paging, Issues.Search.Builder response) { | |||
response.setP(paging.pageIndex()); | |||
response.setPs(paging.pageSize()); | |||
response.setTotal(paging.total()); | |||
response.setPaging(commonFormat.formatPaging(paging)); | |||
} | |||
private void formatIssues(Set<SearchAdditionalField> fields, SearchResponseData data, Issues.Search.Builder response) { | |||
Issues.Issue.Builder issueBuilder = Issues.Issue.newBuilder(); | |||
for (IssueDto dto : data.getIssues()) { | |||
issueBuilder.clear(); | |||
formatIssue(issueBuilder, dto, data); | |||
if (fields.contains(SearchAdditionalField.ACTIONS)) { | |||
formatIssueActions(data, issueBuilder, dto); | |||
} | |||
if (fields.contains(SearchAdditionalField.TRANSITIONS)) { | |||
formatIssueTransitions(data, issueBuilder, dto); | |||
} | |||
if (fields.contains(SearchAdditionalField.COMMENTS)) { | |||
formatIssueComments(data, issueBuilder, dto); | |||
} | |||
// TODO attributes | |||
response.addIssues(issueBuilder.build()); | |||
} | |||
} | |||
private void formatIssue(Issues.Issue.Builder issueBuilder, IssueDto dto, SearchResponseData data) { | |||
issueBuilder.setKey(dto.getKey()); | |||
ComponentDto component = data.getComponentByUuid(dto.getComponentUuid()); | |||
issueBuilder.setComponent(dto.getComponentUuid()); | |||
// Only used for the compatibility with the Issues Java WS Client <= 4.4 used by Eclipse | |||
issueBuilder.setComponentId(component.getId()); | |||
ComponentDto project = data.getComponentByUuid(dto.getProjectUuid()); | |||
if (project != null) { | |||
issueBuilder.setProject(project.uuid()); | |||
} | |||
issueBuilder.setRule(dto.getRuleKey().toString()); | |||
issueBuilder.setSeverity(Common.Severity.valueOf(dto.getSeverity())); | |||
issueBuilder.setAssignee(nullToEmpty(dto.getAssignee())); | |||
issueBuilder.setReporter(nullToEmpty(dto.getReporter())); | |||
issueBuilder.setResolution(nullToEmpty(dto.getResolution())); | |||
issueBuilder.setStatus(nullToEmpty(dto.getStatus())); | |||
issueBuilder.setActionPlan(nullToEmpty(dto.getActionPlanKey())); | |||
issueBuilder.setMessage(nullToEmpty(dto.getMessage())); | |||
issueBuilder.addAllTags(dto.getTags()); | |||
Long debt = dto.getDebt(); | |||
if (debt != null) { | |||
issueBuilder.setDebt(durations.encode(Duration.create(debt))); | |||
} | |||
Integer line = dto.getLine(); | |||
if (line != null) { | |||
issueBuilder.setLine(line); | |||
} | |||
issueBuilder.setAuthor(nullToEmpty(dto.getAuthorLogin())); | |||
Date date = dto.getIssueCreationDate(); | |||
if (date != null) { | |||
issueBuilder.setCreationDate(DateUtils.formatDateTime(date)); | |||
} | |||
date = dto.getIssueUpdateDate(); | |||
if (date != null) { | |||
issueBuilder.setUpdateDate(DateUtils.formatDateTime(date)); | |||
} | |||
date = dto.getIssueCloseDate(); | |||
if (date != null) { | |||
issueBuilder.setCloseDate(DateUtils.formatDateTime(date)); | |||
} | |||
} | |||
private void formatIssueTransitions(SearchResponseData data, Issues.Issue.Builder issueBuilder, IssueDto dto) { | |||
issueBuilder.setTransitionsPresentIfEmpty(true); | |||
List<Transition> transitions = data.getTransitionsForIssueKey(dto.getKey()); | |||
if (transitions != null) { | |||
for (Transition transition : transitions) { | |||
issueBuilder.addTransitions(transition.key()); | |||
} | |||
} | |||
} | |||
private void formatIssueActions(SearchResponseData data, Issues.Issue.Builder issueBuilder, IssueDto dto) { | |||
issueBuilder.setActionsPresentIfEmpty(true); | |||
List<String> actions = data.getActionsForIssueKey(dto.getKey()); | |||
if (actions != null) { | |||
issueBuilder.addAllActions(actions); | |||
} | |||
} | |||
private void formatIssueComments(SearchResponseData data, Issues.Issue.Builder issueBuilder, IssueDto dto) { | |||
issueBuilder.setCommentsPresentIfEmpty(true); | |||
List<IssueChangeDto> comments = data.getCommentsForIssueKey(dto.getKey()); | |||
if (comments != null) { | |||
Issues.Comment.Builder commentBuilder = Issues.Comment.newBuilder(); | |||
for (IssueChangeDto comment : comments) { | |||
String markdown = comment.getChangeData(); | |||
commentBuilder | |||
.clear() | |||
.setKey(comment.getKey()) | |||
.setLogin(nullToEmpty(comment.getUserLogin())) | |||
.setUpdatable(data.isUpdatableComment(comment.getKey())) | |||
.setCreatedAt(DateUtils.formatDateTime(new Date(comment.getCreatedAt()))); | |||
if (markdown != null) { | |||
commentBuilder | |||
.setHtmlText(Markdown.convertToHtml(markdown)) | |||
.setMarkdown(markdown); | |||
} | |||
issueBuilder.addComments(commentBuilder.build()); | |||
} | |||
} | |||
} | |||
private void formatRules(SearchResponseData data, Issues.Search.Builder response) { | |||
response.setRulesPresentIfEmpty(true); | |||
List<RuleDto> rules = data.getRules(); | |||
if (rules != null) { | |||
for (RuleDto rule : rules) { | |||
response.addRules(commonFormat.formatRule(rule)); | |||
} | |||
} | |||
} | |||
private void formatComponents(SearchResponseData data, Issues.Search.Builder response) { | |||
response.setComponentsPresentIfEmpty(true); | |||
Collection<ComponentDto> components = data.getComponents(); | |||
if (components != null) { | |||
for (ComponentDto dto : components) { | |||
response.addComponents(commonFormat.formatComponent(dto)); | |||
} | |||
} | |||
} | |||
private void formatUsers(SearchResponseData data, Issues.Search.Builder response) { | |||
response.setUsersPresentIfEmpty(true); | |||
List<UserDto> users = data.getUsers(); | |||
if (users != null) { | |||
for (UserDto user : users) { | |||
response.addUsers(commonFormat.formatUser(user)); | |||
} | |||
} | |||
} | |||
private void formatActionPlans(SearchResponseData data, Issues.Search.Builder response) { | |||
response.setActionPlansPresentIfEmpty(true); | |||
List<ActionPlanDto> actionPlans = data.getActionPlans(); | |||
if (actionPlans != null) { | |||
Issues.ActionPlan.Builder planBuilder = Issues.ActionPlan.newBuilder(); | |||
for (ActionPlanDto actionPlan : actionPlans) { | |||
planBuilder | |||
.clear() | |||
.setKey(actionPlan.getKey()) | |||
.setName(nullToEmpty(actionPlan.getName())) | |||
.setStatus(nullToEmpty(actionPlan.getStatus())) | |||
.setProject(nullToEmpty(actionPlan.getProjectUuid())); | |||
Date deadLine = actionPlan.getDeadLine(); | |||
if (deadLine != null) { | |||
planBuilder.setDeadLine(DateUtils.formatDateTime(deadLine)); | |||
} | |||
response.addActionPlans(planBuilder.build()); | |||
} | |||
} | |||
} | |||
private void formatLanguages(Issues.Search.Builder response) { | |||
response.setLanguagesPresentIfEmpty(true); | |||
Issues.Language.Builder builder = Issues.Language.newBuilder(); | |||
for (Language lang : languages.all()) { | |||
builder | |||
.clear() | |||
.setKey(lang.getKey()) | |||
.setName(lang.getName()); | |||
response.addLanguages(builder.build()); | |||
} | |||
} | |||
private void formatFacets(Facets facets, Issues.Search.Builder response) { | |||
response.setFacetsPresentIfEmpty(true); | |||
Common.Facet.Builder facetBuilder = Common.Facet.newBuilder(); | |||
for (Map.Entry<String, LinkedHashMap<String, Long>> facet : facets.getAll().entrySet()) { | |||
facetBuilder.clear(); | |||
facetBuilder.setProperty(facet.getKey()); | |||
LinkedHashMap<String, Long> buckets = facet.getValue(); | |||
if (buckets != null) { | |||
for (Map.Entry<String, Long> bucket : buckets.entrySet()) { | |||
Common.FacetValue.Builder valueBuilder = facetBuilder.addValuesBuilder(); | |||
valueBuilder.setVal(bucket.getKey()); | |||
valueBuilder.setCount(bucket.getValue()); | |||
valueBuilder.build(); | |||
} | |||
} else { | |||
facetBuilder.addAllValues(Collections.<Common.FacetValue>emptyList()); | |||
} | |||
response.addFacets(facetBuilder.build()); | |||
} | |||
} | |||
} |
@@ -0,0 +1,241 @@ | |||
/* | |||
* 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.MultimapBuilder; | |||
import com.google.common.collect.SetMultimap; | |||
import java.util.Collection; | |||
import java.util.EnumSet; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.IssueChangeDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.server.es.Facets; | |||
import org.sonar.server.issue.ActionService; | |||
import org.sonar.server.issue.IssueCommentService; | |||
import org.sonar.server.issue.IssueService; | |||
import org.sonar.server.issue.index.IssueIndex; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.ACTIONS; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.ACTION_PLANS; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.COMMENTS; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.RULES; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.TRANSITIONS; | |||
import static org.sonar.server.issue.ws.SearchAdditionalField.USERS; | |||
/** | |||
* Loads all the information required for the response of api/issues/search. | |||
*/ | |||
public class SearchResponseLoader { | |||
private final DbClient dbClient; | |||
private final IssueService issueService; | |||
private final ActionService actionService; | |||
private final IssueCommentService commentService; | |||
public SearchResponseLoader(DbClient dbClient, IssueService issueService, ActionService actionService, IssueCommentService commentService) { | |||
this.dbClient = dbClient; | |||
this.issueService = issueService; | |||
this.actionService = actionService; | |||
this.commentService = commentService; | |||
} | |||
/** | |||
* The issue keys are given by the multi-criteria search in Elasticsearch index. | |||
*/ | |||
public SearchResponseData load(Collector collector, @Nullable Facets facets) { | |||
DbSession dbSession = dbClient.openSession(false); | |||
try { | |||
SearchResponseData result = new SearchResponseData(dbClient.issueDao().selectByOrderedKeys(dbSession, collector.getIssueKeys())); | |||
collector.collect(result.getIssues()); | |||
loadRules(collector, dbSession, result); | |||
// order is important - loading of comments complete the list of users: loadComments() is | |||
// before loadUsers() | |||
loadComments(collector, dbSession, result); | |||
loadUsers(collector, dbSession, result); | |||
loadActionPlans(collector, dbSession, result); | |||
loadComponents(collector, dbSession, result); | |||
loadActionsAndTransitions(collector, result); | |||
completeTotalDebtFromFacet(facets, result); | |||
return result; | |||
} finally { | |||
dbClient.closeSession(dbSession); | |||
} | |||
} | |||
private void loadUsers(Collector collector, DbSession dbSession, SearchResponseData result) { | |||
if (collector.contains(USERS)) { | |||
result.setUsers(dbClient.userDao().selectByLogins(dbSession, collector.<String>get(USERS))); | |||
} | |||
} | |||
private void loadComments(Collector collector, DbSession dbSession, SearchResponseData result) { | |||
if (collector.contains(COMMENTS)) { | |||
List<IssueChangeDto> comments = dbClient.issueChangeDao().selectByTypeAndIssueKeys(dbSession, collector.getIssueKeys(), IssueChangeDto.TYPE_COMMENT); | |||
result.setComments(comments); | |||
for (IssueChangeDto comment : comments) { | |||
collector.add(USERS, comment.getUserLogin()); | |||
if (commentService.canEditOrDelete(comment)) { | |||
result.addUpdatableComment(comment.getKey()); | |||
} | |||
} | |||
} | |||
} | |||
private void loadActionPlans(Collector collector, DbSession dbSession, SearchResponseData result) { | |||
if (collector.contains(ACTION_PLANS)) { | |||
result.setActionPlans(dbClient.actionPlanDao().selectByKeys(dbSession, collector.<String>get(ACTION_PLANS))); | |||
} | |||
} | |||
private void loadRules(Collector collector, DbSession dbSession, SearchResponseData result) { | |||
if (collector.contains(RULES)) { | |||
result.setRules(dbClient.ruleDao().selectByKeys(dbSession, collector.<RuleKey>get(RULES))); | |||
} | |||
} | |||
private void loadComponents(Collector collector, DbSession dbSession, SearchResponseData result) { | |||
// always load components and projects, because some issue fields still relate to component ids/keys. | |||
// They should be dropped but are kept for backward-compatibility (see SearchResponseFormat) | |||
result.addComponents(dbClient.componentDao().selectByUuids(dbSession, collector.getComponentUuids())); | |||
result.addComponents(dbClient.componentDao().selectSubProjectsByComponentUuids(dbSession, collector.getComponentUuids())); | |||
for (ComponentDto component : result.getComponents()) { | |||
collector.addProjectUuid(component.projectUuid()); | |||
} | |||
List<ComponentDto> projects = dbClient.componentDao().selectByUuids(dbSession, collector.getProjectUuids()); | |||
result.addComponents(projects); | |||
} | |||
private void loadActionsAndTransitions(Collector collector, SearchResponseData result) { | |||
if (collector.contains(ACTIONS) || collector.contains(TRANSITIONS)) { | |||
for (IssueDto dto : result.getIssues()) { | |||
// so that IssueDto can be used. | |||
if (collector.contains(ACTIONS)) { | |||
result.addActions(dto.getKey(), actionService.listAvailableActions(dto)); | |||
} | |||
if (collector.contains(TRANSITIONS)) { | |||
// TODO workflow and action engines must not depend on org.sonar.api.issue.Issue but on a generic interface | |||
DefaultIssue issue = dto.toDefaultIssue(); | |||
result.addTransitions(issue.key(), issueService.listTransitions(issue)); | |||
} | |||
} | |||
} | |||
} | |||
private void completeTotalDebtFromFacet(@Nullable Facets facets, SearchResponseData result) { | |||
if (facets != null) { | |||
Map<String, Long> debtFacet = facets.get(IssueIndex.DEBT_AGGREGATION_NAME); | |||
if (debtFacet != null) { | |||
result.setDebtTotal(debtFacet.get(Facets.TOTAL)); | |||
} | |||
} | |||
} | |||
/** | |||
* Collects the keys of all the data to be loaded (users, rules, ...) | |||
*/ | |||
public static class Collector { | |||
private final EnumSet<SearchAdditionalField> fields; | |||
private final SetMultimap<SearchAdditionalField, Object> fieldValues = MultimapBuilder.enumKeys(SearchAdditionalField.class).hashSetValues().build(); | |||
private final Set<String> componentUuids = new HashSet<>(); | |||
private final Set<String> projectUuids = new HashSet<>(); | |||
private final List<String> issueKeys; | |||
public Collector(EnumSet<SearchAdditionalField> fields, List<String> issueKeys) { | |||
this.fields = fields; | |||
this.issueKeys = issueKeys; | |||
} | |||
void collect(List<IssueDto> issues) { | |||
for (IssueDto issue : issues) { | |||
componentUuids.add(issue.getComponentUuid()); | |||
projectUuids.add(issue.getProjectUuid()); | |||
add(ACTION_PLANS, issue.getActionPlanKey()); | |||
add(RULES, issue.getRuleKey()); | |||
add(USERS, issue.getReporter()); | |||
add(USERS, issue.getAssignee()); | |||
} | |||
} | |||
public void add(SearchAdditionalField key, @Nullable Object value) { | |||
if (value != null) { | |||
fieldValues.put(key, value); | |||
} | |||
} | |||
public void addComponentUuid(String uuid) { | |||
this.componentUuids.add(uuid); | |||
} | |||
public void addComponentUuids(@Nullable Collection<String> uuids) { | |||
if (uuids != null) { | |||
this.componentUuids.addAll(uuids); | |||
} | |||
} | |||
public void addProjectUuid(String uuid) { | |||
this.projectUuids.add(uuid); | |||
} | |||
public void addProjectUuids(@Nullable Collection<String> uuids) { | |||
if (uuids != null) { | |||
this.projectUuids.addAll(uuids); | |||
} | |||
} | |||
public void addAll(SearchAdditionalField key, @Nullable Iterable values) { | |||
if (values != null) { | |||
for (Object value : values) { | |||
add(key, value); | |||
} | |||
} | |||
} | |||
<T> List<T> get(SearchAdditionalField key) { | |||
return newArrayList((Set<T>) fieldValues.get(key)); | |||
} | |||
boolean contains(SearchAdditionalField field) { | |||
return fields.contains(field); | |||
} | |||
public List<String> getIssueKeys() { | |||
return issueKeys; | |||
} | |||
public Set<String> getComponentUuids() { | |||
return componentUuids; | |||
} | |||
public Set<String> getProjectUuids() { | |||
return projectUuids; | |||
} | |||
} | |||
} |
@@ -158,6 +158,8 @@ import org.sonar.server.issue.ws.IssueActionsWriter; | |||
import org.sonar.server.issue.ws.IssueComponentHelper; | |||
import org.sonar.server.issue.ws.IssueJsonWriter; | |||
import org.sonar.server.issue.ws.IssuesWs; | |||
import org.sonar.server.issue.ws.SearchResponseFormat; | |||
import org.sonar.server.issue.ws.SearchResponseLoader; | |||
import org.sonar.server.issue.ws.SetTagsAction; | |||
import org.sonar.server.language.ws.LanguageWs; | |||
import org.sonar.server.measure.MeasureFilterEngine; | |||
@@ -321,6 +323,7 @@ import org.sonar.server.view.index.ViewIndexDefinition; | |||
import org.sonar.server.view.index.ViewIndexer; | |||
import org.sonar.server.ws.ListingWs; | |||
import org.sonar.server.ws.WebServiceEngine; | |||
import org.sonar.server.ws.WsResponseCommonFormat; | |||
public class PlatformLevel4 extends PlatformLevel { | |||
@@ -602,8 +605,12 @@ public class PlatformLevel4 extends PlatformLevel { | |||
IssuesWs.class, | |||
IssueJsonWriter.class, | |||
IssueComponentHelper.class, | |||
WsResponseCommonFormat.class, | |||
SearchResponseLoader.class, | |||
SearchResponseFormat.class, | |||
org.sonar.server.issue.ws.ShowAction.class, | |||
org.sonar.server.issue.ws.SearchAction.class, | |||
org.sonar.server.issue.ws.Search2Action.class, | |||
org.sonar.server.issue.ws.TagsAction.class, | |||
SetTagsAction.class, | |||
ComponentTagsAction.class, |
@@ -31,6 +31,8 @@ import org.sonar.db.rule.RuleDto; | |||
import org.sonar.server.plugins.MimeTypes; | |||
import org.sonarqube.ws.Rules.ListResponse; | |||
import static com.google.common.base.Strings.nullToEmpty; | |||
public class ListAction implements RulesWsAction { | |||
private final DbClient dbClient; | |||
@@ -62,11 +64,9 @@ public class ListAction implements RulesWsAction { | |||
ruleBuilder | |||
.clear() | |||
.setRepository(dto.getRepositoryKey()) | |||
.setKey(dto.getRuleKey()); | |||
String internalKey = dto.getConfigKey(); | |||
if (!Strings.isNullOrEmpty(internalKey)) { | |||
ruleBuilder.setInternalKey(internalKey); | |||
} | |||
.setKey(dto.getRuleKey()) | |||
.setName(nullToEmpty(dto.getName())) | |||
.setInternalKey(nullToEmpty(dto.getConfigKey())); | |||
listResponseBuilder.addRules(ruleBuilder.build()); | |||
} | |||
}); |
@@ -0,0 +1,111 @@ | |||
/* | |||
* 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 com.google.common.base.Strings; | |||
import org.sonar.api.resources.Language; | |||
import org.sonar.api.resources.Languages; | |||
import org.sonar.api.utils.Paging; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.markdown.Markdown; | |||
import org.sonarqube.ws.Common; | |||
import static com.google.common.base.Strings.nullToEmpty; | |||
import static java.lang.String.format; | |||
public class WsResponseCommonFormat { | |||
private final Languages languages; | |||
public WsResponseCommonFormat(Languages languages) { | |||
this.languages = languages; | |||
} | |||
public Common.Paging.Builder formatPaging(Paging paging) { | |||
return Common.Paging.newBuilder() | |||
.setPageIndex(paging.pageIndex()) | |||
.setPages(paging.pages()) | |||
.setPageSize(paging.pageSize()) | |||
.setTotal(paging.total()); | |||
} | |||
public Common.Rule.Builder formatRule(RuleDto rule) { | |||
Common.Rule.Builder builder = Common.Rule.newBuilder() | |||
.setKey(rule.getKey().toString()) | |||
.setDesc(nullToEmpty(rule.getDescription())) | |||
.setStatus(Common.RuleStatus.valueOf(rule.getStatus().name())); | |||
builder.setLang(nullToEmpty(rule.getLanguage())); | |||
Language lang = languages.get(rule.getLanguage()); | |||
if (lang != null) { | |||
builder.setLangName(lang.getName()); | |||
} | |||
String desc = rule.getDescription(); | |||
if (desc != null) { | |||
switch (rule.getDescriptionFormat()) { | |||
case HTML: | |||
builder.setDesc(desc); | |||
break; | |||
case MARKDOWN: | |||
builder.setDesc(Markdown.convertToHtml(desc)); | |||
break; | |||
default: | |||
throw new IllegalArgumentException(format("Unknown description format '%s' on rule '%s'", rule.getDescriptionFormat(), rule.getKey())); | |||
} | |||
} | |||
return builder; | |||
} | |||
public Common.Component.Builder formatComponent(ComponentDto dto) { | |||
Common.Component.Builder builder = Common.Component.newBuilder() | |||
.setId(dto.uuid()) | |||
.setKey(dto.key()) | |||
.setQualifier(dto.qualifier()) | |||
.setName(nullToEmpty(dto.name())) | |||
.setLongName(nullToEmpty(dto.longName())) | |||
.setEnabled(dto.isEnabled()); | |||
String path = dto.path(); | |||
// path is not applicable to the components that are not files. | |||
// Value must not be "" in this case. | |||
if (!Strings.isNullOrEmpty(path)) { | |||
builder.setPath(path); | |||
} | |||
// On a root project, parentProjectId is null but projectId is equal to itself, which make no sense. | |||
if (dto.projectUuid() != null && dto.parentProjectId() != null) { | |||
builder.setProject(dto.projectUuid()); | |||
} | |||
if (dto.parentProjectId() != null) { | |||
builder.setSubProject(dto.moduleUuid()); | |||
} | |||
return builder; | |||
} | |||
public Common.User.Builder formatUser(UserDto user) { | |||
return Common.User.newBuilder() | |||
.setLogin(user.getLogin()) | |||
.setName(nullToEmpty(user.getName())) | |||
.setEmail(nullToEmpty(user.getEmail())) | |||
.setActive(user.isActive()); | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* 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 com.google.protobuf.Message; | |||
import java.io.OutputStream; | |||
import java.io.OutputStreamWriter; | |||
import org.apache.commons.io.IOUtils; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.utils.text.JsonWriter; | |||
import org.sonar.core.util.ProtobufJsonFormat; | |||
import org.sonar.server.plugins.MimeTypes; | |||
public class WsUtils { | |||
private WsUtils() { | |||
// only statics | |||
} | |||
public static void writeProtobuf(Message msg, Request request, Response response) throws Exception { | |||
OutputStream output = response.stream().output(); | |||
try { | |||
if (request.getMediaType().equals(MimeTypes.PROTOBUF)) { | |||
response.stream().setMediaType(MimeTypes.PROTOBUF); | |||
msg.writeTo(output); | |||
} else { | |||
response.stream().setMediaType(MimeTypes.JSON); | |||
try (OutputStreamWriter writer = new OutputStreamWriter(output)) { | |||
ProtobufJsonFormat.write(msg, JsonWriter.of(writer)); | |||
} | |||
} | |||
} finally { | |||
IOUtils.closeQuietly(output); | |||
} | |||
} | |||
} |
@@ -1,39 +0,0 @@ | |||
// SonarQube, open source software quality management tool. | |||
// Copyright (C) 2008-2015 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. | |||
syntax = "proto2"; | |||
package sonarqube.ws.rules; | |||
option java_package = "org.sonarqube.ws"; | |||
option java_outer_classname = "Rules"; | |||
option optimize_for = SPEED; | |||
// WS api/rules/list for internal use only | |||
message ListResponse { | |||
message Rule { | |||
optional string repository = 1; | |||
optional string key = 2; | |||
optional string internal_key = 3; | |||
optional string name = 4; | |||
} | |||
repeated Rule rules = 1; | |||
} |
@@ -1,243 +0,0 @@ | |||
/* | |||
* SonarQube, open source software quality management tool. | |||
* Copyright (C) 2008-2014 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* SonarQube is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* SonarQube is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.issue; | |||
import java.util.List; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.component.Component; | |||
import org.sonar.api.config.Settings; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.action.Actions; | |||
import org.sonar.api.issue.action.Function; | |||
import org.sonar.api.issue.condition.Condition; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.core.issue.IssueChangeContext; | |||
import org.sonar.core.issue.IssueUpdater; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDao; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.issue.IssueDto; | |||
import org.sonar.db.property.PropertiesDao; | |||
import org.sonar.db.property.PropertyDto; | |||
import org.sonar.db.rule.RuleTesting; | |||
import org.sonar.server.component.ComponentTesting; | |||
import org.sonar.server.user.ThreadLocalUserSession; | |||
import org.sonar.server.user.UserSession; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.fail; | |||
import static org.mockito.Mockito.any; | |||
import static org.mockito.Mockito.anyString; | |||
import static org.mockito.Mockito.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.mockito.Mockito.when; | |||
public class ActionServiceTest { | |||
DbClient dbClient; | |||
DbSession session; | |||
ComponentDao componentDao; | |||
IssueService issueService; | |||
IssueStorage issueStorage; | |||
IssueUpdater updater; | |||
PropertiesDao propertiesDao; | |||
Settings settings; | |||
Actions actions; | |||
ActionService actionService; | |||
IssueDto issue; | |||
@Before | |||
public void before() { | |||
dbClient = mock(DbClient.class); | |||
session = mock(DbSession.class); | |||
when(dbClient.openSession(false)).thenReturn(session); | |||
componentDao = mock(ComponentDao.class); | |||
when(dbClient.componentDao()).thenReturn(componentDao); | |||
issueService = mock(IssueService.class); | |||
issueStorage = mock(IssueStorage.class); | |||
updater = mock(IssueUpdater.class); | |||
propertiesDao = mock(PropertiesDao.class); | |||
settings = new Settings(); | |||
actions = new Actions(); | |||
ComponentDto project = ComponentTesting.newProjectDto(); | |||
issue = IssueTesting.newDto(RuleTesting.newXooX1().setId(10), ComponentTesting.newFileDto(project), project).setKee("ABCD"); | |||
actionService = new ActionService(dbClient, issueService, issueStorage, updater, settings, propertiesDao, actions); | |||
} | |||
@Test | |||
public void execute_functions() { | |||
Function function1 = mock(Function.class); | |||
Function function2 = mock(Function.class); | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()).setFunctions(function1, function2); | |||
assertThat(actionService.execute("ABCD", "link-to-jira", mock(ThreadLocalUserSession.class))).isNotNull(); | |||
verify(function1).execute(any(Function.Context.class)); | |||
verify(function2).execute(any(Function.Context.class)); | |||
verifyNoMoreInteractions(function1, function2); | |||
} | |||
@Test | |||
public void modify_issue_when_executing_a_function() { | |||
Function function = new TweetFunction(); | |||
UserSession userSession = mock(ThreadLocalUserSession.class); | |||
when(userSession.getLogin()).thenReturn("arthur"); | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()).setFunctions(function); | |||
assertThat(actionService.execute("ABCD", "link-to-jira", userSession)).isNotNull(); | |||
verify(updater).addComment(any(DefaultIssue.class), eq("New tweet on issue ABCD"), any(IssueChangeContext.class)); | |||
verify(updater).setAttribute(any(DefaultIssue.class), eq("tweet"), eq("tweet sent"), any(IssueChangeContext.class)); | |||
} | |||
@Test | |||
public void inject_project_settings_when_executing_a_function() { | |||
Function function = new TweetFunction(); | |||
UserSession userSession = mock(ThreadLocalUserSession.class); | |||
when(userSession.getLogin()).thenReturn("arthur"); | |||
when(componentDao.selectOrFailByKey(session, "struts")).thenReturn(new ComponentDto().setKey("struts")); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue.setProjectKey("struts")); | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()).setFunctions(function); | |||
assertThat(actionService.execute("ABCD", "link-to-jira", userSession)).isNotNull(); | |||
verify(propertiesDao).selectProjectProperties(eq("struts")); | |||
} | |||
@Test | |||
public void not_execute_function_if_action_not_found() { | |||
Function function = mock(Function.class); | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()).setFunctions(function); | |||
try { | |||
actionService.execute("ABCD", "tweet", mock(ThreadLocalUserSession.class)); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Action is not found : tweet"); | |||
} | |||
verifyZeroInteractions(function); | |||
} | |||
@Test | |||
public void not_execute_function_if_action_is_not_supported() { | |||
Function function = mock(Function.class); | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
actions.add("link-to-jira").setConditions(new NeverMatch()).setFunctions(function); | |||
try { | |||
actionService.execute("ABCD", "link-to-jira", mock(ThreadLocalUserSession.class)); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("A condition is not respected"); | |||
} | |||
verifyZeroInteractions(function); | |||
} | |||
@Test | |||
public void list_available_supported_actions() { | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()); | |||
actions.add("tweet").setConditions(new NeverMatch()); | |||
assertThat(actionService.listAvailableActions("ABCD")).hasSize(1); | |||
} | |||
@Test | |||
public void return_no_action() { | |||
when(componentDao.selectOrFailByKey(eq(session), anyString())).thenReturn(mock(ComponentDto.class)); | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issue); | |||
assertThat(actionService.listAvailableActions("ABCD")).isEmpty(); | |||
} | |||
@Test | |||
public void get_project_settings() { | |||
Component project = mock(Component.class); | |||
when(project.key()).thenReturn("struts"); | |||
// Global property | |||
settings.appendProperty("sonar.core.version", "3.6"); | |||
// Project property | |||
List<PropertyDto> projectProperties = newArrayList(new PropertyDto().setKey("sonar.jira.project.key").setValue("STRUTS")); | |||
when(propertiesDao.selectProjectProperties("struts")).thenReturn(projectProperties); | |||
Settings result = actionService.getProjectSettings(project); | |||
assertThat(result).isNotNull(); | |||
assertThat(result.hasKey("sonar.core.version")).isTrue(); | |||
assertThat(result.hasKey("sonar.jira.project.key")).isTrue(); | |||
} | |||
@Test | |||
public void list_all_actions() { | |||
actions.add("link-to-jira").setConditions(new AlwaysMatch()); | |||
assertThat(actionService.listAllActions()).hasSize(1); | |||
} | |||
public class AlwaysMatch implements Condition { | |||
@Override | |||
public boolean matches(Issue issue) { | |||
return true; | |||
} | |||
} | |||
public class NeverMatch implements Condition { | |||
@Override | |||
public boolean matches(Issue issue) { | |||
return false; | |||
} | |||
} | |||
public class TweetFunction implements Function { | |||
@Override | |||
public void execute(Context context) { | |||
context.addComment("New tweet on issue " + context.issue().key()); | |||
context.setAttribute("tweet", "tweet sent"); | |||
} | |||
} | |||
} |
@@ -158,16 +158,6 @@ public class InternalRubyIssueServiceTest { | |||
assertThat(service.listResolutions()).isEqualTo(Issue.RESOLUTIONS); | |||
} | |||
@Test | |||
public void list_plugin_actions() { | |||
Action action = mock(Action.class); | |||
when(action.key()).thenReturn("link-to-jira"); | |||
when(actionService.listAllActions()).thenReturn(newArrayList(action)); | |||
assertThat(service.listPluginActions()).containsOnly("link-to-jira"); | |||
} | |||
@Test | |||
public void find_comments_by_issue_key() { | |||
service.findComments("ABCD"); |
@@ -114,7 +114,7 @@ public class IssueCommentServiceMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
service.addComment(issue.getKey(), "my comment", userSessionRule); | |||
service.addComment(issue.getKey(), "my comment"); | |||
List<DefaultIssueComment> comments = service.findComments(issue.getKey()); | |||
assertThat(comments).hasSize(1); | |||
@@ -131,7 +131,7 @@ public class IssueCommentServiceMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
service.addComment(issue.getKey(), "my comment", userSessionRule); | |||
service.addComment(issue.getKey(), "my comment"); | |||
List<DefaultIssueComment> comments = service.findComments(issue.getKey()); | |||
assertThat(comments).hasSize(1); |
@@ -88,7 +88,7 @@ public class IssueCommentServiceTest { | |||
when(dbClient.openSession(false)).thenReturn(session); | |||
when(dbClient.issueChangeDao()).thenReturn(changeDao); | |||
issueCommentService = new IssueCommentService(dbClient, issueService, updater); | |||
issueCommentService = new IssueCommentService(dbClient, issueService, updater, userSessionRule); | |||
} | |||
@Test | |||
@@ -109,7 +109,7 @@ public class IssueCommentServiceTest { | |||
when(issueService.getByKeyForUpdate(session, "ABCD")).thenReturn(issueDto); | |||
when(issueCommentService.findComments(session, "ABCD")).thenReturn(newArrayList(new DefaultIssueComment())); | |||
issueCommentService.addComment("ABCD", "my comment", userSessionRule); | |||
issueCommentService.addComment("ABCD", "my comment"); | |||
verify(updater).addComment(eq(issueDto.toDefaultIssue()), eq("my comment"), any(IssueChangeContext.class)); | |||
verify(issueService).saveIssue(eq(session), eq(issueDto.toDefaultIssue()), any(IssueChangeContext.class), eq("my comment")); | |||
@@ -120,7 +120,7 @@ public class IssueCommentServiceTest { | |||
throwable.expect(UnauthorizedException.class); | |||
userSessionRule.anonymous(); | |||
issueCommentService.addComment("myIssue", "my comment", userSessionRule); | |||
issueCommentService.addComment("myIssue", "my comment"); | |||
verify(updater, never()).addComment(any(DefaultIssue.class), anyString(), any(IssueChangeContext.class)); | |||
verifyZeroInteractions(issueService); | |||
@@ -130,7 +130,7 @@ public class IssueCommentServiceTest { | |||
public void should_prevent_adding_empty_comment() { | |||
throwable.expect(BadRequestException.class); | |||
issueCommentService.addComment("myIssue", " ", userSessionRule); | |||
issueCommentService.addComment("myIssue", " "); | |||
verify(updater, never()).addComment(any(DefaultIssue.class), anyString(), any(IssueChangeContext.class)); | |||
verifyZeroInteractions(issueService); | |||
@@ -140,7 +140,7 @@ public class IssueCommentServiceTest { | |||
public void should_prevent_adding_null_comment() { | |||
throwable.expect(BadRequestException.class); | |||
issueCommentService.addComment("myIssue", null, userSessionRule); | |||
issueCommentService.addComment("myIssue", null); | |||
verify(updater, never()).addComment(any(DefaultIssue.class), anyString(), any(IssueChangeContext.class)); | |||
verifyZeroInteractions(issueService); | |||
@@ -154,7 +154,7 @@ public class IssueCommentServiceTest { | |||
when(issueCommentService.findComments(session, "ABCD")).thenReturn(Collections.<DefaultIssueComment>emptyList()); | |||
try { | |||
issueCommentService.addComment("ABCD", "my comment", userSessionRule); | |||
issueCommentService.addComment("ABCD", "my comment"); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Fail to add a comment on issue ABCD"); | |||
@@ -165,7 +165,7 @@ public class IssueCommentServiceTest { | |||
public void should_delete_comment() { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(new DefaultIssueComment().setUserLogin("admin").setIssueKey("EFGH")); | |||
issueCommentService.deleteComment("ABCD", userSessionRule); | |||
issueCommentService.deleteComment("ABCD"); | |||
verify(changeDao).delete("ABCD"); | |||
verify(issueService).getByKey("EFGH"); | |||
@@ -177,7 +177,7 @@ public class IssueCommentServiceTest { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(null); | |||
issueCommentService.deleteComment("ABCD", userSessionRule); | |||
issueCommentService.deleteComment("ABCD"); | |||
verify(changeDao, never()).delete(anyString()); | |||
} | |||
@@ -188,7 +188,7 @@ public class IssueCommentServiceTest { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(new DefaultIssueComment().setUserLogin("julien")); | |||
issueCommentService.deleteComment("ABCD", userSessionRule); | |||
issueCommentService.deleteComment("ABCD"); | |||
verify(changeDao, never()).delete(anyString()); | |||
} | |||
@@ -197,7 +197,7 @@ public class IssueCommentServiceTest { | |||
public void should_update_comment() { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(new DefaultIssueComment().setIssueKey("EFGH").setUserLogin("admin")); | |||
issueCommentService.editComment("ABCD", "updated comment", userSessionRule); | |||
issueCommentService.editComment("ABCD", "updated comment"); | |||
verify(changeDao).update(any(IssueChangeDto.class)); | |||
verify(issueService).getByKey("EFGH"); | |||
@@ -209,7 +209,7 @@ public class IssueCommentServiceTest { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(null); | |||
issueCommentService.editComment("ABCD", "updated comment", userSessionRule); | |||
issueCommentService.editComment("ABCD", "updated comment"); | |||
verify(changeDao, never()).update(any(IssueChangeDto.class)); | |||
} | |||
@@ -218,7 +218,7 @@ public class IssueCommentServiceTest { | |||
public void should_prevent_updating_empty_comment() { | |||
throwable.expect(BadRequestException.class); | |||
issueCommentService.editComment("ABCD", "", userSessionRule); | |||
issueCommentService.editComment("ABCD", ""); | |||
verify(changeDao, never()).update(any(IssueChangeDto.class)); | |||
} | |||
@@ -227,7 +227,7 @@ public class IssueCommentServiceTest { | |||
public void should_prevent_updating_null_comment() { | |||
throwable.expect(BadRequestException.class); | |||
issueCommentService.editComment("ABCD", null, userSessionRule); | |||
issueCommentService.editComment("ABCD", null); | |||
verify(changeDao, never()).update(any(IssueChangeDto.class)); | |||
} | |||
@@ -238,7 +238,7 @@ public class IssueCommentServiceTest { | |||
when(changeDao.selectCommentByKey("ABCD")).thenReturn(new DefaultIssueComment().setUserLogin("julien")); | |||
issueCommentService.editComment("ABCD", "updated comment", userSessionRule); | |||
issueCommentService.editComment("ABCD", "updated comment"); | |||
verify(changeDao, never()).update(any(IssueChangeDto.class)); | |||
} |
@@ -59,6 +59,7 @@ import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.issue.index.IssueDoc; | |||
import org.sonar.server.issue.index.IssueIndex; | |||
import org.sonar.server.issue.index.IssueIndexDefinition; | |||
import org.sonar.server.issue.index.IssueIndexer; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.permission.PermissionChange; | |||
@@ -478,7 +479,7 @@ public class IssueServiceMediumTest { | |||
ComponentDto file = newFile(project); | |||
saveIssue(IssueTesting.newDto(rule, file, project)); | |||
List<IssueDoc> result = service.search(IssueQuery.builder(userSessionRule).build(), new SearchOptions()).getDocs(); | |||
List<IssueDoc> result = service.search(IssueQuery.builder(userSessionRule).build(), new SearchOptions().addFields(IssueIndexDefinition.FIELD_ISSUE_KEY)).getDocs(); | |||
assertThat(result).hasSize(1); | |||
} | |||
@@ -28,11 +28,10 @@ import org.junit.runner.RunWith; | |||
import org.mockito.Mock; | |||
import org.mockito.runners.MockitoJUnitRunner; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.issue.action.Action; | |||
import org.sonar.core.issue.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.DefaultIssue; | |||
import org.sonar.core.issue.workflow.Transition; | |||
import org.sonar.server.issue.ActionService; | |||
import org.sonar.server.issue.IssueService; | |||
@@ -41,7 +40,6 @@ import org.sonar.test.JsonAssert; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.mockito.Matchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
@RunWith(MockitoJUnitRunner.class) | |||
@@ -81,26 +79,6 @@ public class IssueActionsWriterTest { | |||
"]}"); | |||
} | |||
@Test | |||
public void write_plugin_actions() { | |||
Issue issue = new DefaultIssue() | |||
.setKey("ABCD") | |||
.setComponentKey("sample:src/main/xoo/sample/Sample.xoo") | |||
.setProjectKey("sample") | |||
.setRuleKey(RuleKey.of("squid", "AvoidCycle")); | |||
userSessionRule.login("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\", \"set_tags\", \"assign_to_me\", \"plan\", \"link-to-jira\"\n" + | |||
"]}"); | |||
} | |||
@Test | |||
public void write_only_comment_action() { | |||
Issue issue = new DefaultIssue() |
@@ -43,8 +43,8 @@ import org.sonar.server.component.ComponentTesting; | |||
import org.sonar.server.issue.IssueTesting; | |||
import org.sonar.server.issue.filter.IssueFilterParameters; | |||
import org.sonar.server.issue.index.IssueIndexer; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.permission.PermissionChange; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.rule.db.RuleDao; | |||
import org.sonar.server.tester.ServerTester; | |||
import org.sonar.server.tester.UserSessionRule; | |||
@@ -83,9 +83,9 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void issues_on_different_projects() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(rule, file, project) | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") | |||
.setStatus("OPEN").setResolution("OPEN") | |||
@@ -94,9 +94,9 @@ public class SearchActionComponentsMediumTest { | |||
.setIssueUpdateDate(DateUtils.parseDateTime("2017-12-04T00:00:00+0100")); | |||
db.issueDao().insert(session, issue); | |||
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("DBCA").setKey("MyProject2")); | |||
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("P2").setKey("MyProject2")); | |||
setDefaultProjectPermission(project2); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "EDCB").setKey("MyComponent2")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "F2").setKey("MyComponent2")); | |||
IssueDto issue2 = IssueTesting.newDto(rule, file2, project2) | |||
.setKee("92fd47d4-b650-4037-80bc-7b112bd4eac2") | |||
.setStatus("OPEN").setResolution("OPEN") | |||
@@ -107,36 +107,36 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).execute(); | |||
result.assertJson(this.getClass(), "issues_on_different_projects.json"); | |||
} | |||
@Test | |||
public void search_by_project_uuid() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.PROJECT_UUIDS, project.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_project_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.PROJECT_UUIDS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_project_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -144,15 +144,15 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void project_facet_is_sticky() throws Exception { | |||
ComponentDto project1 = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject1")); | |||
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("BCDE").setKey("MyProject2")); | |||
ComponentDto project3 = insertComponent(ComponentTesting.newProjectDto("CDEF").setKey("MyProject3")); | |||
ComponentDto project1 = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject1")); | |||
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("P2").setKey("MyProject2")); | |||
ComponentDto project3 = insertComponent(ComponentTesting.newProjectDto("P3").setKey("MyProject3")); | |||
setDefaultProjectPermission(project1); | |||
setDefaultProjectPermission(project2); | |||
setDefaultProjectPermission(project3); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project1, "FEDC").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "EDCB").setKey("MyComponent2")); | |||
ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project3, "DCBA").setKey("MyComponent3")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project1, "F1").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "F2").setKey("MyComponent2")); | |||
ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project3, "F3").setKey("MyComponent3")); | |||
RuleDto rule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(rule, file1, project1).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
IssueDto issue2 = IssueTesting.newDto(rule, file2, project2).setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"); | |||
@@ -161,7 +161,7 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.PROJECT_UUIDS, project1.uuid()) | |||
.setParam(WebService.Param.FACETS, "projectUuids") | |||
.execute() | |||
@@ -170,30 +170,30 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_file_uuid() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.FILE_UUIDS, file.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_file_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.FILE_UUIDS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, file.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_file_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -201,10 +201,10 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_file_key() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto unitTest = insertComponent(ComponentTesting.newFileDto(project, "CDEF").setQualifier(Qualifiers.UNIT_TEST_FILE).setKey("MyComponentTest")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
ComponentDto unitTest = insertComponent(ComponentTesting.newFileDto(project, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setKey("MyComponentTest")); | |||
RuleDto rule = newRule(); | |||
IssueDto issueOnFile = IssueTesting.newDto(rule, file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
IssueDto issueOnTest = IssueTesting.newDto(rule, unitTest, project).setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"); | |||
@@ -212,12 +212,12 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENTS, file.key()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_file_key.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENTS, unitTest.key()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_test_key.json"); | |||
@@ -226,11 +226,11 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void display_file_facet() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project, "CDEF").setKey("MyComponent2")); | |||
ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project, "DEFA").setKey("MyComponent3")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project, "F2").setKey("MyComponent2")); | |||
ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project, "F3").setKey("MyComponent3")); | |||
RuleDto newRule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(newRule, file1, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
IssueDto issue2 = IssueTesting.newDto(newRule, file2, project).setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"); | |||
@@ -238,7 +238,7 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid()) | |||
.setParam(IssueFilterParameters.FILE_UUIDS, file1.uuid() + "," + file3.uuid()) | |||
.setParam(WebService.Param.FACETS, "fileUuids") | |||
@@ -248,31 +248,31 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_directory_path() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java")); | |||
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "D1", "src/main/java/dir")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, directory.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_file_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_file_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -280,14 +280,14 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_directory_path_in_different_modules() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto module1 = insertComponent(ComponentTesting.newModuleDto(project).setKey("module1")); | |||
ComponentDto module2 = insertComponent(ComponentTesting.newModuleDto(project).setKey("module2")); | |||
ComponentDto directory1 = insertComponent(ComponentTesting.newDirectory(module1, "src/main/java/dir")); | |||
ComponentDto directory2 = insertComponent(ComponentTesting.newDirectory(module2, "src/main/java/dir")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(module1, "BCDE").setKey("module1:MyComponent").setPath(directory1.path() + "/MyComponent.java")); | |||
insertComponent(ComponentTesting.newFileDto(module2, "CDEF").setKey("module2:MyComponent").setPath(directory2.path() + "/MyComponent.java")); | |||
ComponentDto module1 = insertComponent(ComponentTesting.newModuleDto("M1", project).setKey("module1")); | |||
ComponentDto module2 = insertComponent(ComponentTesting.newModuleDto("M2", project).setKey("module2")); | |||
ComponentDto directory1 = insertComponent(ComponentTesting.newDirectory(module1, "D1", "src/main/java/dir")); | |||
ComponentDto directory2 = insertComponent(ComponentTesting.newDirectory(module2, "D2", "src/main/java/dir")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(module1, "F1").setKey("module1:MyComponent").setPath(directory1.path() + "/MyComponent.java")); | |||
insertComponent(ComponentTesting.newFileDto(module2, "F2").setKey("module2:MyComponent").setPath(directory2.path() + "/MyComponent.java")); | |||
RuleDto rule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(rule, file1, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue1); | |||
@@ -295,34 +295,34 @@ public class SearchActionComponentsMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, directory1.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_directory_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, directory2.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.MODULE_UUIDS, module1.uuid()) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_directory_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.MODULE_UUIDS, module2.uuid()) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir") | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_directory_uuid.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.DIRECTORIES, "src/main/java") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -330,14 +330,14 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void display_module_facet() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto module = insertComponent(ComponentTesting.newModuleDto("BCDE", project).setKey("MyModule")); | |||
ComponentDto subModule1 = insertComponent(ComponentTesting.newModuleDto("CDEF", module).setKey("MySubModule1")); | |||
ComponentDto subModule2 = insertComponent(ComponentTesting.newModuleDto("DEFA", module).setKey("MySubModule2")); | |||
ComponentDto subModule3 = insertComponent(ComponentTesting.newModuleDto("EFAB", module).setKey("MySubModule3")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(subModule1, "FEDC").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(subModule2, "EDCB").setKey("MyComponent2")); | |||
ComponentDto module = insertComponent(ComponentTesting.newModuleDto("M1", project).setKey("MyModule")); | |||
ComponentDto subModule1 = insertComponent(ComponentTesting.newModuleDto("SUBM1", module).setKey("MySubModule1")); | |||
ComponentDto subModule2 = insertComponent(ComponentTesting.newModuleDto("SUBM2", module).setKey("MySubModule2")); | |||
ComponentDto subModule3 = insertComponent(ComponentTesting.newModuleDto("SUBM3", module).setKey("MySubModule3")); | |||
ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(subModule1, "F1").setKey("MyComponent1")); | |||
ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(subModule2, "F2").setKey("MyComponent2")); | |||
RuleDto newRule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(newRule, file1, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
IssueDto issue2 = IssueTesting.newDto(newRule, file2, project).setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"); | |||
@@ -345,7 +345,7 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, module.uuid()) | |||
.setParam(IssueFilterParameters.MODULE_UUIDS, subModule1.uuid() + "," + subModule3.uuid()) | |||
.setParam(WebService.Param.FACETS, "moduleUuids") | |||
@@ -355,17 +355,17 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void display_directory_facet() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java")); | |||
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "D1", "src/main/java/dir")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam(WebService.Param.FACETS, "directories") | |||
.execute(); | |||
@@ -374,18 +374,18 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_view_uuid() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("CDEF").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
indexView(view.uuid(), newArrayList(project.uuid())); | |||
setAnyoneProjectPermission(view, UserRole.USER); | |||
userSessionRule.login("john").addProjectUuidPermissions(UserRole.USER, view.uuid()); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, view.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_view_uuid.json"); | |||
@@ -393,19 +393,19 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_view_uuid_return_only_authorized_view() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("CDEF").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
indexView(view.uuid(), newArrayList(project.uuid())); | |||
setAnyoneProjectPermission(view, UserRole.USER); | |||
// User has wrong permission on the view, no issue will be returned | |||
userSessionRule.login("john").addProjectUuidPermissions(UserRole.CODEVIEWER, view.uuid()); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, view.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -413,20 +413,20 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_sub_view_uuid() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("CDEF").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
indexView(view.uuid(), newArrayList(project.uuid())); | |||
ComponentDto subView = insertComponent(ComponentTesting.newProjectDto("DEFG").setQualifier(Qualifiers.SUBVIEW).setKey("MySubView")); | |||
ComponentDto subView = insertComponent(ComponentTesting.newProjectDto("SV1").setQualifier(Qualifiers.SUBVIEW).setKey("MySubView")); | |||
indexView(subView.uuid(), newArrayList(project.uuid())); | |||
setAnyoneProjectPermission(view, UserRole.USER); | |||
userSessionRule.login("john").addComponentUuidPermission(UserRole.USER, view.uuid(), subView.uuid()); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, subView.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_view_uuid.json"); | |||
@@ -434,30 +434,31 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_sub_view_uuid_return_only_authorized_view() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("CDEF").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView")); | |||
indexView(view.uuid(), newArrayList(project.uuid())); | |||
ComponentDto subView = insertComponent(ComponentTesting.newProjectDto("DEFG").setQualifier(Qualifiers.SUBVIEW).setKey("MySubView")); | |||
ComponentDto subView = insertComponent(ComponentTesting.newProjectDto("SV1").setQualifier(Qualifiers.SUBVIEW).setKey("MySubView")); | |||
indexView(subView.uuid(), newArrayList(project.uuid())); | |||
setAnyoneProjectPermission(view, UserRole.USER); | |||
// User has wrong permission on the view, no issue will be returned | |||
userSessionRule.login("john").addComponentUuidPermission(UserRole.CODEVIEWER, view.uuid(), subView.uuid()); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, subView.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
} | |||
@Test | |||
public void search_by_author() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
RuleDto newRule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(newRule, file, project).setAuthorLogin("leia").setKee("2bd4eac2-b650-4037-80bc-7b112bd4eac2"); | |||
IssueDto issue2 = IssueTesting.newDto(newRule, file, project).setAuthorLogin("luke@skywalker.name").setKee("82fd47d4-b650-4037-80bc-7b1182fd47d4"); | |||
@@ -466,13 +467,13 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.AUTHORS, "leia") | |||
.setParam(WebService.Param.FACETS, "authors") | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_authors.json"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.AUTHORS, "unknown") | |||
.execute() | |||
.assertJson(this.getClass(), "no_issue.json"); | |||
@@ -481,9 +482,9 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_developer() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
ComponentDto developer = insertComponent(ComponentTesting.newDeveloper("Anakin Skywalker")); | |||
db.authorDao().insertAuthor("vader", developer.getId()); | |||
db.authorDao().insertAuthor("anakin@skywalker.name", developer.getId()); | |||
@@ -495,7 +496,7 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, developer.uuid()) | |||
.execute() | |||
.assertJson(this.getClass(), "search_by_developer.json"); | |||
@@ -503,17 +504,17 @@ public class SearchActionComponentsMediumTest { | |||
@Test | |||
public void search_by_developer_technical_project() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("MyComponent")); | |||
ComponentDto otherProject = insertComponent(ComponentTesting.newProjectDto("XXXX").setKey("OtherProject")); | |||
ComponentDto otherProject = insertComponent(ComponentTesting.newProjectDto("P2").setKey("OtherProject")); | |||
setDefaultProjectPermission(otherProject); | |||
ComponentDto otherFile = insertComponent(ComponentTesting.newFileDto(otherProject, "YYYY").setKey("OtherComponent")); | |||
ComponentDto otherFile = insertComponent(ComponentTesting.newFileDto(otherProject, "F2").setKey("OtherComponent")); | |||
ComponentDto developer = insertComponent(ComponentTesting.newDeveloper("Anakin Skywalker")); | |||
ComponentDto technicalProject = insertComponent(ComponentTesting.newDevProjectCopy("CDEF", project, developer)); | |||
insertComponent(ComponentTesting.newDevProjectCopy("DEFG", otherProject, developer)); | |||
ComponentDto technicalProject = insertComponent(ComponentTesting.newDevProjectCopy("COPY_P1", project, developer)); | |||
insertComponent(ComponentTesting.newDevProjectCopy("COPY_P2", otherProject, developer)); | |||
db.authorDao().insertAuthor("vader", developer.getId()); | |||
db.authorDao().insertAuthor("anakin@skywalker.name", developer.getId()); | |||
@@ -527,7 +528,7 @@ public class SearchActionComponentsMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam(IssueFilterParameters.COMPONENT_UUIDS, technicalProject.uuid()) | |||
.execute(); | |||
result |
@@ -24,8 +24,10 @@ import com.google.common.collect.ImmutableMap; | |||
import org.junit.After; | |||
import org.junit.Before; | |||
import org.junit.ClassRule; | |||
import org.junit.Ignore; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.api.security.DefaultGroups; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -50,14 +52,15 @@ import org.sonar.server.issue.IssueQuery; | |||
import org.sonar.server.issue.IssueTesting; | |||
import org.sonar.server.issue.filter.IssueFilterParameters; | |||
import org.sonar.server.issue.index.IssueIndexer; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.permission.PermissionChange; | |||
import org.sonar.server.permission.PermissionService; | |||
import org.sonar.server.rule.db.RuleDao; | |||
import org.sonar.server.search.QueryContext; | |||
import org.sonar.server.tester.ServerTester; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.WsTester; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class SearchActionMediumTest { | |||
@@ -89,19 +92,19 @@ public class SearchActionMediumTest { | |||
public void define_action() { | |||
WebService.Controller controller = wsTester.controller("api/issues"); | |||
WebService.Action show = controller.action("search"); | |||
WebService.Action show = controller.action("search2"); | |||
assertThat(show).isNotNull(); | |||
assertThat(show.handler()).isNotNull(); | |||
assertThat(show.since()).isEqualTo("3.6"); | |||
assertThat(show.isPost()).isFalse(); | |||
assertThat(show.isInternal()).isFalse(); | |||
assertThat(show.responseExampleAsString()).isNotEmpty(); | |||
assertThat(show.params()).hasSize(40); | |||
assertThat(show.params()).hasSize(37); | |||
} | |||
@Test | |||
public void empty_search() throws Exception { | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION); | |||
WsTester.Result result = request.execute(); | |||
assertThat(result).isNotNull(); | |||
@@ -109,40 +112,43 @@ public class SearchActionMediumTest { | |||
} | |||
@Test | |||
public void issue() throws Exception { | |||
public void response_contains_all_fields_except_additional_fields() throws Exception { | |||
db.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com")); | |||
db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setDebt(10L) | |||
.setStatus("OPEN").setResolution("OPEN") | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") | |||
.setDebt(10L) | |||
.setMessage("the message") | |||
.setStatus(Issue.STATUS_RESOLVED) | |||
.setResolution(Issue.RESOLUTION_FIXED) | |||
.setSeverity("MAJOR") | |||
.setAuthorLogin("John") | |||
.setAssignee("simon") | |||
.setReporter("fabrice") | |||
.setActionPlanKey("AP-ABCD") | |||
.setTags(asList("bug", "owasp")) | |||
.setIssueCreationDate(DateUtils.parseDateTime("2014-09-04T00:00:00+0100")) | |||
.setIssueUpdateDate(DateUtils.parseDateTime("2017-12-04T00:00:00+0100")); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
result.assertJson(this.getClass(), "issue.json"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).execute(); | |||
result.assertJson(this.getClass(), "response_contains_all_fields_except_additional_fields.json"); | |||
} | |||
@Test | |||
public void issue_with_comment() throws Exception { | |||
public void issue_with_comments() throws Exception { | |||
db.userDao().insert(session, new UserDto().setLogin("john").setName("John")); | |||
db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
@@ -153,20 +159,22 @@ public class SearchActionMediumTest { | |||
.setChangeData("*My comment*") | |||
.setChangeType(IssueChangeDto.TYPE_COMMENT) | |||
.setUserLogin("john") | |||
.setCreatedAt(DateUtils.parseDate("2014-09-09").getTime())); | |||
.setCreatedAt(DateUtils.parseDateTime("2014-09-09T12:00:00+0000").getTime())); | |||
tester.get(IssueChangeDao.class).insert(session, | |||
new IssueChangeDto().setIssueKey(issue.getKey()) | |||
.setKey("COMMENT-ABCE") | |||
.setChangeData("Another comment") | |||
.setChangeType(IssueChangeDto.TYPE_COMMENT) | |||
.setUserLogin("fabrice") | |||
.setCreatedAt(DateUtils.parseDate("2014-09-10").getTime())); | |||
.setCreatedAt(DateUtils.parseDateTime("2014-09-10T12:00:00+0000").getTime())); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
result.assertJson(this.getClass(), "issue_with_comment.json"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("additionalFields", "comments,users") | |||
.execute(); | |||
result.assertJson(this.getClass(), "issue_with_comments.json"); | |||
} | |||
@Test | |||
@@ -174,9 +182,9 @@ public class SearchActionMediumTest { | |||
db.userDao().insert(session, new UserDto().setLogin("john").setName("John").setEmail("john@email.com")); | |||
db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"); | |||
db.issueDao().insert(session, issue); | |||
@@ -187,28 +195,28 @@ public class SearchActionMediumTest { | |||
.setChangeData("*My comment*") | |||
.setChangeType(IssueChangeDto.TYPE_COMMENT) | |||
.setUserLogin("john") | |||
.setCreatedAt(DateUtils.parseDate("2014-09-09").getTime())); | |||
.setCreatedAt(DateUtils.parseDateTime("2014-09-09T12:00:00+0000").getTime())); | |||
tester.get(IssueChangeDao.class).insert(session, | |||
new IssueChangeDto().setIssueKey(issue.getKey()) | |||
.setKey("COMMENT-ABCE") | |||
.setChangeData("Another comment") | |||
.setChangeType(IssueChangeDto.TYPE_COMMENT) | |||
.setUserLogin("fabrice") | |||
.setCreatedAt(DateUtils.parseDate("2014-09-10").getTime())); | |||
.setCreatedAt(DateUtils.parseDateTime("2014-09-10T19:10:03+0000").getTime())); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).setParam(IssueFilterParameters.HIDE_COMMENTS, "true").execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).setParam(IssueFilterParameters.HIDE_COMMENTS, "true").execute(); | |||
result.assertJson(this.getClass(), "issue_with_comment_hidden.json"); | |||
assertThat(result.outputAsString()).doesNotContain("fabrice"); | |||
} | |||
@Test | |||
public void issue_with_action_plan() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
tester.get(ActionPlanDao.class).save(new ActionPlanDto() | |||
.setKey("AP-ABCD") | |||
@@ -227,15 +235,18 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("additionalFields", "actionPlans") | |||
.execute(); | |||
result.assertJson(this.getClass(), "issue_with_action_plan.json"); | |||
} | |||
@Ignore("temporarily disabled") | |||
@Test | |||
public void issue_with_attributes() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") | |||
.setIssueAttributes(KeyValueFormat.format(ImmutableMap.of("jira-issue-key", "SONAR-1234"))); | |||
@@ -243,17 +254,18 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.execute(); | |||
result.assertJson(this.getClass(), "issue_with_attributes.json"); | |||
} | |||
@Test | |||
public void issue_with_extra_fields() throws Exception { | |||
public void load_additional_fields() throws Exception { | |||
db.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com")); | |||
db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
tester.get(ActionPlanDao.class).save(new ActionPlanDto() | |||
.setKey("AP-ABCD") | |||
@@ -273,17 +285,17 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
.setParam("f", "assignee,reporter,actionPlan,actions,transitions,actionPlanName").execute(); | |||
result.assertJson(this.getClass(), "issue_with_extra_fields.json"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("additionalFields", "_all").execute(); | |||
result.assertJson(this.getClass(), "load_additional_fields.json"); | |||
} | |||
@Test | |||
public void issue_linked_on_removed_file() throws Exception { | |||
public void issue_on_removed_file() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto removedFile = insertComponent(ComponentTesting.newFileDto(project).setUuid("EDCB") | |||
ComponentDto removedFile = insertComponent(ComponentTesting.newFileDto(project).setUuid("REMOVED_FILE_ID") | |||
.setEnabled(false) | |||
.setKey("RemovedComponent")); | |||
@@ -298,30 +310,31 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
result.assertJson(this.getClass(), "issue_linked_on_removed_file.json"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.execute(); | |||
result.assertJson(this.getClass(), "issue_on_removed_file.json"); | |||
} | |||
@Test | |||
public void issue_contains_component_id_for_eclipse() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).execute(); | |||
assertThat(result.outputAsString()).contains("\"componentId\":" + file.getId() + ","); | |||
} | |||
@Test | |||
public void apply_paging_with_one_component() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
for (int i = 0; i < QueryContext.MAX_LIMIT + 1; i++) { | |||
IssueDto issue = IssueTesting.newDto(rule, file, project); | |||
tester.get(IssueDao.class).insert(session, issue); | |||
@@ -329,13 +342,13 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).setParam(IssueFilterParameters.COMPONENTS, file.getKey()).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).setParam(IssueFilterParameters.COMPONENTS, file.getKey()).execute(); | |||
result.assertJson(this.getClass(), "apply_paging_with_one_component.json"); | |||
} | |||
@Test | |||
public void components_contains_sub_projects() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("ProjectHavingModule")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("ProjectHavingModule")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto module = insertComponent(ComponentTesting.newModuleDto(project).setKey("ModuleHavingFile")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(module, "BCDE").setKey("FileLinkedToModule")); | |||
@@ -344,15 +357,15 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION).setParam(Search2Action.ADDITIONAL_FIELDS, "_all").execute(); | |||
result.assertJson(this.getClass(), "components_contains_sub_projects.json"); | |||
} | |||
@Test | |||
public void display_facets() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
.setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) | |||
@@ -365,7 +378,7 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans") | |||
.execute(); | |||
@@ -374,9 +387,9 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void display_facets_in_debt_mode() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
.setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) | |||
@@ -389,7 +402,7 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans") | |||
.setParam("facetMode", "debt") | |||
@@ -399,9 +412,9 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void display_zero_valued_facets_for_selected_items() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
.setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) | |||
@@ -414,7 +427,7 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam("severities", "MAJOR,MINOR") | |||
.setParam("languages", "xoo,polop,palap") | |||
@@ -427,9 +440,9 @@ public class SearchActionMediumTest { | |||
public void filter_by_assigned_to_me() throws Exception { | |||
db.userDao().insert(session, new UserDto().setLogin("john").setName("John").setEmail("john@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
RuleDto rule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(rule, file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
@@ -459,7 +472,7 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam("assignees", "__me__") | |||
.setParam(WebService.Param.FACETS, "assignees,assigned_to_me") | |||
@@ -471,9 +484,9 @@ public class SearchActionMediumTest { | |||
public void filter_by_assigned_to_me_unauthenticated() throws Exception { | |||
userSessionRule.login(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
RuleDto rule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(rule, file, project) | |||
.setStatus("OPEN") | |||
@@ -490,7 +503,7 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam("assignees", "__me__") | |||
.execute() | |||
@@ -501,9 +514,9 @@ public class SearchActionMediumTest { | |||
public void assigned_to_me_facet_is_sticky_relative_to_assignees() throws Exception { | |||
db.userDao().insert(session, new UserDto().setLogin("alice").setName("Alice").setEmail("alice@email.com")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyFile")); | |||
RuleDto rule = newRule(); | |||
IssueDto issue1 = IssueTesting.newDto(rule, file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
@@ -533,7 +546,7 @@ public class SearchActionMediumTest { | |||
tester.get(IssueIndexer.class).indexAll(); | |||
userSessionRule.login("john-bob.polop"); | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("resolved", "false") | |||
.setParam("assignees", "alice") | |||
.setParam(WebService.Param.FACETS, "assignees,assigned_to_me") | |||
@@ -541,32 +554,12 @@ public class SearchActionMediumTest { | |||
.assertJson(this.getClass(), "assigned_to_me_facet_sticky.json"); | |||
} | |||
@Test | |||
public void hide_rules() throws Exception { | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
IssueDto issue = IssueTesting.newDto(newRule(), file, project) | |||
.setIssueCreationDate(DateUtils.parseDate("2014-09-04")) | |||
.setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) | |||
.setDebt(10L) | |||
.setStatus("OPEN") | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") | |||
.setSeverity("MAJOR"); | |||
db.issueDao().insert(session, issue); | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).setParam(IssueFilterParameters.HIDE_RULES, "true").execute(); | |||
result.assertJson(this.getClass(), "hide_rules.json"); | |||
} | |||
@Test | |||
public void sort_by_updated_at() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
db.issueDao().insert(session, IssueTesting.newDto(rule, file, project) | |||
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac1") | |||
.setIssueUpdateDate(DateUtils.parseDateTime("2014-11-02T00:00:00+0100"))); | |||
@@ -579,7 +572,7 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) | |||
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION) | |||
.setParam("sort", IssueQuery.SORT_BY_UPDATE_DATE) | |||
.setParam("asc", "false") | |||
.execute(); | |||
@@ -589,9 +582,9 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void paging() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
for (int i = 0; i < 12; i++) { | |||
IssueDto issue = IssueTesting.newDto(rule, file, project); | |||
tester.get(IssueDao.class).insert(session, issue); | |||
@@ -599,7 +592,7 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION); | |||
request.setParam(WebService.Param.PAGE, "2"); | |||
request.setParam(WebService.Param.PAGE_SIZE, "9"); | |||
@@ -610,9 +603,9 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void paging_with_page_size_to_minus_one() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
for (int i = 0; i < 12; i++) { | |||
IssueDto issue = IssueTesting.newDto(rule, file, project); | |||
tester.get(IssueDao.class).insert(session, issue); | |||
@@ -620,7 +613,7 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION); | |||
request.setParam(WebService.Param.PAGE, "1"); | |||
request.setParam(WebService.Param.PAGE_SIZE, "-1"); | |||
@@ -631,9 +624,9 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void deprecated_paging() throws Exception { | |||
RuleDto rule = newRule(); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); | |||
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("MyProject")); | |||
setDefaultProjectPermission(project); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); | |||
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "FILE_ID").setKey("MyComponent")); | |||
for (int i = 0; i < 12; i++) { | |||
IssueDto issue = IssueTesting.newDto(rule, file, project); | |||
tester.get(IssueDao.class).insert(session, issue); | |||
@@ -641,7 +634,7 @@ public class SearchActionMediumTest { | |||
session.commit(); | |||
tester.get(IssueIndexer.class).indexAll(); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION); | |||
request.setParam(IssueFilterParameters.PAGE_INDEX, "2"); | |||
request.setParam(IssueFilterParameters.PAGE_SIZE, "9"); | |||
@@ -651,7 +644,7 @@ public class SearchActionMediumTest { | |||
@Test | |||
public void default_page_size_is_100() throws Exception { | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION); | |||
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, Search2Action.SEARCH_ACTION); | |||
WsTester.Result result = request.execute(); | |||
result.assertJson(this.getClass(), "default_page_size_is_100.json"); |
@@ -55,7 +55,7 @@ public class ListActionTest { | |||
dbTester.getSession().commit(); | |||
TestResponse response = tester.newRequest() | |||
.setMimeType(MimeTypes.PROTOBUF) | |||
.setMediaType(MimeTypes.PROTOBUF) | |||
.execute(); | |||
assertThat(response.getMediaType()).isEqualTo(MimeTypes.PROTOBUF); | |||
@@ -63,8 +63,8 @@ public class ListActionTest { | |||
assertThat(listResponse.getRulesCount()).isEqualTo(2); | |||
assertThat(listResponse.getRules(0).getKey()).isEqualTo("S001"); | |||
assertThat(listResponse.getRules(0).hasInternalKey()).isFalse(); | |||
assertThat(listResponse.getRules(0).hasName()).isFalse(); | |||
assertThat(listResponse.getRules(0).getInternalKey()).isEqualTo(""); | |||
assertThat(listResponse.getRules(0).getName()).isEqualTo(""); | |||
assertThat(listResponse.getRules(1).getKey()).isEqualTo("S002"); | |||
assertThat(listResponse.getRules(1).getInternalKey()).isEqualTo("I002"); | |||
assertThat(listResponse.getRules(1).getName()).isEqualTo("Rule Two"); |
@@ -64,7 +64,7 @@ public class TestRequest extends ValidatingRequest { | |||
return mimeType; | |||
} | |||
public TestRequest setMimeType(String type) { | |||
public TestRequest setMediaType(String type) { | |||
checkNotNull(type); | |||
this.mimeType = type; | |||
return this; |
@@ -0,0 +1,38 @@ | |||
package org.sonar.server.ws; | |||
import org.junit.Test; | |||
import org.sonar.server.plugins.MimeTypes; | |||
import org.sonarqube.ws.Issues; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class WsUtilsTest { | |||
@Test | |||
public void write_json_by_default() throws Exception { | |||
TestRequest request = new TestRequest(); | |||
DumbResponse response = new DumbResponse(); | |||
Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); | |||
WsUtils.writeProtobuf(msg, request, response); | |||
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.JSON); | |||
assertThat(response.outputAsString()) | |||
.startsWith("{") | |||
.contains("\"key\":\"I1\"") | |||
.endsWith("}"); | |||
} | |||
@Test | |||
public void write_protobuf() throws Exception { | |||
TestRequest request = new TestRequest(); | |||
request.setMediaType(MimeTypes.PROTOBUF); | |||
DumbResponse response = new DumbResponse(); | |||
Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); | |||
WsUtils.writeProtobuf(msg, request, response); | |||
assertThat(response.stream().mediaType()).isEqualTo(MimeTypes.PROTOBUF); | |||
assertThat(Issues.Issue.parseFrom(response.getFlushedOutput()).getKey()).isEqualTo("I1"); | |||
} | |||
} |
@@ -1,37 +1,34 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"projects": [ | |||
{ "key": "MyProject" } | |||
], | |||
"components": [ | |||
{ "key": "MyProject" }, | |||
{ "key": "MyComponent1" }, | |||
{ "key": "MyComponent2" }, | |||
{ "key": "MyComponent3" } | |||
], | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent1", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
], | |||
"components": [ | |||
{ "id": "P1" }, | |||
{ "id": "F1" }, | |||
{ "id": "F2" }, | |||
{ "id": "F3" } | |||
], | |||
"facets": [ | |||
{ | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", | |||
"val": "F1", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "CDEF", | |||
"val": "F2", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "DEFA", | |||
"val": "F3", | |||
"count": 0 | |||
} | |||
] |
@@ -1,39 +1,34 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"projects": [ | |||
{ "key": "MyProject" } | |||
], | |||
"components": [ | |||
{ "key": "MyProject" }, | |||
{ "key": "MyModule" }, | |||
{ "key": "MySubModule1" }, | |||
{ "key": "MySubModule2" }, | |||
{ "key": "MySubModule3" }, | |||
{ "key": "MyComponent1" } | |||
], | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent1", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
], | |||
"components": [ | |||
{ "id": "P1" }, | |||
{ "id": "M1" }, | |||
{ "id": "SUBM1" }, | |||
{ "id": "SUBM2" }, | |||
{ "id": "SUBM3" }, | |||
{ "id": "F1" } | |||
], | |||
"facets": [ | |||
{ | |||
"property": "moduleUuids", | |||
"values": [ | |||
{ | |||
"val": "CDEF", | |||
"val": "SUBM1", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "DEFA", | |||
"val": "SUBM2", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "EFAB", | |||
"val": "SUBM3", | |||
"count": 0 | |||
} | |||
] |
@@ -1,13 +1,6 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"projects": [ | |||
{ "key": "MyProject1" } | |||
], | |||
"components": [ | |||
{ "key": "MyProject1" }, | |||
{ "key": "MyComponent1" } | |||
], | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
@@ -16,6 +9,10 @@ | |||
"rule": "xoo:x1" | |||
} | |||
], | |||
"components": [ | |||
{ "key": "MyProject1" }, | |||
{ "key": "MyComponent1" } | |||
], | |||
"facets": [ | |||
{ | |||
"property": "projectUuids", |
@@ -1,39 +1,32 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"projects": [ | |||
{ "key": "MyProject1" }, | |||
{ "key": "MyProject2" }, | |||
{ "key": "MyProject3" } | |||
], | |||
"components": [ | |||
{ "key": "MyProject1" }, | |||
{ "key": "MyProject2" }, | |||
{ "key": "MyProject3" }, | |||
{ "key": "MyComponent1" } | |||
], | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent1", | |||
"project": "MyProject1", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
], | |||
"components": [ | |||
{ "id": "P1" }, | |||
{ "id": "P2" }, | |||
{ "id": "P3" }, | |||
{ "id": "F1" } | |||
], | |||
"facets": [ | |||
{ | |||
"property": "projectUuids", | |||
"values": [ | |||
{ | |||
"val": "ABCD", | |||
"val": "P1", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "BCDE", | |||
"val": "P2", | |||
"count": 1 | |||
}, | |||
{ | |||
"val": "CDEF", | |||
"val": "P3", | |||
"count": 1 | |||
} | |||
] |
@@ -2,8 +2,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"resolution": "OPEN", | |||
@@ -12,8 +12,8 @@ | |||
}, | |||
{ | |||
"key": "92fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent2", | |||
"project": "MyProject2", | |||
"component": "F2", | |||
"project": "P2", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"resolution": "OPEN", | |||
@@ -23,34 +23,24 @@ | |||
], | |||
"components": [ | |||
{ | |||
"uuid": "BCDE", | |||
"id": "F1", | |||
"key": "MyComponent", | |||
"enabled" : true | |||
}, | |||
{ | |||
"uuid": "ABCD", | |||
"id": "P1", | |||
"key": "MyProject", | |||
"enabled" : true | |||
}, | |||
{ | |||
"uuid": "EDCB", | |||
"id": "F2", | |||
"key": "MyComponent2", | |||
"enabled" : true | |||
}, | |||
{ | |||
"uuid": "DBCA", | |||
"id": "P2", | |||
"key": "MyProject2", | |||
"enabled" : true | |||
} | |||
], | |||
"projects": [ | |||
{ | |||
"uuid": "ABCD", | |||
"key": "MyProject" | |||
}, | |||
{ | |||
"uuid": "DBCA", | |||
"key": "MyProject2" | |||
} | |||
] | |||
} |
@@ -4,8 +4,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "2bd4eac2-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1", | |||
"author": "leia" | |||
} |
@@ -1,18 +1,16 @@ | |||
{ | |||
"total": 2, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "2bd4eac2-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1", | |||
"author": "vader" | |||
}, | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b1182fd47d4", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1", | |||
"author": "anakin@skywalker.name" | |||
} |
@@ -1,11 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "module1:MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -1,11 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -1,11 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -1,12 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"ps": 100, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -1,11 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "2bd4eac2-b650-4037-80bc-7b1182fd47d4", | |||
"component": "MyComponentTest", | |||
"project": "MyProject", | |||
"component": "F2", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -1,12 +1,9 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"ps": 100, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "F1", | |||
"project": "P1", | |||
"rule": "xoo:x1" | |||
} | |||
] |
@@ -2,8 +2,7 @@ | |||
"issues": [ | |||
{ | |||
"key": "7b112bd4-b650-4037-80bc-82fd47d4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", |
@@ -9,10 +9,5 @@ | |||
{ | |||
"key": "ProjectHavingModule" | |||
} | |||
], | |||
"projects": [ | |||
{ | |||
"key": "ProjectHavingModule" | |||
} | |||
] | |||
} |
@@ -6,7 +6,6 @@ | |||
"pageIndex": 1, | |||
"pageSize": 100, | |||
"total": 0, | |||
"fTotal": "0", | |||
"pages": 0 | |||
} | |||
} |
@@ -3,7 +3,6 @@ | |||
"pageIndex": 2, | |||
"pageSize": 9, | |||
"total": 12, | |||
"fTotal": "12", | |||
"pages": 2 | |||
} | |||
} |
@@ -2,8 +2,7 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", | |||
@@ -90,7 +89,7 @@ | |||
"property": "projectUuids", | |||
"values": [ | |||
{ | |||
"val": "ABCD", | |||
"val": "PROJECT_ID", | |||
"count": 1 | |||
} | |||
] | |||
@@ -108,7 +107,7 @@ | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", | |||
"val": "FILE_ID", | |||
"count": 1 | |||
} | |||
] |
@@ -3,8 +3,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", | |||
@@ -40,6 +40,10 @@ | |||
{ | |||
"property": "severities", | |||
"values": [ | |||
{ | |||
"val": "MAJOR", | |||
"count": 10 | |||
}, | |||
{ | |||
"val": "INFO", | |||
"count": 0 | |||
@@ -48,10 +52,6 @@ | |||
"val": "MINOR", | |||
"count": 0 | |||
}, | |||
{ | |||
"val": "MAJOR", | |||
"count": 10 | |||
}, | |||
{ | |||
"val": "CRITICAL", | |||
"count": 0 | |||
@@ -91,7 +91,7 @@ | |||
"property": "projectUuids", | |||
"values": [ | |||
{ | |||
"val": "ABCD", | |||
"val": "PROJECT_ID", | |||
"count": 10 | |||
} | |||
] | |||
@@ -109,7 +109,7 @@ | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", | |||
"val": "FILE_ID", | |||
"count": 10 | |||
} | |||
] |
@@ -2,8 +2,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", | |||
@@ -90,7 +90,7 @@ | |||
"property": "projectUuids", | |||
"values": [ | |||
{ | |||
"val": "ABCD", | |||
"val": "PROJECT_ID", | |||
"count": 1 | |||
} | |||
] | |||
@@ -108,7 +108,7 @@ | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", | |||
"val": "FILE_ID", | |||
"count": 1 | |||
} | |||
] |
@@ -6,10 +6,7 @@ | |||
"pageIndex": 1, | |||
"pageSize": 100, | |||
"total": 0, | |||
"fTotal": "0", | |||
"pages": 0 | |||
}, | |||
"issues": [], | |||
"components": [], | |||
"projects": [] | |||
"issues": [] | |||
} |
@@ -2,8 +2,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", |
@@ -2,8 +2,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"severity": "MAJOR", |
@@ -1,62 +0,0 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"ps": 100, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"resolution": "OPEN", | |||
"severity": "MAJOR", | |||
"debt": "10min", | |||
"author": "John", | |||
"assignee": "simon", | |||
"reporter": "fabrice", | |||
"actionPlan": "AP-ABCD", | |||
"updateDate": "2017-12-04T00:00:00+0100" | |||
} | |||
], | |||
"rules": [ | |||
{ | |||
"key": "xoo:x1", | |||
"name": "Rule name", | |||
"desc": "Rule desc", | |||
"status": "READY" | |||
} | |||
], | |||
"components": [ | |||
{ | |||
"uuid": "BCDE", | |||
"key": "MyComponent", | |||
"enabled" : true | |||
}, | |||
{ | |||
"uuid": "ABCD", | |||
"key": "MyProject", | |||
"enabled" : true | |||
} | |||
], | |||
"projects": [ | |||
{ | |||
"uuid": "ABCD", | |||
"key": "MyProject" | |||
} | |||
], | |||
"users": [ | |||
{ | |||
"login": "simon", | |||
"name": "Simon", | |||
"active": true, | |||
"email": "simon@email.com" | |||
}, | |||
{ | |||
"login": "fabrice", | |||
"name": "Fabrice", | |||
"active": true, | |||
"email": "fabrice@email.com" | |||
} | |||
] | |||
} |
@@ -2,8 +2,8 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "RemovedComponent", | |||
"project": "MyProject", | |||
"component": "REMOVED_FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"resolution": "OPEN", | |||
@@ -13,12 +13,12 @@ | |||
], | |||
"components": [ | |||
{ | |||
"uuid": "EDCB", | |||
"id": "REMOVED_FILE_ID", | |||
"key": "RemovedComponent", | |||
"enabled" : false | |||
}, | |||
{ | |||
"uuid": "ABCD", | |||
"id": "PROJECT_ID", | |||
"key": "MyProject", | |||
"enabled" : true | |||
} |
@@ -10,11 +10,8 @@ | |||
"key": "AP-ABCD", | |||
"name": "1.0", | |||
"status": "OPEN", | |||
"project": "MyProject", | |||
"userLogin": "simon", | |||
"deadLine": "2014-01-24T19:10:03+0000", | |||
"createdAt": "2014-01-22T19:10:03+0000", | |||
"updatedAt": "2014-01-23T19:10:03+0000" | |||
"project": "PROJECT_ID" | |||
} | |||
] | |||
} |
@@ -1,26 +0,0 @@ | |||
{ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"comments": [ | |||
{ | |||
"key": "COMMENT-ABCD", | |||
"login": "john", | |||
"userName": "John", | |||
"htmlText": "<em>My comment</em>", | |||
"markdown": "*My comment*", | |||
"updatable": true | |||
}, | |||
{ | |||
"key": "COMMENT-ABCE", | |||
"login": "fabrice", | |||
"userName": "Fabrice", | |||
"email": "fabrice@email.com", | |||
"htmlText": "Another comment", | |||
"markdown": "Another comment", | |||
"updatable": false | |||
} | |||
] | |||
} | |||
] | |||
} |
@@ -0,0 +1,41 @@ | |||
{ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"rule": "xoo:x1", | |||
"severity": "MAJOR", | |||
"comments": [ | |||
{ | |||
"key": "COMMENT-ABCD", | |||
"login": "john", | |||
"htmlText": "\u003cem\u003eMy comment\u003c/em\u003e", | |||
"markdown": "*My comment*", | |||
"updatable": true, | |||
"createdAt": "2014-09-09T12:00:00+0000" | |||
}, | |||
{ | |||
"key": "COMMENT-ABCE", | |||
"login": "fabrice", | |||
"htmlText": "Another comment", | |||
"markdown": "Another comment", | |||
"updatable": false, | |||
"createdAt": "2014-09-10T12:00:00+0000" | |||
} | |||
] | |||
} | |||
], | |||
"users": [ | |||
{ | |||
"login": "fabrice", | |||
"name": "Fabrice", | |||
"email": "fabrice@email.com", | |||
"active": true | |||
}, | |||
{ | |||
"login": "john", | |||
"name": "John", | |||
"email": "", | |||
"active": true | |||
} | |||
] | |||
} |
@@ -1,58 +0,0 @@ | |||
{ | |||
"maxResultsReached": false, | |||
"total": 1, | |||
"p": 1, | |||
"ps": 100, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"line": 3, | |||
"rule": "xoo:x1", | |||
"status": "OPEN", | |||
"resolution": "OPEN", | |||
"severity": "MAJOR", | |||
"debt": "10min", | |||
"author": "John", | |||
"assignee": "simon", | |||
"reporter": "fabrice", | |||
"updateDate": "2014-12-04T00:00:00+0100" | |||
} | |||
], | |||
"rules": [ | |||
{ | |||
"key": "xoo:x1", | |||
"name": "Rule name", | |||
"desc": "Rule desc", | |||
"status": "READY" | |||
} | |||
], | |||
"components": [ | |||
{ | |||
"key": "MyComponent" | |||
}, | |||
{ | |||
"key": "MyProject" | |||
} | |||
], | |||
"projects": [ | |||
{ | |||
"key": "MyProject" | |||
} | |||
], | |||
"users": [ | |||
{ | |||
"login": "simon", | |||
"name": "Simon", | |||
"active": true, | |||
"email": "simon@email.com" | |||
}, | |||
{ | |||
"login": "fabrice", | |||
"name": "Fabrice", | |||
"active": true, | |||
"email": "fabrice@email.com" | |||
} | |||
] | |||
} |
@@ -5,7 +5,6 @@ | |||
"assignee": "simon", | |||
"reporter": "fabrice", | |||
"actionPlan": "AP-ABCD", | |||
"actionPlanName": "1.0", | |||
"actions": [ | |||
"comment", "assign", "set_tags", "assign_to_me", "plan" | |||
], | |||
@@ -13,5 +12,12 @@ | |||
"confirm", "resolve" | |||
] | |||
} | |||
], | |||
"actionPlans": [ | |||
{ | |||
"key": "AP-ABCD", | |||
"name": "1.0", | |||
"status": "OPEN" | |||
} | |||
] | |||
} |
@@ -0,0 +1,24 @@ | |||
{ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"rule": "xoo:x1", | |||
"severity": "MAJOR", | |||
"component": "FILE_ID", | |||
"resolution": "FIXED", | |||
"status": "RESOLVED", | |||
"message": "the message", | |||
"debt": "10min", | |||
"assignee": "simon", | |||
"reporter": "fabrice", | |||
"author": "John", | |||
"actionPlan": "AP-ABCD", | |||
"tags": [ | |||
"bug", | |||
"owasp" | |||
], | |||
"creationDate": "2014-09-04T01:00:00+0200", | |||
"updateDate": "2017-12-04T00:00:00+0100" | |||
} | |||
] | |||
} |
@@ -2,22 +2,22 @@ | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"updateDate": "2014-11-01T00:00:00+0100" | |||
}, | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac1", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"updateDate": "2014-11-02T00:00:00+0100" | |||
}, | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac3", | |||
"component": "MyComponent", | |||
"project": "MyProject", | |||
"component": "FILE_ID", | |||
"project": "PROJECT_ID", | |||
"rule": "xoo:x1", | |||
"updateDate": "2014-11-03T00:00:00+0100" | |||
} |
@@ -45,4 +45,6 @@ public class Actions { | |||
public List<Action> list() { | |||
return actions; | |||
} | |||
} |
@@ -25,8 +25,8 @@ option java_outer_classname = "Common"; | |||
option optimize_for = SPEED; | |||
message Paging { | |||
optional int32 page_index = 1; | |||
optional int32 page_size = 2; | |||
optional int32 pageIndex = 1; | |||
optional int32 pageSize = 2; | |||
optional int32 total = 3; | |||
optional int32 pages = 4; | |||
} | |||
@@ -42,17 +42,24 @@ message FacetValue { | |||
optional int64 count = 2; | |||
} | |||
enum Severity { | |||
INFO = 0; | |||
MINOR = 1; | |||
MAJOR = 2; | |||
CRITICAL = 3; | |||
BLOCKER = 4; | |||
} | |||
message Component { | |||
optional string uuid = 1; | |||
optional string id = 1; | |||
optional string key = 2; | |||
optional int32 id = 3; | |||
optional bool enabled = 4; | |||
optional string qualifier = 5; | |||
optional string name = 6; | |||
optional string longName = 7; | |||
optional string path = 8; | |||
optional int32 projectId = 9; | |||
optional int32 subProjectId = 10; | |||
optional bool enabled = 3; | |||
optional string qualifier = 4; | |||
optional string name = 5; | |||
optional string longName = 6; | |||
optional string path = 7; | |||
optional string project = 8; | |||
optional string subProject = 9; | |||
} | |||
message Rule { |
@@ -29,22 +29,39 @@ option optimize_for = SPEED; | |||
// Response of URL api/issues/search | |||
message Search { | |||
// TODO errors | |||
optional Paging paging = 1; | |||
repeated Issue issues = 2; | |||
repeated Facet facets = 3; | |||
repeated Component projects = 4; | |||
repeated Component components = 5; | |||
repeated Rule rules = 6; | |||
repeated User users = 7; | |||
optional int64 total = 1; | |||
optional int64 p = 2; | |||
optional int32 ps = 3; | |||
optional Paging paging = 4; | |||
// Total amount of debt, only when the facet "total" is enabled | |||
optional int64 debtTotal = 5; | |||
repeated Issue issues = 6; | |||
optional bool projectsPresentIfEmpty = 8; | |||
repeated Component projects = 9; | |||
optional bool componentsPresentIfEmpty = 10; | |||
repeated Component components = 11; | |||
optional bool rulesPresentIfEmpty = 12; | |||
repeated Rule rules = 13; | |||
optional bool usersPresentIfEmpty = 14; | |||
repeated User users = 15; | |||
optional bool actionPlansPresentIfEmpty = 16; | |||
repeated ActionPlan actionPlans = 17; | |||
optional bool languagesPresentIfEmpty = 18; | |||
repeated Language languages = 19; | |||
repeated Facet facets = 20; | |||
optional bool facetsPresentIfEmpty = 21; | |||
} | |||
message Issue { | |||
optional string key = 1; | |||
optional string rule = 2; | |||
optional string component = 3; | |||
optional int32 componentId = 4; | |||
optional string project = 5; | |||
optional string subProject = 6; | |||
optional Severity severity = 3; | |||
optional string component = 4; | |||
optional int64 componentId = 5; | |||
optional string project = 6; | |||
optional int32 line = 7; | |||
optional string resolution = 8; | |||
optional string status = 9; | |||
@@ -52,27 +69,57 @@ message Issue { | |||
optional string debt = 11; | |||
optional string assignee = 12; | |||
optional string reporter = 13; | |||
optional string scmAuthor = 14; | |||
// SCM login of the committer who introduced the issue | |||
optional string author = 14; | |||
optional string actionPlan = 15; | |||
optional string actionPlanName = 16; | |||
optional string attr = 17; | |||
repeated string tags = 18; | |||
repeated string transitions = 19; | |||
repeated string actions = 20; | |||
repeated Comment comments = 21; | |||
optional string creationDate= 22; | |||
optional string updateDate= 23; | |||
optional string fUpdateAge= 24; | |||
optional string closeDate= 25; | |||
// the transitions allowed for the requesting user. | |||
optional bool transitionsPresentIfEmpty=19; | |||
repeated string transitions = 20; | |||
// the actions allowed for the requesting user. | |||
optional bool actionsPresentIfEmpty=21; | |||
repeated string actions = 22; | |||
optional bool commentsPresentIfEmpty = 23; | |||
repeated Comment comments = 24; | |||
optional string creationDate= 25; | |||
optional string updateDate= 26; | |||
optional string fUpdateAge= 27; | |||
optional string closeDate= 28; | |||
} | |||
message Comment { | |||
optional string key = 1; | |||
optional string login = 2; | |||
// TODO drop, it's already in field "users" | |||
optional string email = 3; | |||
// TODO drop, it's already in field "users" | |||
optional string userName = 4; | |||
optional string htmlText = 5; | |||
// TODO rename markdownText ? | |||
optional string markdown = 6; | |||
optional bool updatable = 7; | |||
optional string createdAt = 8; | |||
} | |||
message ActionPlan { | |||
optional string key = 1; | |||
optional string name = 2; | |||
// TODO define enum | |||
optional string status = 3; | |||
optional string deadLine = 4; | |||
// TODO to be renamed, is it id or key ? | |||
optional string project = 5; | |||
} | |||
message Language { | |||
optional string key = 1; | |||
optional string name = 2; | |||
} |