Skip to content

Instantly share code, notes, and snippets.

@monzou
Last active December 20, 2015 20:38
Show Gist options
  • Save monzou/6191398 to your computer and use it in GitHub Desktop.
Save monzou/6191398 to your computer and use it in GitHub Desktop.
Report outdated tickets from Redmine.
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.filter.LoggingFilter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
/**
* ReportOutdatedTickets
*
* @author monzou
*/
public class ReportOutdatedTickets {
private static final boolean LOGGING_ENABLED = false;
private static final String REDMINE_URL = "PATH_TO_REDMINE";
private static final String ISSUES_URL = String.format("%s/issues", REDMINE_URL);
private static final String ACCESS_KEY = "YOUR_ACCESS_KEY";
private static final Integer QUERY_ID = YOUR_QUERY_ID;
private final API api;
private final Reporter reporter;
public static void main(String[] args) {
Reporter reporter = new Reporter() {
/** {@inheritDoc} */
public void report(String message) {
System.out.println(message);
}
};
try {
int resultCode = new ReportOutdatedTickets(reporter).report(QUERY_ID) ? 0 : -1;
System.exit(resultCode);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
ReportOutdatedTickets(Reporter reporter) {
Client client = LOGGING_ENABLED ? ClientBuilder.newBuilder().register(LoggingFilter.class).build() : ClientBuilder.newClient();
this.api = new API(client);
this.reporter = reporter;
}
boolean report(Integer queryId) throws IOException {
Issues issues = api.getIssues(queryId);
if (issues.isEmpty()) {
return true;
}
reporter.report("");
reporter.report("--------------------------------------------------------------------------------------");
reporter.report(" 期限切れチケット一覧");
reporter.report("--------------------------------------------------------------------------------------");
Map<String, Integer> counterByAssignee = Maps.newHashMap();
for (Issue issue : issues.listByDueDate()) {
String assignee = issue.assigned.name;
Integer counter = counterByAssignee.get(assignee);
counterByAssignee.put(assignee, counter == null ? 1 : ++counter);
reporter.report(String.format("[ %s ] %s : %s", issue.dueDate, assignee, issue.subject));
}
reporter.report("");
reporter.report("--------------------------------------------------------------------------------------");
reporter.report(" 期限切れチケット所有者ランキング");
reporter.report("--------------------------------------------------------------------------------------");
for (Entry<String, Integer> entry : Ordering.natural().reverse().onResultOf(new Function<Entry<String, Integer>, Integer>() {
/** {@inheritDoc} */
public Integer apply(Entry<String, Integer> input) {
return input.getValue();
}
}).sortedCopy(counterByAssignee.entrySet())) {
reporter.report(String.format("%s : %d", entry.getKey(), entry.getValue()));
}
reporter.report("");
reporter.report(String.format("%s?query_id=%d", ISSUES_URL, queryId));
return false;
}
private static class API {
private final Client client;
API(Client client) {
this.client = client;
}
Issues getIssues(Integer queryId) throws IOException {
String response = client.target(String.format("%s.json", ISSUES_URL)). //
queryParam("query_id", QUERY_ID). //
queryParam("key", ACCESS_KEY). //
request(MediaType.APPLICATION_JSON).get().readEntity(String.class);
return createMapper().readValue(response, Issues.class);
}
private ObjectMapper createMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper;
}
}
private static interface Reporter {
void report(String message);
}
private static class Issues {
public List<Issue> issues;
List<Issue> listByDueDate() {
return Ordering.natural().nullsLast().onResultOf(new Function<Issue, String>() {
/** {@inheritDoc} */
public String apply(Issue input) {
return input.dueDate;
}
}).sortedCopy(issues);
}
boolean isEmpty() {
return issues.isEmpty();
}
}
static class Issue {
public Long id;
public String subject;
public String description;
@JsonProperty("start_date")
public String startDate;
@JsonProperty("due_date")
public String dueDate;
public Field project;
public Field tracker;
public Field status;
public Field priority;
public Field author;
@JsonProperty("assigned_to")
public Field assigned;
public Field category;
@JsonProperty("fixed_version")
public Field version;
}
static class Field {
public Long id;
public String name;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment