]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7200 WS api/issues/search filter issues on leak period
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 15 Mar 2016 15:10:17 +0000 (16:10 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 16 Mar 2016 15:53:06 +0000 (16:53 +0100)
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_since_leak_period.json [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssueFilterParameters.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/SearchWsRequest.java

index 2cc8d64f2343b22bc3a6cd05da7b8cca77e66f67..0ddc0f472f82344b4334c92e36556c2109a7b07c 100644 (file)
@@ -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) {
index 30dc75db6aa374fc34b0558050a9eee68e67e764..7430632729ae0f6f45a391400b5125a0a9d663dc 100644 (file)
@@ -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))
index b7601b7ed60ce6c3799dfc681fd01fa948e846f8..659be6dc3c645bfa8174681f89c8805530bc6946 100644 (file)
@@ -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"))
+    );
   }
 }
index c1c808e871255bc476ad3b883ac29412daad33d8..23f995b45cd5acb8ea408dc5fa6c7021bd443fb7 100644 (file)
@@ -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();
@@ -177,6 +186,66 @@ public class SearchActionComponentsMediumTest {
       .assertJson(this.getClass(), "no_issue.json");
   }
 
+  @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"));
@@ -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));
index 8b3ae1755e0e4f6cac37c15f953e502621b56586..ddae87c0089b903907c9be53aeffde5f700b9aa7 100644 (file)
@@ -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 (file)
index 0000000..0cdf5b8
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "issues": [
+    {
+      "key": "AU-Tpxb--iU5OvuD2FLy",
+      "component": "FK1",
+      "project": "PK1",
+      "rule": "xoo:x1"
+    }
+  ]
+}
index 4d32a2de799b1eb46f667397ac7d973a570bcc59..90abaf64a312f1c8fd6a19110b1323d605e1aaad 100644 (file)
@@ -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";
index e8c99d569e9387bb4326b142a61635dc6787ed73..11837e40285fa93103d1f09ddc885b931ef13adc 100644 (file)
@@ -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());
index c6520738eb4441fd497b9335d70d260e2f21fbf3..e782c4d95ab9fb50b53011bdd050b60362b5c64b 100644 (file)
@@ -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;
@@ -353,6 +354,16 @@ public class SearchWsRequest {
     return this;
   }
 
+  @CheckForNull
+  public Boolean getSinceLeakPeriod() {
+    return sinceLeakPeriod;
+  }
+
+  public SearchWsRequest setSinceLeakPeriod(@Nullable Boolean sinceLeakPeriod) {
+    this.sinceLeakPeriod = sinceLeakPeriod;
+    return this;
+  }
+
   @CheckForNull
   public String getSort() {
     return sort;