summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-03-15 16:10:17 +0100
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-03-16 16:53:06 +0100
commit887cda2d00ba7b62ee311bc78a4ea611696e9761 (patch)
tree92ad7a5df04ca4a7657c42dc450a28e0109e3f60
parentb7fa24cc420d8ca593af5df68e4147dbe7da1bfa (diff)
downloadsonarqube-887cda2d00ba7b62ee311bc78a4ea611696e9761.tar.gz
sonarqube-887cda2d00ba7b62ee311bc78a4ea611696e9761.zip
SONAR-7200 WS api/issues/search filter issues on leak period
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java62
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java7
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java37
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java140
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java16
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_since_leak_period.json10
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java1
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java2
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java11
9 files changed, 233 insertions, 53 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
index 2cc8d64f234..0ddc0f472f8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
@@ -21,7 +21,6 @@ package org.sonar.server.issue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
@@ -30,6 +29,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -46,20 +46,29 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
-import org.sonar.server.rule.RuleKeyFunctions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
import org.sonar.server.component.ComponentService;
+import org.sonar.server.rule.RuleKeyFunctions;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.RubyUtils;
import org.sonarqube.ws.client.issue.IssueFilterParameters;
import org.sonarqube.ws.client.issue.SearchWsRequest;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.String.format;
+import static org.sonar.api.utils.DateUtils.longToDate;
import static org.sonar.db.component.ComponentDtoFunctions.toCopyResourceId;
import static org.sonar.db.component.ComponentDtoFunctions.toProjectUuid;
import static org.sonar.db.component.ComponentDtoFunctions.toUuid;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
+import static org.sonar.server.ws.WsUtils.checkRequest;
+import static org.sonarqube.ws.client.issue.IssueFilterParameters.CREATED_AFTER;
+import static org.sonarqube.ws.client.issue.IssueFilterParameters.CREATED_IN_LAST;
+import static org.sonarqube.ws.client.issue.IssueFilterParameters.SINCE_LEAK_PERIOD;
/**
* This component is used to create an IssueQuery, in order to transform the component and component roots keys into uuid.
@@ -103,7 +112,7 @@ public class IssueQueryService {
.planned(RubyUtils.toBoolean(params.get(IssueFilterParameters.PLANNED)))
.hideRules(RubyUtils.toBoolean(params.get(IssueFilterParameters.HIDE_RULES)))
.createdAt(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_AT)))
- .createdAfter(buildCreatedAfter(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_AFTER)), (String) params.get(IssueFilterParameters.CREATED_IN_LAST)))
+ .createdAfter(buildCreatedAfterFromDates(RubyUtils.toDate(params.get(CREATED_AFTER)), (String) params.get(CREATED_IN_LAST)))
.createdBefore(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_BEFORE)));
Set<String> allComponentUuids = Sets.newHashSet();
@@ -147,12 +156,12 @@ public class IssueQueryService {
}
}
- private Date buildCreatedAfter(@Nullable Date createdAfter, @Nullable String createdSince) {
- Preconditions.checkArgument(createdAfter == null || createdSince == null, "createdAfter and createdSince cannot be set simultaneously");
+ private Date buildCreatedAfterFromDates(@Nullable Date createdAfter, @Nullable String createdInLast) {
+ checkArgument(createdAfter == null || createdInLast == null, format("%s and %s cannot be set simultaneously", CREATED_AFTER, CREATED_IN_LAST));
Date actualCreatedAfter = createdAfter;
- if (createdSince != null) {
- actualCreatedAfter = new DateTime(system.now()).minus(ISOPeriodFormat.standard().parsePeriod("P" + createdSince.toUpperCase())).toDate();
+ if (createdInLast != null) {
+ actualCreatedAfter = new DateTime(system.now()).minus(ISOPeriodFormat.standard().parsePeriod("P" + createdInLast.toUpperCase())).toDate();
}
return actualCreatedAfter;
}
@@ -176,7 +185,6 @@ public class IssueQueryService {
.assigned(request.getAssigned())
.planned(request.getPlanned())
.createdAt(parseAsDateTime(request.getCreatedAt()))
- .createdAfter(buildCreatedAfter(parseAsDateTime(request.getCreatedAfter()), request.getCreatedInLast()))
.createdBefore(parseAsDateTime(request.getCreatedBefore()))
.facetMode(request.getFacetMode());
@@ -200,6 +208,8 @@ public class IssueQueryService {
request.getFileUuids(),
request.getAuthors());
+ builder.createdAfter(buildCreatedAfterFromRequest(session, request, allComponentUuids, effectiveOnComponentOnly));
+
String sort = request.getSort();
if (!Strings.isNullOrEmpty(sort)) {
builder.sort(sort);
@@ -212,6 +222,42 @@ public class IssueQueryService {
}
}
+ private Date buildCreatedAfterFromRequest(DbSession dbSession, SearchWsRequest request, Set<String> componentUuids, boolean effectiveOnComponentOnly) {
+ Date createdAfter = parseAsDateTime(request.getCreatedAfter());
+ String createdInLast = request.getCreatedInLast();
+
+ if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod()) {
+ return buildCreatedAfterFromDates(createdAfter, createdInLast);
+ }
+
+ checkRequest(createdAfter == null, "'%s' and '%s' cannot be set simultaneously", CREATED_AFTER, SINCE_LEAK_PERIOD);
+ Set<String> allComponentUuids = new HashSet<>(componentUuids);
+ if (!effectiveOnComponentOnly) {
+ if (request.getProjectKeys() != null) {
+ allComponentUuids.addAll(componentUuids(dbSession, request.getProjectKeys()));
+ }
+ if (request.getProjectUuids() != null) {
+ allComponentUuids.addAll(request.getProjectUuids());
+ }
+ if (request.getModuleUuids() != null) {
+ allComponentUuids.addAll(request.getModuleUuids());
+ }
+ if (request.getFileUuids() != null) {
+ allComponentUuids.addAll(request.getFileUuids());
+ }
+ }
+
+ checkArgument(allComponentUuids.size() == 1, "One and only one component must be provided when searching since leak period");
+ String uuid = allComponentUuids.iterator().next();
+ // TODO use ComponentFinder instead
+ ComponentDto component = checkFoundWithOptional(componentService.getByUuid(uuid), "Component with id '%s' not found", uuid);
+ SnapshotDto snapshot = dbClient.snapshotDao().selectLastSnapshotByComponentId(dbSession, component.getId());
+ Long projectSnapshotId = snapshot == null ? null : snapshot.getRootId();
+ SnapshotDto projectSnapshot = projectSnapshotId == null ? snapshot : dbClient.snapshotDao().selectById(dbSession, projectSnapshotId);
+ Date createdAfterFromSnapshot = projectSnapshot == null ? null : longToDate(projectSnapshot.getPeriodDate(1));
+ return buildCreatedAfterFromDates(createdAfterFromSnapshot, createdInLast);
+ }
+
private List<String> buildAssignees(@Nullable List<String> assigneesFromParams) {
List<String> assignees = Lists.newArrayList();
if (assigneesFromParams != null) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
index 30dc75db6aa..7430632729a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
@@ -92,6 +92,7 @@ import static org.sonarqube.ws.client.issue.IssueFilterParameters.RESOLUTIONS;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.RESOLVED;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.RULES;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.SEVERITIES;
+import static org.sonarqube.ws.client.issue.IssueFilterParameters.SINCE_LEAK_PERIOD;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.STATUSES;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.TAGS;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.TYPES;
@@ -206,6 +207,11 @@ public class SearchAction implements IssuesWsAction {
"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)");
+ action.createParam(SINCE_LEAK_PERIOD)
+ .setDescription("To retrieve issues created since the leak period.<br>" +
+ "If this parameter is set to a truthy value, createdAfter must not be set and one component id or key must be provided.")
+ .setBooleanPossibleValues()
+ .setDefaultValue("false");
}
private static void addComponentRelatedParams(WebService.NewAction action) {
@@ -453,6 +459,7 @@ public class SearchAction implements IssuesWsAction {
.setResolutions(request.paramAsStrings(RESOLUTIONS))
.setResolved(request.paramAsBoolean(RESOLVED))
.setRules(request.paramAsStrings(RULES))
+ .setSinceLeakPeriod(request.mandatoryParamAsBoolean(SINCE_LEAK_PERIOD))
.setSort(request.param(Param.SORT))
.setSeverities(request.paramAsStrings(SEVERITIES))
.setStatuses(request.paramAsStrings(STATUSES))
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
index b7601b7ed60..659be6dc3c6 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
@@ -24,12 +24,14 @@ import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.Map;
import org.assertj.core.api.Fail;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
@@ -47,7 +49,9 @@ import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.user.AuthorDao;
import org.sonar.server.component.ComponentService;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.tester.UserSessionRule;
+import org.sonarqube.ws.client.issue.SearchWsRequest;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@@ -65,6 +69,8 @@ public class IssueQueryServiceTest {
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
@Mock
DbClient dbClient;
@@ -444,7 +450,7 @@ public class IssueQueryServiceTest {
issueQueryService.createFromMap(map);
fail();
} catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("createdAfter and createdSince cannot be set simultaneously");
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("createdAfter and createdInLast cannot be set simultaneously");
}
}
@@ -456,6 +462,35 @@ public class IssueQueryServiceTest {
map.put("createdInLast", "1y2m3w4d");
assertThat(issueQueryService.createFromMap(map).createdAfter()).isEqualTo(DateUtils.parseDateTime("2012-04-30T07:35:00+0100"));
+ }
+
+ @Test
+ public void fail_if_since_leak_period_and_created_after_set_at_the_same_time() {
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously");
+
+ issueQueryService.createFromRequest(new SearchWsRequest()
+ .setSinceLeakPeriod(true)
+ .setCreatedAfter("2013-07-25T07:35:00+0100"));
+ }
+ @Test
+ public void fail_if_no_component_provided_with_since_leak_period() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("One and only one component must be provided when searching since leak period");
+
+ issueQueryService.createFromRequest(new SearchWsRequest().setSinceLeakPeriod(true));
+ }
+
+ @Test
+ public void fail_if_several_components_provided_with_since_leak_period() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("One and only one component must be provided when searching since leak period");
+
+ issueQueryService.createFromRequest(new SearchWsRequest()
+ .setSinceLeakPeriod(true)
+ .setComponentUuids(Collections.singletonList("component-uuid"))
+ .setProjectUuids(Collections.singletonList("project-uuid"))
+ );
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
index c1c808e8712..23f995b45cd 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
@@ -37,6 +37,8 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.component.SnapshotTesting;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.rule.RuleDao;
import org.sonar.db.rule.RuleDto;
@@ -54,11 +56,18 @@ import org.sonar.server.ws.WsActionTester;
import org.sonar.server.ws.WsTester;
import org.sonar.server.ws.WsTester.Result;
import org.sonarqube.ws.Issues;
+import org.sonarqube.ws.Issues.SearchWsResponse;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.client.issue.IssueFilterParameters;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.utils.DateUtils.parseDateTime;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
+import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
+import static org.sonar.db.component.SnapshotTesting.newSnapshotForProject;
public class SearchActionComponentsMediumTest {
@@ -90,7 +99,7 @@ public class SearchActionComponentsMediumTest {
RuleDto rule = newRule();
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
IssueDto issue = IssueTesting.newDto(rule, file, project)
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
.setStatus("OPEN").setResolution("OPEN")
@@ -101,7 +110,7 @@ public class SearchActionComponentsMediumTest {
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("P2").setKey("PK2"));
setDefaultProjectPermission(project2);
- ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "F2").setKey("FK2"));
+ ComponentDto file2 = insertComponent(newFileDto(project2, "F2").setKey("FK2"));
IssueDto issue2 = IssueTesting.newDto(rule, file2, project2)
.setKee("92fd47d4-b650-4037-80bc-7b112bd4eac2")
.setStatus("OPEN").setResolution("OPEN")
@@ -120,8 +129,8 @@ public class SearchActionComponentsMediumTest {
public void do_not_return_module_key_on_single_module_projects() throws IOException {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto module = insertComponent(ComponentTesting.newModuleDto("M1", project).setKey("MK1"));
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(module, "F1").setKey("FK1"));
+ ComponentDto module = insertComponent(newModuleDto("M1", project).setKey("MK1"));
+ ComponentDto file = insertComponent(newFileDto(module, "F1").setKey("FK1"));
RuleDto newRule = newRule();
IssueDto issueInModule = IssueTesting.newDto(newRule, file, project).setKee("ISSUE_IN_MODULE");
IssueDto issueInRootModule = IssueTesting.newDto(newRule, project, project).setKee("ISSUE_IN_ROOT_MODULE");
@@ -133,7 +142,7 @@ public class SearchActionComponentsMediumTest {
TestResponse response = actionTester.newRequest()
.setMediaType(MediaTypes.PROTOBUF)
.execute();
- Issues.SearchWsResponse searchResponse = Issues.SearchWsResponse.parseFrom(response.getInputStream());
+ SearchWsResponse searchResponse = SearchWsResponse.parseFrom(response.getInputStream());
assertThat(searchResponse.getIssuesCount()).isEqualTo(2);
for (Issues.Issue issue : searchResponse.getIssuesList()) {
@@ -150,7 +159,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_project_uuid() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
db.issueDao().insert(session, issue);
session.commit();
@@ -178,6 +187,66 @@ public class SearchActionComponentsMediumTest {
}
@Test
+ public void search_since_leak_period_on_project() throws Exception {
+ ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
+ setDefaultProjectPermission(project);
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
+ SnapshotDto projectSnapshot = db.snapshotDao().insert(session,
+ newSnapshotForProject(project)
+ .setPeriodDate(1, parseDateTime("2015-09-03T00:00:00+0100").getTime()));
+ db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, projectSnapshot));
+ RuleDto rule = newRule();
+ IssueDto issueAfterLeak = IssueTesting.newDto(rule, file, project)
+ .setKee(UUID_EXAMPLE_01)
+ .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
+ .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100"));
+ IssueDto issueBeforeLeak = IssueTesting.newDto(rule, file, project)
+ .setKee(UUID_EXAMPLE_02)
+ .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
+ .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100"));
+ db.issueDao().insert(session, issueAfterLeak, issueBeforeLeak);
+ session.commit();
+ tester.get(IssueIndexer.class).indexAll();
+
+ wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+ .setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid())
+ .setParam(IssueFilterParameters.SINCE_LEAK_PERIOD, "true")
+ .execute()
+ .assertJson(this.getClass(), "search_since_leak_period.json");
+ }
+
+ @Test
+ public void search_since_leak_period_on_file_in_module_project() throws Exception {
+ ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
+ setDefaultProjectPermission(project);
+ ComponentDto module = insertComponent(newModuleDto(project));
+ ComponentDto file = insertComponent(newFileDto(module, "F1").setKey("FK1"));
+ SnapshotDto projectSnapshot = db.snapshotDao().insert(session,
+ newSnapshotForProject(project)
+ .setPeriodDate(1, parseDateTime("2015-09-03T00:00:00+0100").getTime()));
+ SnapshotDto moduleSnapshot = db.snapshotDao().insert(session, SnapshotTesting.createForComponent(module, projectSnapshot));
+ db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, moduleSnapshot));
+ RuleDto rule = newRule();
+ IssueDto issueAfterLeak = IssueTesting.newDto(rule, file, project)
+ .setKee(UUID_EXAMPLE_01)
+ .setIssueCreationDate(parseDateTime("2015-09-04T00:00:00+0100"))
+ .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100"));
+ IssueDto issueBeforeLeak = IssueTesting.newDto(rule, file, project)
+ .setKee(UUID_EXAMPLE_02)
+ .setIssueCreationDate(parseDateTime("2014-09-04T00:00:00+0100"))
+ .setIssueUpdateDate(parseDateTime("2015-10-04T00:00:00+0100"));
+ db.issueDao().insert(session, issueAfterLeak, issueBeforeLeak);
+ session.commit();
+ tester.get(IssueIndexer.class).indexAll();
+
+ wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+ .setParam(IssueFilterParameters.FILE_UUIDS, file.uuid())
+ .setParam(IssueFilterParameters.SINCE_LEAK_PERIOD, "true")
+ .execute()
+ .assertJson(this.getClass(), "search_since_leak_period.json");
+ }
+
+ @Test
public void project_facet_is_sticky() throws Exception {
ComponentDto project1 = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("P2").setKey("PK2"));
@@ -185,9 +254,9 @@ public class SearchActionComponentsMediumTest {
setDefaultProjectPermission(project1);
setDefaultProjectPermission(project2);
setDefaultProjectPermission(project3);
- ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project1, "F1").setKey("FK1"));
- ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "F2").setKey("FK2"));
- ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project3, "F3").setKey("FK3"));
+ ComponentDto file1 = insertComponent(newFileDto(project1, "F1").setKey("FK1"));
+ ComponentDto file2 = insertComponent(newFileDto(project2, "F2").setKey("FK2"));
+ ComponentDto file3 = insertComponent(newFileDto(project3, "F3").setKey("FK3"));
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");
@@ -207,7 +276,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_file_uuid() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
db.issueDao().insert(session, issue);
session.commit();
@@ -238,8 +307,8 @@ public class SearchActionComponentsMediumTest {
public void search_by_file_key() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
- ComponentDto unitTest = insertComponent(ComponentTesting.newFileDto(project, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setKey("FK2"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto unitTest = insertComponent(newFileDto(project, "F2").setQualifier(Qualifiers.UNIT_TEST_FILE).setKey("FK2"));
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");
@@ -256,16 +325,15 @@ public class SearchActionComponentsMediumTest {
.setParam(IssueFilterParameters.COMPONENTS, unitTest.key())
.execute()
.assertJson(this.getClass(), "search_by_test_key.json");
-
}
@Test
public void display_file_facet() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
- ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project, "F2").setKey("FK2"));
- ComponentDto file3 = insertComponent(ComponentTesting.newFileDto(project, "F3").setKey("FK3"));
+ ComponentDto file1 = insertComponent(newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file2 = insertComponent(newFileDto(project, "F2").setKey("FK2"));
+ ComponentDto file3 = insertComponent(newFileDto(project, "F3").setKey("FK3"));
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");
@@ -286,7 +354,7 @@ public class SearchActionComponentsMediumTest {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "D1", "src/main/java/dir"));
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1").setPath(directory.path() + "/MyComponent.java"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1").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();
@@ -317,12 +385,12 @@ public class SearchActionComponentsMediumTest {
public void search_by_directory_path_in_different_modules() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto module1 = insertComponent(ComponentTesting.newModuleDto("M1", project).setKey("MK1"));
- ComponentDto module2 = insertComponent(ComponentTesting.newModuleDto("M2", project).setKey("MK2"));
+ ComponentDto module1 = insertComponent(newModuleDto("M1", project).setKey("MK1"));
+ ComponentDto module2 = insertComponent(newModuleDto("M2", project).setKey("MK2"));
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("FK1").setPath(directory1.path() + "/MyComponent.java"));
- insertComponent(ComponentTesting.newFileDto(module2, "F2").setKey("FK2").setPath(directory2.path() + "/MyComponent.java"));
+ ComponentDto file1 = insertComponent(newFileDto(module1, "F1").setKey("FK1").setPath(directory1.path() + "/MyComponent.java"));
+ insertComponent(newFileDto(module2, "F2").setKey("FK2").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);
@@ -367,12 +435,12 @@ public class SearchActionComponentsMediumTest {
public void display_module_facet() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto module = insertComponent(ComponentTesting.newModuleDto("M1", project).setKey("MK1"));
- ComponentDto subModule1 = insertComponent(ComponentTesting.newModuleDto("SUBM1", module).setKey("SUBMK1"));
- ComponentDto subModule2 = insertComponent(ComponentTesting.newModuleDto("SUBM2", module).setKey("SUBMK2"));
- ComponentDto subModule3 = insertComponent(ComponentTesting.newModuleDto("SUBM3", module).setKey("SUBMK3"));
- ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(subModule1, "F1").setKey("FK1"));
- ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(subModule2, "F2").setKey("FK2"));
+ ComponentDto module = insertComponent(newModuleDto("M1", project).setKey("MK1"));
+ ComponentDto subModule1 = insertComponent(newModuleDto("SUBM1", module).setKey("SUBMK1"));
+ ComponentDto subModule2 = insertComponent(newModuleDto("SUBM2", module).setKey("SUBMK2"));
+ ComponentDto subModule3 = insertComponent(newModuleDto("SUBM3", module).setKey("SUBMK3"));
+ ComponentDto file1 = insertComponent(newFileDto(subModule1, "F1").setKey("FK1"));
+ ComponentDto file2 = insertComponent(newFileDto(subModule2, "F2").setKey("FK2"));
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");
@@ -393,7 +461,7 @@ public class SearchActionComponentsMediumTest {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "D1", "src/main/java/dir"));
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1").setPath(directory.path() + "/MyComponent.java"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1").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();
@@ -411,7 +479,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_view_uuid() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView"));
@@ -430,7 +498,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_view_uuid_return_only_authorized_view() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView"));
@@ -450,7 +518,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_sub_view_uuid() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView"));
@@ -471,7 +539,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_sub_view_uuid_return_only_authorized_view() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
insertIssue(IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
ComponentDto view = insertComponent(ComponentTesting.newProjectDto("V1").setQualifier(Qualifiers.VIEW).setKey("MyView"));
@@ -493,7 +561,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_author() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
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");
@@ -519,7 +587,7 @@ public class SearchActionComponentsMediumTest {
public void search_by_developer() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
ComponentDto developer = insertComponent(ComponentTesting.newDeveloper("Anakin Skywalker"));
db.authorDao().insertAuthor(session, "vader", developer.getId());
db.authorDao().insertAuthor(session, "anakin@skywalker.name", developer.getId());
@@ -541,11 +609,11 @@ public class SearchActionComponentsMediumTest {
public void search_by_developer_technical_project() throws Exception {
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("P1").setKey("PK1"));
setDefaultProjectPermission(project);
- ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "F1").setKey("FK1"));
+ ComponentDto file = insertComponent(newFileDto(project, "F1").setKey("FK1"));
ComponentDto otherProject = insertComponent(ComponentTesting.newProjectDto("P2").setKey("PK2"));
setDefaultProjectPermission(otherProject);
- ComponentDto otherFile = insertComponent(ComponentTesting.newFileDto(otherProject, "F2").setKey("FK2"));
+ ComponentDto otherFile = insertComponent(newFileDto(otherProject, "F2").setKey("FK2"));
ComponentDto developer = insertComponent(ComponentTesting.newDeveloper("Anakin Skywalker"));
ComponentDto technicalProject = insertComponent(ComponentTesting.newDevProjectCopy("COPY_P1", project, developer));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
index 8b3ae1755e0..ddae87c0089 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
@@ -94,14 +94,14 @@ public class SearchActionMediumTest {
public void define_action() {
WebService.Controller controller = wsTester.controller("api/issues");
- WebService.Action show = controller.action("search");
- 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(38);
+ WebService.Action search = controller.action("search");
+ assertThat(search).isNotNull();
+ assertThat(search.handler()).isNotNull();
+ assertThat(search.since()).isEqualTo("3.6");
+ assertThat(search.isPost()).isFalse();
+ assertThat(search.isInternal()).isFalse();
+ assertThat(search.responseExampleAsString()).isNotEmpty();
+ assertThat(search.params()).hasSize(39);
}
@Test
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_since_leak_period.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_since_leak_period.json
new file mode 100644
index 00000000000..0cdf5b8fa6c
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_since_leak_period.json
@@ -0,0 +1,10 @@
+{
+ "issues": [
+ {
+ "key": "AU-Tpxb--iU5OvuD2FLy",
+ "component": "FK1",
+ "project": "PK1",
+ "rule": "xoo:x1"
+ }
+ ]
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java
index 4d32a2de799..90abaf64a31 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java
@@ -62,6 +62,7 @@ public class IssueFilterParameters {
public static final String CREATED_AT = "createdAt";
public static final String CREATED_BEFORE = "createdBefore";
public static final String CREATED_IN_LAST = "createdInLast";
+ public static final String SINCE_LEAK_PERIOD = "sinceLeakPeriod";
public static final String PAGE_SIZE = "pageSize";
public static final String PAGE_INDEX = "pageIndex";
public static final String SORT = "sort";
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java
index e8c99d569e9..11837e40285 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java
@@ -55,6 +55,7 @@ import static org.sonarqube.ws.client.issue.IssueFilterParameters.RESOLUTIONS;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.RESOLVED;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.RULES;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.SEVERITIES;
+import static org.sonarqube.ws.client.issue.IssueFilterParameters.SINCE_LEAK_PERIOD;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.STATUSES;
import static org.sonarqube.ws.client.issue.IssueFilterParameters.TAGS;
@@ -102,6 +103,7 @@ public class IssuesService extends BaseService {
.setParam(RULES, inlineMultipleParamValue(request.getRules()))
.setParam("s", request.getSort())
.setParam(SEVERITIES, inlineMultipleParamValue(request.getSeverities()))
+ .setParam(SINCE_LEAK_PERIOD, request.getSinceLeakPeriod())
.setParam(STATUSES, inlineMultipleParamValue(request.getStatuses()))
.setParam(TAGS, inlineMultipleParamValue(request.getTags())),
SearchWsResponse.parser());
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java
index c6520738eb4..e782c4d95ab 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java
@@ -57,6 +57,7 @@ public class SearchWsRequest {
private List<String> resolutions;
private Boolean resolved;
private List<String> rules;
+ private Boolean sinceLeakPeriod;
private String sort;
private List<String> severities;
private List<String> statuses;
@@ -354,6 +355,16 @@ public class SearchWsRequest {
}
@CheckForNull
+ public Boolean getSinceLeakPeriod() {
+ return sinceLeakPeriod;
+ }
+
+ public SearchWsRequest setSinceLeakPeriod(@Nullable Boolean sinceLeakPeriod) {
+ this.sinceLeakPeriod = sinceLeakPeriod;
+ return this;
+ }
+
+ @CheckForNull
public String getSort() {
return sort;
}