26
26
import subprocess
27
27
from requests .adapters import HTTPAdapter
28
28
from requests .packages .urllib3 .util .retry import Retry
29
+
29
30
# Constants for GitHub API interaction
30
31
RETRIES = 3
31
32
BACKOFF = 5
32
33
RETRY_STATUS = (403 , 500 , 502 , 504 ) # HTTP status codes to retry on
33
34
TIMEOUT = 5 # Default timeout for requests in seconds
34
- TIMEOUT_LONG = 20 # Longer timeout, currently not used by functions in this script
35
35
36
36
# Global variables for the target repository, populated by set_repo_url_standalone()
37
37
OWNER = ''
@@ -374,7 +374,8 @@ def parse_repo_url(url_string):
374
374
filtered_overall_reviews = []
375
375
if overall_reviews : # If not None and not empty
376
376
for review in overall_reviews :
377
- if review .get ("state" ) == "DISMISSED" :
377
+ review_state = review .get ("state" )
378
+ if review_state == "DISMISSED" or review_state == "PENDING" :
378
379
continue
379
380
380
381
if args .since :
@@ -404,31 +405,26 @@ def parse_repo_url(url_string):
404
405
sys .stderr .write (f"Warning: Could not parse review submitted_at timestamp '{ submitted_at_str } ' or --since timestamp '{ args .since } ': { ve } \n " )
405
406
# If parsing fails, we might choose to include the review to be safe, or skip. Current: include.
406
407
407
- # New filter: Exclude "COMMENTED" reviews with an empty body
408
408
if review .get ("state" ) == "COMMENTED" and not review .get ("body" , "" ).strip ():
409
409
continue
410
410
411
411
filtered_overall_reviews .append (review )
412
412
413
- # Sort by submission time, oldest first
414
413
try :
415
414
filtered_overall_reviews .sort (key = lambda r : r .get ("submitted_at" , "" ))
416
415
except Exception as e : # Broad exception for safety
417
416
sys .stderr .write (f"Warning: Could not sort overall reviews: { e } \n " )
418
417
419
- # Output overall reviews if any exist after filtering
420
418
if filtered_overall_reviews :
421
- print ("# Code Reviews\n \n " ) # Changed heading
422
- # Explicitly re-initialize before this loop to be absolutely sure for the update logic within it.
423
- # The main initialization at the top of main() handles the case where this block is skipped.
424
- temp_latest_overall_review_dt = None # Use a temporary variable for this loop's accumulation
419
+ print ("# Code Reviews\n \n " )
420
+ # Use a temporary variable for accumulating latest timestamp within this specific block
421
+ temp_latest_overall_review_dt = None
425
422
for review in filtered_overall_reviews :
426
423
user = review .get ("user" , {}).get ("login" , "Unknown user" )
427
- submitted_at_str = review .get ("submitted_at" , "N/A" ) # Keep original string for printing
424
+ submitted_at_str = review .get ("submitted_at" , "N/A" )
428
425
state = review .get ("state" , "N/A" )
429
426
body = review .get ("body" , "" ).strip ()
430
427
431
- # Track latest overall review timestamp within this block
432
428
if submitted_at_str and submitted_at_str != "N/A" :
433
429
try :
434
430
if sys .version_info < (3 , 11 ):
@@ -445,32 +441,29 @@ def parse_repo_url(url_string):
445
441
review_id = review .get ("id" , "N/A" )
446
442
447
443
print (f"## Review by: **{ user } ** (ID: `{ review_id } `)\n " )
448
- print (f"* **Submitted At**: `{ submitted_at_str } `" ) # Print original string
444
+ print (f"* **Submitted At**: `{ submitted_at_str } `" )
449
445
print (f"* **State**: `{ state } `" )
450
446
print (f"* **URL**: <{ html_url } >\n " )
451
- # Removed duplicated lines here
452
447
453
448
if body :
454
- print ("\n ### Summary Comment:" )
449
+ print ("\n ### Comment:" ) # Changed heading
455
450
print (body )
456
451
print ("\n ---" )
457
452
458
453
# After processing all overall reviews in this block, update the main variable
459
454
if temp_latest_overall_review_dt :
460
455
latest_overall_review_activity_dt = temp_latest_overall_review_dt
461
-
462
- # Add an extra newline to separate from line comments if any overall reviews were printed
463
456
print ("\n " )
464
457
465
458
466
459
sys .stderr .write (f"Fetching line comments for PR #{ pull_request_number } from { OWNER } /{ REPO } ...\n " )
467
460
if args .since :
468
- sys .stderr .write (f"Filtering line comments updated since: { args .since } \n " ) # Clarify this 'since' is for line comments
461
+ sys .stderr .write (f"Filtering line comments updated since: { args .since } \n " )
469
462
470
463
comments = get_pull_request_review_comments (
471
464
args .token ,
472
465
pull_request_number ,
473
- since = args .since # This 'since' applies to line comment's 'updated_at'
466
+ since = args .since
474
467
)
475
468
476
469
if comments is None :
@@ -479,22 +472,15 @@ def parse_repo_url(url_string):
479
472
# Note: The decision to exit if only line comments fail vs. if only overall reviews fail could be nuanced.
480
473
# For now, failure to fetch either is treated as a critical error for the script's purpose.
481
474
482
- # Initializations for latest_overall_review_activity_dt, latest_line_comment_activity_dt,
483
- # and processed_comments_count have been moved to the top of the main() function.
484
-
485
475
# Handling for line comments
486
- if not comments : # comments is an empty list here (None case handled above)
476
+ if not comments :
487
477
sys .stderr .write (f"No line comments found for PR #{ pull_request_number } (or matching filters).\n " )
488
- # If there were also no overall reviews, and no line comments, then nothing to show.
489
- # The 'next command' suggestion logic below will still run if overall_reviews had content.
490
- if not filtered_overall_reviews : # and not comments (implicitly true here)
491
- # Only return (and skip 'next command' suggestion) if NO content at all was printed.
492
- # If overall_reviews were printed, we still want the 'next command' suggestion.
493
- pass # Let it fall through to the 'next command' suggestion logic
478
+ # If filtered_overall_reviews is also empty, then overall_latest_activity_dt will be None,
479
+ # and no 'next command' suggestion will be printed. This is correct.
494
480
else :
495
481
print ("# Review Comments\n \n " )
496
482
497
- for comment in comments : # if comments is empty, this loop is skipped.
483
+ for comment in comments :
498
484
created_at_str = comment .get ("created_at" )
499
485
500
486
current_pos = comment .get ("position" )
@@ -531,16 +517,16 @@ def parse_repo_url(url_string):
531
517
else :
532
518
dt_str_updated = updated_at_str
533
519
current_comment_activity_dt = datetime .datetime .fromisoformat (dt_str_updated )
534
- if latest_line_comment_activity_dt is None or current_comment_activity_dt > latest_line_comment_activity_dt : # Corrected variable name
535
- latest_line_comment_activity_dt = current_comment_activity_dt # Corrected variable name
520
+ if latest_line_comment_activity_dt is None or current_comment_activity_dt > latest_line_comment_activity_dt :
521
+ latest_line_comment_activity_dt = current_comment_activity_dt
536
522
except ValueError :
537
523
sys .stderr .write (f"Warning: Could not parse line comment updated_at for --since suggestion: { updated_at_str } \n " )
538
524
539
525
user = comment .get ("user" , {}).get ("login" , "Unknown user" )
540
526
path = comment .get ("path" , "N/A" )
541
527
body = comment .get ("body" , "" ).strip ()
542
528
543
- if not body : # Skip comments with no actual text content
529
+ if not body :
544
530
continue
545
531
546
532
processed_comments_count += 1
@@ -561,11 +547,11 @@ def parse_repo_url(url_string):
561
547
print ("\n ### Context:" )
562
548
print ("```" )
563
549
if diff_hunk and diff_hunk .strip ():
564
- if args .context_lines == 0 : # 0 means full hunk
550
+ if args .context_lines == 0 :
565
551
print (diff_hunk )
566
- else : # Display header (if any) and last N lines
552
+ else :
567
553
hunk_lines = diff_hunk .split ('\n ' )
568
- if hunk_lines and hunk_lines [0 ].startswith ("@@ " ): # Diff hunk header
554
+ if hunk_lines and hunk_lines [0 ].startswith ("@@ " ):
569
555
print (hunk_lines [0 ])
570
556
hunk_lines = hunk_lines [1 :]
571
557
print ("\n " .join (hunk_lines [- args .context_lines :]))
@@ -590,14 +576,13 @@ def parse_repo_url(url_string):
590
576
591
577
if overall_latest_activity_dt :
592
578
try :
593
- # Suggest next command with '--since' pointing to just after the latest activity.
594
579
next_since_dt = overall_latest_activity_dt .astimezone (timezone .utc ) + timedelta (seconds = 2 )
595
580
next_since_str = next_since_dt .strftime ('%Y-%m-%dT%H:%M:%SZ' )
596
581
597
582
new_cmd_args = [sys .executable , sys .argv [0 ]]
598
583
i = 1
599
584
while i < len (sys .argv ):
600
- if sys .argv [i ] == "--since" : # Skip existing --since argument and its value
585
+ if sys .argv [i ] == "--since" :
601
586
i += 2
602
587
continue
603
588
new_cmd_args .append (sys .argv [i ])
0 commit comments