diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2022-09-08 08:50:47 -0500 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-09-16 20:03:14 +0000 |
commit | d6abb3ee19911c06bd8c01f4e57bcf8aaff445f9 (patch) | |
tree | 6d3b8179001ff390dc45490f64e34aafcd40433e /server/sonar-webserver-webapi | |
parent | 47f5baa558b751f48cd04d06c63c044424904c37 (diff) | |
download | sonarqube-d6abb3ee19911c06bd8c01f4e57bcf8aaff445f9.tar.gz sonarqube-d6abb3ee19911c06bd8c01f4e57bcf8aaff445f9.zip |
SONAR-17287 Return optional flow description and type in WS responses
Diffstat (limited to 'server/sonar-webserver-webapi')
6 files changed, 97 insertions, 66 deletions
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><div>line1<br/>line2</div>"); } - @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)); } |