Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide outdated summary comments on GitHub #435

Merged
merged 1 commit into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2021 Julien Roy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.github.mc1arke.sonarqube.plugin.almclient.github.v4;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.aexp.nodes.graphql.annotations.GraphQLProperty;

public class Actor {
@GraphQLProperty(name = "__typename")
private final String type;
private final String login;

@JsonCreator
public Actor(@JsonProperty("__typename") String type, @JsonProperty("login") String login) {
this.type = type;
this.login = login;
}

public String getType() {
return type;
}

public String getLogin() {
return login;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2021 Julien Roy, Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.github.mc1arke.sonarqube.plugin.almclient.github.v4;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.aexp.nodes.graphql.annotations.GraphQLProperty;

import java.util.List;

public class Comments {
private final List<CommentNode> nodes;
private final PageInfo pageInfo;

@JsonCreator
public Comments(@JsonProperty("nodes") List<CommentNode> nodes, @JsonProperty("pageInfo") PageInfo pageInfo) {
this.nodes = nodes;
this.pageInfo = pageInfo;
}

public List<CommentNode> getNodes() {
return nodes;
}

public PageInfo getPageInfo() {
return pageInfo;
}


public static class CommentNode {

private final String id;
private final Actor author;
@GraphQLProperty(name = "isMinimized")
private final boolean minimized;

@JsonCreator
public CommentNode(@JsonProperty("id") String id, @JsonProperty("author") Actor author, @JsonProperty("isMinimized") boolean minimized) {
this.id = id;
this.author = author;
this.minimized = minimized;
}

public String getId() {
return id;
}

public Actor getAuthor() {
return author;
}

public boolean isMinimized() {
return minimized;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,22 @@ public static class PullRequest {

private final String id;

@GraphQLProperty(name = "comments", arguments = {@GraphQLArgument(name = "first", optional = true, type = "Integer"), @GraphQLArgument(name = "after", optional = true, type = "String")})
private final Comments comments;

@JsonCreator
public PullRequest(@JsonProperty("id") String id) {
public PullRequest(@JsonProperty("id") String id, @JsonProperty("comments") Comments comments) {
this.id = id;
this.comments = comments;
}

public String getId() {
return id;
}

public Comments getComments() {
return comments;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.github.mc1arke.sonarqube.plugin.almclient.github.RepositoryAuthenticationToken;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v4.model.CheckAnnotationLevel;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v4.model.CheckConclusionState;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v4.model.CommentClassifiers;
import com.github.mc1arke.sonarqube.plugin.almclient.github.v4.model.RequestableCheckStatusState;
import com.github.mc1arke.sonarqube.plugin.ce.pullrequest.AnalysisDetails;
import com.github.mc1arke.sonarqube.plugin.ce.pullrequest.DecorationResult;
Expand All @@ -45,6 +46,7 @@
import org.sonar.db.alm.setting.ProjectAlmSettingDto;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -142,10 +144,11 @@ public DecorationResult createCheckRun(AnalysisDetails analysisDetails, AlmSetti
InputObject.Builder<Object> repositoryInputObjectBuilder = graphqlProvider.createInputObject();
inputObjectArguments.forEach(repositoryInputObjectBuilder::put);

String graphqlUrl = getGraphqlUrl(apiUrl);

GraphQLRequestEntity.RequestBuilder graphQLRequestEntityBuilder =
graphqlProvider.createRequestBuilder()
.url(getGraphqlUrl(apiUrl))
.url(graphqlUrl)
.headers(headers)
.request(CreateCheckRun.class)
.arguments(new Arguments("createCheckRun", new Argument<>(INPUT, repositoryInputObjectBuilder
Expand All @@ -163,7 +166,7 @@ public DecorationResult createCheckRun(AnalysisDetails analysisDetails, AlmSetti


if (Optional.ofNullable(projectAlmSettingDto.getSummaryCommentEnabled()).orElse(true)) {
postSummaryComment(apiUrl, headers, projectPath, analysisDetails.getBranchName(), summary);
postSummaryComment(graphqlUrl, headers, projectPath, analysisDetails.getBranchName(), summary);
}

return DecorationResult.builder()
Expand All @@ -172,29 +175,21 @@ public DecorationResult createCheckRun(AnalysisDetails analysisDetails, AlmSetti

}

private void postSummaryComment(String apiUrl, Map<String, String> headers, String projectPath, String pullRequestKey, String summary) throws IOException {
private void postSummaryComment(String graphqlUrl, Map<String, String> headers, String projectPath, String pullRequestKey, String summary) throws IOException {
String login = getLogin(graphqlUrl, headers);

String[] paths = projectPath.split("/", 2);
String owner = paths[0];
String projectName = paths[1];

GraphQLRequestEntity getPullRequest =
graphqlProvider.createRequestBuilder()
.url(getGraphqlUrl(apiUrl))
.headers(headers)
.request(GetPullRequest.class)
.arguments(
new Arguments("repository", new Argument<>("owner", owner), new Argument<>("name", projectName)),
new Arguments("repository.pullRequest", new Argument<>("number", Integer.valueOf(pullRequestKey)))
)
.requestMethod(GraphQLTemplate.GraphQLMethod.QUERY)
.build();

GetPullRequest.PullRequest pullRequest = getPullRequest(graphqlUrl, headers, projectName, pullRequestKey, owner);
String pullRequestId = pullRequest.getId();

GraphQLResponseEntity<GetPullRequest> response =
executeRequest((r, t) -> graphqlProvider.createGraphQLTemplate().execute(r, t), getPullRequest, GetPullRequest.class);

String pullRequestId = response.getResponse().getPullRequest().getId();
getComments(pullRequest, graphqlUrl, headers, projectName, pullRequestKey, owner).stream()
.filter(c -> "Bot".equalsIgnoreCase(c.getAuthor().getType()) && login.equalsIgnoreCase(c.getAuthor().getLogin()))
.filter(c -> !c.isMinimized())
.map(Comments.CommentNode::getId)
.forEach(commentId -> this.minimizeComment(graphqlUrl, headers, commentId));

InputObject.Builder<Object> repositoryInputObjectBuilder = graphqlProvider.createInputObject();

Expand All @@ -205,7 +200,7 @@ private void postSummaryComment(String apiUrl, Map<String, String> headers, Stri

GraphQLRequestEntity graphQLRequestEntity =
graphqlProvider.createRequestBuilder()
.url(getGraphqlUrl(apiUrl))
.url(graphqlUrl)
.headers(headers)
.request(AddComment.class)
.arguments(new Arguments("addComment", new Argument<>(INPUT, input)))
Expand All @@ -216,6 +211,74 @@ private void postSummaryComment(String apiUrl, Map<String, String> headers, Stri

}

private List<Comments.CommentNode> getComments(GetPullRequest.PullRequest pullRequest, String graphqlUrl, Map<String, String> headers, String projectName, String pullRequestKey, String owner) throws MalformedURLException {
List<Comments.CommentNode> comments = new ArrayList<>(pullRequest.getComments().getNodes());

PageInfo currentPageInfo = pullRequest.getComments().getPageInfo();
if (currentPageInfo.hasNextPage()) {
GetPullRequest.PullRequest response = getPullRequest(graphqlUrl, headers, projectName, pullRequestKey, owner, currentPageInfo);
comments.addAll(getComments(response, graphqlUrl, headers, projectName, pullRequestKey, owner));
}

return comments;
}

private GetPullRequest.PullRequest getPullRequest(String graphqlUrl, Map<String, String> headers, String projectName, String pullRequestKey, String owner) throws MalformedURLException {
return getPullRequest(graphqlUrl, headers, projectName, pullRequestKey, owner, null);
}

private GetPullRequest.PullRequest getPullRequest(String graphqlUrl, Map<String, String> headers, String projectName, String pullRequestKey, String owner, PageInfo pageInfo) throws MalformedURLException {
GraphQLRequestEntity getPullRequest =
graphqlProvider.createRequestBuilder()
.url(graphqlUrl)
.headers(headers)
.request(GetPullRequest.class)
.arguments(
new Arguments("repository", new Argument<>("owner", owner), new Argument<>("name", projectName)),
new Arguments("repository.pullRequest", new Argument<>("number", Integer.valueOf(pullRequestKey))),
new Arguments("repository.pullRequest.comments", new Argument<>("first", 100), new Argument<>("after", Optional.ofNullable(pageInfo).map(PageInfo::getEndCursor).orElse(null)))
)
.build();

return executeRequest((r, t) -> graphqlProvider.createGraphQLTemplate().query(r, t), getPullRequest, GetPullRequest.class).getResponse().getPullRequest();
}

private void minimizeComment(String graphqlUrl, Map<String, String> headers, String commentId) {
InputObject<Object> input = graphqlProvider.createInputObject()
.put("subjectId", commentId)
.put("classifier", CommentClassifiers.OUTDATED)
.build();

try {

GraphQLRequestEntity graphQLRequestEntity = graphqlProvider.createRequestBuilder()
.url(graphqlUrl)
.headers(headers)
.request(MinimizeComment.class)
.arguments(new Arguments("minimizeComment", new Argument<>(INPUT, input)))
.requestMethod(GraphQLTemplate.GraphQLMethod.MUTATE)
.build();

executeRequest((r, t) -> graphqlProvider.createGraphQLTemplate().mutate(r, t), graphQLRequestEntity, MinimizeComment.class);

} catch (IOException e) {
LOGGER.error("Error during minimize comment", e);
}
}

private String getLogin(String graphqlUrl, Map<String, String> headers) throws IOException {
GraphQLRequestEntity viewerQuery = graphqlProvider.createRequestBuilder()
.url(graphqlUrl)
.headers(headers)
.request(Viewer.class)
.build();

GraphQLResponseEntity<Viewer> response =
executeRequest((r, t) -> graphqlProvider.createGraphQLTemplate().query(r, t), viewerQuery, Viewer.class);

return response.getResponse().getLogin().replace("[bot]", "");
}

private static <R> GraphQLResponseEntity<R> executeRequest(
BiFunction<GraphQLRequestEntity, Class<R>, GraphQLResponseEntity<R>> executor, GraphQLRequestEntity graphQLRequestEntity, Class<R> responseType) {
LOGGER.debug("Using request: " + graphQLRequestEntity.getRequest());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2021 Julien Roy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.github.mc1arke.sonarqube.plugin.almclient.github.v4;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.aexp.nodes.graphql.annotations.GraphQLArgument;
import io.aexp.nodes.graphql.annotations.GraphQLProperty;

@GraphQLProperty(name = "minimizeComment", arguments = {@GraphQLArgument(name = "input")})
public class MinimizeComment {

private final String clientMutationId;

@JsonCreator
public MinimizeComment(@JsonProperty("clientMutationId") String clientMutationId) {
this.clientMutationId = clientMutationId;
}

public String getClientMutationId() {
return clientMutationId;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2021 Michael Clarke
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package com.github.mc1arke.sonarqube.plugin.almclient.github.v4;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class PageInfo {
private final boolean hasNextPage;
private final String endCursor;

@JsonCreator
public PageInfo(@JsonProperty("hasNextPage") boolean hasNextPage, @JsonProperty("endCursor") String endCursor) {
this.hasNextPage = hasNextPage;
this.endCursor = endCursor;
}

public boolean hasNextPage() {
return hasNextPage;
}

public String getEndCursor() {
return endCursor;
}
}