Skip to content

Feature/closed issues remove triage label #14

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/main/java/io/spring/issuebot/IssueBotApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.util.List;

import io.spring.issuebot.github.GitHubOperations;
import io.spring.issuebot.github.GitHubTemplate;
import io.spring.issuebot.github.RegexLinkParser;

Expand Down Expand Up @@ -49,11 +48,10 @@ GitHubTemplate gitHubTemplate(GitHubProperties gitHubProperties) {
}

@Bean
RepositoryMonitor repositoryMonitor(GitHubOperations gitHub,
MonitoringProperties monitoringProperties,
List<IssueListener> issueListeners) {
return new RepositoryMonitor(gitHub, monitoringProperties.getRepositories(),
issueListeners);
RepositoryMonitor repositoryMonitor(MonitoringProperties monitoringProperties,
List<RepositoryListener> repositoryListeners) {
return new RepositoryMonitor(monitoringProperties.getRepositories(),
repositoryListeners);
}

}
45 changes: 45 additions & 0 deletions src/main/java/io/spring/issuebot/IssueMonitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.spring.issuebot;

import io.spring.issuebot.github.Issue;
import io.spring.issuebot.github.Page;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class IssueMonitor {

private static final Logger log = LoggerFactory.getLogger(IssueMonitor.class);

private final List<IssueListener> issueListeners;

public IssueMonitor(List<IssueListener> issueListeners) {
this.issueListeners = issueListeners;
}

public void monitorIssue(Page<Issue> page, IssueOperation issueOperation) {
while (page != null) {
for (Issue issue : page.getContent()) {
for (IssueListener issueListener : this.issueListeners) {
try {
issueOperation.run(issue, issueListener);
}
catch (Exception ex) {
log.warn("Listener '{}' failed when handling issue '{}'",
issueListener, issue, ex);
}
}
}
page = page.next();
}
}

@FunctionalInterface
public interface IssueOperation {

void run(Issue issue, IssueListener issueListener);

}

}
14 changes: 14 additions & 0 deletions src/main/java/io/spring/issuebot/RepositoryListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.spring.issuebot;

/**
* A {@code RepositoryListener} is called when monitoring a repository
*/
public interface RepositoryListener {

/**
* Handle the specific repository
* @param repository the repository
*/
void handle(Repository repository);

}
48 changes: 9 additions & 39 deletions src/main/java/io/spring/issuebot/RepositoryMonitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,8 @@
package io.spring.issuebot;

import java.util.List;

import io.spring.issuebot.github.GitHubOperations;
import io.spring.issuebot.github.Issue;
import io.spring.issuebot.github.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.scheduling.annotation.Scheduled;

/**
Expand All @@ -35,52 +30,27 @@ class RepositoryMonitor {

private static final Logger log = LoggerFactory.getLogger(RepositoryMonitor.class);

private final GitHubOperations gitHub;

private final List<Repository> repositories;

private final List<IssueListener> issueListeners;
private final List<RepositoryListener> repositoryListeners;

RepositoryMonitor(GitHubOperations gitHub, List<Repository> repositories,
List<IssueListener> issueListeners) {
this.gitHub = gitHub;
RepositoryMonitor(List<Repository> repositories,
List<RepositoryListener> repositoryListeners) {
this.repositories = repositories;
this.issueListeners = issueListeners;
this.repositoryListeners = repositoryListeners;
}

@Scheduled(fixedRate = 5 * 60 * 1000)
void monitor() {
for (Repository repository : this.repositories) {
monitor(repository);
}
}

private void monitor(Repository repository) {
log.info("Monitoring {}/{}", repository.getOrganization(), repository.getName());
try {
Page<Issue> page = this.gitHub.getIssues(repository.getOrganization(),
log.info("Monitoring {}/{}", repository.getOrganization(),
repository.getName());
while (page != null) {
for (Issue issue : page.getContent()) {
for (IssueListener issueListener : this.issueListeners) {
try {
issueListener.onOpenIssue(repository, issue);
}
catch (Exception ex) {
log.warn("Listener '{}' failed when handling issue '{}'",
issueListener, issue, ex);
}
}
}
page = page.next();
for (RepositoryListener repositoryListener : repositoryListeners) {
repositoryListener.handle(repository);
}
log.info("Monitoring of {}/{} completed", repository.getOrganization(),
repository.getName());
}
catch (Exception ex) {
log.warn("A failure occurred during monitoring of {}/{}",
repository.getOrganization(), repository.getName(), ex);
}
log.info("Monitoring of {}/{} completed", repository.getOrganization(),
repository.getName());
}

}
39 changes: 39 additions & 0 deletions src/main/java/io/spring/issuebot/github/ClosedIssuesListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.spring.issuebot.github;

import io.spring.issuebot.IssueMonitor;
import io.spring.issuebot.Repository;
import io.spring.issuebot.RepositoryListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class ClosedIssuesListener implements RepositoryListener {

private static final Logger log = LoggerFactory.getLogger(ClosedIssuesListener.class);

private final GitHubOperations gitHub;

private final IssueMonitor issueMonitor;

public ClosedIssuesListener(GitHubOperations gitHub, IssueMonitor issueMonitor) {
this.issueMonitor = issueMonitor;
this.gitHub = gitHub;
}

@Override
public void handle(Repository repository) {
try {
Page<Issue> page = this.gitHub.getClosedIssuesWithLabel(
repository.getOrganization(), repository.getName(),
"status: waiting-for-triage");
issueMonitor.monitorIssue(page, (issue, issueListener) -> issueListener
.onIssueClosure(repository, issue));
}
catch (Exception ex) {
log.warn("A failure occurred during monitoring of {}/{}",
repository.getOrganization(), repository.getName(), ex);
}
}

}
11 changes: 11 additions & 0 deletions src/main/java/io/spring/issuebot/github/GitHubOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ public interface GitHubOperations {
*/
Page<Issue> getIssues(String organization, String repository);

/**
* Returns the open closed issues in the {@code repository} owned by the given
* {@code organization} with the given label.
* @param organization the name of the organization
* @param repository the name of the repository
* @param label the label the issues need to have
* @return the issues
*/
Page<Issue> getClosedIssuesWithLabel(String organization, String repository,
String label);

/**
* Returns the comments that have been made on the given {@code issue}.
* @param issue the issue
Expand Down
20 changes: 14 additions & 6 deletions src/main/java/io/spring/issuebot/github/GitHubTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ public Page<Issue> getIssues(String organization, String repository) {
return getPage(url, Issue[].class);
}

@Override
public Page<Issue> getClosedIssuesWithLabel(String organization, String repository,
String label) {
String url = "https://api.github.com/repos/" + organization + "/" + repository
+ "/issues?state=closed&labels=" + label;
return getPage(url, Issue[].class);
}

@Override
public Page<Comment> getComments(Issue issue) {
return getPage(issue.getCommentsUrl(), Comment[].class);
Expand Down Expand Up @@ -149,7 +157,7 @@ public Issue addLabel(Issue issue, String labelName) {
}
return new Issue(issue.getUrl(), issue.getCommentsUrl(), issue.getEventsUrl(),
issue.getLabelsUrl(), issue.getUser(), Arrays.asList(response.getBody()),
issue.getMilestone(), issue.getPullRequest());
issue.getMilestone(), issue.getPullRequest(), issue.getState());
}

@Override
Expand All @@ -161,17 +169,17 @@ public Issue removeLabel(Issue issue, String labelName) {
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);
URI uri = URI.create(issue.getLabelsUrl().replace("{/name}", "/" + encodedName));
log.info("Removing label {} on {}", labelName, uri);
ResponseEntity<Label[]> response = this.rest
.exchange(new RequestEntity<Void>(HttpMethod.DELETE, uri), 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());
issue.getMilestone(), issue.getPullRequest(), issue.getState());
}

@Override
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/io/spring/issuebot/github/Issue.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class Issue {

private final PullRequest pullRequest;

private final String state;

/**
* Creates a new {@code Issue}.
* @param url the url of the issue in the GitHub API
Expand All @@ -54,6 +56,7 @@ public class 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)
* @param state the state of the issue, open or closed
*/
@JsonCreator
public Issue(@JsonProperty("url") String url,
Expand All @@ -62,7 +65,8 @@ public Issue(@JsonProperty("url") String url,
@JsonProperty("labels_url") String labelsUrl, @JsonProperty("user") User user,
@JsonProperty("labels") List<Label> labels,
@JsonProperty("milestone") Milestone milestone,
@JsonProperty("pull_request") PullRequest pullRequest) {
@JsonProperty("pull_request") PullRequest pullRequest,
@JsonProperty("state") String state) {
this.url = url;
this.commentsUrl = commentsUrl;
this.eventsUrl = eventsUrl;
Expand All @@ -71,6 +75,7 @@ public Issue(@JsonProperty("url") String url,
this.labels = labels;
this.milestone = milestone;
this.pullRequest = pullRequest;
this.state = state;
}

String getUrl() {
Expand Down Expand Up @@ -105,6 +110,18 @@ public PullRequest getPullRequest() {
return this.pullRequest;
}

public String getState() {
return this.state;
}

public boolean isOpen() {
return this.getState().equals("open");
}

public boolean isClosed() {
return this.getState().equals("closed");
}

@Override
public String toString() {
return this.url;
Expand Down
38 changes: 38 additions & 0 deletions src/main/java/io/spring/issuebot/github/OpenIssuesListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.spring.issuebot.github;

import io.spring.issuebot.IssueMonitor;
import io.spring.issuebot.Repository;
import io.spring.issuebot.RepositoryListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class OpenIssuesListener implements RepositoryListener {

private static final Logger log = LoggerFactory.getLogger(OpenIssuesListener.class);

private final GitHubOperations gitHub;

private final IssueMonitor issueMonitor;

public OpenIssuesListener(GitHubOperations gitHub, IssueMonitor issueMonitor) {
this.issueMonitor = issueMonitor;
this.gitHub = gitHub;
}

@Override
public void handle(Repository repository) {
try {
Page<Issue> page = this.gitHub.getIssues(repository.getOrganization(),
repository.getName());
issueMonitor.monitorIssue(page, (issue, issueListener) -> issueListener
.onOpenIssue(repository, issue));
}
catch (Exception ex) {
log.warn("A failure occurred during monitoring of {}/{}",
repository.getOrganization(), repository.getName(), ex);
}
}

}
Loading