diff --git a/pom.xml b/pom.xml index 7df2e81..0817777 100644 --- a/pom.xml +++ b/pom.xml @@ -24,23 +24,10 @@ - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - org.apache.httpcomponents httpclient - - org.springframework.boot - spring-boot-starter-test - test - org.projectlombok lombok @@ -48,8 +35,23 @@ provided - org.springframework.data - spring-data-commons + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + provided + + + + org.springframework.boot + spring-boot-starter-test + test diff --git a/src/main/java/io/spring/issuebot/GitHubProperties.java b/src/main/java/io/spring/issuebot/GitHubProperties.java new file mode 100644 index 0000000..0639c3f --- /dev/null +++ b/src/main/java/io/spring/issuebot/GitHubProperties.java @@ -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; + + } + +} diff --git a/src/main/java/io/spring/issuebot/IssueBotApplication.java b/src/main/java/io/spring/issuebot/IssueBotApplication.java index 415d4db..64cc18f 100644 --- a/src/main/java/io/spring/issuebot/IssueBotApplication.java +++ b/src/main/java/io/spring/issuebot/IssueBotApplication.java @@ -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 issueListeners) { + return new RepositoryMonitor(gitHub, + new MonitoredRepository( + gitHubProperties.getRepository().getOrganization(), + gitHubProperties.getRepository().getName()), + issueListeners); + } + } diff --git a/src/main/java/io/spring/issuebot/triage/filter/TriageFilters.java b/src/main/java/io/spring/issuebot/IssueListener.java similarity index 56% rename from src/main/java/io/spring/issuebot/triage/filter/TriageFilters.java rename to src/main/java/io/spring/issuebot/IssueListener.java index 9d363f7..2a67320 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/TriageFilters.java +++ b/src/main/java/io/spring/issuebot/IssueListener.java @@ -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); } diff --git a/src/main/java/io/spring/issuebot/triage/MonitoredRepository.java b/src/main/java/io/spring/issuebot/MonitoredRepository.java similarity index 69% rename from src/main/java/io/spring/issuebot/triage/MonitoredRepository.java rename to src/main/java/io/spring/issuebot/MonitoredRepository.java index ed974d9..be02ae4 100644 --- a/src/main/java/io/spring/issuebot/triage/MonitoredRepository.java +++ b/src/main/java/io/spring/issuebot/MonitoredRepository.java @@ -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 collaborators; - - /** - * The name of the label that should be applied to issues that are waiting for triage. - */ - private String label; + private final String name; } diff --git a/src/main/java/io/spring/issuebot/triage/RepositoryMonitor.java b/src/main/java/io/spring/issuebot/RepositoryMonitor.java similarity index 50% rename from src/main/java/io/spring/issuebot/triage/RepositoryMonitor.java rename to src/main/java/io/spring/issuebot/RepositoryMonitor.java index ecb64d2..6d39058 100644 --- a/src/main/java/io/spring/issuebot/triage/RepositoryMonitor.java +++ b/src/main/java/io/spring/issuebot/RepositoryMonitor.java @@ -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 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 repositoryConfigurations) { + private final List issueListeners; + + RepositoryMonitor(GitHubOperations gitHub, MonitoredRepository repository, + List 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 page = this.gitHub.getIssues(repository.getOrganization(), - repository.getName()); + log.info("Monitoring {}/{}", this.repository.getOrganization(), + this.repository.getName()); + Page 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()); } } diff --git a/src/main/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilter.java b/src/main/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilter.java similarity index 92% rename from src/main/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilter.java rename to src/main/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilter.java index 0da76ec..754f322 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilter.java +++ b/src/main/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilter.java @@ -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 */ diff --git a/src/main/java/io/spring/issuebot/triage/LabelApplyingTriageListener.java b/src/main/java/io/spring/issuebot/triage/LabelApplyingTriageListener.java index 8cbf235..72e9539 100644 --- a/src/main/java/io/spring/issuebot/triage/LabelApplyingTriageListener.java +++ b/src/main/java/io/spring/issuebot/triage/LabelApplyingTriageListener.java @@ -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); } } diff --git a/src/main/java/io/spring/issuebot/triage/filter/LabelledTriageFilter.java b/src/main/java/io/spring/issuebot/triage/LabelledTriageFilter.java similarity index 96% rename from src/main/java/io/spring/issuebot/triage/filter/LabelledTriageFilter.java rename to src/main/java/io/spring/issuebot/triage/LabelledTriageFilter.java index 3a2959d..9cebe73 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/LabelledTriageFilter.java +++ b/src/main/java/io/spring/issuebot/triage/LabelledTriageFilter.java @@ -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; diff --git a/src/main/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilter.java b/src/main/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilter.java similarity index 91% rename from src/main/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilter.java rename to src/main/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilter.java index 3e2b772..7694b99 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilter.java +++ b/src/main/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilter.java @@ -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); diff --git a/src/main/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilter.java b/src/main/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilter.java similarity index 97% rename from src/main/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilter.java rename to src/main/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilter.java index 8b4bdea..d6d2c36 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilter.java +++ b/src/main/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilter.java @@ -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; diff --git a/src/main/java/io/spring/issuebot/triage/TriageConfiguration.java b/src/main/java/io/spring/issuebot/triage/TriageConfiguration.java index f1f2804..3412aa2 100644 --- a/src/main/java/io/spring/issuebot/triage/TriageConfiguration.java +++ b/src/main/java/io/spring/issuebot/triage/TriageConfiguration.java @@ -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(); - } - } diff --git a/src/main/java/io/spring/issuebot/triage/filter/TriageFilter.java b/src/main/java/io/spring/issuebot/triage/TriageFilter.java similarity index 93% rename from src/main/java/io/spring/issuebot/triage/filter/TriageFilter.java rename to src/main/java/io/spring/issuebot/triage/TriageFilter.java index e41acda..4e04c0a 100644 --- a/src/main/java/io/spring/issuebot/triage/filter/TriageFilter.java +++ b/src/main/java/io/spring/issuebot/triage/TriageFilter.java @@ -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 diff --git a/src/main/java/io/spring/issuebot/triage/TriageIssueListener.java b/src/main/java/io/spring/issuebot/triage/TriageIssueListener.java new file mode 100644 index 0000000..69d955c --- /dev/null +++ b/src/main/java/io/spring/issuebot/triage/TriageIssueListener.java @@ -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 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 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; + } + +} diff --git a/src/main/java/io/spring/issuebot/triage/TriageListener.java b/src/main/java/io/spring/issuebot/triage/TriageListener.java index b64a488..abe4e64 100644 --- a/src/main/java/io/spring/issuebot/triage/TriageListener.java +++ b/src/main/java/io/spring/issuebot/triage/TriageListener.java @@ -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); } diff --git a/src/main/java/io/spring/issuebot/triage/TriageProperties.java b/src/main/java/io/spring/issuebot/triage/TriageProperties.java index e1e8f0c..5942c48 100644 --- a/src/main/java/io/spring/issuebot/triage/TriageProperties.java +++ b/src/main/java/io/spring/issuebot/triage/TriageProperties.java @@ -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 repositories; + private List 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; } diff --git a/src/main/java/io/spring/issuebot/triage/filter/DelegatingTriageFilter.java b/src/main/java/io/spring/issuebot/triage/filter/DelegatingTriageFilter.java deleted file mode 100644 index f45da0d..0000000 --- a/src/main/java/io/spring/issuebot/triage/filter/DelegatingTriageFilter.java +++ /dev/null @@ -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 filters; - - DelegatingTriageFilter(List 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; - } - -} diff --git a/src/main/java/io/spring/issuebot/triage/filter/StandardTriageFilters.java b/src/main/java/io/spring/issuebot/triage/filter/StandardTriageFilters.java deleted file mode 100644 index 3babf92..0000000 --- a/src/main/java/io/spring/issuebot/triage/filter/StandardTriageFilters.java +++ /dev/null @@ -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))); - } - -} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7843c6a..2769535 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -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 diff --git a/src/test/java/io/spring/issuebot/RepositoryMonitorTests.java b/src/test/java/io/spring/issuebot/RepositoryMonitorTests.java new file mode 100644 index 0000000..4595e72 --- /dev/null +++ b/src/test/java/io/spring/issuebot/RepositoryMonitorTests.java @@ -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 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); + } + +} diff --git a/src/test/java/io/spring/issuebot/github/GitHubTemplateTests.java b/src/test/java/io/spring/issuebot/github/GitHubTemplateTests.java index d40dc02..89e5bb2 100644 --- a/src/test/java/io/spring/issuebot/github/GitHubTemplateTests.java +++ b/src/test/java/io/spring/issuebot/github/GitHubTemplateTests.java @@ -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; diff --git a/src/test/java/io/spring/issuebot/github/RegexLinkParserTests.java b/src/test/java/io/spring/issuebot/github/RegexLinkParserTests.java index 21fc5e0..2b941bd 100644 --- a/src/test/java/io/spring/issuebot/github/RegexLinkParserTests.java +++ b/src/test/java/io/spring/issuebot/github/RegexLinkParserTests.java @@ -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; diff --git a/src/test/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilterTests.java b/src/test/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilterTests.java similarity index 98% rename from src/test/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilterTests.java rename to src/test/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilterTests.java index 1648f9a..fbd7d9f 100644 --- a/src/test/java/io/spring/issuebot/triage/filter/CommentedByCollaboratorTriageFilterTests.java +++ b/src/test/java/io/spring/issuebot/triage/CommentedByCollaboratorTriageFilterTests.java @@ -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; diff --git a/src/test/java/io/spring/issuebot/triage/LabelApplyingTriageListenerTests.java b/src/test/java/io/spring/issuebot/triage/LabelApplyingTriageListenerTests.java index 6324fcb..fb640ca 100644 --- a/src/test/java/io/spring/issuebot/triage/LabelApplyingTriageListenerTests.java +++ b/src/test/java/io/spring/issuebot/triage/LabelApplyingTriageListenerTests.java @@ -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"); } diff --git a/src/test/java/io/spring/issuebot/triage/filter/LabelledTriageFilterTests.java b/src/test/java/io/spring/issuebot/triage/LabelledTriageFilterTests.java similarity index 97% rename from src/test/java/io/spring/issuebot/triage/filter/LabelledTriageFilterTests.java rename to src/test/java/io/spring/issuebot/triage/LabelledTriageFilterTests.java index 8f89deb..f4972e3 100644 --- a/src/test/java/io/spring/issuebot/triage/filter/LabelledTriageFilterTests.java +++ b/src/test/java/io/spring/issuebot/triage/LabelledTriageFilterTests.java @@ -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; diff --git a/src/test/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilterTests.java b/src/test/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilterTests.java similarity index 96% rename from src/test/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilterTests.java rename to src/test/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilterTests.java index 0708a91..fd9a071 100644 --- a/src/test/java/io/spring/issuebot/triage/filter/MilestoneAppliedTriageFilterTests.java +++ b/src/test/java/io/spring/issuebot/triage/MilestoneAppliedTriageFilterTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.issuebot.triage.filter; +package io.spring.issuebot.triage; import org.junit.Test; diff --git a/src/test/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilterTests.java b/src/test/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilterTests.java similarity index 97% rename from src/test/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilterTests.java rename to src/test/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilterTests.java index 85034d9..d450b2b 100644 --- a/src/test/java/io/spring/issuebot/triage/filter/OpenedByCollaboratorTriageFilterTests.java +++ b/src/test/java/io/spring/issuebot/triage/OpenedByCollaboratorTriageFilterTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.issuebot.triage.filter; +package io.spring.issuebot.triage; import java.util.Arrays; diff --git a/src/test/java/io/spring/issuebot/triage/RepositoryMonitorTests.java b/src/test/java/io/spring/issuebot/triage/RepositoryMonitorTests.java deleted file mode 100644 index f120cef..0000000 --- a/src/test/java/io/spring/issuebot/triage/RepositoryMonitorTests.java +++ /dev/null @@ -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 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 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); - } - -} diff --git a/src/test/java/io/spring/issuebot/triage/TriageIssueListenerTests.java b/src/test/java/io/spring/issuebot/triage/TriageIssueListenerTests.java new file mode 100644 index 0000000..2c7e46f --- /dev/null +++ b/src/test/java/io/spring/issuebot/triage/TriageIssueListenerTests.java @@ -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); + } + +} diff --git a/src/test/java/io/spring/issuebot/triage/filter/DelegatingTriageFilterTests.java b/src/test/java/io/spring/issuebot/triage/filter/DelegatingTriageFilterTests.java deleted file mode 100644 index d620841..0000000 --- a/src/test/java/io/spring/issuebot/triage/filter/DelegatingTriageFilterTests.java +++ /dev/null @@ -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); - - } -} diff --git a/src/test/resources/io/spring/issuebot/triage/github/comments-page-one.json b/src/test/resources/io/spring/issuebot/github/comments-page-one.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/comments-page-one.json rename to src/test/resources/io/spring/issuebot/github/comments-page-one.json diff --git a/src/test/resources/io/spring/issuebot/triage/github/comments-page-two.json b/src/test/resources/io/spring/issuebot/github/comments-page-two.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/comments-page-two.json rename to src/test/resources/io/spring/issuebot/github/comments-page-two.json diff --git a/src/test/resources/io/spring/issuebot/triage/github/issue-single-label.json b/src/test/resources/io/spring/issuebot/github/issue-single-label.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/issue-single-label.json rename to src/test/resources/io/spring/issuebot/github/issue-single-label.json diff --git a/src/test/resources/io/spring/issuebot/triage/github/issue-two-labels.json b/src/test/resources/io/spring/issuebot/github/issue-two-labels.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/issue-two-labels.json rename to src/test/resources/io/spring/issuebot/github/issue-two-labels.json diff --git a/src/test/resources/io/spring/issuebot/triage/github/issues-page-one.json b/src/test/resources/io/spring/issuebot/github/issues-page-one.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/issues-page-one.json rename to src/test/resources/io/spring/issuebot/github/issues-page-one.json diff --git a/src/test/resources/io/spring/issuebot/triage/github/issues-page-two.json b/src/test/resources/io/spring/issuebot/github/issues-page-two.json similarity index 100% rename from src/test/resources/io/spring/issuebot/triage/github/issues-page-two.json rename to src/test/resources/io/spring/issuebot/github/issues-page-two.json