Upgrade to Spring Boot 3.1.4

This commit is contained in:
Ryan Baxter
2023-09-28 15:10:37 +08:00
parent 364e314289
commit e892efb82f
27 changed files with 245 additions and 330 deletions

View File

@@ -49,11 +49,9 @@ public class IssueBotApplication {
}
@Bean
RepositoryMonitor repositoryMonitor(GitHubOperations gitHub,
MonitoringProperties monitoringProperties,
RepositoryMonitor repositoryMonitor(GitHubOperations gitHub, MonitoringProperties monitoringProperties,
List<MultiRepositoryIssueListener> issueListeners) {
return new RepositoryMonitor(gitHub, monitoringProperties.getRepositories(),
issueListeners);
return new RepositoryMonitor(gitHub, monitoringProperties.getRepositories(), issueListeners);
}
}

View File

@@ -59,8 +59,7 @@ class RepositoryMonitor {
private void monitor(Repository repository) {
log.info("Monitoring {}/{}", repository.getOrganization(), repository.getName());
try {
Page<Issue> page = this.gitHub.getIssues(repository.getOrganization(),
repository.getName());
Page<Issue> page = this.gitHub.getIssues(repository.getOrganization(), repository.getName());
while (page != null) {
for (Issue issue : page.getContent()) {
for (MultiRepositoryIssueListener issueListener : this.issueListeners) {
@@ -68,8 +67,7 @@ class RepositoryMonitor {
issueListener.onOpenIssue(repository, issue);
}
catch (Exception ex) {
log.warn("Listener '{}' failed when handling issue '{}'",
issueListener, issue, ex);
log.warn("Listener '{}' failed when handling issue '{}'", issueListener, issue, ex);
}
}
}
@@ -77,11 +75,10 @@ class RepositoryMonitor {
}
}
catch (Exception ex) {
log.warn("A failure occurred during monitoring of {}/{}",
repository.getOrganization(), repository.getName(), ex);
log.warn("A failure occurred during monitoring of {}/{}", repository.getOrganization(),
repository.getName(), ex);
}
log.info("Monitoring of {}/{} completed", repository.getOrganization(),
repository.getName());
log.info("Monitoring of {}/{} completed", repository.getOrganization(), repository.getName());
}
}

View File

@@ -44,29 +44,23 @@ import org.springframework.context.annotation.Configuration;
class FeedbackConfiguration {
@Bean
MultiRepositoryIssueListener feedbackIssueListener(
MonitoringProperties monitoringProperties, GitHubOperations gitHub,
GitHubProperties githubProperties, FeedbackProperties feedbackProperties) {
MultiRepositoryIssueListener feedbackIssueListener(MonitoringProperties monitoringProperties,
GitHubOperations gitHub, GitHubProperties githubProperties, FeedbackProperties feedbackProperties) {
Map<Repository, IssueListener> delegates = monitoringProperties.getRepositories()
.stream()
.collect(Collectors.toMap(Function.identity(),
(repository) -> createListener(repository, gitHub,
githubProperties, feedbackProperties)));
.stream()
.collect(Collectors.toMap(Function.identity(),
(repository) -> createListener(repository, gitHub, githubProperties, feedbackProperties)));
return new RoutingMultiRepositoryIssueListener(delegates);
}
private FeedbackIssueListener createListener(Repository repository,
GitHubOperations gitHub, GitHubProperties githubProperties,
FeedbackProperties feedbackProperties) {
return new FeedbackIssueListener(gitHub, feedbackProperties.getRequiredLabel(),
repository.getCollaborators(),
private FeedbackIssueListener createListener(Repository repository, GitHubOperations gitHub,
GitHubProperties githubProperties, FeedbackProperties feedbackProperties) {
return new FeedbackIssueListener(gitHub, feedbackProperties.getRequiredLabel(), repository.getCollaborators(),
githubProperties.getCredentials().getUsername(),
new StandardFeedbackListener(gitHub,
feedbackProperties.getProvidedLabel(),
feedbackProperties.getRequiredLabel(),
feedbackProperties.getReminderLabel(),
feedbackProperties.getReminderComment(),
feedbackProperties.getCloseComment(), Collections.emptyList()));
new StandardFeedbackListener(gitHub, feedbackProperties.getProvidedLabel(),
feedbackProperties.getRequiredLabel(), feedbackProperties.getReminderLabel(),
feedbackProperties.getReminderComment(), feedbackProperties.getCloseComment(),
Collections.emptyList()));
}
}

View File

@@ -43,8 +43,7 @@ final class FeedbackIssueListener implements IssueListener {
private final FeedbackListener feedbackListener;
FeedbackIssueListener(GitHubOperations gitHub, String labelName,
List<String> collaborators, String username,
FeedbackIssueListener(GitHubOperations gitHub, String labelName, List<String> collaborators, String username,
FeedbackListener feedbackListener) {
this.gitHub = gitHub;
this.labelName = labelName;
@@ -90,8 +89,7 @@ final class FeedbackIssueListener implements IssueListener {
Page<Event> page = this.gitHub.getEvents(issue);
while (page != null) {
for (Event event : page.getContent()) {
if (Event.Type.LABELED.equals(event.getType())
&& this.labelName.equals(event.getLabel().getName())) {
if (Event.Type.LABELED.equals(event.getType()) && this.labelName.equals(event.getLabel().getName())) {
createdAt = event.getCreationTime();
}
}

View File

@@ -45,9 +45,8 @@ final class StandardFeedbackListener implements FeedbackListener {
private final List<IssueListener> issueListeners;
StandardFeedbackListener(GitHubOperations gitHub, String providedLabel,
String requiredLabel, String reminderLabel, String reminderComment,
String closeComment, List<IssueListener> issueListeners) {
StandardFeedbackListener(GitHubOperations gitHub, String providedLabel, String requiredLabel, String reminderLabel,
String reminderComment, String closeComment, List<IssueListener> issueListeners) {
this.gitHub = gitHub;
this.providedLabel = providedLabel;
this.requiredLabel = requiredLabel;

View File

@@ -39,8 +39,7 @@ public final class Comment {
* @param creationTime the creation time
*/
@JsonCreator
public Comment(@JsonProperty("user") User user,
@JsonProperty("created_at") OffsetDateTime creationTime) {
public Comment(@JsonProperty("user") User user, @JsonProperty("created_at") OffsetDateTime creationTime) {
this.user = user;
this.creationTime = creationTime;
}

View File

@@ -45,8 +45,7 @@ public class Event {
* @param label the label associated with the event
*/
@JsonCreator
public Event(@JsonProperty("event") String type,
@JsonProperty("created_at") OffsetDateTime creationTime,
public Event(@JsonProperty("event") String type, @JsonProperty("created_at") OffsetDateTime creationTime,
@JsonProperty("label") Label label) {
this.type = Type.valueFrom(type);
this.creationTime = creationTime;

View File

@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.hc.client5.http.utils.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,7 +45,6 @@ import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.Base64Utils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
@@ -86,31 +86,24 @@ public class GitHubTemplate implements GitHubOperations {
rest.setErrorHandler(new DefaultResponseErrorHandler() {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getStatusCode() == HttpStatus.FORBIDDEN && response
.getHeaders().getFirst("X-RateLimit-Remaining").equals("0")) {
throw new IllegalStateException(
"Rate limit exceeded. Limit will reset at "
+ new Date(Long
.valueOf(response.getHeaders()
.getFirst("X-RateLimit-Reset"))
* 1000));
if (response.getStatusCode() == HttpStatus.FORBIDDEN
&& response.getHeaders().getFirst("X-RateLimit-Remaining").equals("0")) {
throw new IllegalStateException("Rate limit exceeded. Limit will reset at "
+ new Date(Long.valueOf(response.getHeaders().getFirst("X-RateLimit-Reset")) * 1000));
}
}
});
BufferingClientHttpRequestFactory bufferingClient = new BufferingClientHttpRequestFactory(
new HttpComponentsClientHttpRequestFactory());
rest.setRequestFactory(bufferingClient);
rest.setInterceptors(Collections
.singletonList(new BasicAuthorizationInterceptor(username, password)));
rest.setMessageConverters(
Arrays.asList(new ErrorLoggingMappingJackson2HttpMessageConverter()));
rest.setInterceptors(Collections.singletonList(new BasicAuthorizationInterceptor(username, password)));
rest.setMessageConverters(Arrays.asList(new ErrorLoggingMappingJackson2HttpMessageConverter()));
return rest;
}
@Override
public Page<Issue> getIssues(String organization, String repository) {
String url = "https://api.github.com/repos/" + organization + "/" + repository
+ "/issues";
String url = "https://api.github.com/repos/" + organization + "/" + repository + "/issues";
return getPage(url, Issue[].class);
}
@@ -129,8 +122,7 @@ public class GitHubTemplate implements GitHubOperations {
return null;
}
ResponseEntity<T[]> contents = this.rest.getForEntity(url, type);
return new StandardPage<>(Arrays.asList(contents.getBody()),
() -> getPage(getNextUrl(contents), type));
return new StandardPage<>(Arrays.asList(contents.getBody()), () -> getPage(getNextUrl(contents), type));
}
private String getNextUrl(ResponseEntity<?> response) {
@@ -141,16 +133,13 @@ public class GitHubTemplate implements GitHubOperations {
public Issue addLabel(Issue issue, String labelName) {
URI uri = URI.create(issue.getLabelsUrl().replace("{/name}", ""));
log.info("Adding label {} to {}", labelName, uri);
ResponseEntity<Label[]> response = this.rest.exchange(
new RequestEntity<>(Arrays.asList(labelName), HttpMethod.POST, uri),
Label[].class);
ResponseEntity<Label[]> response = this.rest
.exchange(new RequestEntity<>(Arrays.asList(labelName), HttpMethod.POST, uri), Label[].class);
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to add label to issue. Response status: "
+ response.getStatusCode());
log.warn("Failed to add label to issue. Response status: " + response.getStatusCode());
}
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(),
issue.getLabelsUrl(), issue.getUser(), Arrays.asList(response.getBody()),
issue.getMilestone(), issue.getPullRequest());
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(), issue.getLabelsUrl(),
issue.getUser(), Arrays.asList(response.getBody()), issue.getMilestone(), issue.getPullRequest());
}
@Override
@@ -162,42 +151,35 @@ public class GitHubTemplate implements GitHubOperations {
catch (URISyntaxException ex) {
throw new RuntimeException(ex);
}
ResponseEntity<Label[]> response = this.rest.exchange(
new RequestEntity<Void>(HttpMethod.DELETE, URI.create(
issue.getLabelsUrl().replace("{/name}", "/" + encodedName))),
Label[].class);
ResponseEntity<Label[]> response = this.rest.exchange(new RequestEntity<Void>(HttpMethod.DELETE,
URI.create(issue.getLabelsUrl().replace("{/name}", "/" + encodedName))), Label[].class);
List<Label> labels;
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to remove label from issue. Response status: "
+ response.getStatusCode());
log.warn("Failed to remove label from issue. Response status: " + response.getStatusCode());
labels = Collections.emptyList();
}
else {
labels = Arrays.asList(response.getBody());
}
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(),
issue.getLabelsUrl(), issue.getUser(), labels, issue.getMilestone(),
issue.getPullRequest());
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(), issue.getLabelsUrl(),
issue.getUser(), labels, issue.getMilestone(), issue.getPullRequest());
}
@Override
public Comment addComment(Issue issue, String comment) {
Map<String, String> body = new HashMap<>();
body.put("body", comment);
return this.rest.postForEntity(issue.getCommentsUrl(), body, Comment.class)
.getBody();
return this.rest.postForEntity(issue.getCommentsUrl(), body, Comment.class).getBody();
}
@Override
public Issue close(Issue issue) {
Map<String, String> body = new HashMap<>();
body.put("state", "closed");
ResponseEntity<Issue> response = this.rest.exchange(
new RequestEntity<>(body, HttpMethod.PATCH, URI.create(issue.getUrl())),
Issue.class);
ResponseEntity<Issue> response = this.rest
.exchange(new RequestEntity<>(body, HttpMethod.PATCH, URI.create(issue.getUrl())), Issue.class);
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to close issue. Response status: "
+ response.getStatusCode());
log.warn("Failed to close issue. Response status: " + response.getStatusCode());
}
return response.getBody();
}
@@ -208,8 +190,7 @@ public class GitHubTemplate implements GitHubOperations {
private static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
@Override
public Object read(Type type, Class<?> contextClass,
HttpInputMessage inputMessage)
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
try {
return super.read(type, contextClass, inputMessage);
@@ -226,8 +207,7 @@ public class GitHubTemplate implements GitHubOperations {
if (inputMessage instanceof ClientHttpResponse) {
ClientHttpResponse response = (ClientHttpResponse) inputMessage;
if (response.getStatusCode().is2xxSuccessful()) {
log.error("Failed to create {} from {}", type.getTypeName(),
read(inputMessage), ex);
log.error("Failed to create {} from {}", type.getTypeName(), read(inputMessage), ex);
throw ex;
}
}
@@ -241,8 +221,7 @@ public class GitHubTemplate implements GitHubOperations {
}
private static class BasicAuthorizationInterceptor
implements ClientHttpRequestInterceptor {
private static class BasicAuthorizationInterceptor implements ClientHttpRequestInterceptor {
private static final Charset UTF_8 = Charset.forName("UTF-8");
@@ -256,10 +235,9 @@ public class GitHubTemplate implements GitHubOperations {
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
String token = Base64Utils.encodeToString(
(this.username + ":" + this.password).getBytes(UTF_8));
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
throws IOException {
String token = Base64.encodeBase64String((this.username + ":" + this.password).getBytes(UTF_8));
request.getHeaders().add("Authorization", "Basic " + token);
return execution.execute(request, body);
}

View File

@@ -56,13 +56,10 @@ public class Issue {
* @param pullRequest details of the pull request (if this issue is a pull request)
*/
@JsonCreator
public Issue(@JsonProperty("url") String url,
@JsonProperty("comments_url") String commentsUrl,
@JsonProperty("events_url") String eventsUrl,
@JsonProperty("labels_url") String labelsUrl, @JsonProperty("user") User user,
@JsonProperty("labels") List<Label> labels,
@JsonProperty("milestone") Milestone milestone,
@JsonProperty("pull_request") PullRequest pullRequest) {
public Issue(@JsonProperty("url") String url, @JsonProperty("comments_url") String commentsUrl,
@JsonProperty("events_url") String eventsUrl, @JsonProperty("labels_url") String labelsUrl,
@JsonProperty("user") User user, @JsonProperty("labels") List<Label> labels,
@JsonProperty("milestone") Milestone milestone, @JsonProperty("pull_request") PullRequest pullRequest) {
this.url = url;
this.commentsUrl = commentsUrl;
this.eventsUrl = eventsUrl;

View File

@@ -43,19 +43,17 @@ import org.springframework.context.annotation.Configuration;
class QuestionConfiguration {
@Bean
MultiRepositoryIssueListener questionIssueListener(
MonitoringProperties monitoringProperties, GitHubOperations gitHub,
QuestionProperties questionProperties) {
MultiRepositoryIssueListener questionIssueListener(MonitoringProperties monitoringProperties,
GitHubOperations gitHub, QuestionProperties questionProperties) {
Map<Repository, IssueListener> delegates = monitoringProperties.getRepositories()
.stream().collect(Collectors.toMap(Function.identity(),
(repository) -> createListener(gitHub, questionProperties)));
.stream()
.collect(Collectors.toMap(Function.identity(), (repository) -> createListener(gitHub, questionProperties)));
return new RoutingMultiRepositoryIssueListener(delegates);
}
private QuestionIssueListener createListener(GitHubOperations gitHub,
QuestionProperties questionProperties) {
return new QuestionIssueListener(gitHub, questionProperties.getLabel(),
questionProperties.getCloseComment(), Collections.emptyList());
private QuestionIssueListener createListener(GitHubOperations gitHub, QuestionProperties questionProperties) {
return new QuestionIssueListener(gitHub, questionProperties.getLabel(), questionProperties.getCloseComment(),
Collections.emptyList());
}
}

View File

@@ -87,8 +87,7 @@ final class QuestionIssueListener implements IssueListener {
Page<Event> page = this.gitHub.getEvents(issue);
while (page != null) {
for (Event event : page.getContent()) {
if (Event.Type.LABELED.equals(event.getType())
&& this.labelName.equals(event.getLabel().getName())) {
if (Event.Type.LABELED.equals(event.getType()) && this.labelName.equals(event.getLabel().getName())) {
createdAt = event.getCreationTime();
}
}

View File

@@ -33,8 +33,7 @@ final class MilestoneAppliedTriageFilter implements TriageFilter {
@Override
public boolean triaged(Issue issue) {
if (issue.getMilestone() != null) {
log.debug("Issue has been triaged. It has been added to milestone {}",
issue.getMilestone().getTitle());
log.debug("Issue has been triaged. It has been added to milestone {}", issue.getMilestone().getTitle());
return true;
}
return false;

View File

@@ -31,14 +31,12 @@ import org.slf4j.LoggerFactory;
*/
final class OpenedByCollaboratorTriageFilter implements TriageFilter {
private static final Logger log = LoggerFactory
.getLogger(OpenedByCollaboratorTriageFilter.class);
private static final Logger log = LoggerFactory.getLogger(OpenedByCollaboratorTriageFilter.class);
private final List<String> collaborators;
OpenedByCollaboratorTriageFilter(List<String> collaborators) {
this.collaborators = (collaborators != null) ? collaborators
: Collections.emptyList();
this.collaborators = (collaborators != null) ? collaborators : Collections.emptyList();
}
@Override

View File

@@ -47,22 +47,18 @@ class TriageConfiguration {
TriageProperties triageProperties, MonitoringProperties monitoringProperties,
GitHubProperties gitHubProperties) {
Map<Repository, IssueListener> delegates = monitoringProperties.getRepositories()
.stream()
.collect(Collectors.toMap(Function.identity(),
(repository) -> createListener(repository, gitHubOperations,
triageProperties)));
.stream()
.collect(Collectors.toMap(Function.identity(),
(repository) -> createListener(repository, gitHubOperations, triageProperties)));
return new RoutingMultiRepositoryIssueListener(delegates);
}
private TriageIssueListener createListener(Repository repository,
GitHubOperations gitHubOperations, TriageProperties triageProperties) {
private TriageIssueListener createListener(Repository repository, GitHubOperations gitHubOperations,
TriageProperties triageProperties) {
return new TriageIssueListener(
Arrays.asList(
new OpenedByCollaboratorTriageFilter(
repository.getCollaborators()),
Arrays.asList(new OpenedByCollaboratorTriageFilter(repository.getCollaborators()),
new LabelledTriageFilter(), new MilestoneAppliedTriageFilter()),
new LabelApplyingTriageListener(gitHubOperations,
triageProperties.getLabel()));
new LabelApplyingTriageListener(gitHubOperations, triageProperties.getLabel()));
}
}