@@ -37,6 +37,7 @@ const (
3737 maxPRsToProcess = 200
3838 minUpdateInterval = 10 * time .Second
3939 defaultUpdateInterval = 1 * time .Minute
40+ blockedPRIconDuration = 25 * time .Minute
4041 maxRetryDelay = 2 * time .Minute
4142 maxRetries = 10
4243 minorFailureThreshold = 3
@@ -655,64 +656,92 @@ func (app *App) checkForNewlyBlockedPRs(ctx context.Context) {
655656
656657 // Check incoming PRs
657658 for i := range incoming {
658- if incoming [i ].NeedsReview {
659- currentBlocked [incoming [i ].URL ] = true
660- // Track when first blocked
661- if blockedTime , exists := blockedTimes [incoming [i ].URL ]; exists {
662- newBlockedTimes [incoming [i ].URL ] = blockedTime
663- incoming [i ].FirstBlockedAt = blockedTime
664- } else if ! previousBlocked [incoming [i ].URL ] {
665- // Newly blocked PR
666- newBlockedTimes [incoming [i ].URL ] = now
667- incoming [i ].FirstBlockedAt = now
668- log .Printf ("[BLOCKED] Setting FirstBlockedAt for incoming PR: %s #%d at %v" ,
669- incoming [i ].Repository , incoming [i ].Number , now )
670-
671- // Skip sound and auto-open for stale PRs when hideStaleIncoming is enabled
672- isStale := incoming [i ].UpdatedAt .Before (staleThreshold )
673- if hideStaleIncoming && isStale {
674- log .Printf ("[BLOCKED] New incoming PR blocked (stale, skipping): %s #%d - %s" ,
675- incoming [i ].Repository , incoming [i ].Number , incoming [i ].Title )
676- } else {
677- log .Printf ("[BLOCKED] New incoming PR blocked: %s #%d - %s" ,
678- incoming [i ].Repository , incoming [i ].Number , incoming [i ].Title )
679- app .notifyWithSound (ctx , incoming [i ], true , & playedHonk )
680- app .tryAutoOpenPR (ctx , incoming [i ], autoBrowserEnabled , startTime )
681- }
659+ if ! incoming [i ].NeedsReview {
660+ continue
661+ }
662+
663+ pr := & incoming [i ]
664+ currentBlocked [pr .URL ] = true
665+
666+ if previousBlocked [pr .URL ] {
667+ // PR was blocked before and is still blocked - preserve timestamp
668+ if blockedTime , exists := blockedTimes [pr .URL ]; exists {
669+ newBlockedTimes [pr .URL ] = blockedTime
670+ pr .FirstBlockedAt = blockedTime
671+ log .Printf ("[BLOCKED] Preserving FirstBlockedAt for still-blocked incoming PR: %s #%d (blocked since %v, %v ago)" ,
672+ pr .Repository , pr .Number , blockedTime , time .Since (blockedTime ))
673+ } else {
674+ // Edge case: PR was marked as blocked but timestamp is missing
675+ log .Printf ("[BLOCKED] WARNING: Missing timestamp for previously blocked incoming PR: %s #%d - setting new timestamp" ,
676+ pr .Repository , pr .Number )
677+ newBlockedTimes [pr .URL ] = now
678+ pr .FirstBlockedAt = now
679+ }
680+ } else {
681+ // PR is newly blocked (wasn't blocked in previous check)
682+ newBlockedTimes [pr .URL ] = now
683+ pr .FirstBlockedAt = now
684+ log .Printf ("[BLOCKED] Setting FirstBlockedAt for incoming PR: %s #%d at %v" ,
685+ pr .Repository , pr .Number , now )
686+
687+ // Skip sound and auto-open for stale PRs when hideStaleIncoming is enabled
688+ isStale := pr .UpdatedAt .Before (staleThreshold )
689+ if hideStaleIncoming && isStale {
690+ log .Printf ("[BLOCKED] New incoming PR blocked (stale, skipping): %s #%d - %s" ,
691+ pr .Repository , pr .Number , pr .Title )
692+ } else {
693+ log .Printf ("[BLOCKED] New incoming PR blocked: %s #%d - %s" ,
694+ pr .Repository , pr .Number , pr .Title )
695+ app .notifyWithSound (ctx , * pr , true , & playedHonk )
696+ app .tryAutoOpenPR (ctx , * pr , autoBrowserEnabled , startTime )
682697 }
683698 }
684699 }
685700
686701 // Check outgoing PRs
687702 for i := range outgoing {
688- if outgoing [i ].IsBlocked {
689- currentBlocked [outgoing [i ].URL ] = true
690- // Track when first blocked
691- if blockedTime , exists := blockedTimes [outgoing [i ].URL ]; exists {
692- newBlockedTimes [outgoing [i ].URL ] = blockedTime
693- outgoing [i ].FirstBlockedAt = blockedTime
694- } else if ! previousBlocked [outgoing [i ].URL ] {
695- // Newly blocked PR
696- newBlockedTimes [outgoing [i ].URL ] = now
697- outgoing [i ].FirstBlockedAt = now
698- log .Printf ("[BLOCKED] Setting FirstBlockedAt for outgoing PR: %s #%d at %v" ,
699- outgoing [i ].Repository , outgoing [i ].Number , now )
700-
701- // Skip sound and auto-open for stale PRs when hideStaleIncoming is enabled
702- isStale := outgoing [i ].UpdatedAt .Before (staleThreshold )
703- if hideStaleIncoming && isStale {
704- log .Printf ("[BLOCKED] New outgoing PR blocked (stale, skipping): %s #%d - %s" ,
705- outgoing [i ].Repository , outgoing [i ].Number , outgoing [i ].Title )
706- } else {
707- // Add delay if we already played honk sound
708- if playedHonk && ! playedJet {
709- time .Sleep (2 * time .Second )
710- }
711- log .Printf ("[BLOCKED] New outgoing PR blocked: %s #%d - %s" ,
712- outgoing [i ].Repository , outgoing [i ].Number , outgoing [i ].Title )
713- app .notifyWithSound (ctx , outgoing [i ], false , & playedJet )
714- app .tryAutoOpenPR (ctx , outgoing [i ], autoBrowserEnabled , startTime )
703+ if ! outgoing [i ].IsBlocked {
704+ continue
705+ }
706+
707+ pr := & outgoing [i ]
708+ currentBlocked [pr .URL ] = true
709+
710+ if previousBlocked [pr .URL ] {
711+ // PR was blocked before and is still blocked - preserve timestamp
712+ if blockedTime , exists := blockedTimes [pr .URL ]; exists {
713+ newBlockedTimes [pr .URL ] = blockedTime
714+ pr .FirstBlockedAt = blockedTime
715+ log .Printf ("[BLOCKED] Preserving FirstBlockedAt for still-blocked outgoing PR: %s #%d (blocked since %v, %v ago)" ,
716+ pr .Repository , pr .Number , blockedTime , time .Since (blockedTime ))
717+ } else {
718+ // Edge case: PR was marked as blocked but timestamp is missing
719+ log .Printf ("[BLOCKED] WARNING: Missing timestamp for previously blocked outgoing PR: %s #%d - setting new timestamp" ,
720+ pr .Repository , pr .Number )
721+ newBlockedTimes [pr .URL ] = now
722+ pr .FirstBlockedAt = now
723+ }
724+ } else {
725+ // PR is newly blocked (wasn't blocked in previous check)
726+ newBlockedTimes [pr .URL ] = now
727+ pr .FirstBlockedAt = now
728+ log .Printf ("[BLOCKED] Setting FirstBlockedAt for outgoing PR: %s #%d at %v" ,
729+ pr .Repository , pr .Number , now )
730+
731+ // Skip sound and auto-open for stale PRs when hideStaleIncoming is enabled
732+ isStale := pr .UpdatedAt .Before (staleThreshold )
733+ if hideStaleIncoming && isStale {
734+ log .Printf ("[BLOCKED] New outgoing PR blocked (stale, skipping): %s #%d - %s" ,
735+ pr .Repository , pr .Number , pr .Title )
736+ } else {
737+ // Add delay if we already played honk sound
738+ if playedHonk && ! playedJet {
739+ time .Sleep (2 * time .Second )
715740 }
741+ log .Printf ("[BLOCKED] New outgoing PR blocked: %s #%d - %s" ,
742+ pr .Repository , pr .Number , pr .Title )
743+ app .notifyWithSound (ctx , * pr , false , & playedJet )
744+ app .tryAutoOpenPR (ctx , * pr , autoBrowserEnabled , startTime )
716745 }
717746 }
718747 }
0 commit comments