aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuarte Meneses <duarte.meneses@sonarsource.com>2022-09-08 08:50:47 -0500
committersonartech <sonartech@sonarsource.com>2022-09-16 20:03:14 +0000
commitd6abb3ee19911c06bd8c01f4e57bcf8aaff445f9 (patch)
tree6d3b8179001ff390dc45490f64e34aafcd40433e
parent47f5baa558b751f48cd04d06c63c044424904c37 (diff)
downloadsonarqube-d6abb3ee19911c06bd8c01f4e57bcf8aaff445f9.tar.gz
sonarqube-d6abb3ee19911c06bd8c01f4e57bcf8aaff445f9.zip
SONAR-17287 Return optional flow description and type in WS responses
-rw-r--r--build.gradle2
-rw-r--r--server/sonar-db-dao/src/main/protobuf/db-issues.proto5
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java12
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java23
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/TextRangeResponseFormatter.java30
-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.java8
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java89
-rw-r--r--sonar-scanner-protocol/src/main/protobuf/scanner_report.proto6
-rw-r--r--sonar-ws/src/main/protobuf/ws-commons.proto8
-rw-r--r--sonar-ws/src/main/protobuf/ws-issues.proto2
11 files changed, 114 insertions, 72 deletions
diff --git a/build.gradle b/build.gradle
index e353e1501b3..ef529ad5313 100644
--- a/build.gradle
+++ b/build.gradle
@@ -201,7 +201,7 @@ subprojects {
dependency 'org.sonarsource.kotlin:sonar-kotlin-plugin:2.10.0.1456'
dependency 'org.sonarsource.slang:sonar-ruby-plugin:1.10.0.3710'
dependency 'org.sonarsource.slang:sonar-scala-plugin:1.10.0.3710'
- dependency 'org.sonarsource.api.plugin:sonar-plugin-api:9.10.0.269'
+ dependency 'org.sonarsource.api.plugin:sonar-plugin-api:9.11.0.290'
dependency 'org.sonarsource.xml:sonar-xml-plugin:2.5.0.3376'
dependency 'org.sonarsource.iac:sonar-iac-plugin:1.9.2.2279'
dependency 'org.sonarsource.text:sonar-text-plugin:1.1.0.282'
diff --git a/server/sonar-db-dao/src/main/protobuf/db-issues.proto b/server/sonar-db-dao/src/main/protobuf/db-issues.proto
index 3138260372d..a094ea162ca 100644
--- a/server/sonar-db-dao/src/main/protobuf/db-issues.proto
+++ b/server/sonar-db-dao/src/main/protobuf/db-issues.proto
@@ -43,8 +43,9 @@ message Flow {
}
enum FlowType {
- DATA = 0;
- EXECUTION = 1;
+ UNDEFINED = 0;
+ DATA = 1;
+ EXECUTION = 2;
}
message Location {
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java
index 7a6b742820a..6abb2b5bc43 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java
@@ -199,7 +199,8 @@ public class SearchAction implements HotspotsWsAction {
.setSince("8.1")
.setInternal(true)
.setChangelog(
- new Change("9.6", "Added parameters 'pciDss-3.2' and 'pciDss-4.0"));
+ new Change("9.6", "Added parameters 'pciDss-3.2' and 'pciDss-4.0"),
+ new Change("9.7", "Hotspot flows in the response may contain a description and a type"));
action.addPagingParams(100);
action.createParam(PARAM_PROJECT_KEY)
@@ -603,14 +604,7 @@ public class SearchAction implements HotspotsWsAction {
}
textRangeFormatter.formatTextRange(locations, hotspotBuilder::setTextRange);
-
- for (DbIssues.Flow flow : locations.getFlowList()) {
- Common.Flow.Builder targetFlow = Common.Flow.newBuilder();
- for (DbIssues.Location flowLocation : flow.getLocationList()) {
- targetFlow.addLocations(textRangeFormatter.formatLocation(flowLocation, hotspotBuilder.getComponent(), data.getComponentsByUuid()));
- }
- hotspotBuilder.addFlows(targetFlow.build());
- }
+ hotspotBuilder.addAllFlows(textRangeFormatter.formatFlows(locations, hotspotBuilder.getComponent(), data.getComponentsByUuid()));
}
private void formatComponents(SearchResponseData searchResponseData, SearchWsResponse.Builder responseBuilder) {
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java
index 9cadb2e3035..39d3a514d8c 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java
@@ -105,7 +105,8 @@ public class ShowAction implements HotspotsWsAction {
.setDescription("Provides the details of a Security Hotspot.")
.setSince("8.1")
.setChangelog(new Change("9.5", "The fields rule.riskDescription, rule.fixRecommendations, rule.vulnerabilityDescription of the response are deprecated."
- + " /api/rules/show endpoint should be used to fetch rule descriptions."));
+ + " /api/rules/show endpoint should be used to fetch rule descriptions."),
+ new Change("9.7", "Hotspot flows in the response may contain a description and a type"));
action.createParam(PARAM_HOTSPOT_KEY)
.setDescription("Key of the Security Hotspot")
@@ -222,13 +223,7 @@ public class ShowAction implements HotspotsWsAction {
Set<String> componentUuids = readComponentUuidsFromLocations(hotspot, locations);
Map<String, ComponentDto> componentsByUuids = loadComponents(dbSession, componentUuids);
- for (DbIssues.Flow flow : locations.getFlowList()) {
- Common.Flow.Builder targetFlow = Common.Flow.newBuilder();
- for (DbIssues.Location flowLocation : flow.getLocationList()) {
- targetFlow.addLocations(textRangeFormatter.formatLocation(flowLocation, hotspotBuilder.getComponent().getKey(), componentsByUuids));
- }
- hotspotBuilder.addFlows(targetFlow.build());
- }
+ hotspotBuilder.addAllFlows(textRangeFormatter.formatFlows(locations, hotspotBuilder.getComponent().getKey(), componentsByUuids));
}
private static Set<String> readComponentUuidsFromLocations(IssueDto hotspot, Locations locations) {
@@ -246,7 +241,7 @@ public class ShowAction implements HotspotsWsAction {
private Map<String, ComponentDto> loadComponents(DbSession dbSession, Set<String> componentUuids) {
Map<String, ComponentDto> componentsByUuids = dbClient.componentDao().selectSubProjectsByComponentUuids(dbSession,
- componentUuids)
+ componentUuids)
.stream()
.collect(toMap(ComponentDto::uuid, Function.identity(), (componentDto, componentDto2) -> componentDto2));
@@ -278,10 +273,10 @@ public class ShowAction implements HotspotsWsAction {
private void formatUsers(ShowWsResponse.Builder responseBuilder, Users users, FormattingContext formattingContext) {
Common.User.Builder userBuilder = Common.User.newBuilder();
Stream.concat(
- Stream.of(users.getAssignee(), users.getAuthor())
- .filter(Optional::isPresent)
- .map(Optional::get),
- formattingContext.getUsers().stream())
+ Stream.of(users.getAssignee(), users.getAuthor())
+ .filter(Optional::isPresent)
+ .map(Optional::get),
+ formattingContext.getUsers().stream())
.distinct()
.map(user -> userFormatter.formatUser(userBuilder, user))
.forEach(responseBuilder::addUsers);
@@ -302,7 +297,7 @@ public class ShowAction implements HotspotsWsAction {
boolean hotspotOnProject = Objects.equals(project.uuid(), componentUuid);
ComponentDto component = hotspotOnProject ? project
: dbClient.componentDao().selectByUuid(dbSession, componentUuid)
- .orElseThrow(() -> new NotFoundException(format("Component with uuid '%s' does not exist", componentUuid)));
+ .orElseThrow(() -> new NotFoundException(format("Component with uuid '%s' does not exist", componentUuid)));
return new Components(project, component);
}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/TextRangeResponseFormatter.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/TextRangeResponseFormatter.java
index 9bbb4bda6f9..d105c4e533c 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/TextRangeResponseFormatter.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/TextRangeResponseFormatter.java
@@ -19,8 +19,11 @@
*/
package org.sonar.server.issue;
+import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.protobuf.DbCommons;
@@ -46,6 +49,33 @@ public class TextRangeResponseFormatter {
}
}
+ public List<Common.Flow> formatFlows(DbIssues.Locations locations, String issueComponent, Map<String, ComponentDto> componentsByUuid) {
+ return locations.getFlowList().stream().map(flow -> {
+ Common.Flow.Builder targetFlow = Common.Flow.newBuilder();
+ for (DbIssues.Location flowLocation : flow.getLocationList()) {
+ targetFlow.addLocations(formatLocation(flowLocation, issueComponent, componentsByUuid));
+ }
+ if (flow.hasDescription()) {
+ targetFlow.setDescription(flow.getDescription());
+ }
+ if (flow.hasType()) {
+ convertFlowType(flow.getType()).ifPresent(targetFlow::setFlowType);
+ }
+ return targetFlow.build();
+ }).collect(Collectors.toList());
+ }
+
+ private static Optional<Common.FlowType> convertFlowType(DbIssues.FlowType flowType) {
+ switch (flowType) {
+ case DATA:
+ return Optional.of(Common.FlowType.DATA);
+ case EXECUTION:
+ return Optional.of(Common.FlowType.EXECUTION);
+ default:
+ return Optional.empty();
+ }
+ }
+
public Common.Location formatLocation(DbIssues.Location source, String issueComponent, Map<String, ComponentDto> componentsByUuid) {
Common.Location.Builder target = Common.Location.newBuilder();
if (source.hasMsg()) {
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 51b9ac1bbd4..36aa53d81cb 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
@@ -193,6 +193,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.7", "Issues flows in the response may contain a description and a type"),
new Change("9.6", "Response field 'fromHotspot' dropped."),
new Change("9.6", "Added facets 'pciDss-3.2' and 'pciDss-4.0"),
new Change("9.6", "Added parameters 'pciDss-3.2' and 'pciDss-4.0"),
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 40ff06f7f74..f62a2077ecb 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
@@ -226,13 +226,7 @@ public class SearchResponseFormat {
return;
}
textRangeFormatter.formatTextRange(locations, issueBuilder::setTextRange);
- for (DbIssues.Flow flow : locations.getFlowList()) {
- Common.Flow.Builder targetFlow = Common.Flow.newBuilder();
- for (DbIssues.Location flowLocation : flow.getLocationList()) {
- targetFlow.addLocations(textRangeFormatter.formatLocation(flowLocation, issueBuilder.getComponent(), data.getComponentsByUuid()));
- }
- issueBuilder.addFlows(targetFlow.build());
- }
+ issueBuilder.addAllFlows(textRangeFormatter.formatFlows(locations, issueBuilder.getComponent(), data.getComponentsByUuid()));
}
private static Transitions createIssueTransition(SearchResponseData data, IssueDto dto) {
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
index 2d1e0e8ae55..cfcced32b9c 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java
@@ -204,36 +204,50 @@ public class ShowActionTest {
ComponentDto project = dbTester.components().insertPublicProject();
ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
ComponentDto anotherFile = dbTester.components().insertComponent(newFileDto(project));
- DbIssues.Locations.Builder locations = DbIssues.Locations.newBuilder().addFlow(DbIssues.Flow.newBuilder().addAllLocation(Arrays.asList(
- DbIssues.Location.newBuilder()
- .setComponentId(file.uuid())
- .setMsg("FLOW MESSAGE")
- .setTextRange(DbCommons.TextRange.newBuilder()
- .setStartLine(1)
- .setEndLine(1)
- .setStartOffset(0)
- .setEndOffset(12)
- .build())
- .build(),
- DbIssues.Location.newBuilder()
- .setComponentId(anotherFile.uuid())
- .setMsg("ANOTHER FLOW MESSAGE")
- .setTextRange(DbCommons.TextRange.newBuilder()
- .setStartLine(1)
- .setEndLine(1)
- .setStartOffset(0)
- .setEndOffset(12)
- .build())
- .build(),
- DbIssues.Location.newBuilder()
- .setMsg("FLOW MESSAGE WITHOUT FILE UUID")
- .setTextRange(DbCommons.TextRange.newBuilder()
- .setStartLine(1)
- .setEndLine(1)
- .setStartOffset(0)
- .setEndOffset(12)
- .build())
- .build())));
+ DbIssues.Locations.Builder locations = DbIssues.Locations.newBuilder()
+ .addFlow(DbIssues.Flow.newBuilder()
+ .setDescription("FLOW DESCRIPTION")
+ .setType(DbIssues.FlowType.DATA)
+ .addAllLocation(Arrays.asList(
+ DbIssues.Location.newBuilder()
+ .setComponentId(file.uuid())
+ .setMsg("FLOW MESSAGE")
+ .setTextRange(DbCommons.TextRange.newBuilder()
+ .setStartLine(1)
+ .setEndLine(1)
+ .setStartOffset(0)
+ .setEndOffset(12)
+ .build())
+ .build(),
+ DbIssues.Location.newBuilder()
+ .setComponentId(anotherFile.uuid())
+ .setMsg("ANOTHER FLOW MESSAGE")
+ .setTextRange(DbCommons.TextRange.newBuilder()
+ .setStartLine(1)
+ .setEndLine(1)
+ .setStartOffset(0)
+ .setEndOffset(12)
+ .build())
+ .build(),
+ DbIssues.Location.newBuilder()
+ .setMsg("FLOW MESSAGE WITHOUT FILE UUID")
+ .setTextRange(DbCommons.TextRange.newBuilder()
+ .setStartLine(1)
+ .setEndLine(1)
+ .setStartOffset(0)
+ .setEndOffset(12)
+ .build())
+ .build())))
+ .addFlow(DbIssues.Flow.newBuilder()
+ .addAllLocation(Arrays.asList(
+ DbIssues.Location.newBuilder()
+ .setComponentId(file.uuid())
+ .setTextRange(DbCommons.TextRange.newBuilder()
+ .setStartLine(1)
+ .setStartOffset(0)
+ .setEndOffset(12)
+ .build())
+ .build())));
RuleDto rule = newRule(SECURITY_HOTSPOT);
var hotspot = dbTester.issues().insertHotspot(rule, project, file, i -> i.setLocations(locations.build()));
mockChangelogAndCommentsFormattingContext();
@@ -244,13 +258,18 @@ public class ShowActionTest {
.executeProtobuf(Hotspots.ShowWsResponse.class);
assertThat(response.getKey()).isEqualTo(hotspot.getKey());
- assertThat(response.getFlowsCount()).isEqualTo(1);
+ assertThat(response.getFlowsCount()).isEqualTo(2);
+ assertThat(response.getFlows(0).getDescription()).isEqualTo("FLOW DESCRIPTION");
+ assertThat(response.getFlows(0).getFlowType()).isEqualTo(Common.FlowType.DATA);
assertThat(response.getFlows(0).getLocationsList())
.extracting(Location::getMsg, Location::getComponent)
.containsExactlyInAnyOrder(
tuple("FLOW MESSAGE", file.getKey()),
tuple("ANOTHER FLOW MESSAGE", anotherFile.getKey()),
tuple("FLOW MESSAGE WITHOUT FILE UUID", file.getKey()));
+
+ assertThat(response.getFlows(1).getDescription()).isEmpty();
+ assertThat(response.getFlows(1).hasFlowType()).isFalse();
}
@Test
@@ -435,7 +454,6 @@ public class ShowActionTest {
};
}
-
@Test
public void dispatch_description_sections_of_advanced_rule_in_relevant_field() {
ComponentDto project = dbTester.components().insertPrivateProject();
@@ -481,7 +499,7 @@ public class ShowActionTest {
RuleDto rule = newRuleWithoutSection(SECURITY_HOTSPOT,
r -> r.addRuleDescriptionSectionDto(introductionSection)
- .setDescriptionFormat(HTML));
+ .setDescriptionFormat(HTML));
IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file);
mockChangelogAndCommentsFormattingContext();
@@ -559,7 +577,6 @@ public class ShowActionTest {
assertThat(response.getRule().getRiskDescription()).isEqualTo("<h2>Title</h2>&lt;div&gt;line1<br/>line2&lt;/div&gt;");
}
-
@Test
public void handles_null_description_for_custom_rules() {
ComponentDto project = dbTester.components().insertPrivateProject();
@@ -1037,8 +1054,8 @@ public class ShowActionTest {
.extracting(User::getLogin, User::getName, User::getActive)
.containsExactlyInAnyOrder(
Stream.concat(
- Stream.of(author, assignee),
- changeLogAndCommentsUsers.stream())
+ Stream.of(author, assignee),
+ changeLogAndCommentsUsers.stream())
.map(t -> tuple(t.getLogin(), t.getName(), t.isActive()))
.toArray(Tuple[]::new));
}
diff --git a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
index da7c32d0cfc..8e2be64f50f 100644
--- a/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
+++ b/sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
@@ -241,9 +241,9 @@ message Flow {
}
enum FlowType {
- DATA = 0;
- EXECUTION = 1;
- UNKNOWN = 2;
+ UNDEFINED = 0;
+ DATA = 1;
+ EXECUTION = 2;
}
message Changesets {
diff --git a/sonar-ws/src/main/protobuf/ws-commons.proto b/sonar-ws/src/main/protobuf/ws-commons.proto
index 7a49f67ccb1..71a564212a0 100644
--- a/sonar-ws/src/main/protobuf/ws-commons.proto
+++ b/sonar-ws/src/main/protobuf/ws-commons.proto
@@ -95,6 +95,14 @@ message TextRange {
message Flow {
repeated Location locations = 1;
+ optional string description = 2;
+ optional FlowType flowType = 3;
+}
+
+enum FlowType {
+ UNDEFINED = 0;
+ DATA = 1;
+ EXECUTION = 2;
}
message Location {
diff --git a/sonar-ws/src/main/protobuf/ws-issues.proto b/sonar-ws/src/main/protobuf/ws-issues.proto
index 15735d26244..ca76506ec2c 100644
--- a/sonar-ws/src/main/protobuf/ws-issues.proto
+++ b/sonar-ws/src/main/protobuf/ws-issues.proto
@@ -287,4 +287,6 @@ message TaintVulnerabilityLite {
message Flow {
repeated Location locations = 1;
+ optional string description = 2;
+ optional sonarqube.ws.commons.FlowType type = 3;
}