Initial commit
This commit is contained in:
34
src/main/java/io/spring/issuebot/IssueBotApplication.java
Normal file
34
src/main/java/io/spring/issuebot/IssueBotApplication.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Main class for launching Issue Bot.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class IssueBotApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(IssueBotApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 io.spring.issuebot.triage.github.GitHubOperations;
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@link TriageListener} that applies a label to any issues that require triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class LabelApplyingTriageListener implements TriageListener {
|
||||
|
||||
private final GitHubOperations gitHub;
|
||||
|
||||
/**
|
||||
* Creates a new {@code LabelApplyingTriageListener} that will use the given
|
||||
* {@code gitHubOperations} to apply a label to any issues that require triage.
|
||||
*
|
||||
* @param gitHubOperations the GitHubOperations
|
||||
*/
|
||||
public LabelApplyingTriageListener(GitHubOperations gitHubOperations) {
|
||||
this.gitHub = gitHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requiresTriage(Issue issue, MonitoredRepository repository) {
|
||||
this.gitHub.addLabel(issue, repository.getLabel());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* A repository that should be monitored.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class MonitoredRepository {
|
||||
|
||||
/**
|
||||
* The name of the organization that owns the repository.
|
||||
*/
|
||||
private 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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import io.spring.issuebot.triage.filter.TriageFilter;
|
||||
import io.spring.issuebot.triage.filter.TriageFilters;
|
||||
import io.spring.issuebot.triage.github.GitHubOperations;
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
import io.spring.issuebot.triage.github.Page;
|
||||
|
||||
/**
|
||||
* Central class for monitoring the configured repositories and labeling issues as waiting
|
||||
* for triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
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;
|
||||
|
||||
RepositoryMonitor(GitHubOperations gitHub, TriageFilters filters,
|
||||
TriageListener listener, List<MonitoredRepository> repositoryConfigurations) {
|
||||
this.gitHub = gitHub;
|
||||
this.filters = filters;
|
||||
this.listener = listener;
|
||||
this.repositoryConfigurations = repositoryConfigurations;
|
||||
}
|
||||
|
||||
@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());
|
||||
while (page != null) {
|
||||
for (Issue issue : page.getContent()) {
|
||||
if (!filter.triaged(issue)) {
|
||||
this.listener.requiresTriage(issue, repository);
|
||||
}
|
||||
}
|
||||
page = page.next();
|
||||
}
|
||||
log.info("Monitoring of {}/{} completed", repository.getOrganization(),
|
||||
repository.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import io.spring.issuebot.triage.filter.StandardTriageFilters;
|
||||
import io.spring.issuebot.triage.github.GitHubTemplate;
|
||||
import io.spring.issuebot.triage.github.RegexLinkParser;
|
||||
|
||||
/**
|
||||
* Central configuration for the beans involved in identifying issues that require triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
class TriageConfiguration {
|
||||
|
||||
@Bean
|
||||
TriageProperties triageProperties() {
|
||||
return new TriageProperties();
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
||||
35
src/main/java/io/spring/issuebot/triage/TriageListener.java
Normal file
35
src/main/java/io/spring/issuebot/triage/TriageListener.java
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@code TriageListener} is notified of issues that require triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public 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);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
|
||||
/**
|
||||
* {@link EnableConfigurationProperties Configuration properties} for triaging GitHub
|
||||
* issues.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "issuebot.triage")
|
||||
public class TriageProperties {
|
||||
|
||||
/**
|
||||
* Repositories that will be monitored.
|
||||
*/
|
||||
private List<MonitoredRepository> repositories;
|
||||
|
||||
/**
|
||||
* GitHub username.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* GitHub password.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -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.filter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.spring.issuebot.triage.github.Comment;
|
||||
import io.spring.issuebot.triage.github.GitHubOperations;
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
import io.spring.issuebot.triage.github.Page;
|
||||
|
||||
/**
|
||||
* A {@code TriageFilter} that considers an issue has having been triaged if a
|
||||
* collaborator has commented on it.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class CommentedByCollaboratorTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(CommentedByCollaboratorTriageFilter.class);
|
||||
|
||||
private final List<String> collaborators;
|
||||
|
||||
private final GitHubOperations gitHub;
|
||||
|
||||
CommentedByCollaboratorTriageFilter(List<String> collaborators,
|
||||
GitHubOperations gitHub) {
|
||||
this.collaborators = collaborators == null ? Collections.emptyList()
|
||||
: collaborators;
|
||||
this.gitHub = gitHub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triaged(Issue issue) {
|
||||
Page<Comment> page = this.gitHub.getComments(issue);
|
||||
while (page != null) {
|
||||
for (Comment comment : page.getContent()) {
|
||||
if (this.collaborators.contains(comment.getUser().getLogin())) {
|
||||
log.debug("{} has been triaged. It was commented on by {}",
|
||||
issue.getUrl(), comment.getUser().getLogin());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
page = page.next();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.triage.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@link TriageFilter} that considers an issue as having been triaged if any labels
|
||||
* have been applied to it.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class LabelledTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LabelledTriageFilter.class);
|
||||
|
||||
@Override
|
||||
public boolean triaged(Issue issue) {
|
||||
if (issue.getLabels() != null && !issue.getLabels().isEmpty()) {
|
||||
log.debug("{} has been triaged. It has been labelled.", issue.getUrl());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@link TriageFilter} that considers an issue as having been triaged if a milestone
|
||||
* has been applied to it.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class MilestoneAppliedTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LabelledTriageFilter.class);
|
||||
|
||||
@Override
|
||||
public boolean triaged(Issue issue) {
|
||||
if (issue.getMilestone() != null) {
|
||||
log.debug("Issue has been triaged. It has been added to milestone {}",
|
||||
issue.getMilestone().getTitle());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@link TriageFilter} that considers an issue as having been triaged if it was opened
|
||||
* by a collaborator.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class OpenedByCollaboratorTriageFilter implements TriageFilter {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(OpenedByCollaboratorTriageFilter.class);
|
||||
|
||||
private final List<String> collaborators;
|
||||
|
||||
OpenedByCollaboratorTriageFilter(List<String> collaborators) {
|
||||
this.collaborators = collaborators == null ? Collections.emptyList()
|
||||
: collaborators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triaged(Issue issue) {
|
||||
if (this.collaborators.contains(issue.getUser().getLogin())) {
|
||||
log.debug("{} has been triaged. It was opened by {}", issue.getUrl(),
|
||||
issue.getUser().getLogin());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.triage.MonitoredRepository;
|
||||
import io.spring.issuebot.triage.github.GitHubOperations;
|
||||
|
||||
/**
|
||||
* 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)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 io.spring.issuebot.triage.github.Issue;
|
||||
|
||||
/**
|
||||
* A {@code TriageFilter} is used to identify issues which are waiting for triage.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface TriageFilter {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given issue has already been triaged, otherwise
|
||||
* {@code false}.
|
||||
*
|
||||
* @param issue the issue
|
||||
* @return {@code true} if the issue has been triaged, {@code false} otherwise
|
||||
*/
|
||||
boolean triaged(Issue issue);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 io.spring.issuebot.triage.MonitoredRepository;
|
||||
|
||||
/**
|
||||
* {@code TriageFilters} is used to retrieve a {@code TriageFilter} for a particular
|
||||
* {@link MonitoredRepository repository}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface TriageFilters {
|
||||
|
||||
/**
|
||||
* Returns the {@code TriageFilter} that should be used to process issues for the
|
||||
* given {@code repository}.
|
||||
*
|
||||
* @param repository the repository
|
||||
* @return the filter for the repository
|
||||
*/
|
||||
TriageFilter filterForRepository(MonitoredRepository repository);
|
||||
|
||||
}
|
||||
43
src/main/java/io/spring/issuebot/triage/github/Comment.java
Normal file
43
src/main/java/io/spring/issuebot/triage/github/Comment.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A comment that has been made on a GitHub issue.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
public final class Comment {
|
||||
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* Creates a new comment that was authored by the given {@code user}.
|
||||
*
|
||||
* @param user the user
|
||||
*/
|
||||
@JsonCreator
|
||||
public Comment(@JsonProperty("user") User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
/**
|
||||
* Operations that can be performed against the GitHub API.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface GitHubOperations {
|
||||
|
||||
/**
|
||||
* Returns the open issues in the {@code repository} owned by the given
|
||||
* {@code organization}.
|
||||
*
|
||||
* @param organization the name of the organization
|
||||
* @param repository the name of the repository
|
||||
* @return the issues
|
||||
*/
|
||||
Page<Issue> getIssues(String organization, String repository);
|
||||
|
||||
/**
|
||||
* Returns the comments that have been made on the given {@code issue}.
|
||||
*
|
||||
* @param issue the issue
|
||||
* @return the comments
|
||||
*/
|
||||
Page<Comment> getComments(Issue issue);
|
||||
|
||||
/**
|
||||
* Adds the given {@code label} to the given {@code issue}.
|
||||
*
|
||||
* @param issue the issue
|
||||
* @param label the label;
|
||||
* @return the updated issue
|
||||
*/
|
||||
Issue addLabel(Issue issue, String label);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.util.Base64Utils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Central class for interacting with GitHub's REST API.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class GitHubTemplate implements GitHubOperations {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GitHubTemplate.class);
|
||||
|
||||
private final RestOperations rest;
|
||||
|
||||
private final LinkParser linkParser;
|
||||
|
||||
/**
|
||||
* Creates a new {@code GitHubTemplate} that will use the given {@code username} and
|
||||
* {@code password} to authenticate, and the given {@code linkParser} to parse links
|
||||
* from responses' {@code Link} header.
|
||||
*
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @param linkParser the link parser
|
||||
*/
|
||||
public GitHubTemplate(String username, String password, LinkParser linkParser) {
|
||||
this(createDefaultRestTemplate(username, password), linkParser);
|
||||
}
|
||||
|
||||
GitHubTemplate(RestOperations rest, LinkParser linkParser) {
|
||||
this.rest = rest;
|
||||
this.linkParser = linkParser;
|
||||
}
|
||||
|
||||
RestOperations getRestOperations() {
|
||||
return this.rest;
|
||||
}
|
||||
|
||||
static RestTemplate createDefaultRestTemplate(String username, String password) {
|
||||
RestTemplate rest = new RestTemplate();
|
||||
rest.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
if (response.getStatusCode() == HttpStatus.FORBIDDEN && response
|
||||
.getHeaders().getFirst("X-RateLimit-Remaining").equals("0")) {
|
||||
throw new IllegalStateException(
|
||||
"Rate limit exceeded. Limit will reset at "
|
||||
+ new Date(Long
|
||||
.valueOf(response.getHeaders()
|
||||
.getFirst("X-RateLimit-Reset"))
|
||||
* 1000));
|
||||
}
|
||||
}
|
||||
});
|
||||
rest.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
|
||||
rest.setInterceptors(Collections
|
||||
.singletonList(new BasicAuthorizationInterceptor(username, password)));
|
||||
return rest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Issue> getIssues(String organization, String repository) {
|
||||
String url = "https://api.github.com/repos/" + organization + "/" + repository
|
||||
+ "/issues";
|
||||
return getIssues(url);
|
||||
}
|
||||
|
||||
private Page<Issue> getIssues(String url) {
|
||||
if (!StringUtils.hasText(url)) {
|
||||
return null;
|
||||
}
|
||||
ResponseEntity<Issue[]> issues = this.rest.getForEntity(url, Issue[].class);
|
||||
return new StandardPage<Issue>(Arrays.asList(issues.getBody()),
|
||||
() -> getIssues(getNextUrl(issues)));
|
||||
}
|
||||
|
||||
private String getNextUrl(ResponseEntity<?> response) {
|
||||
return this.linkParser.parse(response.getHeaders().getFirst("Link")).get("next");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Comment> getComments(Issue issue) {
|
||||
return getComments(issue.getCommentsUrl());
|
||||
}
|
||||
|
||||
private Page<Comment> getComments(String url) {
|
||||
if (!StringUtils.hasText(url)) {
|
||||
return null;
|
||||
}
|
||||
ResponseEntity<Comment[]> comments = this.rest.getForEntity(url, Comment[].class);
|
||||
return new StandardPage<Comment>(Arrays.asList(comments.getBody()),
|
||||
() -> getComments(getNextUrl(comments)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Issue addLabel(Issue issue, String labelName) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("labels", Arrays.asList(labelName));
|
||||
ResponseEntity<Issue> exchange = this.rest.exchange(
|
||||
new RequestEntity<>(body, HttpMethod.POST, URI.create(issue.getUrl())),
|
||||
Issue.class);
|
||||
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||
log.warn("Failed to add label to issue. Response status: "
|
||||
+ exchange.getStatusCode());
|
||||
}
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
private static class BasicAuthorizationInterceptor
|
||||
implements ClientHttpRequestInterceptor {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String password;
|
||||
|
||||
BasicAuthorizationInterceptor(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = (password == null ? "" : password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
String token = Base64Utils.encodeToString(
|
||||
(this.username + ":" + this.password).getBytes(UTF_8));
|
||||
request.getHeaders().add("Authorization", "Basic " + token);
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
64
src/main/java/io/spring/issuebot/triage/github/Issue.java
Normal file
64
src/main/java/io/spring/issuebot/triage/github/Issue.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A GitHub issue.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
public class Issue {
|
||||
|
||||
private final String url;
|
||||
|
||||
private final String commentsUrl;
|
||||
|
||||
private final User user;
|
||||
|
||||
private final List<Label> labels;
|
||||
|
||||
private final Milestone milestone;
|
||||
|
||||
/**
|
||||
* Creates a new {@code Issue}.
|
||||
*
|
||||
* @param url the url of the issue in the GitHub API
|
||||
* @param commentsUrl the url of the comments on the issue in the GitHub API
|
||||
* @param user the user that created the issue
|
||||
* @param labels the labels applied to the issue
|
||||
* @param milestone the milestone applied to the issue
|
||||
*/
|
||||
@JsonCreator
|
||||
public Issue(@JsonProperty("url") String url,
|
||||
@JsonProperty("comments_url") String commentsUrl,
|
||||
@JsonProperty("user") User user, @JsonProperty("labels") List<Label> labels,
|
||||
@JsonProperty("milestone") Milestone milestone) {
|
||||
this.url = url;
|
||||
this.commentsUrl = commentsUrl;
|
||||
this.user = user;
|
||||
this.labels = labels;
|
||||
this.milestone = milestone;
|
||||
}
|
||||
|
||||
}
|
||||
43
src/main/java/io/spring/issuebot/triage/github/Label.java
Normal file
43
src/main/java/io/spring/issuebot/triage/github/Label.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A label that can be applied to a GitHub issue.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
public class Label {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Creates a new label with the given {@code name}.
|
||||
*
|
||||
* @param name the name of the label
|
||||
*/
|
||||
@JsonCreator
|
||||
public Label(@JsonProperty("name") String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@code LinkParser} can be used to parse the
|
||||
* <a href="https://developer.github.com/v3/#link-header">{@code Link} header</a> that is
|
||||
* returned by the GitHub API.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
interface LinkParser {
|
||||
|
||||
/**
|
||||
* Parse the given {@code header} into a map of rel:url pairs.
|
||||
*
|
||||
* @param header the header to parse
|
||||
* @return the map of links
|
||||
*/
|
||||
Map<String, String> parse(String header);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A milestone to which a GitHub Issue can be added.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
public class Milestone {
|
||||
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* Creates a new {@code Milestone} with the given {@code title}.
|
||||
*
|
||||
* @param title the title
|
||||
*/
|
||||
@JsonCreator
|
||||
public Milestone(@JsonProperty("title") String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
}
|
||||
43
src/main/java/io/spring/issuebot/triage/github/Page.java
Normal file
43
src/main/java/io/spring/issuebot/triage/github/Page.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A page of results.
|
||||
*
|
||||
* @param <T> the type of the contents of the page
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public interface Page<T> {
|
||||
|
||||
/**
|
||||
* Returns the next page, if any.
|
||||
*
|
||||
* @return The next page or {@code null}
|
||||
*/
|
||||
Page<T> next();
|
||||
|
||||
/**
|
||||
* Returns the contents of the page.
|
||||
*
|
||||
* @return the contents
|
||||
*/
|
||||
List<T> getContent();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.spring.issuebot.triage.github;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@code LinkParser} that uses a regular expression to parse the header.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class RegexLinkParser implements LinkParser {
|
||||
|
||||
private static final Pattern LINK_PATTERN = Pattern.compile("<(.+)>; rel=\"(.+)\"");
|
||||
|
||||
@Override
|
||||
public Map<String, String> parse(String input) {
|
||||
Map<String, String> links = new HashMap<>();
|
||||
for (String link : StringUtils.commaDelimitedListToStringArray(input)) {
|
||||
Matcher matcher = LINK_PATTERN.matcher(link.trim());
|
||||
if (matcher.matches()) {
|
||||
links.put(matcher.group(2), matcher.group(1));
|
||||
}
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Standard implementation of {@link Page}.
|
||||
*
|
||||
* @param <T> the type of the contents of the page
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class StandardPage<T> implements Page<T> {
|
||||
|
||||
private List<T> content;
|
||||
|
||||
private Supplier<Page<T>> nextSupplier;
|
||||
|
||||
/**
|
||||
* Creates a new {@code StandardPage} that has the given {@code content}. The given
|
||||
* {@code nextSupplier} will be used to obtain the next page {@link #next when
|
||||
* requested}.
|
||||
*
|
||||
* @param content the content
|
||||
* @param nextSupplier the supplier of the next page
|
||||
*/
|
||||
public StandardPage(List<T> content, Supplier<Page<T>> nextSupplier) {
|
||||
this.content = content;
|
||||
this.nextSupplier = nextSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> next() {
|
||||
return this.nextSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
}
|
||||
43
src/main/java/io/spring/issuebot/triage/github/User.java
Normal file
43
src/main/java/io/spring/issuebot/triage/github/User.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* A GitHub user.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@Getter
|
||||
public class User {
|
||||
|
||||
private final String login;
|
||||
|
||||
/**
|
||||
* Creates a new {@code User} with the given login.
|
||||
*
|
||||
* @param login the login
|
||||
*/
|
||||
@JsonCreator
|
||||
public User(@JsonProperty("login") String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user