Created
January 14, 2021 13:03
-
-
Save mp911de/86d04b1faa013cdb59141ce066856167 to your computer and use it in GitHub Desktop.
Spring Data Project Assessment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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