@@ -4,13 +4,52 @@ import { Diff } from '../../Git/@types/PatchTypes';
44import { CommitStatus } from './CommitStatus' ;
55import { Log } from '../../Logger' ;
66import { IAnalyzerBot } from '../../AnalyzerBot/@interfaces/IAnalyzerBot' ;
7+ import { Comment } from '../../AnalyzerBot/@types/CommentTypes' ;
78
89export class GitHubAdapter implements VCSAdapter {
910 private commitId : string ;
11+ private existingComments : Set < string > = new Set ( ) ;
12+ private existingCommentIds : Map < string , number > = new Map ( ) ;
13+ private existingReviewIds : Map < string , number > = new Map ( ) ;
14+
1015 constructor ( private readonly prService : IGitHubPRService ) { }
1116
1217 async init ( ) : Promise < void > {
1318 this . commitId = await this . prService . getLatestCommitSha ( ) ;
19+
20+ // Store existing comments for duplicate detection
21+ const [ userId , comments , reviews ] = await Promise . all ( [
22+ this . prService . getCurrentUserId ( ) ,
23+ this . prService . listAllComments ( ) ,
24+ this . prService . listAllReviewComments ( ) ,
25+ ] ) ;
26+
27+ // Store regular comments
28+ comments
29+ . filter ( ( comment ) => comment . user ?. id === userId )
30+ . forEach ( ( comment ) => {
31+ if ( comment . body ) {
32+ this . existingComments . add ( comment . body ) ;
33+ this . existingCommentIds . set ( comment . body , comment . id ) ;
34+ }
35+ } ) ;
36+
37+ // Store review comments
38+ reviews
39+ . filter ( ( review ) => review . user ?. id === userId )
40+ . forEach ( ( review ) => {
41+ const key = this . generateCommentKey (
42+ review . path || '' ,
43+ review . line || 0 ,
44+ review . body ,
45+ ) ;
46+ this . existingComments . add ( key ) ;
47+ this . existingReviewIds . set ( key , review . id ) ;
48+ } ) ;
49+ }
50+
51+ private generateCommentKey ( file : string , line : number , text : string ) : string {
52+ return `${ file } :${ line } :${ text } ` ;
1453 }
1554
1655 async wrapUp ( analyzer : IAnalyzerBot ) : Promise < boolean > {
@@ -29,8 +68,14 @@ export class GitHubAdapter implements VCSAdapter {
2968 diff ( ) : Promise < Diff [ ] > {
3069 return this . prService . diff ( ) ;
3170 }
71+
3272 createComment ( comment : string ) : Promise < void > {
33- return this . prService . createComment ( comment ) ;
73+ if ( ! this . existingComments . has ( comment ) ) {
74+ return this . prService . createComment ( comment ) ;
75+ } else {
76+ Log . debug ( 'Skipped creating duplicate comment' ) ;
77+ return Promise . resolve ( ) ;
78+ }
3479 }
3580
3681 createReviewComment (
@@ -39,27 +84,51 @@ export class GitHubAdapter implements VCSAdapter {
3984 line : number ,
4085 nLines : number ,
4186 ) : Promise < void > {
42- return this . prService . createReviewComment ( this . commitId , text , file , line , nLines ) ;
87+ const commentKey = this . generateCommentKey ( file , line , text ) ;
88+
89+ if ( ! this . existingComments . has ( commentKey ) ) {
90+ return this . prService . createReviewComment ( this . commitId , text , file , line , nLines ) ;
91+ } else {
92+ Log . debug ( 'Skipped creating duplicate review comment' ) ;
93+ return Promise . resolve ( ) ;
94+ }
4395 }
4496
45- async removeExistingComments ( ) : Promise < void > {
46- const [ userId , comments , reviews ] = await Promise . all ( [
47- this . prService . getCurrentUserId ( ) ,
48- this . prService . listAllComments ( ) ,
49- this . prService . listAllReviewComments ( ) ,
50- ] ) ;
51- Log . debug ( 'Get existing CodeCoach comments completed' ) ;
97+ async removeExistingComments ( currentComments : Comment [ ] ) : Promise < void > {
98+ // Create a set of current issue keys
99+ const currentIssueKeys = new Set < string > ( ) ;
100+ currentComments . forEach ( ( comment ) => {
101+ const key = this . generateCommentKey ( comment . file , comment . line , comment . text ) ;
102+ currentIssueKeys . add ( key ) ;
103+ } ) ;
52104
53- const deleteComments = comments
54- . filter ( ( comment ) => comment . user ?. id === userId )
55- . map ( ( comment ) => this . prService . deleteComment ( comment . id ) ) ;
105+ // Delete comments that are no longer relevant
106+ const commentsToDelete : Promise < void > [ ] = [ ] ;
56107
57- const deleteReviews = reviews
58- . filter ( ( review ) => review . user ?. id === userId )
59- . map ( ( review ) => this . prService . deleteReviewComment ( review . id ) ) ;
108+ // Check regular comments
109+ this . existingCommentIds . forEach ( ( commentId , commentText ) => {
110+ if ( ! currentIssueKeys . has ( commentText ) ) {
111+ commentsToDelete . push ( this . prService . deleteComment ( commentId ) ) ;
112+ this . existingComments . delete ( commentText ) ;
113+ this . existingCommentIds . delete ( commentText ) ;
114+ }
115+ } ) ;
116+
117+ // Check review comments
118+ this . existingReviewIds . forEach ( ( reviewId , commentKey ) => {
119+ if ( ! currentIssueKeys . has ( commentKey ) ) {
120+ commentsToDelete . push ( this . prService . deleteReviewComment ( reviewId ) ) ;
121+ this . existingComments . delete ( commentKey ) ;
122+ this . existingReviewIds . delete ( commentKey ) ;
123+ }
124+ } ) ;
60125
61- await Promise . all ( [ ...deleteComments , ...deleteReviews ] ) ;
62- Log . debug ( 'Delete CodeCoach comments completed' ) ;
126+ if ( commentsToDelete . length > 0 ) {
127+ await Promise . all ( commentsToDelete ) ;
128+ Log . debug ( `Deleted ${ commentsToDelete . length } outdated comments` ) ;
129+ } else {
130+ Log . debug ( 'No outdated comments to delete' ) ;
131+ }
63132 }
64133
65134 private async setCommitStatus ( analyzer : IAnalyzerBot ) {
0 commit comments