-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Caching and UPDATED-sorting for the Github Data Sync Algorithm #94
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package de.tum.in.www1.hephaestus.codereview.pullrequest.review; | ||
|
||
import java.time.OffsetDateTime; | ||
|
||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
|
||
@JsonInclude(JsonInclude.Include.NON_EMPTY) | ||
public record PullRequestReviewDTO(Long id, OffsetDateTime createdAt, OffsetDateTime updatedAt, | ||
OffsetDateTime submittedAt, PullRequestReviewState state) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,24 @@ | ||
package de.tum.in.www1.hephaestus.leaderboard; | ||
|
||
import java.time.OffsetDateTime; | ||
import java.time.ZoneOffset; | ||
import java.util.ArrayList; | ||
import java.util.Comparator; | ||
import java.util.Date; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.stream.Collectors; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
|
||
import de.tum.in.www1.hephaestus.codereview.pullrequest.PullRequest; | ||
import de.tum.in.www1.hephaestus.codereview.pullrequest.review.PullRequestReviewDTO; | ||
import de.tum.in.www1.hephaestus.codereview.user.User; | ||
import de.tum.in.www1.hephaestus.codereview.user.UserService; | ||
import de.tum.in.www1.hephaestus.codereview.user.UserType; | ||
|
@@ -22,6 +29,9 @@ public class LeaderboardService { | |
|
||
private final UserService userService; | ||
|
||
@Value("${monitoring.timeframe}") | ||
private int timeframe; | ||
|
||
public LeaderboardService(UserService userService) { | ||
this.userService = userService; | ||
} | ||
|
@@ -32,32 +42,47 @@ public List<LeaderboardEntry> createLeaderboard() { | |
List<User> users = userService.getAllUsers(); | ||
logger.info("Found " + users.size() + " users"); | ||
|
||
OffsetDateTime cutOffTime = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * timeframe) | ||
.toInstant().atOffset(ZoneOffset.UTC); | ||
|
||
List<LeaderboardEntry> leaderboard = users.stream().map(user -> { | ||
if (user.getType() != UserType.USER) { | ||
return null; | ||
} | ||
int comments = user.getIssueComments().size(); | ||
AtomicInteger changesRequested = new AtomicInteger(0); | ||
AtomicInteger changesApproved = new AtomicInteger(0); | ||
logger.info("User: " + user.getLogin()); | ||
AtomicInteger score = new AtomicInteger(0); | ||
user.getReviews().stream().forEach(review -> { | ||
switch (review.getState()) { | ||
case CHANGES_REQUESTED: | ||
changesRequested.incrementAndGet(); | ||
break; | ||
case APPROVED: | ||
changesApproved.incrementAndGet(); | ||
break; | ||
default: | ||
break; | ||
} | ||
score.addAndGet(calculateScore(review.getPullRequest())); | ||
}); | ||
Set<PullRequestReviewDTO> changesRequestedSet = new HashSet<>(); | ||
Set<PullRequestReviewDTO> approvedSet = new HashSet<>(); | ||
Set<PullRequestReviewDTO> commentSet = new HashSet<>(); | ||
|
||
user.getReviews().stream() | ||
.filter(review -> (review.getCreatedAt() != null && review.getCreatedAt().isAfter(cutOffTime)) | ||
|| (review.getUpdatedAt() != null && review.getUpdatedAt().isAfter(cutOffTime))) | ||
.forEach(review -> { | ||
if (review.getPullRequest().getAuthor().getLogin().equals(user.getLogin())) { | ||
return; | ||
} | ||
PullRequestReviewDTO reviewDTO = new PullRequestReviewDTO(review.getId(), review.getCreatedAt(), | ||
review.getUpdatedAt(), review.getSubmittedAt(), review.getState()); | ||
switch (review.getState()) { | ||
case CHANGES_REQUESTED: | ||
changesRequestedSet.add(reviewDTO); | ||
break; | ||
case APPROVED: | ||
approvedSet.add(reviewDTO); | ||
break; | ||
default: | ||
commentSet.add(reviewDTO); | ||
break; | ||
} | ||
score.addAndGet(calculateScore(review.getPullRequest())); | ||
}); | ||
return new LeaderboardEntry(user.getLogin(), user.getAvatarUrl(), user.getName(), user.getType(), | ||
score.get(), | ||
0, // preliminary rank | ||
changesRequested.get(), | ||
changesApproved.get(), comments); | ||
changesRequestedSet.toArray(new PullRequestReviewDTO[changesRequestedSet.size()]), | ||
approvedSet.toArray(new PullRequestReviewDTO[approvedSet.size()]), | ||
commentSet.toArray(new PullRequestReviewDTO[commentSet.size()])); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think everything is fine for now, in the future we might want store the score for each activity also in the database and then we can just calculate rank and aggregated score more easily. For example, a pull request review comes in via webhooks, we estimate the effort it took to do this review and store it in the database. I think as it is now the score is not stable since the PR might get more changes and reviews get dismissed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is very true. |
||
}).filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new)); | ||
|
||
// update ranks by score | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens with the dismissed reviews?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting point! They were counted as comments for now. This should be fixed in: #97.
In the future we might want to do some sort of state replacement similar to the original Python script.