From c3fa85a2d570e3616fe404d6967a8cb17ee4c16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 2 Nov 2017 12:34:13 +0100 Subject: [PATCH] implement resetting of overview comments --- .../sonar/plugins/stash/StashPluginUtils.java | 6 + .../plugins/stash/StashRequestFacade.java | 57 ++++--- .../plugins/stash/client/StashClient.java | 159 +++++++++++++++--- .../stash/issue/collector/StashCollector.java | 16 +- 4 files changed, 185 insertions(+), 53 deletions(-) diff --git a/src/main/java/org/sonar/plugins/stash/StashPluginUtils.java b/src/main/java/org/sonar/plugins/stash/StashPluginUtils.java index 49dc1621..f064fd1e 100644 --- a/src/main/java/org/sonar/plugins/stash/StashPluginUtils.java +++ b/src/main/java/org/sonar/plugins/stash/StashPluginUtils.java @@ -3,7 +3,9 @@ import com.google.common.base.CharMatcher; import java.io.IOException; import java.util.Collection; +import java.util.Optional; import java.util.Properties; +import java.util.stream.Stream; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.InputModule; import org.sonar.api.batch.postjob.issue.PostJobIssue; @@ -72,4 +74,8 @@ public static String removeEnd(String s, String suffix) { } return s; } + + public static Stream removeEmpty(Optional v) { + return v.map(Stream::of).orElse(Stream.empty()); + } } diff --git a/src/main/java/org/sonar/plugins/stash/StashRequestFacade.java b/src/main/java/org/sonar/plugins/stash/StashRequestFacade.java index 06452827..3c26c36b 100644 --- a/src/main/java/org/sonar/plugins/stash/StashRequestFacade.java +++ b/src/main/java/org/sonar/plugins/stash/StashRequestFacade.java @@ -398,39 +398,46 @@ public void resetComments(PullRequestRef pr, StashUser sonarUser, StashClient stashClient) { try { - // Let's call this "diffRep_loop" - for (StashComment comment : diffReport.getComments()) { - - // delete comment only if published by the current SQ user - if (sonarUser.getId() != comment.getAuthor().getId()) { - continue; - // Next element in "diffRep_loop" - - // comment contains tasks which cannot be deleted => do nothing - } else if (comment.containsPermanentTasks()) { - LOGGER.debug("Comment \"{}\" (path:\"{}\", line:\"{}\")" - + "CANNOT be deleted because one of its tasks is not deletable.", comment.getId(), - comment.getPath(), - comment.getLine()); - continue; // Next element in "diffRep_loop" - } - - // delete tasks linked to the current comment - for (StashTask task : comment.getTasks()) { - stashClient.deleteTaskOnComment(task); - } - - stashClient.deletePullRequestComment(pr, comment); - } + // FIXME delete tasks on file-wide comments + // resetComments(diffReport.getComments(), pr, sonarUser, stashClient); + resetComments(stashClient.getPullRequestOverviewComments(pr), pr, sonarUser, stashClient); LOGGER.info("SonarQube issues reported to Stash by user \"{}\" have been reset", sonarUser.getName()); - } catch (StashClientException e) { LOGGER.error("Unable to reset comment list", e); } } + private void resetComments(Collection comments, PullRequestRef pr, StashUser sonarUser, StashClient stashClient) + throws StashClientException { + for (StashComment comment : comments) { + if (comment.getId() == 2079776) { + LOGGER.warn(comment.toString()); + LOGGER.warn(comment.getTasks().toString()); + } + + if (sonarUser.getId() != comment.getAuthor().getId()) { + continue; + } + + if (comment.containsPermanentTasks()) { + LOGGER.debug("Comment \"{}\" (path:\"{}\", line:\"{}\")" + + "CANNOT be deleted because one of its tasks is not deletable.", comment.getId(), + comment.getPath(), + comment.getLine()); + continue; // Next element in "diffRep_loop" + } + + // delete tasks linked to the current comment + for (StashTask task : comment.getTasks()) { + stashClient.deleteTaskOnComment(task); + } + + stashClient.deletePullRequestComment(pr, comment); + } + } + @Override public String getIssuePath(PostJobIssue issue) { InputComponent ip = issue.inputComponent(); diff --git a/src/main/java/org/sonar/plugins/stash/client/StashClient.java b/src/main/java/org/sonar/plugins/stash/client/StashClient.java index b7c45f01..43df0e4e 100644 --- a/src/main/java/org/sonar/plugins/stash/client/StashClient.java +++ b/src/main/java/org/sonar/plugins/stash/client/StashClient.java @@ -1,6 +1,12 @@ package org.sonar.plugins.stash.client; +import java.util.Collection; import java.util.Optional; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.BoundRequestBuilder; import org.asynchttpclient.DefaultAsyncHttpClient; @@ -19,7 +25,6 @@ import org.sonar.plugins.stash.PeekableInputStream; import org.sonar.plugins.stash.PluginInfo; import org.sonar.plugins.stash.PullRequestRef; -import org.sonar.plugins.stash.StashPlugin; import org.sonar.plugins.stash.StashPlugin.IssueType; import org.sonar.plugins.stash.StashPluginUtils; import org.sonar.plugins.stash.exceptions.StashClientException; @@ -64,7 +69,7 @@ public class StashClient implements AutoCloseable { private static final String API_ONE_PR_ALL_COMMENTS = API_ONE_PR + "/comments"; private static final String API_ONE_PR_DIFF = API_ONE_PR + "/diff?withComments=true"; private static final String API_ONE_PR_APPROVAL = API_ONE_PR + "/approve"; - private static final String API_ONE_PR_COMMENT_PATH = API_ONE_PR + "/comments?path={4}&start={5,number,#}"; + private static final String API_ONE_PR_COMMENT_PATH = API_ONE_PR + "/comments?path={4}"; private static final String API_ONE_PR_ONE_COMMENT = API_ONE_PR_ALL_COMMENTS + "/{4}?version={5}"; @@ -111,35 +116,33 @@ public void postCommentOnPullRequest(PullRequestRef pr, String report) postCreate(request, json, MessageFormat.format(COMMENT_POST_ERROR_MESSAGE, pr.repository(), pr.pullRequestId())); } + public Collection getPullRequestOverviewComments(PullRequestRef pr) throws StashClientException { + return getPaged( + MessageFormat.format(API_ONE_PR + "/activities", baseUrl, pr.project(), pr.repository(), pr.pullRequestId()), + "Error!" + ).map(StashCollector::extractCommentFromActivity).flatMap(StashPluginUtils::removeEmpty).collect(Collectors.toList()); + } + public StashCommentReport getPullRequestComments(PullRequestRef pr, String path) throws StashClientException { StashCommentReport result = new StashCommentReport(); - long start = 0; - boolean isLastPage = false; + String url = MessageFormat.format(API_ONE_PR_COMMENT_PATH, + baseUrl, + pr.project(), + pr.repository(), + pr.pullRequestId(), + path); - while (!isLastPage) { + getPaged(url, + MessageFormat.format(COMMENT_GET_ERROR_MESSAGE, pr.repository(), pr.pullRequestId()) + ).forEach(v -> { try { - String request = MessageFormat.format(API_ONE_PR_COMMENT_PATH, - baseUrl, - pr.project(), - pr.repository(), - pr.pullRequestId(), - path, - start); - JsonObject jsonComments = get(request, - MessageFormat.format(COMMENT_GET_ERROR_MESSAGE, - pr.repository(), - pr.pullRequestId())); - result.add(StashCollector.extractComments(jsonComments)); - - // Stash pagination: check if you get all comments linked to the pull-request - isLastPage = StashCollector.isLastPage(jsonComments); - start = StashCollector.getNextPageStart(jsonComments); + result.add(StashCollector.extractComment(v)); } catch (StashReportExtractionException e) { - throw new StashClientException(e); + throw new RuntimeException(e); } - } + }); return result; } @@ -310,6 +313,10 @@ private JsonObject get(String url, String errorMessage) throws StashClientExcept return performRequest(httpClient.prepareGet(url), null, HttpURLConnection.HTTP_OK, errorMessage); } + private Stream getPaged(String url, String errorMessage) throws StashClientException { + return performPagedRequest(httpClient.prepareGet(url), null, HttpURLConnection.HTTP_OK, errorMessage); + } + private JsonObject post(String url, JsonObject body, String errorMessage) throws StashClientException { return performRequest(httpClient.preparePost(url), body, HttpURLConnection.HTTP_OK, errorMessage); } @@ -456,4 +463,110 @@ AsyncHttpClient createHttpClient(String sonarQubeVersion) { .build() ); } + + private Stream performPagedRequest(BoundRequestBuilder requestBuilder, + JsonObject body, + int expectedStatusCode, + String errorMessage) { + return StreamSupport.stream( + new StashClientSpliterator(this, requestBuilder, body, expectedStatusCode, errorMessage), + false + ); + } + + private abstract class BatchedSpliterator implements Spliterator { + private List buffer = new ArrayList<>(); + + abstract void fillBuffer(Collection buffer); + abstract boolean isDone(); + + @Override + public boolean tryAdvance(Consumer action) { + if (nextElement(action)) { + return true; + } + + if (isDone()) { + return false; + } + + fillBuffer(buffer); + return nextElement(action); + } + + private boolean nextElement(Consumer action) { + if (!buffer.isEmpty()) { + action.accept(buffer.remove(0)); + return true; + } + return false; + } + + } + + private class StashClientSpliterator extends BatchedSpliterator { + + private StashClient stashClient; + private final BoundRequestBuilder requestBuilder; + private final JsonObject body; + private final int expectedStatusCode; + private final String errorMessage; + + private boolean isLastPage = false; + private int nextPageStart = 0; + // FIXME size/limit support + + StashClientSpliterator( + StashClient stashClient, BoundRequestBuilder requestBuilder, + JsonObject body, int expectedStatusCode, String errorMessage) { + this.stashClient = stashClient; + this.requestBuilder = requestBuilder; + this.body = body; + this.expectedStatusCode = expectedStatusCode; + this.errorMessage = errorMessage; + } + + @Override + boolean isDone() { + return isLastPage; + } + + @Override + void fillBuffer(Collection buffer) { + // FIXME should we mutate this here? + if (nextPageStart > 0) { + requestBuilder.addQueryParam("start", String.valueOf(nextPageStart)); + } + + try { + JsonObject res = stashClient.performRequest(requestBuilder, body, expectedStatusCode, errorMessage); + ((JsonArray) res.get("values")).asCollection(buffer); + isLastPage = res.getBoolean("isLastPage"); + if (isLastPage) { + nextPageStart = -1; + } else { + nextPageStart = res.getInteger("nextPageStart"); + } + } catch (StashClientException e) { + // FIXME + throw new RuntimeException(e); + } + + } + + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() { + return Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL; + } + } } diff --git a/src/main/java/org/sonar/plugins/stash/issue/collector/StashCollector.java b/src/main/java/org/sonar/plugins/stash/issue/collector/StashCollector.java index 8d4898a4..5d53ebe5 100644 --- a/src/main/java/org/sonar/plugins/stash/issue/collector/StashCollector.java +++ b/src/main/java/org/sonar/plugins/stash/issue/collector/StashCollector.java @@ -1,6 +1,8 @@ package org.sonar.plugins.stash.issue.collector; import java.math.BigDecimal; +import java.util.Objects; +import java.util.Optional; import org.json.simple.JsonArray; import org.json.simple.JsonObject; import org.sonar.plugins.stash.PullRequestRef; @@ -20,9 +22,7 @@ public final class StashCollector { private static final String AUTHOR = "author"; private static final String VERSION = "version"; - private StashCollector() { - // Hiding implicit public constructor with an explicit private one (squid:S1118) - } + private StashCollector() {} public static StashCommentReport extractComments(JsonObject jsonComments) throws StashReportExtractionException { StashCommentReport result = new StashCommentReport(); @@ -41,8 +41,11 @@ public static StashCommentReport extractComments(JsonObject jsonComments) throws return result; } - public static StashComment extractComment(JsonObject jsonComment, String path, Long line) { + public static Optional extractCommentFromActivity(JsonObject json) { + return Optional.ofNullable((JsonObject) json.get("comment")).filter(Objects::nonNull).map(j -> StashCollector.extractComment(j, null, null)); + } + public static StashComment extractComment(JsonObject jsonComment, String path, Long line) { long id = getLong(jsonComment, "id"); String message = (String)jsonComment.get("text"); @@ -51,7 +54,10 @@ public static StashComment extractComment(JsonObject jsonComment, String path, L JsonObject jsonAuthor = (JsonObject)jsonComment.get(AUTHOR); StashUser stashUser = extractUser(jsonAuthor); - return new StashComment(id, message, path, line, stashUser, version); + StashComment result = new StashComment(id, message, path, line, stashUser, version); + // FIXME do this at some central place + updateCommentTasks(result, (JsonArray) jsonComment.get("tasks")); + return result; } public static StashComment extractComment(JsonObject jsonComment) throws StashReportExtractionException {