Restructure code to make it less triage-specific

This commit is contained in:
Andy Wilkinson
2015-12-07 15:38:16 +00:00
parent c0c4e2d901
commit d19f043c41
36 changed files with 414 additions and 438 deletions

32
pom.xml
View File

@@ -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>

View 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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());
}
}

View File

@@ -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
*/

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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)));
}
}

View File

@@ -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

View 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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.spring.issuebot.triage.filter;
package io.spring.issuebot.triage;
import org.junit.Test;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.spring.issuebot.triage.filter;
package io.spring.issuebot.triage;
import java.util.Arrays;

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}