diff options
7 files changed, 283 insertions, 24 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java index 635d536adb1..73af0581ff8 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java @@ -43,6 +43,7 @@ public class SearchRequest { private List<String> facets; private List<String> files; private List<String> issues; + private Boolean inNewCodePeriod; private Set<String> scopes; private List<String> languages; private Boolean onComponentOnly; @@ -298,11 +299,19 @@ public class SearchRequest { return this; } + /** + * @deprecated since 9.4 - replaced by getInNewCodePeriod() + */ + @Deprecated(since = "9.4") @CheckForNull public Boolean getSinceLeakPeriod() { return sinceLeakPeriod; } + /** + * @deprecated since 9.4 - replaced by setInNewCodePeriod() + */ + @Deprecated(since = "9.4") public SearchRequest setSinceLeakPeriod(@Nullable Boolean sinceLeakPeriod) { this.sinceLeakPeriod = sinceLeakPeriod; return this; @@ -447,4 +456,14 @@ public class SearchRequest { this.timeZone = timeZone; return this; } + + @CheckForNull + public Boolean getInNewCodePeriod() { + return inNewCodePeriod; + } + + public SearchRequest setInNewCodePeriod(@Nullable Boolean inNewCodePeriod) { + this.inNewCodePeriod = inNewCodePeriod; + return this; + } } diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java index bdfe716bc3e..73b402692ea 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java @@ -47,7 +47,8 @@ public class SearchRequestTest { .setCreatedBefore("2013-04-17T09:08:24+0200") .setRules(asList("key-a", "key-b")) .setSort("CREATION_DATE") - .setAsc(true); + .setAsc(true) + .setInNewCodePeriod(true); assertThat(underTest.getIssues()).containsOnlyOnce("anIssueKey"); assertThat(underTest.getSeverities()).containsExactly("MAJOR", "MINOR"); @@ -67,6 +68,7 @@ public class SearchRequestTest { assertThat(underTest.getRules()).containsExactly("key-a", "key-b"); assertThat(underTest.getSort()).isEqualTo("CREATION_DATE"); assertThat(underTest.getAsc()).isTrue(); + assertThat(underTest.getInNewCodePeriod()).isTrue(); } @Test diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java index 97a95a5477a..9d5ec45406d 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java @@ -77,6 +77,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_K import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_LAST; +import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IN_NEW_CODE_PERIOD; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD; /** @@ -181,15 +182,16 @@ public class IssueQueryFactory { Date createdAfter = parseStartingDateOrDateTime(request.getCreatedAfter(), timeZone); String createdInLast = request.getCreatedInLast(); - if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod()) { + if (notInNewCodePeriod(request)) { checkArgument(createdAfter == null || createdInLast == null, format("Parameters %s and %s cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_CREATED_IN_LAST)); setCreatedAfterFromDates(builder, createdAfter, createdInLast, true); } else { // If the filter is on leak period - checkArgument(createdAfter == null, "Parameters '%s' and '%s' cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_SINCE_LEAK_PERIOD); - checkArgument(createdInLast == null, format("Parameters %s and %s cannot be set simultaneously", PARAM_CREATED_IN_LAST, PARAM_SINCE_LEAK_PERIOD)); + checkArgument(createdAfter == null, "Parameters '%s' and '%s' or '%s' cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_IN_NEW_CODE_PERIOD, PARAM_SINCE_LEAK_PERIOD); + checkArgument(createdInLast == null, + format("Parameters '%s' and '%s' or '%s' cannot be set simultaneously", PARAM_CREATED_IN_LAST, PARAM_IN_NEW_CODE_PERIOD, PARAM_SINCE_LEAK_PERIOD)); - checkArgument(componentUuids.size() == 1, "One and only one component must be provided when searching since leak period"); + checkArgument(componentUuids.size() == 1, "One and only one component must be provided when searching in new code period"); ComponentDto component = componentUuids.iterator().next(); if (!QUALIFIERS_WITHOUT_LEAK_PERIOD.contains(component.qualifier()) && request.getPullRequest() == null) { @@ -206,6 +208,23 @@ public class IssueQueryFactory { } } + private static boolean notInNewCodePeriod(SearchRequest request) { + Boolean sinceLeakPeriod = request.getSinceLeakPeriod(); + Boolean inNewCodePeriod = request.getInNewCodePeriod(); + + checkArgument(validPeriodParameterValues(sinceLeakPeriod, inNewCodePeriod), + "If both provided, the following parameters %s and %s must match.", PARAM_SINCE_LEAK_PERIOD, PARAM_IN_NEW_CODE_PERIOD); + + sinceLeakPeriod = Boolean.TRUE.equals(sinceLeakPeriod); + inNewCodePeriod = Boolean.TRUE.equals(inNewCodePeriod); + + return !sinceLeakPeriod && !inNewCodePeriod; + } + + private static boolean validPeriodParameterValues(@Nullable Boolean sinceLeakPeriod, @Nullable Boolean inNewCodePeriod) { + return atMostOneNonNullElement(sinceLeakPeriod, inNewCodePeriod) || !Boolean.logicalXor(sinceLeakPeriod, inNewCodePeriod); + } + private Date findCreatedAfterFromComponentUuid(Optional<SnapshotDto> snapshot) { return snapshot.map(s -> longToDate(s.getPeriodDate())).orElseGet(() -> new Date(clock.millis())); } @@ -344,7 +363,7 @@ public class IssueQueryFactory { } private void addCreatedAfterByProjects(IssueQuery.Builder builder, DbSession dbSession, SearchRequest request, Set<String> applicationUuids) { - if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod() || request.getPullRequest() != null) { + if (notInNewCodePeriod(request) || request.getPullRequest() != null) { return; } diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java index edb0d518841..dbc9f40ecae 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryFactoryTest.java @@ -168,6 +168,28 @@ public class IssueQueryFactoryTest { } @Test + public void in_new_code_period_start_date_is_exclusive() { + long newCodePeriodStart = addDays(new Date(), -14).getTime(); + + ComponentDto project = db.components().insertPublicProject(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + + SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setPeriodDate(newCodePeriodStart)); + + SearchRequest request = new SearchRequest() + .setComponentUuids(Collections.singletonList(file.uuid())) + .setOnComponentOnly(true) + .setInNewCodePeriod(true); + + IssueQuery query = underTest.create(request); + + assertThat(query.componentUuids()).containsOnly(file.uuid()); + assertThat(query.createdAfter().date()).isEqualTo(new Date(newCodePeriodStart)); + assertThat(query.createdAfter().inclusive()).isFalse(); + assertThat(query.newCodeOnReference()).isNull(); + } + + @Test public void leak_period_does_not_rely_on_date_for_reference_branch() { long leakPeriodStart = addDays(new Date(), -14).getTime(); @@ -190,6 +212,27 @@ public class IssueQueryFactoryTest { } @Test + public void new_code_period_does_not_rely_on_date_for_reference_branch() { + + ComponentDto project = db.components().insertPublicProject(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + + SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setPeriodMode(REFERENCE_BRANCH.name()) + .setPeriodParam("master")); + + SearchRequest request = new SearchRequest() + .setComponentUuids(Collections.singletonList(file.uuid())) + .setOnComponentOnly(true) + .setInNewCodePeriod(true); + + IssueQuery query = underTest.create(request); + + assertThat(query.componentUuids()).containsOnly(file.uuid()); + assertThat(query.newCodeOnReference()).isTrue(); + assertThat(query.createdAfter()).isNull(); + } + + @Test public void dates_are_inclusive() { when(clock.getZone()).thenReturn(ZoneId.of("Europe/Paris")); SearchRequest request = new SearchRequest() @@ -365,6 +408,37 @@ public class IssueQueryFactoryTest { } @Test + public void application_search_project_issues_in_new_code() { + Date now = new Date(); + when(clock.millis()).thenReturn(now.getTime()); + ComponentDto project1 = db.components().insertPublicProject(); + SnapshotDto analysis1 = db.components().insertSnapshot(project1, s -> s.setPeriodDate(addDays(now, -14).getTime())); + ComponentDto project2 = db.components().insertPublicProject(); + db.components().insertSnapshot(project2, s -> s.setPeriodDate(null)); + ComponentDto project3 = db.components().insertPublicProject(); + ComponentDto project4 = db.components().insertPublicProject(); + SnapshotDto analysis2 = db.components().insertSnapshot(project4, + s -> s.setPeriodMode(REFERENCE_BRANCH.name()).setPeriodParam("master")); + ComponentDto application = db.components().insertPublicApplication(); + db.components().insertComponents(newProjectCopy("PC1", project1, application)); + db.components().insertComponents(newProjectCopy("PC2", project2, application)); + db.components().insertComponents(newProjectCopy("PC3", project3, application)); + db.components().insertComponents(newProjectCopy("PC4", project4, application)); + userSession.registerApplication(application, project1, project2, project3, project4); + + IssueQuery result = underTest.create(new SearchRequest() + .setComponentUuids(singletonList(application.uuid())) + .setInNewCodePeriod(true)); + + assertThat(result.createdAfterByProjectUuids()).hasSize(1); + assertThat(result.createdAfterByProjectUuids().entrySet()).extracting(Map.Entry::getKey, e -> e.getValue().date(), e -> e.getValue().inclusive()).containsOnly( + tuple(project1.uuid(), new Date(analysis1.getPeriodDate()), false)); + assertThat(result.newCodeOnReferenceByProjectUuids()).hasSize(1); + assertThat(result.newCodeOnReferenceByProjectUuids()).containsOnly(project4.uuid()); + assertThat(result.viewUuids()).containsExactlyInAnyOrder(application.uuid()); + } + + @Test public void return_empty_results_if_not_allowed_to_search_for_subview() { ComponentDto view = db.components().insertPrivatePortfolio(); ComponentDto subView = db.components().insertComponent(newSubPortfolio(view)); @@ -606,14 +680,56 @@ public class IssueQueryFactoryTest { .setSinceLeakPeriod(true) .setCreatedAfter("2013-07-25T07:35:00+0100"))) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Parameters 'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously"); + .hasMessageContaining("Parameters 'createdAfter' and 'inNewCodePeriod' or 'sinceLeakPeriod' cannot be set simultaneously"); + } + + @Test + public void fail_if_in_new_code_period_and_created_after_set_at_the_same_time() { + SearchRequest searchRequest = new SearchRequest() + .setInNewCodePeriod(true) + .setCreatedAfter("2013-07-25T07:35:00+0100"); + + assertThatThrownBy(() -> underTest.create(searchRequest)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Parameters 'createdAfter' and 'inNewCodePeriod' or 'sinceLeakPeriod' cannot be set simultaneously"); + } + + @Test + public void fail_if_since_leak_period_and_created_in_last_set_at_the_same_time() { + SearchRequest searchRequest = new SearchRequest() + .setSinceLeakPeriod(true) + .setCreatedInLast("1y2m3w4d"); + + assertThatThrownBy(() -> underTest.create(searchRequest)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Parameters 'createdInLast' and 'inNewCodePeriod' or 'sinceLeakPeriod' cannot be set simultaneously"); + } + + @Test + public void fail_if_in_new_code_period_and_created_in_last_set_at_the_same_time() { + SearchRequest searchRequest = new SearchRequest() + .setInNewCodePeriod(true) + .setCreatedInLast("1y2m3w4d"); + + assertThatThrownBy(() -> underTest.create(searchRequest)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Parameters 'createdInLast' and 'inNewCodePeriod' or 'sinceLeakPeriod' cannot be set simultaneously"); } @Test public void fail_if_no_component_provided_with_since_leak_period() { assertThatThrownBy(() -> underTest.create(new SearchRequest().setSinceLeakPeriod(true))) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("One and only one component must be provided when searching since leak period"); + .hasMessageContaining("One and only one component must be provided when searching in new code period"); + } + + @Test + public void fail_if_no_component_provided_with_in_new_code_period() { + SearchRequest searchRequest = new SearchRequest().setInNewCodePeriod(true); + + assertThatThrownBy(() -> underTest.create(searchRequest)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("One and only one component must be provided when searching in new code period"); } @Test @@ -625,7 +741,21 @@ public class IssueQueryFactoryTest { .setSinceLeakPeriod(true) .setComponents(asList(project1.getKey(), project2.getKey())))) .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("One and only one component must be provided when searching since leak period"); + .hasMessageContaining("One and only one component must be provided when searching in new code period"); + } + + @Test + public void fail_if_several_components_provided_with_in_new_code_period() { + ComponentDto project1 = db.components().insertPrivateProject(); + ComponentDto project2 = db.components().insertPrivateProject(); + + SearchRequest searchRequest = new SearchRequest() + .setInNewCodePeriod(true) + .setComponents(asList(project1.getKey(), project2.getKey())); + + assertThatThrownBy(() -> underTest.create(searchRequest)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("One and only one component must be provided when searching in new code period"); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java index bba59cc0594..11b0987297f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -107,6 +107,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CWE; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILES; +import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IN_NEW_CODE_PERIOD; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ON_COMPONENT_ONLY; @@ -188,6 +189,7 @@ public class SearchAction implements IssuesWsAction { + "<br/>When issue indexation is in progress returns 503 service unavailable HTTP code.") .setSince("3.6") .setChangelog( + new Change("9.4", format("Parameter '%s' is deprecated, please use '%s' instead", PARAM_SINCE_LEAK_PERIOD, PARAM_IN_NEW_CODE_PERIOD)), new Change("9.2", "Response field 'quickFixAvailable' added"), new Change("9.1", "Deprecated parameters 'authors', 'facetMode' and 'moduleUuids' were dropped"), new Change("8.6", "Parameter 'timeZone' added"), @@ -308,8 +310,12 @@ public class SearchAction implements IssuesWsAction { action.createParam(PARAM_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 uuid or key must be provided.") + .setBooleanPossibleValues(); + action.createParam(PARAM_IN_NEW_CODE_PERIOD) + .setDescription("To retrieve issues created in the new code period.<br>" + + "If this parameter is set to a truthy value, createdAfter must not be set and one component uuid or key must be provided.") .setBooleanPossibleValues() - .setDefaultValue("false"); + .setSince("9.4"); action.createParam(PARAM_TIMEZONE) .setDescription( "To resolve dates passed to '" + PARAM_CREATED_AFTER + "' or '" + PARAM_CREATED_BEFORE + "' (does not apply to datetime) and to compute creation date histogram") @@ -509,6 +515,7 @@ public class SearchAction implements IssuesWsAction { .setDirectories(request.paramAsStrings(PARAM_DIRECTORIES)) .setFacets(request.paramAsStrings(FACETS)) .setFiles(request.paramAsStrings(PARAM_FILES)) + .setInNewCodePeriod(request.paramAsBoolean(PARAM_IN_NEW_CODE_PERIOD)) .setIssues(request.paramAsStrings(PARAM_ISSUES)) .setScopes(request.paramAsStrings(PARAM_SCOPES)) .setLanguages(request.paramAsStrings(PARAM_LANGUAGES)) @@ -521,7 +528,7 @@ public class SearchAction implements IssuesWsAction { .setResolutions(request.paramAsStrings(PARAM_RESOLUTIONS)) .setResolved(request.paramAsBoolean(PARAM_RESOLVED)) .setRules(request.paramAsStrings(PARAM_RULES)) - .setSinceLeakPeriod(request.mandatoryParamAsBoolean(PARAM_SINCE_LEAK_PERIOD)) + .setSinceLeakPeriod(request.paramAsBoolean(PARAM_SINCE_LEAK_PERIOD)) .setSort(request.param(Param.SORT)) .setSeverities(request.paramAsStrings(PARAM_SEVERITIES)) .setStatuses(request.paramAsStrings(PARAM_STATUSES)) diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java index c412d2b4879..1472c038a33 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java @@ -110,6 +110,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_HIDE_COMMENTS; +import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_IN_NEW_CODE_PERIOD; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD; @@ -558,7 +559,7 @@ public class SearchActionTest { } @Test - public void filter_by_leak_period() { + public void filter_by_new_code_period() { UserDto john = db.users().insertUser(u -> u.setLogin("john").setName("John").setEmail("john@email.com")); UserDto alice = db.users().insertUser(u -> u.setLogin("alice").setName("Alice").setEmail("alice@email.com")); ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto("PROJECT_ID").setDbKey("PROJECT_KEY")); @@ -594,6 +595,38 @@ public class SearchActionTest { .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") .execute() .assertJson(this.getClass(), "filter_by_leak_period.json"); + + ws.newRequest() + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .execute() + .assertJson(this.getClass(), "filter_by_leak_period.json"); + + ws.newRequest() + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .setParam(PARAM_SINCE_LEAK_PERIOD, "true") + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .execute() + .assertJson(this.getClass(), "filter_by_leak_period.json"); + } + + @Test + public void explicit_false_value_for_new_code_period_parameters_has_no_effect() { + ws.newRequest() + .setParam(PARAM_IN_NEW_CODE_PERIOD, "false") + .execute() + .assertJson(this.getClass(), "default_page_size_is_100.json"); + + ws.newRequest() + .setParam(PARAM_SINCE_LEAK_PERIOD, "false") + .execute() + .assertJson(this.getClass(), "default_page_size_is_100.json"); + + ws.newRequest() + .setParam(PARAM_IN_NEW_CODE_PERIOD, "false") + .setParam(PARAM_SINCE_LEAK_PERIOD, "false") + .execute() + .assertJson(this.getClass(), "default_page_size_is_100.json"); } @Test @@ -632,6 +665,19 @@ public class SearchActionTest { .setParam(PARAM_SINCE_LEAK_PERIOD, "true") .execute() .assertJson(this.getClass(), "empty_result.json"); + + ws.newRequest() + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .execute() + .assertJson(this.getClass(), "empty_result.json"); + + ws.newRequest() + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .setParam(PARAM_SINCE_LEAK_PERIOD, "true") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .execute() + .assertJson(this.getClass(), "empty_result.json"); } @Test @@ -672,6 +718,21 @@ public class SearchActionTest { .setParam(PARAM_SINCE_LEAK_PERIOD, "true") .execute() .assertJson(this.getClass(), "filter_by_leak_period_has_no_effect_on_prs.json"); + + ws.newRequest() + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .setParam(PARAM_PULL_REQUEST, "pr") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .execute() + .assertJson(this.getClass(), "filter_by_leak_period_has_no_effect_on_prs.json"); + + ws.newRequest() + .setParam(PARAM_COMPONENT_KEYS, "PROJECT_KEY") + .setParam(PARAM_PULL_REQUEST, "pr") + .setParam(PARAM_SINCE_LEAK_PERIOD, "true") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true") + .execute() + .assertJson(this.getClass(), "filter_by_leak_period_has_no_effect_on_prs.json"); } @Test @@ -1257,12 +1318,12 @@ public class SearchActionTest { @Test public void paging_with_page_size_to_minus_one() { - assertThatThrownBy(() -> { - ws.newRequest() - .setParam(WebService.Param.PAGE, "1") - .setParam(WebService.Param.PAGE_SIZE, "-1") - .execute(); - }) + + TestRequest requestWithNegativePageSize = ws.newRequest() + .setParam(WebService.Param.PAGE, "1") + .setParam(WebService.Param.PAGE_SIZE, "-1"); + + assertThatThrownBy(requestWithNegativePageSize::execute) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Page size must be between 1 and 500 (got -1)"); } @@ -1299,11 +1360,10 @@ public class SearchActionTest { @Test public void fail_when_invalid_format() { - assertThatThrownBy(() -> { - ws.newRequest() - .setParam(PARAM_CREATED_AFTER, "wrong-date-input") - .execute(); - }) + TestRequest invalidFormatRequest = ws.newRequest() + .setParam(PARAM_CREATED_AFTER, "wrong-date-input"); + + assertThatThrownBy(invalidFormatRequest::execute) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Date 'wrong-date-input' cannot be parsed as either a date or date+time"); } @@ -1321,7 +1381,7 @@ public class SearchActionTest { "additionalFields", "asc", "assigned", "assignees", "author", "componentKeys", "branch", "pullRequest", "createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facets", "files", "issues", "scopes", "languages", "onComponentOnly", "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "statuses", "tags", "types", "owaspTop10", "sansTop25", - "cwe", "sonarsourceSecurity", "timeZone"); + "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod"); WebService.Param branch = def.param(PARAM_BRANCH); assertThat(branch.isInternal()).isFalse(); @@ -1333,6 +1393,26 @@ public class SearchActionTest { "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. If this parameter is set, projectUuids must not be set."); } + @Test + public void fail_when_mismatching_sinceLeakPeriod_and_inNewCodePeriod() { + + TestRequest requestLeakTrueNewCodeFalse = ws.newRequest() + .setParam(PARAM_SINCE_LEAK_PERIOD, "true") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "false"); + + assertThatThrownBy(requestLeakTrueNewCodeFalse::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("If both provided, the following parameters sinceLeakPeriod and inNewCodePeriod must match."); + + TestRequest requestLeakFalseNewCodeTrue = ws.newRequest() + .setParam(PARAM_SINCE_LEAK_PERIOD, "false") + .setParam(PARAM_IN_NEW_CODE_PERIOD, "true"); + + assertThatThrownBy(requestLeakFalseNewCodeTrue::execute) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("If both provided, the following parameters sinceLeakPeriod and inNewCodePeriod must match."); + } + private RuleDto newIssueRule() { RuleDto rule = RuleTesting.newXooX1() .setName("Rule name") diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java index cdd9de19c1d..008a8ebc59d 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java @@ -89,7 +89,9 @@ public class IssuesWsParameters { public static final String PARAM_CREATED_AT = "createdAt"; public static final String PARAM_CREATED_BEFORE = "createdBefore"; public static final String PARAM_CREATED_IN_LAST = "createdInLast"; + @Deprecated public static final String PARAM_SINCE_LEAK_PERIOD = "sinceLeakPeriod"; + public static final String PARAM_IN_NEW_CODE_PERIOD = "inNewCodePeriod"; public static final String PARAM_ASC = "asc"; public static final String PARAM_ADDITIONAL_FIELDS = "additionalFields"; public static final String PARAM_TIMEZONE = "timeZone"; |