Restructure code to make it less triage-specific
This commit is contained in:
32
pom.xml
32
pom.xml
@@ -24,23 +24,10 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
@@ -48,8 +35,23 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
78
src/main/java/io/spring/issuebot/GitHubProperties.java
Normal file
78
src/main/java/io/spring/issuebot/GitHubProperties.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
/**
|
||||
* {@link ConfigurationProperties} for connecting to GitHub.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "issuebot.github")
|
||||
@Getter
|
||||
@Setter
|
||||
public class GitHubProperties {
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private Repository repository = new Repository();
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private Credentials credentials = new Credentials();
|
||||
|
||||
/**
|
||||
* Configuration for a GitHub repository.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Repository {
|
||||
|
||||
/**
|
||||
* The name of the organization that owns the repository.
|
||||
*/
|
||||
private String organization;
|
||||
|
||||
/**
|
||||
* The name of the repository.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for the credentials used to authenticate with GitHub.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class Credentials {
|
||||
|
||||
/**
|
||||
* The username used for authentication with GitHub.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The password used for authentication with GitHub.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,16 @@
|
||||
|
||||
package io.spring.issuebot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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 io.spring.issuebot.github.GitHubOperations;
|
||||
import io.spring.issuebot.github.GitHubTemplate;
|
||||
import io.spring.issuebot.github.RegexLinkParser;
|
||||
|
||||
/**
|
||||
* Main class for launching Issue Bot.
|
||||
@@ -25,10 +33,27 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties(GitHubProperties.class)
|
||||
public class IssueBotApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(IssueBotApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
GitHubTemplate gitHubTemplate(GitHubProperties gitHubProperties) {
|
||||
return new GitHubTemplate(gitHubProperties.getCredentials().getUsername(),
|
||||
gitHubProperties.getCredentials().getPassword(), new RegexLinkParser());
|
||||
}
|
||||
|
||||
@Bean
|
||||
RepositoryMonitor repositoryMonitor(GitHubOperations gitHub,
|
||||
GitHubProperties gitHubProperties, List<IssueListener> issueListeners) {
|
||||
return new RepositoryMonitor(gitHub,
|
||||
new MonitoredRepository(
|
||||
gitHubProperties.getRepository().getOrganization(),
|
||||
gitHubProperties.getRepository().getName()),
|
||||
issueListeners);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,25 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot;
|
||||
|
||||
import io.spring.issuebot.triage.MonitoredRepository;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
/**
|
||||
* {@code TriageFilters} is used to retrieve a {@code TriageFilter} for a particular
|
||||
* {@link MonitoredRepository repository}.
|
||||
* An {@code IssueListener} is notified of issues found during repository monitoring.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface TriageFilters {
|
||||
public interface IssueListener {
|
||||
|
||||
/**
|
||||
* Returns the {@code TriageFilter} that should be used to process issues for the
|
||||
* given {@code repository}.
|
||||
* Notification that the given {@code issue} is open.
|
||||
*
|
||||
* @param repository the repository
|
||||
* @return the filter for the repository
|
||||
* @param issue the open issue
|
||||
*/
|
||||
TriageFilter filterForRepository(MonitoredRepository repository);
|
||||
void onOpenIssue(Issue issue);
|
||||
|
||||
}
|
||||
@@ -14,40 +14,28 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.List;
|
||||
package io.spring.issuebot;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* A repository that should be monitored.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class MonitoredRepository {
|
||||
|
||||
/**
|
||||
* The name of the organization that owns the repository.
|
||||
*/
|
||||
private String organization;
|
||||
private final String organization;
|
||||
|
||||
/**
|
||||
* The name of the repository.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private String label;
|
||||
private final String name;
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage;
|
||||
package io.spring.issuebot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -25,12 +25,9 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
import io.spring.issuebot.github.GitHubOperations;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
import io.spring.issuebot.github.Page;
|
||||
import io.spring.issuebot.triage.filter.TriageFilter;
|
||||
import io.spring.issuebot.triage.filter.TriageFilters;
|
||||
|
||||
/**
|
||||
* Central class for monitoring the configured repositories and labeling issues as waiting
|
||||
* for triage.
|
||||
* Central class for monitoring the configured repository.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@@ -38,44 +35,35 @@ class RepositoryMonitor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RepositoryMonitor.class);
|
||||
|
||||
private final List<MonitoredRepository> repositoryConfigurations;
|
||||
|
||||
private final TriageFilters filters;
|
||||
|
||||
private final GitHubOperations gitHub;
|
||||
|
||||
private final TriageListener listener;
|
||||
private final MonitoredRepository repository;
|
||||
|
||||
RepositoryMonitor(GitHubOperations gitHub, TriageFilters filters,
|
||||
TriageListener listener, List<MonitoredRepository> repositoryConfigurations) {
|
||||
private final List<IssueListener> issueListeners;
|
||||
|
||||
RepositoryMonitor(GitHubOperations gitHub, MonitoredRepository repository,
|
||||
List<IssueListener> issueListeners) {
|
||||
this.gitHub = gitHub;
|
||||
this.filters = filters;
|
||||
this.listener = listener;
|
||||
this.repositoryConfigurations = repositoryConfigurations;
|
||||
this.repository = repository;
|
||||
this.issueListeners = issueListeners;
|
||||
}
|
||||
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000)
|
||||
void monitor() {
|
||||
for (MonitoredRepository configuration : this.repositoryConfigurations) {
|
||||
monitor(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
private void monitor(MonitoredRepository repository) {
|
||||
log.info("Monitoring {}/{}", repository.getOrganization(), repository.getName());
|
||||
TriageFilter filter = this.filters.filterForRepository(repository);
|
||||
Page<Issue> page = this.gitHub.getIssues(repository.getOrganization(),
|
||||
repository.getName());
|
||||
log.info("Monitoring {}/{}", this.repository.getOrganization(),
|
||||
this.repository.getName());
|
||||
Page<Issue> page = this.gitHub.getIssues(this.repository.getOrganization(),
|
||||
this.repository.getName());
|
||||
while (page != null) {
|
||||
for (Issue issue : page.getContent()) {
|
||||
if (!filter.triaged(issue)) {
|
||||
this.listener.requiresTriage(issue, repository);
|
||||
for (IssueListener issueListener : this.issueListeners) {
|
||||
issueListener.onOpenIssue(issue);
|
||||
}
|
||||
}
|
||||
page = page.next();
|
||||
}
|
||||
log.info("Monitoring of {}/{} completed", repository.getOrganization(),
|
||||
repository.getName());
|
||||
log.info("Monitoring of {}/{} completed", this.repository.getOrganization(),
|
||||
this.repository.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -28,8 +28,8 @@ import io.spring.issuebot.github.Issue;
|
||||
import io.spring.issuebot.github.Page;
|
||||
|
||||
/**
|
||||
* A {@code TriageFilter} that considers an issue has having been triaged if a
|
||||
* collaborator has commented on it.
|
||||
* A {@code TriageFilter} that considers an issue as having been triaged if a collaborator
|
||||
* has commented on it.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@@ -24,23 +24,28 @@ import io.spring.issuebot.github.Issue;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LabelApplyingTriageListener implements TriageListener {
|
||||
final class LabelApplyingTriageListener implements TriageListener {
|
||||
|
||||
private final GitHubOperations gitHub;
|
||||
|
||||
private final String label;
|
||||
|
||||
/**
|
||||
* Creates a new {@code LabelApplyingTriageListener} that will use the given
|
||||
* {@code gitHubOperations} to apply a label to any issues that require triage.
|
||||
* {@code gitHubOperations} to apply the given {@code label} to any issues that
|
||||
* require triage.
|
||||
*
|
||||
* @param gitHubOperations the GitHubOperations
|
||||
* @param label the label
|
||||
*/
|
||||
public LabelApplyingTriageListener(GitHubOperations gitHubOperations) {
|
||||
LabelApplyingTriageListener(GitHubOperations gitHubOperations, String label) {
|
||||
this.gitHub = gitHubOperations;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requiresTriage(Issue issue, MonitoredRepository repository) {
|
||||
this.gitHub.addLabel(issue, repository.getLabel());
|
||||
public void requiresTriage(Issue issue) {
|
||||
this.gitHub.addLabel(issue, this.label);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -27,7 +27,7 @@ import io.spring.issuebot.github.Issue;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MilestoneAppliedTriageFilter implements TriageFilter {
|
||||
final class MilestoneAppliedTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LabelledTriageFilter.class);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
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.github.GitHubTemplate;
|
||||
import io.spring.issuebot.github.RegexLinkParser;
|
||||
import io.spring.issuebot.triage.filter.StandardTriageFilters;
|
||||
import io.spring.issuebot.github.GitHubOperations;
|
||||
|
||||
/**
|
||||
* Central configuration for the beans involved in identifying issues that require triage.
|
||||
@@ -31,39 +32,20 @@ import io.spring.issuebot.triage.filter.StandardTriageFilters;
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
@EnableConfigurationProperties(TriageProperties.class)
|
||||
class TriageConfiguration {
|
||||
|
||||
@Bean
|
||||
TriageProperties triageProperties() {
|
||||
return new TriageProperties();
|
||||
TriageIssueListener triageIssueListener(GitHubOperations gitHubOperations,
|
||||
TriageProperties triageProperties) {
|
||||
return new TriageIssueListener(
|
||||
Arrays.asList(
|
||||
new OpenedByCollaboratorTriageFilter(
|
||||
triageProperties.getCollaborators()),
|
||||
new LabelledTriageFilter(), new MilestoneAppliedTriageFilter(),
|
||||
new CommentedByCollaboratorTriageFilter(
|
||||
triageProperties.getCollaborators(), gitHubOperations)),
|
||||
new LabelApplyingTriageListener(gitHubOperations,
|
||||
triageProperties.getLabel()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
LabelApplyingTriageListener triageListener() {
|
||||
return new LabelApplyingTriageListener(gitHubTemplate());
|
||||
}
|
||||
|
||||
@Bean
|
||||
RepositoryMonitor repositoryMonitor() {
|
||||
return new RepositoryMonitor(gitHubTemplate(), triageFilters(), triageListener(),
|
||||
triageProperties().getRepositories());
|
||||
}
|
||||
|
||||
@Bean
|
||||
GitHubTemplate gitHubTemplate() {
|
||||
TriageProperties triageProperties = triageProperties();
|
||||
return new GitHubTemplate(triageProperties.getUsername(),
|
||||
triageProperties.getPassword(), linkParser());
|
||||
}
|
||||
|
||||
@Bean
|
||||
StandardTriageFilters triageFilters() {
|
||||
return new StandardTriageFilters(gitHubTemplate());
|
||||
}
|
||||
|
||||
@Bean
|
||||
RegexLinkParser linkParser() {
|
||||
return new RegexLinkParser();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
@@ -23,7 +23,7 @@ import io.spring.issuebot.github.Issue;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface TriageFilter {
|
||||
interface TriageFilter {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given issue has already been triaged, otherwise
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.triage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.spring.issuebot.IssueListener;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
/**
|
||||
* {@link IssueListener} that identifies open issues that require triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class TriageIssueListener implements IssueListener {
|
||||
|
||||
private final List<TriageFilter> triageFilters;
|
||||
|
||||
private final TriageListener triageListener;
|
||||
|
||||
/**
|
||||
* Creates a new {@code TriageIssueListener} that will use the given
|
||||
* {@code triageFilters} to identify issues that require triage and notify the given
|
||||
* {@code triageListener} of those that do.
|
||||
*
|
||||
* @param triageFilters the triage filters
|
||||
* @param triageListener the triage listener
|
||||
*/
|
||||
TriageIssueListener(List<TriageFilter> triageFilters, TriageListener triageListener) {
|
||||
this.triageFilters = triageFilters;
|
||||
this.triageListener = triageListener;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see io.spring.issuebot.IssueListener#onOpenIssue(io.spring.issuebot.github.Issue)
|
||||
*/
|
||||
@Override
|
||||
public void onOpenIssue(Issue issue) {
|
||||
if (requiresTriage(issue)) {
|
||||
this.triageListener.requiresTriage(issue);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresTriage(Issue issue) {
|
||||
for (TriageFilter filter : this.triageFilters) {
|
||||
if (filter.triaged(issue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,13 +23,12 @@ import io.spring.issuebot.github.Issue;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface TriageListener {
|
||||
interface TriageListener {
|
||||
|
||||
/**
|
||||
* Notification that the given {@code issue} requires triage.
|
||||
*
|
||||
* @param issue the issue
|
||||
* @param repository the monitored repository to which the issue belongs
|
||||
*/
|
||||
void requiresTriage(Issue issue, MonitoredRepository repository);
|
||||
void requiresTriage(Issue issue);
|
||||
}
|
||||
|
||||
@@ -32,21 +32,16 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "issuebot.triage")
|
||||
public class TriageProperties {
|
||||
class TriageProperties {
|
||||
|
||||
/**
|
||||
* Repositories that will be monitored.
|
||||
* The names of the project collaborators whose issues do not require triage.
|
||||
*/
|
||||
private List<MonitoredRepository> repositories;
|
||||
private List<String> collaborators;
|
||||
|
||||
/**
|
||||
* GitHub username.
|
||||
* The name of the label that should be applied to issues that are waiting for triage.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* GitHub password.
|
||||
*/
|
||||
private String password;
|
||||
private String label;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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.triage.filter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@link TriageFilter} that delegates to one or more filters.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class DelegatingTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(DelegatingTriageFilter.class);
|
||||
|
||||
private final List<TriageFilter> filters;
|
||||
|
||||
DelegatingTriageFilter(List<TriageFilter> filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triaged(Issue issue) {
|
||||
for (TriageFilter filter : this.filters) {
|
||||
if (filter.triaged(issue)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
log.info("{} is waiting for triage", issue.getUrl());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.triage.filter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import io.spring.issuebot.github.GitHubOperations;
|
||||
import io.spring.issuebot.triage.MonitoredRepository;
|
||||
|
||||
/**
|
||||
* Standard implementation of {@code TriageFilters}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class StandardTriageFilters implements TriageFilters {
|
||||
|
||||
private final GitHubOperations gitHub;
|
||||
|
||||
/**
|
||||
* Creates a new {@code StandardTriageFilters} that will use the given
|
||||
* {@code gitHubOperations} to interact with GitHub.
|
||||
*
|
||||
* @param gitHubOperations the GitHubOperations
|
||||
*/
|
||||
public StandardTriageFilters(GitHubOperations gitHubOperations) {
|
||||
this.gitHub = gitHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriageFilter filterForRepository(MonitoredRepository repository) {
|
||||
return new DelegatingTriageFilter(Arrays.asList(
|
||||
new OpenedByCollaboratorTriageFilter(repository.getCollaborators()),
|
||||
new LabelledTriageFilter(), new MilestoneAppliedTriageFilter(),
|
||||
new CommentedByCollaboratorTriageFilter(repository.getCollaborators(),
|
||||
this.gitHub)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
issuebot:
|
||||
github:
|
||||
repository:
|
||||
organization: spring-projects
|
||||
name: spring-boot
|
||||
triage:
|
||||
repositories:
|
||||
- organization: spring-projects
|
||||
name: spring-boot
|
||||
label: waiting-for-triage
|
||||
collaborators:
|
||||
- dsyer
|
||||
- philwebb
|
||||
- snicoll
|
||||
- wilkinsona
|
||||
label: waiting-for-triage
|
||||
collaborators:
|
||||
- dsyer
|
||||
- philwebb
|
||||
- snicoll
|
||||
- wilkinsona
|
||||
|
||||
71
src/test/java/io/spring/issuebot/RepositoryMonitorTests.java
Normal file
71
src/test/java/io/spring/issuebot/RepositoryMonitorTests.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.spring.issuebot.github.GitHubOperations;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
import io.spring.issuebot.github.Page;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link RepositoryMonitor}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RepositoryMonitorTests {
|
||||
|
||||
private final GitHubOperations gitHub = mock(GitHubOperations.class);
|
||||
|
||||
private final IssueListener issueListenerOne = mock(IssueListener.class);
|
||||
|
||||
private final IssueListener issueListenerTwo = mock(IssueListener.class);
|
||||
|
||||
private final RepositoryMonitor repositoryMonitor = new RepositoryMonitor(this.gitHub,
|
||||
new MonitoredRepository("test", "test"),
|
||||
Arrays.asList(this.issueListenerOne, this.issueListenerTwo));
|
||||
|
||||
@Test
|
||||
public void repositoryWithNoIssues() {
|
||||
given(this.gitHub.getIssues("test", "test")).willReturn(null);
|
||||
this.repositoryMonitor.monitor();
|
||||
verifyNoMoreInteractions(this.issueListenerOne, this.issueListenerTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repositoryWithOpenIssues() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Page<Issue> page = mock(Page.class);
|
||||
Issue issueOne = new Issue(null, null, null, null, null);
|
||||
Issue issueTwo = new Issue(null, null, null, null, null);
|
||||
given(page.getContent()).willReturn(Arrays.asList(issueOne, issueTwo));
|
||||
given(this.gitHub.getIssues("test", "test")).willReturn(page);
|
||||
this.repositoryMonitor.monitor();
|
||||
verify(this.issueListenerOne).onOpenIssue(issueOne);
|
||||
verify(this.issueListenerOne).onOpenIssue(issueTwo);
|
||||
verify(this.issueListenerTwo).onOpenIssue(issueOne);
|
||||
verify(this.issueListenerTwo).onOpenIssue(issueTwo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,12 +33,6 @@ import org.springframework.test.web.client.response.DefaultResponseCreator;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import io.spring.issuebot.github.Comment;
|
||||
import io.spring.issuebot.github.GitHubTemplate;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
import io.spring.issuebot.github.Page;
|
||||
import io.spring.issuebot.github.RegexLinkParser;
|
||||
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@@ -20,9 +20,6 @@ import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.spring.issuebot.github.LinkParser;
|
||||
import io.spring.issuebot.github.RegexLinkParser;
|
||||
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -33,16 +33,13 @@ public class LabelApplyingTriageListenerTests {
|
||||
|
||||
private GitHubOperations gitHub = mock(GitHubOperations.class);
|
||||
|
||||
private final MonitoredRepository repository = new MonitoredRepository();
|
||||
|
||||
private final LabelApplyingTriageListener listener = new LabelApplyingTriageListener(
|
||||
this.gitHub);
|
||||
this.gitHub, "test");
|
||||
|
||||
@Test
|
||||
public void requiresTriage() {
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
this.repository.setLabel("test");
|
||||
this.listener.requiresTriage(issue, this.repository);
|
||||
this.listener.requiresTriage(issue);
|
||||
verify(this.gitHub).addLabel(issue, "test");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.filter;
|
||||
package io.spring.issuebot.triage;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* 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.triage;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.spring.issuebot.github.GitHubOperations;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
import io.spring.issuebot.github.Page;
|
||||
import io.spring.issuebot.triage.filter.TriageFilter;
|
||||
import io.spring.issuebot.triage.filter.TriageFilters;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link RepositoryMonitor}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RepositoryMonitorTests {
|
||||
|
||||
private final GitHubOperations gitHub = mock(GitHubOperations.class);
|
||||
|
||||
private final TriageFilters triageFilters = mock(TriageFilters.class);
|
||||
|
||||
private final TriageFilter triageFilter = mock(TriageFilter.class);
|
||||
|
||||
private final TriageListener listener = mock(TriageListener.class);
|
||||
|
||||
@Test
|
||||
public void repositoryWithNoIssues() {
|
||||
MonitoredRepository repository = new MonitoredRepository();
|
||||
repository.setOrganization("test");
|
||||
repository.setName("test");
|
||||
RepositoryMonitor repositoryMonitor = new RepositoryMonitor(this.gitHub,
|
||||
this.triageFilters, this.listener, Arrays.asList(repository));
|
||||
given(this.triageFilters.filterForRepository(repository))
|
||||
.willReturn(this.triageFilter);
|
||||
given(this.gitHub.getIssues("test", "test")).willReturn(null);
|
||||
|
||||
repositoryMonitor.monitor();
|
||||
|
||||
verifyNoMoreInteractions(this.listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repositoryWithIssueRequiringTriage() {
|
||||
MonitoredRepository repository = new MonitoredRepository();
|
||||
repository.setOrganization("test");
|
||||
repository.setName("test");
|
||||
RepositoryMonitor repositoryMonitor = new RepositoryMonitor(this.gitHub,
|
||||
this.triageFilters, this.listener, Arrays.asList(repository));
|
||||
given(this.triageFilters.filterForRepository(repository))
|
||||
.willReturn(this.triageFilter);
|
||||
@SuppressWarnings("unchecked")
|
||||
Page<Issue> page = mock(Page.class);
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
given(page.getContent()).willReturn(Arrays.asList(issue));
|
||||
given(this.gitHub.getIssues("test", "test")).willReturn(page);
|
||||
given(this.triageFilter.triaged(issue)).willReturn(false);
|
||||
|
||||
repositoryMonitor.monitor();
|
||||
|
||||
verify(this.listener).requiresTriage(issue, repository);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repositoryWithIssueThatHasAlreadyBeenTriaged() {
|
||||
MonitoredRepository repository = new MonitoredRepository();
|
||||
repository.setOrganization("test");
|
||||
repository.setName("test");
|
||||
RepositoryMonitor repositoryMonitor = new RepositoryMonitor(this.gitHub,
|
||||
this.triageFilters, this.listener, Arrays.asList(repository));
|
||||
given(this.triageFilters.filterForRepository(repository))
|
||||
.willReturn(this.triageFilter);
|
||||
@SuppressWarnings("unchecked")
|
||||
Page<Issue> page = mock(Page.class);
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
given(page.getContent()).willReturn(Arrays.asList(issue));
|
||||
given(this.gitHub.getIssues("test", "test")).willReturn(page);
|
||||
given(this.triageFilter.triaged(issue)).willReturn(true);
|
||||
|
||||
repositoryMonitor.monitor();
|
||||
|
||||
verifyNoMoreInteractions(this.listener);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.triage;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.spring.issuebot.IssueListener;
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link TriageIssueListener}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class TriageIssueListenerTests {
|
||||
|
||||
private final TriageFilter triageFilterOne = mock(TriageFilter.class);
|
||||
|
||||
private final TriageFilter triageFilterTwo = mock(TriageFilter.class);
|
||||
|
||||
private final TriageListener listener = mock(TriageListener.class);
|
||||
|
||||
private final IssueListener issueListener = new TriageIssueListener(
|
||||
Arrays.asList(this.triageFilterOne, this.triageFilterTwo), this.listener);
|
||||
|
||||
@Test
|
||||
public void listenerIsCalledWhenIssueRequiresTriage() {
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
given(this.triageFilterOne.triaged(issue)).willReturn(false);
|
||||
given(this.triageFilterTwo.triaged(issue)).willReturn(false);
|
||||
this.issueListener.onOpenIssue(issue);
|
||||
verify(this.triageFilterOne).triaged(issue);
|
||||
verify(this.triageFilterTwo).triaged(issue);
|
||||
verify(this.listener).requiresTriage(issue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerIsNotCalledWhenIssueHasAlreadyBeenTriaged() {
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
given(this.triageFilterOne.triaged(issue)).willReturn(true);
|
||||
this.issueListener.onOpenIssue(issue);
|
||||
verify(this.triageFilterOne).triaged(issue);
|
||||
verifyNoMoreInteractions(this.triageFilterTwo, this.listener);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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.triage.filter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import io.spring.issuebot.github.Issue;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingTriageFilter}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class DelegatingTriageFilterTests {
|
||||
|
||||
private TriageFilter delegate1 = mock(TriageFilter.class);
|
||||
|
||||
private TriageFilter delegate2 = mock(TriageFilter.class);
|
||||
|
||||
private TriageFilter delegate3 = mock(TriageFilter.class);
|
||||
|
||||
private TriageFilter filter = new DelegatingTriageFilter(
|
||||
Arrays.asList(this.delegate1, this.delegate2, this.delegate3));
|
||||
|
||||
@Test
|
||||
public void notTriagedWhenAllDelegatesReturnFalse() {
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
assertThat(this.filter.triaged(issue), is(false));
|
||||
verify(this.delegate1).triaged(issue);
|
||||
verify(this.delegate2).triaged(issue);
|
||||
verify(this.delegate3).triaged(issue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void triagedAsSoonAsADelegateReturnsTrue() {
|
||||
Issue issue = new Issue(null, null, null, null, null);
|
||||
given(this.delegate2.triaged(issue)).willReturn(true);
|
||||
assertThat(this.filter.triaged(issue), is(true));
|
||||
verify(this.delegate1).triaged(issue);
|
||||
verify(this.delegate2).triaged(issue);
|
||||
verifyNoMoreInteractions(this.delegate3);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user