@@ -56,6 +56,9 @@ export async function handleWebhook(request, env) {
5656 case "issue_comment" :
5757 return handleIssueCommentEvent ( payload , env ) ;
5858
59+ case "pull_request_review_comment" :
60+ return handlePullRequestReviewCommentEvent ( payload , env ) ;
61+
5962 default :
6063 console . log ( `Unhandled event type: ${ eventType } ` ) ;
6164 return corsResponse ( { message : `Ignored: ${ eventType } ` } ) ;
@@ -274,15 +277,20 @@ async function handleIssueCommentEvent(payload, env) {
274277 const prNumber = issue . number ;
275278
276279 // ๋ฉ์
๊ฐ์ง: @dalestudy๋ง ์ฒดํฌ
277- const commentBody = comment . body . toLowerCase ( ) ;
278- const isMentioned = commentBody . includes ( "@dalestudy" ) ;
280+ const commentBody = comment . body ;
281+ const lowerBody = commentBody . toLowerCase ( ) ;
282+ const isMentioned = lowerBody . includes ( "@dalestudy" ) ;
279283
280284 if ( ! isMentioned ) {
281285 console . log ( "Ignoring: bot not mentioned" ) ;
282286 return corsResponse ( { message : "Ignored: not mentioned" } ) ;
283287 }
284288
285- console . log ( `AI review requested for PR #${ prNumber } ` ) ;
289+ // ๋ฉ์
๋ค์ ํ
์คํธ ์ถ์ถ
290+ const mentionMatch = commentBody . match ( / @ d a l e s t u d y \s * ( .* ) / i) ;
291+ const userRequest = mentionMatch && mentionMatch [ 1 ] . trim ( ) ? mentionMatch [ 1 ] . trim ( ) : null ;
292+
293+ console . log ( `AI review requested for PR #${ prNumber } ${ userRequest ? ` - Request: ${ userRequest } ` : "" } ` ) ;
286294
287295 // OPENAI_API_KEY ํ์ธ
288296 if ( ! env . OPENAI_API_KEY ) {
@@ -294,15 +302,24 @@ async function handleIssueCommentEvent(payload, env) {
294302 try {
295303 const appToken = await generateGitHubAppToken ( env ) ;
296304
305+ // ๐ reaction ์ถ๊ฐ (๋ฆฌ๋ทฐ ์์ ์๋ฆผ)
306+ await fetch (
307+ `https://api.github.com/repos/${ repoOwner } /${ repoName } /issues/comments/${ comment . id } /reactions` ,
308+ {
309+ method : "POST" ,
310+ headers : getGitHubHeaders ( appToken ) ,
311+ body : JSON . stringify ( { content : "eyes" } ) ,
312+ }
313+ ) ;
314+
297315 await performAIReview (
298316 repoOwner ,
299317 repoName ,
300318 prNumber ,
301319 issue . title ,
302320 issue . body ,
303321 appToken ,
304- env . OPENAI_API_KEY ,
305- comment . id // ์๋ณธ ๋๊ธ ID ์ ๋ฌ
322+ env . OPENAI_API_KEY
306323 ) ;
307324
308325 console . log ( `AI review completed for PR #${ prNumber } ` ) ;
@@ -316,3 +333,96 @@ async function handleIssueCommentEvent(payload, env) {
316333 return errorResponse ( `AI review failed: ${ error . message } ` , 500 ) ;
317334 }
318335}
336+
337+ /**
338+ * Pull Request Review Comment ์ด๋ฒคํธ ์ฒ๋ฆฌ (์ฝ๋ ๋ผ์ธ ๋๊ธ์ ๋ํ AI ๋ฆฌ๋ทฐ)
339+ */
340+ async function handlePullRequestReviewCommentEvent ( payload , env ) {
341+ const action = payload . action ;
342+
343+ // created ์ก์
๋ง ์ฒ๋ฆฌ
344+ if ( action !== "created" ) {
345+ console . log ( `Ignoring pull_request_review_comment action: ${ action } ` ) ;
346+ return corsResponse ( { message : `Ignored: ${ action } ` } ) ;
347+ }
348+
349+ console . log ( `Processing pull_request_review_comment action: ${ action } ` ) ;
350+
351+ const comment = payload . comment ;
352+ const pullRequest = payload . pull_request ;
353+ const repoOwner = payload . repository . owner . login ;
354+ const repoName = payload . repository . name ;
355+ const prNumber = pullRequest . number ;
356+
357+ // ๋ฉ์
๊ฐ์ง: @dalestudy๋ง ์ฒดํฌ
358+ const commentBody = comment . body . toLowerCase ( ) ;
359+ const isMentioned = commentBody . includes ( "@dalestudy" ) ;
360+
361+ if ( ! isMentioned ) {
362+ console . log ( "Ignoring: bot not mentioned" ) ;
363+ return corsResponse ( { message : "Ignored: not mentioned" } ) ;
364+ }
365+
366+ console . log ( `AI review requested for PR #${ prNumber } (review comment)` ) ;
367+
368+ // OPENAI_API_KEY ํ์ธ
369+ if ( ! env . OPENAI_API_KEY ) {
370+ console . log ( "OPENAI_API_KEY not configured" ) ;
371+ return corsResponse ( { message : "AI review not configured" } ) ;
372+ }
373+
374+ // AI ์ฝ๋ ๋ฆฌ๋ทฐ ์คํ (์ค๋ ๋ ๋ต๋ณ)
375+ try {
376+ const appToken = await generateGitHubAppToken ( env ) ;
377+
378+ // ๐ reaction ์ถ๊ฐ
379+ await fetch (
380+ `https://api.github.com/repos/${ repoOwner } /${ repoName } /pulls/comments/${ comment . id } /reactions` ,
381+ {
382+ method : "POST" ,
383+ headers : getGitHubHeaders ( appToken ) ,
384+ body : JSON . stringify ( { content : "eyes" } ) ,
385+ }
386+ ) ;
387+
388+ // AI ๋ฆฌ๋ทฐ ์์ฑ
389+ const { generateCodeReview } = await import ( "../utils/openai.js" ) ;
390+ const { getPRDiff } = await import ( "../utils/prReview.js" ) ;
391+
392+ const prDiff = await getPRDiff ( repoOwner , repoName , prNumber , appToken ) ;
393+
394+ // diff๊ฐ ๋๋ฌด ํฌ๋ฉด ์คํต
395+ const diffLines = prDiff . split ( "\n" ) . length ;
396+ if ( diffLines > 1000 ) {
397+ console . log ( `Skipping AI review: diff too large (${ diffLines } lines)` ) ;
398+ return corsResponse ( { message : "Diff too large" } ) ;
399+ }
400+
401+ const reviewContent = await generateCodeReview (
402+ prDiff ,
403+ pullRequest . title ,
404+ pullRequest . body ,
405+ env . OPENAI_API_KEY
406+ ) ;
407+
408+ // ์ค๋ ๋ ๋ต๋ณ์ผ๋ก ์์ฑ
409+ await fetch (
410+ `https://api.github.com/repos/${ repoOwner } /${ repoName } /pulls/${ prNumber } /comments/${ comment . id } /replies` ,
411+ {
412+ method : "POST" ,
413+ headers : getGitHubHeaders ( appToken ) ,
414+ body : JSON . stringify ( { body : reviewContent } ) ,
415+ }
416+ ) ;
417+
418+ console . log ( `AI review completed for PR #${ prNumber } (thread reply)` ) ;
419+
420+ return corsResponse ( {
421+ message : "AI review posted as thread reply" ,
422+ pr : prNumber ,
423+ } ) ;
424+ } catch ( error ) {
425+ console . error ( `AI review failed for PR #${ prNumber } :` , error ) ;
426+ return errorResponse ( `AI review failed: ${ error . message } ` , 500 ) ;
427+ }
428+ }
0 commit comments