aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukasz Jarocki <lukasz.jarocki@sonarsource.com>2021-10-08 13:52:07 +0200
committersonartech <sonartech@sonarsource.com>2021-10-13 20:03:34 +0000
commit6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7 (patch)
tree904a85dacd34f2b337727b4dc45e14202b434568
parentae8cda9b5442652dfff87819ac45fc3dd03eb36d (diff)
downloadsonarqube-6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7.tar.gz
sonarqube-6a8bc0c123bf5dd10f4eb73a0bcea47288269aa7.zip
SONAR-15486 add a new field to response of /api/issues/search endpoint - quickFixAvailable
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java1
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java4
-rw-r--r--server/sonar-webserver-webapi/src/main/resources/org/sonar/server/issue/ws/search-example.json3
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java99
-rw-r--r--sonar-ws/src/main/protobuf/ws-issues.proto2
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 {