Skip to content

Instantly share code, notes, and snippets.

@mp911de
Created January 14, 2021 13:03
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mp911de/86d04b1faa013cdb59141ce066856167 to your computer and use it in GitHub Desktop.
Spring Data Project Assessment
package com.example.demo;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.IntStream;
import com.example.demo.jira.JiraClient;
import com.example.demo.jira.JiraComment;
import com.example.demo.jira.JiraComponent;
import com.example.demo.jira.JiraConfig;
import com.example.demo.jira.JiraIssue;
import com.example.demo.jira.JiraIssueType;
import com.example.demo.jira.JiraResolution;
import com.example.demo.jira.JiraUser;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class DemoApplication {
public static final DateTimeFormatter FORMATTER = DateTimeFormat
.forPattern("YYYY-MM");
public static final Collection<String> TEAM = Arrays
.asList("Blum", "Drotbohm", "Strobl", "Gierke", "Paluch", "Schauder", "Turnquist");
public static void main(String[] args) {
JiraConfig config = new JiraConfig();
config.setBaseUrl("https://jira.spring.io");
config.setProjectId("DATAREST");
Map<String, Summary> summary = new TreeMap<>();
JiraClient client = new JiraClient(config);
List<JiraIssue> issues = client.findIssues(config
.getMigrateJql());
for (JiraIssue issue : issues) {
JiraIssue.Fields fields = issue.getFields();
if (fields.getCreated().getYear() != 2020 && fields
.getUpdated().getYear() != 2020) {
continue;
}
boolean teamIssue = isTeam(fields.getReporter());
Summary created = summary.computeIfAbsent(toKey(fields
.getCreated()), s -> new Summary());
Summary updated = summary.computeIfAbsent(toKey(fields
.getResolutionDate()), s -> new Summary());
if (teamIssue) {
created.team++;
}
else {
created.inbound++;
}
JiraResolution resolution = fields.getResolution();
if (isRejected(resolution)) {
updated.rejections++;
}
else if (isDuplicate(resolution)) {
updated.duplicates++;
}
else if (isUnresolved(resolution)) {
}
else if (isTask(resolution, fields.getComponents(), fields.getIssuetype())) {
updated.tasks++;
}
else if (isDocumentation(resolution, fields.getComponents())) {
if (isBug(resolution, fields.getIssuetype())) {
updated.bugs++;
}
updated.docs++;
}
else if (isEnhancement(resolution, fields.getIssuetype())) {
updated.enhancements++;
}
else if (isBug(resolution, fields.getIssuetype())) {
updated.bugs++;
}
else if (isTask(resolution, fields.getIssuetype())) {
updated.tasks++;
}
else {
System.out.println("unknown type " + issue.getKey());
}
if (fields.getFixVersions().size() > 1) {
updated.port += fields.getFixVersions().size() - 1;
}
if (!isTeam(fields.getReporter()) && woComment(fields)) {
created.woComment++;
}
}
System.out.println("Team created per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.team);
});
System.out.println("Community created per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.inbound);
});
System.out.println("Closed as duplicate (or equivelant) per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.duplicates);
});
System.out.println("Closed as a question (StackOverflow/etc) per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.questions);
});
System.out.println("Closed as declined/invalid or equivelant) per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.rejections);
});
System.out.println("Closed as an enhancement per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.enhancements);
});
System.out.println("Closed to be backported/forward-port per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.port);
});
System.out.println("Closed as regression or bug per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.bugs);
});
System.out.println("Closed as task/dependency upgrade/etc per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.tasks);
});
System.out.println("Closed as a documentation/site related issue per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.docs);
});
System.out.println("Issues without a comment from a team member per month");
IntStream.range(1, 13).forEach(i -> {
Summary s = summary
.computeIfAbsent(String.format("2020-%02d", i), it -> new Summary());
System.out.println(s.woComment);
});
/*
logger.info("Inbound Volume: " + this.statsService.calculateInboundVolume(start, end,
this.properties.getProject().getMembers(), this.properties.getProject().getBots()).block());
logger.info("Team Volume: " + this.statsService.calculateTeamVolume(start, end,
this.properties.getProject().getMembers(), this.properties.getProject().getBots()).block());
logger.info("Rejections: " + this.statsService.calculateRejections(start, end,
this.properties.getLabels().getRejected()).block());
logger.info("Adjusted Inbound Volume: " + this.statsService.calculateAdjustedInboundVolume(start, end).block());
logger.info("Output Volume: " + this.statsService.calculateOutputVolume(start, end, this.properties.getLabels().getPorts()).block());
logger.info("Output Volume (questions): " + this.statsService.calculateOutputVolumeByType(start, end, this.properties.getLabels().getQuestions()).block());
logger.info("Output Volume (enhancements): " + this.statsService.calculateOutputVolumeByType(start, end, this.properties.getLabels().getEnhancements()).block());
logger.info("Output Volume (bugs): " + this.statsService.calculateOutputVolumeByType(start, end, this.properties.getLabels().getBugs()).block());
logger.info("Output Volume (tasks): " + this.statsService.calculateOutputVolumeByType(start, end, this.properties.getLabels().getTasks()).block());
logger.info("Output Volume (docs): " + this.statsService.calculateOutputVolumeByType(start, end, this.properties.getLabels().getDocs()).block());
*/
}
private static boolean woComment(JiraIssue.Fields fields) {
if (fields.getComment().getComments().isEmpty()) {
return true;
}
DateTime created = fields.getCreated();
DateTime firstTeamComment = null;
for (JiraComment comment : fields.getComment().getComments()) {
if (isTeam(comment.getAuthor())) {
firstTeamComment = comment.getCreated();
break;
}
}
if (isFixed(fields
.getResolution()) && (firstTeamComment == null || firstTeamComment
.isAfter(fields.getResolved()))) {
firstTeamComment = fields.getResolved();
}
if (firstTeamComment == null) {
return true;
}
int days = Days.daysBetween(created, firstTeamComment).getDays();
if (days > 30) {
return true;
}
return false;
}
private static boolean isUnresolved(JiraResolution resolution) {
return resolution == null || resolution.getName().equals("Unresolved");
}
private static boolean isTask(JiraResolution resolution, List<JiraComponent> components, JiraIssueType issuetype) {
boolean componentMatch = components.stream().map(JiraComponent::getName)
.anyMatch(it -> it.toLowerCase(Locale.ROOT).contains("infrastr") || it
.toLowerCase(Locale.ROOT).contains("dependenc"));
boolean typeMatch = issuetype.getName().toLowerCase(Locale.ROOT)
.contains("refactoring") || issuetype.getName().toLowerCase(Locale.ROOT)
.contains("support");
return isFixed(resolution) && (componentMatch || typeMatch);
}
private static boolean isTask(JiraResolution resolution, JiraIssueType issuetype) {
return isFixed(resolution) && issuetype.getName().equals("Task");
}
private static boolean isEnhancement(JiraResolution resolution, JiraIssueType issuetype) {
return isFixed(resolution) && (issuetype.getName()
.equals("New Feature") || issuetype.getName()
.equals("Improvement") || issuetype.getName().equals("Task"));
}
private static boolean isDocumentation(JiraResolution resolution, List<JiraComponent> components) {
return isFixed(resolution) && (components.size() == 1 && components.stream()
.map(JiraComponent::getName)
.anyMatch(it -> it.toLowerCase(Locale.ROOT).contains("docu")));
}
private static boolean isBug(JiraResolution resolution, JiraIssueType issuetype) {
return isFixed(resolution) && (issuetype.getName().equals("Bug") || issuetype.getName().equals("Defect")) ;
}
private static boolean isFixed(JiraResolution resolution) {
return resolution != null && (resolution.getName()
.contains("Done") || resolution.getName()
.contains("Complete") || resolution.getName().contains("Fixed"));
}
private static boolean isRejected(JiraResolution resolution) {
return resolution != null && (resolution.getName()
.contains("Won't Fix") || resolution.getName()
.contains("Incomplete") || resolution.getName()
.contains("Cannot Reproduce") || resolution.getName()
.contains("Invalid") || resolution.getName()
.contains("Works as Designed") || resolution.getName()
.contains("Won't Do"));
}
private static boolean isDuplicate(JiraResolution resolution) {
return resolution != null && (resolution.getName()
.contains("Duplicate"));
}
private static String toKey(DateTime dateTime) {
return FORMATTER.print(dateTime);
}
static boolean isTeam(JiraUser user) {
for (String s : TEAM) {
if (user.getDisplayName().toLowerCase(Locale.ROOT)
.contains(s.toLowerCase(Locale.ROOT))) {
return true;
}
}
return false;
}
static class Summary {
int inbound;
int team;
int adjusted;
int rejections;
int port;
int enhancements;
int duplicates;
int questions;
int bugs;
int tasks;
int docs;
int woComment;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment