Add support for monitoring issues that are waiting for feedback

This commit is contained in:
Andy Wilkinson
2015-12-08 17:00:13 +00:00
parent d19f043c41
commit 2275ca1daa
34 changed files with 1512 additions and 106 deletions

View File

@@ -16,6 +16,8 @@
package io.spring.issuebot;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -54,6 +56,11 @@ public class GitHubProperties {
*/
private String name;
/**
* The names of the repository's collaborators.
*/
private List<String> collaborators;
}
/**

View File

@@ -22,6 +22,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import io.spring.issuebot.github.GitHubOperations;
import io.spring.issuebot.github.GitHubTemplate;
@@ -33,6 +34,7 @@ import io.spring.issuebot.github.RegexLinkParser;
* @author Andy Wilkinson
*/
@SpringBootApplication
@EnableScheduling
@EnableConfigurationProperties(GitHubProperties.class)
public class IssueBotApplication {

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.feedback;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.spring.issuebot.GitHubProperties;
import io.spring.issuebot.github.GitHubOperations;
/**
* Central configuration for the beans involved in managing issues that are waiting for
* feedback.
*
* @author Andy Wilkinson
*/
@Configuration
@EnableConfigurationProperties(FeedbackProperties.class)
class FeedbackConfiguration {
@Bean
FeedbackIssueListener feedbackIssueListener(GitHubOperations gitHub,
GitHubProperties githubProperties, FeedbackProperties feedbackProperties) {
return new FeedbackIssueListener(gitHub, feedbackProperties.getRequiredLabel(),
githubProperties.getRepository().getCollaborators(),
new StandardFeedbackListener(gitHub,
feedbackProperties.getProvidedLabel(),
feedbackProperties.getRequiredLabel(),
feedbackProperties.getReminderComment(),
feedbackProperties.getCloseComment()));
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.feedback;
import java.time.OffsetDateTime;
import java.util.List;
import io.spring.issuebot.IssueListener;
import io.spring.issuebot.github.Comment;
import io.spring.issuebot.github.Event;
import io.spring.issuebot.github.GitHubOperations;
import io.spring.issuebot.github.Issue;
import io.spring.issuebot.github.Label;
import io.spring.issuebot.github.Page;
/**
* An {@link IssueListener} that processes issues that are waiting for feedback.
*
* @author Andy Wilkinson
*/
final class FeedbackIssueListener implements IssueListener {
private final GitHubOperations gitHub;
private final String labelName;
private final List<String> collaborators;
private final FeedbackListener feedbackListener;
FeedbackIssueListener(GitHubOperations gitHub, String labelName,
List<String> collaborators, FeedbackListener feedbackListener) {
this.gitHub = gitHub;
this.labelName = labelName;
this.collaborators = collaborators;
this.feedbackListener = feedbackListener;
}
@Override
public void onOpenIssue(Issue issue) {
if (waitingForFeedback(issue)) {
OffsetDateTime waitingSince = getWaitingSince(issue);
if (waitingSince != null) {
processWaitingIssue(issue, waitingSince);
}
}
}
private void processWaitingIssue(Issue issue, OffsetDateTime waitingSince) {
if (commentedSince(waitingSince, issue)) {
this.feedbackListener.feedbackProvided(issue);
}
else {
this.feedbackListener.feedbackRequired(issue, waitingSince);
}
}
private boolean waitingForFeedback(Issue issue) {
return issue.getPullRequest() == null && labelledAsWaitingForFeedback(issue);
}
private boolean labelledAsWaitingForFeedback(Issue issue) {
for (Label label : issue.getLabels()) {
if (this.labelName.equals(label.getName())) {
return true;
}
}
return false;
}
private OffsetDateTime getWaitingSince(Issue issue) {
OffsetDateTime createdAt = null;
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())) {
createdAt = event.getCreationTime();
}
}
page = page.next();
}
return createdAt;
}
private boolean commentedSince(OffsetDateTime waitingForFeedbackSince, Issue issue) {
Page<Comment> page = this.gitHub.getComments(issue);
while (page != null) {
for (Comment comment : page.getContent()) {
if (!this.collaborators.contains(comment.getUser().getLogin())
&& comment.getCreationTime().isAfter(waitingForFeedbackSince)) {
return true;
}
}
page = page.next();
}
return false;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.feedback;
import java.time.OffsetDateTime;
import io.spring.issuebot.github.Issue;
/**
* A {@code FeedbackListener} is notified when feedback has been provided or is still
* required for an {@link Issue}.
*
* @author Andy Wilkinson
*/
public interface FeedbackListener {
/**
* Notification that feedback has been provided for the given {@code issue}.
*
* @param issue the issue
*/
void feedbackProvided(Issue issue);
/**
* Notification that feedback is still required for the given {@code issue} having
* been requested at the given {@code requestTime}.
*
* @param issue the issue
* @param requestTime the time when feedback was requested
*/
void feedbackRequired(Issue issue, OffsetDateTime requestTime);
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.feedback;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* {@link EnableConfigurationProperties Configuration properties} for configuring the
* monitoring of issues that require user feedback.
*
* @author Andy Wilkinson
*/
@Getter
@Setter
@ConfigurationProperties(prefix = "issuebot.feedback")
final class FeedbackProperties {
/**
* Name of the label that is applied when feedback is required.
*/
private String requiredLabel;
/**
* Name of the label that is applied when feedback has been provided.
*/
private String providedLabel;
/**
* The text of the comment that is added as a reminder that feedback is required.
*/
private String reminderComment;
/**
* The text of the comment that is added when an issue is clsed as feedback has not
* been provided.
*/
private String closeComment;
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.feedback;
import java.time.OffsetDateTime;
import io.spring.issuebot.github.GitHubOperations;
import io.spring.issuebot.github.Issue;
/**
* Standard implementation of {@link FeedbackListener}.
*
* @author Andy Wilkinson
*/
final class StandardFeedbackListener implements FeedbackListener {
private final GitHubOperations gitHub;
private final String providedLabel;
private final String requiredLabel;
private final String reminderComment;
private final String closeComment;
StandardFeedbackListener(GitHubOperations gitHub, String providedLabel,
String requiredLabel, String reminderComment, String closeComment) {
this.gitHub = gitHub;
this.providedLabel = providedLabel;
this.requiredLabel = requiredLabel;
this.reminderComment = reminderComment;
this.closeComment = closeComment;
}
@Override
public void feedbackProvided(Issue issue) {
this.gitHub.addLabel(issue, this.providedLabel);
this.gitHub.removeLabel(issue, this.requiredLabel);
}
@Override
public void feedbackRequired(Issue issue, OffsetDateTime requestTime) {
OffsetDateTime now = OffsetDateTime.now();
if (requestTime.plusDays(14).isBefore(now)) {
close(issue);
}
else if (requestTime.plusDays(7).isBefore(now)) {
remind(issue);
}
}
private void close(Issue issue) {
this.gitHub.addComment(issue, this.closeComment);
this.gitHub.close(issue);
}
private void remind(Issue issue) {
this.gitHub.addComment(issue, this.reminderComment);
}
}

View File

@@ -16,6 +16,8 @@
package io.spring.issuebot.github;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
@@ -30,14 +32,20 @@ public final class Comment {
private final User user;
private final OffsetDateTime creationTime;
/**
* Creates a new comment that was authored by the given {@code user}.
* Creates a new comment that was authored by the given {@code user} at the given
* {@code creationTime}.
*
* @param user the user
* @param creationTime the creation time
*/
@JsonCreator
public Comment(@JsonProperty("user") User user) {
public Comment(@JsonProperty("user") User user,
@JsonProperty("created_at") OffsetDateTime creationTime) {
this.user = user;
this.creationTime = creationTime;
}
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.github;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
/**
* An event that has been performed on an {@link Issue}.
*
* @author Andy Wilkinson
*/
@Getter
public class Event {
private final Type type;
private final OffsetDateTime creationTime;
private final Label label;
/**
* Creates a new {@code Event}.
*
* @param type the type of the event
* @param creationTime the timestamp of when the event was created
* @param label the label associated with the event
*/
@JsonCreator
public Event(@JsonProperty("event") String type,
@JsonProperty("created_at") OffsetDateTime creationTime,
@JsonProperty("label") Label label) {
this.type = Type.valueFrom(type);
this.creationTime = creationTime;
this.label = label;
}
/**
* The type of an {@link Event}.
*
* @author Andy Wilkinson
*/
public enum Type {
/**
* The issue was closed by the actor.
*/
CLOSED("closed"),
/**
* The issue was reopened by the actor.
*/
REOPENED("reopened"),
/**
* The actor subscribed to receive notifications for an issue.
*/
SUBSCRIBED("subscribed"),
/**
* The issue was merged by the actor.
*/
MERGED("merged"),
/**
* The issue was referenced from a commit message.
*/
REFERENCED("referenced"),
/**
* The actor was {@code @mentioned} in an issue body.
*/
MENTIONED("mentioned"),
/**
* The issue was assigned to the actor.
*/
ASSIGNED("assigned"),
/**
* The actor was unassigned from the issue.
*/
UNASSIGNED("unassigned"),
/**
* A label was added to the issue.
*/
LABELED("labeled"),
/**
* A label was removed from the issue.
*/
UNLABELED("unlabeled"),
/**
* The issue was added to a milestone.
*/
MILESTONED("milestoned"),
/**
* The issue was removed from a milestone.
*/
DEMILESTONED("demilestoned"),
/**
* The issue title was changed.
*/
RENAMED("renamed"),
/**
* The issue was locked by the actor.
*/
LOCKED("locked"),
/**
* The issue was unlocked by the actor.
*/
UNLOCKED("unlocked"),
/**
* The pull request's branch was deleted.
*/
HEAD_REF_DELETED("head_ref_deleted"),
/**
* The pull request's branch was restored.
*/
HEAD_REF_RESTORED("head_ref_restored");
private String type;
Type(String type) {
this.type = type;
}
static Type valueFrom(String type) {
for (Type value : values()) {
if (type.equals(value.type)) {
return value;
}
}
throw new IllegalArgumentException(
"'" + type + "' is not a valid event type");
}
}
}

View File

@@ -45,9 +45,43 @@ public interface GitHubOperations {
* Adds the given {@code label} to the given {@code issue}.
*
* @param issue the issue
* @param label the label;
* @return the updated issue
* @param label the label
* @return the modified issue
*/
Issue addLabel(Issue issue, String label);
/**
* Removes the given {@code label} from the given {@code issue}.
*
* @param issue the issue
* @param label the label
* @return the modified issue
*/
Issue removeLabel(Issue issue, String label);
/**
* Adds the given {@code comment} to the given {@code issue}.
*
* @param issue the issue
* @param comment the comment
* @return the added comment
*/
Comment addComment(Issue issue, String comment);
/**
* Closes the given {@code issue}.
*
* @param issue the issue
* @return the modified issue
*/
Issue close(Issue issue);
/**
* Returns the events that have occurred on the given {@code issue}.
*
* @param issue the issue
* @return the events
*/
Page<Event> getEvents(Issue issue);
}

View File

@@ -73,10 +73,6 @@ public class GitHubTemplate implements GitHubOperations {
this.linkParser = linkParser;
}
RestOperations getRestOperations() {
return this.rest;
}
static RestTemplate createDefaultRestTemplate(String username, String password) {
RestTemplate rest = new RestTemplate();
rest.setErrorHandler(new DefaultResponseErrorHandler() {
@@ -103,48 +99,83 @@ public class GitHubTemplate implements GitHubOperations {
public Page<Issue> getIssues(String organization, String repository) {
String url = "https://api.github.com/repos/" + organization + "/" + repository
+ "/issues";
return getIssues(url);
return getPage(url, Issue[].class);
}
private Page<Issue> getIssues(String url) {
@Override
public Page<Comment> getComments(Issue issue) {
return getPage(issue.getCommentsUrl(), Comment[].class);
}
@Override
public Page<Event> getEvents(Issue issue) {
return getPage(issue.getEventsUrl(), Event[].class);
}
private <T> Page<T> getPage(String url, Class<T[]> type) {
if (!StringUtils.hasText(url)) {
return null;
}
ResponseEntity<Issue[]> issues = this.rest.getForEntity(url, Issue[].class);
return new StandardPage<Issue>(Arrays.asList(issues.getBody()),
() -> getIssues(getNextUrl(issues)));
ResponseEntity<T[]> contents = this.rest.getForEntity(url, type);
return new StandardPage<T>(Arrays.asList(contents.getBody()),
() -> getPage(getNextUrl(contents), type));
}
private String getNextUrl(ResponseEntity<?> response) {
return this.linkParser.parse(response.getHeaders().getFirst("Link")).get("next");
}
@Override
public Page<Comment> getComments(Issue issue) {
return getComments(issue.getCommentsUrl());
}
private Page<Comment> getComments(String url) {
if (!StringUtils.hasText(url)) {
return null;
}
ResponseEntity<Comment[]> comments = this.rest.getForEntity(url, Comment[].class);
return new StandardPage<Comment>(Arrays.asList(comments.getBody()),
() -> getComments(getNextUrl(comments)));
}
@Override
public Issue addLabel(Issue issue, String labelName) {
Map<String, Object> body = new HashMap<>();
body.put("labels", Arrays.asList(labelName));
ResponseEntity<Issue> exchange = this.rest.exchange(
ResponseEntity<Label[]> response = this.rest.exchange(
new RequestEntity<>(body, HttpMethod.POST, URI.create(issue.getUrl())),
Issue.class);
if (exchange.getStatusCode() != HttpStatus.OK) {
Label[].class);
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to add label to issue. Response status: "
+ exchange.getStatusCode());
+ response.getStatusCode());
}
return exchange.getBody();
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(),
issue.getLabelsUrl(), issue.getUser(), Arrays.asList(response.getBody()),
issue.getMilestone(), issue.getPullRequest());
}
@Override
public Issue removeLabel(Issue issue, String labelName) {
ResponseEntity<Label[]> response = this.rest.exchange(
new RequestEntity<Void>(HttpMethod.DELETE, URI.create(
issue.getLabelsUrl().replace("{/name}", "/" + labelName))),
Label[].class);
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to remove label from 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());
}
@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();
}
@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);
if (response.getStatusCode() != HttpStatus.OK) {
log.warn("Failed to close issue. Response status: "
+ response.getStatusCode());
}
return response.getBody();
}
private static class BasicAuthorizationInterceptor

View File

@@ -20,6 +20,7 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AccessLevel;
import lombok.Getter;
/**
@@ -27,38 +28,65 @@ import lombok.Getter;
*
* @author Andy Wilkinson
*/
@Getter
public class Issue {
@Getter(AccessLevel.PACKAGE)
private final String url;
@Getter(AccessLevel.PACKAGE)
private final String commentsUrl;
@Getter(AccessLevel.PACKAGE)
private final String eventsUrl;
@Getter(AccessLevel.PACKAGE)
private final String labelsUrl;
@Getter
private final User user;
private final List<Label> labels;
@Getter
private List<Label> labels;
@Getter
private final Milestone milestone;
@Getter
private final PullRequest pullRequest;
/**
* Creates a new {@code Issue}.
*
* @param url the url of the issue in the GitHub API
* @param commentsUrl the url of the comments on the issue in the GitHub API
* @param eventsUrl the url of the events on the issue in the GitHub API
* @param labelsUrl the url of the labels on the issue in the GitHub API
* @param user the user that created the issue
* @param labels the labels applied to the issue
* @param milestone the milestone applied to the 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("user") User user, @JsonProperty("labels") List<Label> labels,
@JsonProperty("milestone") Milestone milestone) {
@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;
this.labelsUrl = labelsUrl;
this.user = user;
this.labels = labels;
this.milestone = milestone;
this.pullRequest = pullRequest;
}
@Override
public String toString() {
return this.url;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.spring.issuebot.github;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
/**
* Details of a GitHub pull request.
*
* @author Andy Wilkinson
*/
@Getter
public class PullRequest {
private final String url;
/**
* Creates a new {@code PullRequest} that has the given {@code url} in the GitHub API.
* @param url the url
*/
@JsonCreator
public PullRequest(@JsonProperty("url") String url) {
this.url = url;
}
}

View File

@@ -40,4 +40,9 @@ public class User {
this.login = login;
}
@Override
public String toString() {
return this.login;
}
}

View File

@@ -55,8 +55,8 @@ final class CommentedByCollaboratorTriageFilter implements TriageFilter {
while (page != null) {
for (Comment comment : page.getContent()) {
if (this.collaborators.contains(comment.getUser().getLogin())) {
log.debug("{} has been triaged. It was commented on by {}",
issue.getUrl(), comment.getUser().getLogin());
log.debug("{} has been triaged. It was commented on by {}", issue,
comment.getUser());
return true;
}
}

View File

@@ -34,7 +34,7 @@ final class LabelledTriageFilter implements TriageFilter {
@Override
public boolean triaged(Issue issue) {
if (issue.getLabels() != null && !issue.getLabels().isEmpty()) {
log.debug("{} has been triaged. It has been labelled.", issue.getUrl());
log.debug("{} has been triaged. It has been labelled.", issue);
return true;
}
return false;

View File

@@ -45,8 +45,7 @@ final class OpenedByCollaboratorTriageFilter implements TriageFilter {
@Override
public boolean triaged(Issue issue) {
if (this.collaborators.contains(issue.getUser().getLogin())) {
log.debug("{} has been triaged. It was opened by {}", issue.getUrl(),
issue.getUser().getLogin());
log.debug("{} has been triaged. It was opened by {}", issue, issue.getUser());
return true;
}
return false;

View File

@@ -21,8 +21,8 @@ import java.util.Arrays;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import io.spring.issuebot.GitHubProperties;
import io.spring.issuebot.github.GitHubOperations;
/**
@@ -31,20 +31,20 @@ import io.spring.issuebot.github.GitHubOperations;
* @author Andy Wilkinson
*/
@Configuration
@EnableScheduling
@EnableConfigurationProperties(TriageProperties.class)
class TriageConfiguration {
@Bean
TriageIssueListener triageIssueListener(GitHubOperations gitHubOperations,
TriageProperties triageProperties) {
TriageProperties triageProperties, GitHubProperties gitHubProperties) {
return new TriageIssueListener(
Arrays.asList(
new OpenedByCollaboratorTriageFilter(
triageProperties.getCollaborators()),
gitHubProperties.getRepository().getCollaborators()),
new LabelledTriageFilter(), new MilestoneAppliedTriageFilter(),
new CommentedByCollaboratorTriageFilter(
triageProperties.getCollaborators(), gitHubOperations)),
gitHubProperties.getRepository().getCollaborators(),
gitHubOperations)),
new LabelApplyingTriageListener(gitHubOperations,
triageProperties.getLabel()));
}

View File

@@ -16,8 +16,6 @@
package io.spring.issuebot.triage;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -34,11 +32,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
@ConfigurationProperties(prefix = "issuebot.triage")
class TriageProperties {
/**
* The names of the project collaborators whose issues do not require triage.
*/
private List<String> collaborators;
/**
* The name of the label that should be applied to issues that are waiting for triage.
*/