blob: c640b7ee78a6e7e9017f1cd4d7373678d3801e57 [file] [log] [blame]
package com.googlesource.gerrit.plugins.chatgpt;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.chatgpt.client.GerritClient;
import com.googlesource.gerrit.plugins.chatgpt.client.OpenAiClient;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Singleton
public class PatchSetReviewer {
private static final String SPLIT_REVIEW_MSG = "Too many changes. Please consider splitting into patches smaller than %s lines for review.";
private static final int COMMENT_BATCH_SIZE = 25;
private final GerritClient gerritClient;
private final OpenAiClient openAiClient;
@Inject
PatchSetReviewer(GerritClient gerritClient, OpenAiClient openAiClient) {
this.gerritClient = gerritClient;
this.openAiClient = openAiClient;
}
public void review(Configuration config, String fullChangeId) throws Exception {
String patchSet = gerritClient.getPatchSet(config, fullChangeId);
if (config.isPatchSetReduction()) {
patchSet = reducePatchSet(patchSet);
log.debug("Reduced patch set: {}", patchSet);
}
String reviewSuggestion = getReviewSuggestion(config, fullChangeId, patchSet);
List<String> reviewBatches = splitReviewIntoBatches(reviewSuggestion);
for (String reviewBatch : reviewBatches) {
gerritClient.postComment(config, fullChangeId, reviewBatch);
}
}
private List<String> splitReviewIntoBatches(String review) {
List<String> batches = new ArrayList<>();
String[] lines = review.split("\n");
StringBuilder batch = new StringBuilder();
for (int i = 0; i < lines.length; i++) {
batch.append(lines[i]).append("\n");
if ((i + 1) % COMMENT_BATCH_SIZE == 0) {
batches.add(batch.toString());
batch = new StringBuilder();
}
}
if (batch.length() > 0) {
batches.add(batch.toString());
}
log.info("Review batches created: {}", batches.size());
return batches;
}
private String reducePatchSet(String patchSet) {
Set<String> skipPrefixes = new HashSet<>(Arrays.asList(
"import", "-", "+package", "+import", "From", "Date:", "Subject:",
"Change-Id:", "diff --git", "index", "---", "+++", "@@", "Binary files differ"
));
return Arrays.stream(patchSet.split("\n"))
.map(line -> line.replace("\t", "").replace(" ", ""))
.filter(line -> skipPrefixes.stream().noneMatch(line::startsWith))
.filter(line -> !line.trim().isEmpty())
.collect(Collectors.joining("\n"));
}
private String getReviewSuggestion(Configuration config, String changeId, String patchSet) throws Exception {
List<String> patchLines = Arrays.asList(patchSet.split("\n"));
if (patchLines.size() > config.getMaxReviewLines()) {
log.warn("Patch set too large. Skipping review. changeId: {}", changeId);
return String.format(SPLIT_REVIEW_MSG, config.getMaxReviewLines());
}
return openAiClient.ask(config, patchSet);
}
}