diff options
9 files changed, 74 insertions, 57 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java index 06cce4c77bf..1b6c6e43a3b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -126,7 +126,8 @@ public class SearchAction implements IssuesWsAction { "At most one of the following parameters can be provided at the same time: %s, %s, %s, %s, %s<br>" + "Since 5.5, response field 'debt' has been renamed to 'effort'.<br>" + "Since 5.5, response field 'actionPlan' has been removed.<br>" + - "Since 5.5, response field 'reporter' has been removed, as manual issue feature has been dropped.", + "Since 5.5, response field 'reporter' has been removed, as manual issue feature has been dropped." + + "Since 6.3, response field 'email' has been replaced by 'avatar'", PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS, PARAM_COMPONENTS, PARAM_COMPONENT_ROOT_UUIDS, PARAM_COMPONENT_ROOTS) .setSince("3.6") .setResponseExample(getClass().getResource("search-example.json")); diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java index bfb2d239718..f6cb0bdbe65 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchResponseFormat.java @@ -20,6 +20,7 @@ package org.sonar.server.issue.ws; import com.google.common.base.Strings; +import com.google.common.hash.Hashing; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -51,7 +52,20 @@ import org.sonarqube.ws.Issues; import static com.google.common.base.Strings.emptyToNull; import static com.google.common.base.Strings.nullToEmpty; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Locale.ENGLISH; import static org.sonar.core.util.Protobuf.setNullable; +import static org.sonarqube.ws.Issues.Actions; +import static org.sonarqube.ws.Issues.Comment; +import static org.sonarqube.ws.Issues.Comments; +import static org.sonarqube.ws.Issues.Component; +import static org.sonarqube.ws.Issues.Flow; +import static org.sonarqube.ws.Issues.Issue; +import static org.sonarqube.ws.Issues.Location; +import static org.sonarqube.ws.Issues.Operation; +import static org.sonarqube.ws.Issues.SearchWsResponse; +import static org.sonarqube.ws.Issues.Transitions; +import static org.sonarqube.ws.Issues.Users; public class SearchResponseFormat { @@ -65,9 +79,9 @@ public class SearchResponseFormat { this.languages = languages; } - public Issues.SearchWsResponse formatSearch(Set<SearchAdditionalField> fields, SearchResponseData data, + public SearchWsResponse formatSearch(Set<SearchAdditionalField> fields, SearchResponseData data, Paging paging, @Nullable Facets facets) { - Issues.SearchWsResponse.Builder response = Issues.SearchWsResponse.newBuilder(); + SearchWsResponse.Builder response = SearchWsResponse.newBuilder(); formatPaging(paging, response); formatEffortTotal(data, response); @@ -88,11 +102,11 @@ public class SearchResponseFormat { return response.build(); } - public Issues.Operation formatOperation(SearchResponseData data) { - Issues.Operation.Builder response = Issues.Operation.newBuilder(); + public Operation formatOperation(SearchResponseData data) { + Operation.Builder response = Operation.newBuilder(); if (data.getIssues().size() == 1) { - Issues.Issue.Builder issueBuilder = Issues.Issue.newBuilder(); + Issue.Builder issueBuilder = Issue.newBuilder(); IssueDto dto = data.getIssues().get(0); formatIssue(issueBuilder, dto, data); formatIssueActions(data, issueBuilder, dto); @@ -106,7 +120,7 @@ public class SearchResponseFormat { return response.build(); } - private void formatEffortTotal(SearchResponseData data, Issues.SearchWsResponse.Builder response) { + private void formatEffortTotal(SearchResponseData data, SearchWsResponse.Builder response) { Long effort = data.getEffortTotal(); if (effort != null) { response.setDebtTotal(effort); @@ -114,7 +128,7 @@ public class SearchResponseFormat { } } - private void formatPaging(Paging paging, Issues.SearchWsResponse.Builder response) { + private void formatPaging(Paging paging, SearchWsResponse.Builder response) { response.setP(paging.pageIndex()); response.setPs(paging.pageSize()); response.setTotal(paging.total()); @@ -123,8 +137,8 @@ public class SearchResponseFormat { private List<Issues.Issue> formatIssues(Set<SearchAdditionalField> fields, SearchResponseData data) { List<Issues.Issue> result = new ArrayList<>(); - Issues.Issue.Builder issueBuilder = Issues.Issue.newBuilder(); - for (IssueDto dto : data.getIssues()) { + Issue.Builder issueBuilder = Issue.newBuilder(); + data.getIssues().forEach(dto -> { issueBuilder.clear(); formatIssue(issueBuilder, dto, data); if (fields.contains(SearchAdditionalField.ACTIONS)) { @@ -137,11 +151,11 @@ public class SearchResponseFormat { formatIssueComments(data, issueBuilder, dto); } result.add(issueBuilder.build()); - } + }); return result; } - private void formatIssue(Issues.Issue.Builder issueBuilder, IssueDto dto, SearchResponseData data) { + private void formatIssue(Issue.Builder issueBuilder, IssueDto dto, SearchResponseData data) { issueBuilder.setKey(dto.getKey()); setNullable(dto.getType(), issueBuilder::setType, Common.RuleType::valueOf); @@ -179,7 +193,7 @@ public class SearchResponseFormat { setNullable(dto.getIssueCloseDate(), issueBuilder::setCloseDate, DateUtils::formatDateTime); } - private void completeIssueLocations(IssueDto dto, Issues.Issue.Builder issueBuilder) { + private void completeIssueLocations(IssueDto dto, Issue.Builder issueBuilder) { DbIssues.Locations locations = dto.parseLocations(); if (locations == null) { return; @@ -189,7 +203,7 @@ public class SearchResponseFormat { issueBuilder.setTextRange(convertTextRange(textRange)); } for (DbIssues.Flow flow : locations.getFlowList()) { - Issues.Flow.Builder targetFlow = Issues.Flow.newBuilder(); + Flow.Builder targetFlow = Flow.newBuilder(); for (DbIssues.Location flowLocation : flow.getLocationList()) { targetFlow.addLocations(convertLocation(flowLocation)); } @@ -197,8 +211,8 @@ public class SearchResponseFormat { } } - private static Issues.Location convertLocation(DbIssues.Location source) { - Issues.Location.Builder target = Issues.Location.newBuilder(); + private static Location convertLocation(DbIssues.Location source) { + Location.Builder target = Location.newBuilder(); if (source.hasComponentId()) { target.setComponentId(source.getComponentId()); } @@ -230,8 +244,8 @@ public class SearchResponseFormat { return targetRange; } - private static void formatIssueTransitions(SearchResponseData data, Issues.Issue.Builder wsIssue, IssueDto dto) { - Issues.Transitions.Builder wsTransitions = Issues.Transitions.newBuilder(); + private static void formatIssueTransitions(SearchResponseData data, Issue.Builder wsIssue, IssueDto dto) { + Transitions.Builder wsTransitions = Transitions.newBuilder(); List<Transition> transitions = data.getTransitionsForIssueKey(dto.getKey()); if (transitions != null) { for (Transition transition : transitions) { @@ -241,8 +255,8 @@ public class SearchResponseFormat { wsIssue.setTransitions(wsTransitions); } - private static void formatIssueActions(SearchResponseData data, Issues.Issue.Builder wsIssue, IssueDto dto) { - Issues.Actions.Builder wsActions = Issues.Actions.newBuilder(); + private static void formatIssueActions(SearchResponseData data, Issue.Builder wsIssue, IssueDto dto) { + Actions.Builder wsActions = Actions.newBuilder(); List<String> actions = data.getActionsForIssueKey(dto.getKey()); if (actions != null) { wsActions.addAllActions(actions); @@ -250,11 +264,11 @@ public class SearchResponseFormat { wsIssue.setActions(wsActions); } - private static void formatIssueComments(SearchResponseData data, Issues.Issue.Builder wsIssue, IssueDto dto) { - Issues.Comments.Builder wsComments = Issues.Comments.newBuilder(); + private static void formatIssueComments(SearchResponseData data, Issue.Builder wsIssue, IssueDto dto) { + Comments.Builder wsComments = Comments.newBuilder(); List<IssueChangeDto> comments = data.getCommentsForIssueKey(dto.getKey()); if (comments != null) { - Issues.Comment.Builder wsComment = Issues.Comment.newBuilder(); + Comment.Builder wsComment = Comment.newBuilder(); for (IssueChangeDto comment : comments) { String markdown = comment.getChangeData(); wsComment @@ -293,7 +307,7 @@ public class SearchResponseFormat { List<Issues.Component> result = new ArrayList<>(); for (ComponentDto dto : components) { String uuid = dto.uuid(); - Issues.Component.Builder builder = Issues.Component.newBuilder() + Component.Builder builder = Component.newBuilder() .setOrganization(data.getOrganizationKey(dto.getOrganizationUuid())) .setId(dto.getId()) .setKey(dto.key()) @@ -322,17 +336,30 @@ public class SearchResponseFormat { return result; } - private Common.Users.Builder formatUsers(SearchResponseData data) { - Common.Users.Builder wsUsers = Common.Users.newBuilder(); + private Users.Builder formatUsers(SearchResponseData data) { + Users.Builder wsUsers = Users.newBuilder(); List<UserDto> users = data.getUsers(); if (users != null) { for (UserDto user : users) { - wsUsers.addUsers(commonFormat.formatUser(user)); + wsUsers.addUsers(formatUser(user)); } } return wsUsers; } + public Users.User.Builder formatUser(UserDto user) { + Users.User.Builder builder = Users.User.newBuilder() + .setLogin(user.getLogin()) + .setName(nullToEmpty(user.getName())) + .setActive(user.isActive()); + setNullable(user.getEmail(), text -> builder.setAvatar(hash(text))); + return builder; + } + + private static String hash(String text) { + return Hashing.md5().hashString(text.toLowerCase(ENGLISH), UTF_8).toString(); + } + private Issues.Languages.Builder formatLanguages() { Issues.Languages.Builder wsLangs = Issues.Languages.newBuilder(); Issues.Language.Builder wsLang = Issues.Language.newBuilder(); @@ -346,7 +373,7 @@ public class SearchResponseFormat { return wsLangs; } - private void formatFacets(Facets facets, Issues.SearchWsResponse.Builder wsSearch) { + private void formatFacets(Facets facets, SearchWsResponse.Builder wsSearch) { Common.Facets.Builder wsFacets = Common.Facets.newBuilder(); Common.Facet.Builder wsFacet = Common.Facet.newBuilder(); for (Map.Entry<String, LinkedHashMap<String, Long>> facet : facets.getAll().entrySet()) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java index d30eaa5d823..b2333685896 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ws/WsResponseCommonFormat.java @@ -23,7 +23,6 @@ import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.utils.Paging; import org.sonar.db.rule.RuleDto; -import org.sonar.db.user.UserDto; import org.sonarqube.ws.Common; import static com.google.common.base.Strings.nullToEmpty; @@ -57,11 +56,4 @@ public class WsResponseCommonFormat { return builder; } - public Common.User.Builder formatUser(UserDto user) { - return Common.User.newBuilder() - .setLogin(user.getLogin()) - .setName(nullToEmpty(user.getName())) - .setEmail(nullToEmpty(user.getEmail())) - .setActive(user.isActive()); - } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/search-example.json index 2bb9d5fc008..f14ef06f785 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/search-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/search-example.json @@ -81,7 +81,7 @@ "login": "admin", "name": "Administrator", "active": true, - "email": "admin@sonarqube.org" + "avatar": "ab0ec6adc38ad44a15105f207394946f" } ] diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue_with_comments.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue_with_comments.json index ccbba305815..0c6e1982ca7 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue_with_comments.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue_with_comments.json @@ -29,13 +29,12 @@ { "login": "fabrice", "name": "Fabrice", - "email": "fabrice@email.com", + "avatar": "1c7a5823d4ad91e32a88f91242d2c9c2", "active": true }, { "login": "john", "name": "John", - "email": "", "active": true } ] diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields.json index abaebf76bb6..f5510c017e5 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields.json @@ -20,13 +20,12 @@ { "login": "simon", "name": "Simon", - "email": "simon@email.com", + "avatar": "ab0ec6adc38ad44a15105f207394946f", "active": true }, { "login": "admin", "name": "Administrator", - "email": "", "active": true } ] diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields_with_issue_admin_permission.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields_with_issue_admin_permission.json index a25410deaca..745ffde8fa5 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields_with_issue_admin_permission.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/load_additional_fields_with_issue_admin_permission.json @@ -17,20 +17,19 @@ "resolve", "falsepositive", "wontfix" - ], + ] } ], "users": [ { "login": "simon", "name": "Simon", - "email": "simon@email.com", + "avatar": "ab0ec6adc38ad44a15105f207394946f", "active": true }, { "login": "admin", "name": "Administrator", - "email": "", "active": true } ] diff --git a/sonar-ws/src/main/protobuf/ws-commons.proto b/sonar-ws/src/main/protobuf/ws-commons.proto index 6f9c6805103..50a4fa4268c 100644 --- a/sonar-ws/src/main/protobuf/ws-commons.proto +++ b/sonar-ws/src/main/protobuf/ws-commons.proto @@ -72,17 +72,6 @@ enum RuleStatus { REMOVED = 3; } -message User { - optional string login = 1; - optional string name = 2; - optional string email = 3; - optional bool active = 4; -} - -message Users { - repeated User users = 1; -} - // Lines start at 1 and line offsets start at 0 message TextRange { // Start line. Should never be absent diff --git a/sonar-ws/src/main/protobuf/ws-issues.proto b/sonar-ws/src/main/protobuf/ws-issues.proto index a2d1aa67a2f..361efbd4a92 100644 --- a/sonar-ws/src/main/protobuf/ws-issues.proto +++ b/sonar-ws/src/main/protobuf/ws-issues.proto @@ -41,7 +41,7 @@ message SearchWsResponse { repeated Issue issues = 6; repeated Component components = 7; optional sonarqube.ws.commons.Rules rules = 8; - optional sonarqube.ws.commons.Users users = 9; + optional Users users = 9; // Deprecated since 5.5, action plan has been removed optional ActionPlans unusedActionPlans = 10; @@ -54,7 +54,7 @@ message Operation { optional Issue issue = 1; repeated Component components = 2; repeated sonarqube.ws.commons.Rule rules = 3; - repeated sonarqube.ws.commons.User users = 4; + repeated Users.User users = 4; // Deprecated since 5.5, action plan has been removed repeated ActionPlan actiunusedActionPlansonPlans = 5; } @@ -211,5 +211,16 @@ message BulkChangeWsResponse { optional int64 failures = 4; } +message Users { + repeated User users = 1; + + message User { + optional string login = 1; + optional string name = 2; + optional string avatar = 3; + optional bool active = 4; + } +} + |