diff options
author | Lukasz Jarocki <lukasz.jarocki@sonarsource.com> | 2021-10-08 13:52:07 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-10-13 20:03:34 +0000 |
commit | 6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7 (patch) | |
tree | 904a85dacd34f2b337727b4dc45e14202b434568 | |
parent | ae8cda9b5442652dfff87819ac45fc3dd03eb36d (diff) | |
download | sonarqube-6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7.tar.gz sonarqube-6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7.zip |
SONAR-15486 add a new field to response of /api/issues/search endpoint - quickFixAvailable
5 files changed, 68 insertions, 41 deletions
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 3c3ad99b5a9..4113f7b8b2c 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 @@ -186,6 +186,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.2", "Response field 'quickFixAvailable' added"), new Change("9.1", "Deprecated parameters 'authors', 'facetMode' and 'moduleUuids' were dropped"), new Change("8.6", "Parameter 'timeZone' added"), new Change("8.5", "Facet 'fileUuids' is dropped in favour of the new facet 'files'" + diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java index b200d469384..8691b976939 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java @@ -202,6 +202,10 @@ public class SearchResponseFormat { ofNullable(dto.getIssueCreationDate()).map(DateUtils::formatDateTime).ifPresent(issueBuilder::setCreationDate); ofNullable(dto.getIssueUpdateDate()).map(DateUtils::formatDateTime).ifPresent(issueBuilder::setUpdateDate); ofNullable(dto.getIssueCloseDate()).map(DateUtils::formatDateTime).ifPresent(issueBuilder::setCloseDate); + + ofNullable(dto.isQuickFixAvailable()) + .ifPresentOrElse(issueBuilder::setQuickFixAvailable, () -> issueBuilder.setQuickFixAvailable(false)); + issueBuilder.setScope(Qualifiers.UNIT_TEST_FILE.equals(component.qualifier()) ? IssueScope.TEST.name() : IssueScope.MAIN.name()); } diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/issue/ws/search-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/issue/ws/search-example.json index d4b35d29bfe..4c8efbada3e 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/issue/ws/search-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/issue/ws/search-example.json @@ -76,7 +76,8 @@ } ] } - ] + ], + "quickFixAvailable": false } ], "components": [ 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 691d3065b15..60fecb8c48f 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 @@ -153,7 +153,6 @@ public class SearchActionTest { UserDto user = db.users().insertUser(); userSession.logIn(user); ComponentDto project = db.components().insertPublicProject(); - indexPermissions(); ComponentDto file = db.components().insertComponent(newFileDto(project)); UserDto simon = db.users().insertUser(); RuleDefinitionDto rule = newIssueRule().getDefinition(); @@ -171,7 +170,7 @@ public class SearchActionTest { .setTags(asList("bug", "owasp")) .setIssueCreationDate(parseDate("2014-09-03")) .setIssueUpdateDate(parseDate("2017-12-04"))); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse response = ws.newRequest() .executeProtobuf(SearchWsResponse.class); @@ -179,21 +178,21 @@ public class SearchActionTest { assertThat(response.getIssuesList()) .extracting( Issue::getKey, Issue::getRule, Issue::getSeverity, Issue::getComponent, Issue::getResolution, Issue::getStatus, Issue::getMessage, Issue::getEffort, - Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList, Issue::getCreationDate, Issue::getUpdateDate) + Issue::getAssignee, Issue::getAuthor, Issue::getLine, Issue::getHash, Issue::getTagsList, Issue::getCreationDate, Issue::getUpdateDate, + Issue::getQuickFixAvailable) .containsExactlyInAnyOrder( tuple(issue.getKey(), rule.getKey().toString(), Severity.MAJOR, file.getKey(), RESOLUTION_FIXED, STATUS_RESOLVED, "the message", "10min", simon.getLogin(), "John", 42, "a227e508d6646b55a086ee11d63b21e9", asList("bug", "owasp"), formatDateTime(issue.getIssueCreationDate()), - formatDateTime(issue.getIssueUpdateDate()))); + formatDateTime(issue.getIssueUpdateDate()), false)); } @Test public void issue_on_external_rule() { ComponentDto project = db.components().insertPublicProject(); - indexPermissions(); ComponentDto file = db.components().insertComponent(newFileDto(project)); RuleDefinitionDto rule = db.rules().insertIssueRule(RuleTesting.EXTERNAL_XOO, r -> r.setIsExternal(true).setLanguage("xoo")); IssueDto issue = db.issues().insertIssue(rule, project, file); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse response = ws.newRequest() .executeProtobuf(SearchWsResponse.class); @@ -767,8 +766,7 @@ public class SearchActionTest { IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("leia")); IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("luke")); IssueDto issue3 = db.issues().insertIssue(rule, project, file, i -> i.setAuthorLogin("han, solo")); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse response = ws.newRequest() .setMultiParam("author", asList("leia", "han, solo")) @@ -955,8 +953,7 @@ public class SearchActionTest { IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL)); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("cwe", "20") @@ -981,8 +978,7 @@ public class SearchActionTest { IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL)); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("owaspTop10", "a1") @@ -1007,8 +1003,7 @@ public class SearchActionTest { IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL)); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("sansTop25", "porous-defenses") @@ -1033,8 +1028,7 @@ public class SearchActionTest { IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY)); IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL)); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("sonarsourceSecurity", "sql-injection") @@ -1054,8 +1048,7 @@ public class SearchActionTest { db.issues().insertIssue(rule, project, file, i -> i.setType(RuleType.VULNERABILITY)); db.issues().insertIssue(rule, project, file, i -> i.setType(CODE_SMELL)); db.issues().insertHotspot(project, file); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest().executeProtobuf(SearchWsResponse.class); @@ -1074,8 +1067,7 @@ public class SearchActionTest { IssueDto codeSmellIssue = db.issues().insertIssue(issueRule, project, file, i -> i.setType(CODE_SMELL)); RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(); IssueDto hotspot = db.issues().insertHotspot(hotspotRule, project, file); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("issues", Stream.of(bugIssue, vulnerabilityIssue, codeSmellIssue, hotspot).map(IssueDto::getKey).collect(Collectors.joining(","))) @@ -1124,8 +1116,7 @@ public class SearchActionTest { IssueDto issueDto3 = db.issues().insertIssue(issueRule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid())); IssueDto issueDto4 = db.issues().insertIssue(issueRule, project, file, issueDto -> issueDto.setAssigneeUuid(user.getUuid())); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam(PARAM_ASSIGNEES, user.getLogin()) @@ -1142,8 +1133,7 @@ public class SearchActionTest { ComponentDto file = db.components().insertComponent(newFileDto(project)); RuleDefinitionDto hotspotRule = db.rules().insertHotspotRule(); db.issues().insertHotspot(hotspotRule, project, file); - indexPermissions(); - indexIssues(); + indexPermissionsAndIssues(); SearchWsResponse result = ws.newRequest() .setParam("rules", hotspotRule.getKey().toString()) @@ -1175,14 +1165,11 @@ public class SearchActionTest { public void fail_if_trying_to_filter_issues_by_hotspots() { ComponentDto project = db.components().insertPublicProject(); ComponentDto file = db.components().insertComponent(newFileDto(project)); - RuleDefinitionDto issueRule = newIssueRule().getDefinition(); RuleDefinitionDto hotspotRule = newHotspotRule().getDefinition(); - db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.BUG)); - db.issues().insertIssue(issueRule, project, file, i -> i.setType(RuleType.VULNERABILITY)); - db.issues().insertIssue(issueRule, project, file, i -> i.setType(CODE_SMELL)); db.issues().insertHotspot(hotspotRule, project, file); - indexPermissions(); - indexIssues(); + insertIssues(i -> i.setType(RuleType.BUG), i -> i.setType(RuleType.VULNERABILITY), + i -> i.setType(RuleType.CODE_SMELL)); + indexPermissionsAndIssues(); TestRequest request = ws.newRequest() .setParam("types", RuleType.SECURITY_HOTSPOT.toString()); @@ -1222,15 +1209,8 @@ public class SearchActionTest { @Test public void return_total_effort() { - UserDto john = db.users().insertUser(); - userSession.logIn(john); - RuleDefinitionDto rule = db.rules().insertIssueRule(); - ComponentDto project = db.components().insertPublicProject(); - ComponentDto file = db.components().insertComponent(newFileDto(project)); - IssueDto issue1 = db.issues().insertIssue(rule, project, file, i -> i.setEffort(10L)); - IssueDto issue2 = db.issues().insertIssue(rule, project, file, i -> i.setEffort(15L)); - indexPermissions(); - indexIssues(); + insertIssues(i -> i.setEffort(10L), i -> i.setEffort(15L)); + indexPermissionsAndIssues(); SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class); @@ -1238,6 +1218,28 @@ public class SearchActionTest { } @Test + public void givenNotQuickFixableIssue_returnIssueIsNotQuickFixable() { + insertIssues(i -> i.setQuickFixAvailable(false)); + indexPermissionsAndIssues(); + + SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class); + + assertThat(response.getIssuesList().size()).isEqualTo(1); + assertThat(response.getIssuesList().get(0).getQuickFixAvailable()).isFalse(); + } + + @Test + public void givenQuickFixableIssue_returnIssueIsQuickFixable() { + insertIssues(i -> i.setQuickFixAvailable(true)); + indexPermissionsAndIssues(); + + SearchWsResponse response = ws.newRequest().executeProtobuf(SearchWsResponse.class); + + assertThat(response.getIssuesList().size()).isEqualTo(1); + assertThat(response.getIssuesList().get(0).getQuickFixAvailable()).isTrue(); + } + + @Test public void paging() { RuleDto rule = newIssueRule(); ComponentDto project = db.components().insertComponent(ComponentTesting.newPublicProjectDto("PROJECT_ID").setDbKey("PROJECT_KEY")); @@ -1366,9 +1368,26 @@ public class SearchActionTest { .setGroupUuid(null) .setComponentUuid(project.uuid()) .setComponentName(project.name()) - .setRole(permission), project, null); + .setRole(permission), + project, null); session.commit(); userSession.logIn().addProjectPermission(permission, project); } + private void insertIssues(Consumer<IssueDto>... populators) { + UserDto john = db.users().insertUser(); + userSession.logIn(john); + RuleDefinitionDto rule = db.rules().insertIssueRule(); + ComponentDto project = db.components().insertPublicProject(); + ComponentDto file = db.components().insertComponent(newFileDto(project)); + for (Consumer<IssueDto> populator : populators) { + db.issues().insertIssue(rule, project, file, populator); + } + } + + private void indexPermissionsAndIssues() { + indexPermissions(); + indexIssues(); + } + } diff --git a/sonar-ws/src/main/protobuf/ws-issues.proto b/sonar-ws/src/main/protobuf/ws-issues.proto index 6c5f4ba193f..00d184a98f4 100644 --- a/sonar-ws/src/main/protobuf/ws-issues.proto +++ b/sonar-ws/src/main/protobuf/ws-issues.proto @@ -156,6 +156,8 @@ message Issue { optional string externalRuleEngine = 33; optional bool fromHotspot = 34; optional string scope = 35; + + optional bool quickFixAvailable = 36; } message Transitions { |