Skip to content

Commit e7db99d

Browse files
committed
feat: Implement latest PR version filtering for CodeAnalysis issues in services
1 parent 74643a8 commit e7db99d

3 files changed

Lines changed: 61 additions & 25 deletions

File tree

java-ecosystem/libs/core/src/main/java/org/rostilos/codecrow/core/persistence/repository/codeanalysis/CodeAnalysisIssueRepository.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,42 @@ List<CodeAnalysisIssue> findByProjectIdAndPrNumberAndFilePath(
107107
@Param("prNumber") Long prNumber,
108108
@Param("filePath") String filePath);
109109

110+
/**
111+
* Find issues for the <b>latest PR version only</b>.
112+
* Scopes to the analysis with MAX(prVersion) for this PR number.
113+
* Used by the PR source code viewer (file tree counts).
114+
*/
115+
@Query("SELECT cai FROM CodeAnalysisIssue cai " +
116+
"WHERE cai.analysis.project.id = :projectId " +
117+
"AND cai.analysis.prNumber = :prNumber " +
118+
"AND cai.analysis.prVersion = (" +
119+
" SELECT MAX(a.prVersion) FROM CodeAnalysis a " +
120+
" WHERE a.project.id = :projectId AND a.prNumber = :prNumber" +
121+
") " +
122+
"ORDER BY cai.filePath ASC, cai.lineNumber ASC")
123+
List<CodeAnalysisIssue> findByProjectIdAndPrNumberLatestVersion(
124+
@Param("projectId") Long projectId,
125+
@Param("prNumber") Long prNumber);
126+
127+
/**
128+
* Find issues for a specific file in the <b>latest PR version only</b>.
129+
* Scopes to the analysis with MAX(prVersion) for this PR number.
130+
* Used by the PR source code viewer (inline issue annotations).
131+
*/
132+
@Query("SELECT cai FROM CodeAnalysisIssue cai " +
133+
"WHERE cai.analysis.project.id = :projectId " +
134+
"AND cai.analysis.prNumber = :prNumber " +
135+
"AND cai.filePath = :filePath " +
136+
"AND cai.analysis.prVersion = (" +
137+
" SELECT MAX(a.prVersion) FROM CodeAnalysis a " +
138+
" WHERE a.project.id = :projectId AND a.prNumber = :prNumber" +
139+
") " +
140+
"ORDER BY cai.lineNumber ASC")
141+
List<CodeAnalysisIssue> findByProjectIdAndPrNumberAndFilePathLatestVersion(
142+
@Param("projectId") Long projectId,
143+
@Param("prNumber") Long prNumber,
144+
@Param("filePath") String filePath);
145+
110146
// ── Aggregate queries (for analytics — avoid loading full entity graphs) ──
111147

112148
@Query("SELECT COUNT(cai) FROM CodeAnalysisIssue cai " +

java-ecosystem/libs/core/src/main/java/org/rostilos/codecrow/core/service/CodeAnalysisService.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,22 @@ public List<CodeAnalysisIssue> findIssuesByPrNumberAndFilePath(Long projectId, L
930930
issueRepository.findByProjectIdAndPrNumberAndFilePath(projectId, prNumber, filePath));
931931
}
932932

933+
/**
934+
* Find all issues for the <b>latest PR version only</b>.
935+
* No cross-iteration deduplication needed — single iteration scope.
936+
*/
937+
public List<CodeAnalysisIssue> findIssuesByPrNumberLatestVersion(Long projectId, Long prNumber) {
938+
return issueRepository.findByProjectIdAndPrNumberLatestVersion(projectId, prNumber);
939+
}
940+
941+
/**
942+
* Find issues for a specific file in the <b>latest PR version only</b>.
943+
* No cross-iteration deduplication needed — single iteration scope.
944+
*/
945+
public List<CodeAnalysisIssue> findIssuesByPrNumberAndFilePathLatestVersion(Long projectId, Long prNumber, String filePath) {
946+
return issueRepository.findByProjectIdAndPrNumberAndFilePathLatestVersion(projectId, prNumber, filePath);
947+
}
948+
933949
/**
934950
* Deduplicate issues that span multiple analyses on the same branch.
935951
* When the same logical issue is tracked across analyses (via trackedFromIssueId),
@@ -987,24 +1003,7 @@ private List<CodeAnalysisIssue> deduplicateBranchIssues(List<CodeAnalysisIssue>
9871003
}
9881004
}
9891005

990-
// Pass 3: safety-net dedup for issues that survived with null fingerprints.
991-
// Group by (normalizedTitle + lineNumber) and keep only the latest version.
992-
Map<String, CodeAnalysisIssue> byTitleLine = new LinkedHashMap<>();
993-
for (CodeAnalysisIssue issue : byContentFp.values()) {
994-
String title = issue.getTitle();
995-
int line = issue.getLineNumber() != null ? issue.getLineNumber() : 0;
996-
if (title != null && !title.isBlank()) {
997-
String key = IssueFingerprint.normalizeTitle(title) + "::" + line;
998-
CodeAnalysisIssue existing = byTitleLine.get(key);
999-
if (existing == null || issue.getAnalysis().getId() > existing.getAnalysis().getId()) {
1000-
byTitleLine.put(key, issue);
1001-
}
1002-
} else {
1003-
byTitleLine.put("_id_" + issue.getId(), issue);
1004-
}
1005-
}
1006-
1007-
return new ArrayList<>(byTitleLine.values());
1006+
return new ArrayList<>(byContentFp.values());
10081007
}
10091008

10101009
public void markIssueAsResolved(Long issueId) {

java-ecosystem/services/web-server/src/main/java/org/rostilos/codecrow/webserver/analysis/service/FileViewService.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ public Optional<AnalysisFilesResponse> listPrFiles(Long projectId, Long prNumber
362362
return Optional.empty();
363363
}
364364

365-
// Aggregate issues across all analyses for this PR number
366-
List<CodeAnalysisIssue> issues = codeAnalysisService.findIssuesByPrNumber(projectId, prNumber);
365+
// Only show issues from the latest PR version (not accumulated across all iterations)
366+
List<CodeAnalysisIssue> issues = codeAnalysisService.findIssuesByPrNumberLatestVersion(projectId, prNumber);
367367
Map<String, List<CodeAnalysisIssue>> issuesByFile = issues.stream()
368368
.filter(i -> i.getFilePath() != null)
369369
.filter(FileViewService::hasTitle)
@@ -416,8 +416,8 @@ public Optional<FileViewResponse> getPrFileView(Long projectId, Long prNumber, S
416416
int lineCount = countLines(content);
417417
LineHashSequence lineHashes = LineHashSequence.from(content);
418418

419-
// Aggregate issues across all analyses for this PR number
420-
List<CodeAnalysisIssue> fileIssues = codeAnalysisService.findIssuesByPrNumberAndFilePath(projectId, prNumber, filePath);
419+
// Only show issues from the latest PR version (not accumulated across all iterations)
420+
List<CodeAnalysisIssue> fileIssues = codeAnalysisService.findIssuesByPrNumberAndFilePathLatestVersion(projectId, prNumber, filePath);
421421
List<FileViewResponse.InlineIssue> inlineIssues = fileIssues.stream()
422422
.filter(FileViewService::hasTitle)
423423
.filter(i -> !i.isResolved())
@@ -477,8 +477,8 @@ public Optional<FileSnippetResponse> getPrFileSnippet(
477477
snippetLines.add(new FileSnippetResponse.SnippetLine(i, lineContent));
478478
}
479479

480-
// Get issues for this PR and file, filtered to the snippet range
481-
List<CodeAnalysisIssue> allIssues = codeAnalysisService.findIssuesByPrNumberAndFilePath(projectId, prNumber, filePath);
480+
// Only show issues from the latest PR version, filtered to the snippet range
481+
List<CodeAnalysisIssue> allIssues = codeAnalysisService.findIssuesByPrNumberAndFilePathLatestVersion(projectId, prNumber, filePath);
482482
int finalStartLine = startLine;
483483
int finalEndLine = endLine;
484484
List<FileViewResponse.InlineIssue> inlineIssues = allIssues.stream()
@@ -543,7 +543,8 @@ public Optional<FileSnippetResponse> getPrFileSnippetByRange(
543543
snippetLines.add(new FileSnippetResponse.SnippetLine(i, lineContent));
544544
}
545545

546-
List<CodeAnalysisIssue> allIssues = codeAnalysisService.findIssuesByPrNumberAndFilePath(projectId, prNumber, filePath);
546+
// Only show issues from the latest PR version, filtered to the line range
547+
List<CodeAnalysisIssue> allIssues = codeAnalysisService.findIssuesByPrNumberAndFilePathLatestVersion(projectId, prNumber, filePath);
547548
int finalStart = startLine;
548549
int finalEnd = endLine;
549550
List<FileViewResponse.InlineIssue> inlineIssues = allIssues.stream()

0 commit comments

Comments
 (0)