@@ -13,7 +13,7 @@ def __init__(self):
1313 super ().__init__ ()
1414 self .DAYS_BEFORE_STALE_WARNING = 7
1515 self .DAYS_BEFORE_UNASSIGN = 14
16- self .DAYS_BEFORE_CLOSE = 60
16+ self .DAYS_BEFORE_FINAL_FOLLOWUP = 60
1717
1818 @staticmethod
1919 def _commit_activity_date_for_author (commit , pr_author ):
@@ -244,75 +244,31 @@ def unassign_linked_issues(self, pr):
244244 print (f"Error processing linked issues for PR #{ pr .number } : { e } " )
245245 return 0
246246
247- def close_stale_pr (self , pr , days_inactive ):
248- # TEMPORARY: auto-close disabled. The stale-detection heuristic
249- # has been closing PRs that are merely blocked by bot reviews
250- # (or by reviews the same reviewer later approved). The proper
251- # fix lives in PR #668; until it lands, no PR is auto-closed.
252- print (f"Auto-close currently disabled, skipping PR #{ pr .number } " )
253- return False
254- if pr .state == "closed" :
255- print (f"PR #{ pr .number } is already closed, skipping" )
256- return True
247+ def send_final_followup (self , pr , days_inactive ):
257248 try :
258249 pr_author = pr .user .login if pr .user else None
259250 if not pr_author :
260251 return False
261- close_lines = [
262- "<!-- bot:closed -->" ,
263- f"Hi @{ pr_author } 👋," ,
264- "" ,
265- (
266- "This pull request has been automatically"
267- " closed due to"
268- f" **{ days_inactive } days of inactivity**."
269- " After changes were requested,"
270- " the PR remained inactive."
271- ),
272- "" ,
273- (
274- "We understand that life gets busy,"
275- " and we appreciate your initial"
276- " contribution! 💙"
277- ),
252+ followup_lines = [
253+ "<!-- bot:final_followup -->" ,
254+ f"Hi @{ pr_author } ," ,
278255 "" ,
279- ("**The door is always open**" " for you to come back:" ),
280- (
281- "- You can **reopen this PR** at any time"
282- " if you'd like to continue working on it"
283- ),
284- ("- Feel free to push new commits" " addressing the requested changes" ),
285256 (
286- "- If you reopen the PR, the linked issue "
287- " will be reassigned to you"
257+ f"This PR has been inactive for ** { days_inactive } days** "
258+ " since changes were requested. Are you still working on it? "
288259 ),
289260 "" ,
290261 (
291- "If you have any questions or need help, "
292- " don't hesitate to reach out. "
293- " We're here to support you! "
262+ "If yes, push new commits or reply to let us know. "
263+ " If you've moved on, please close the PR or comment "
264+ " so another contributor can pick it up. "
294265 ),
295- "" ,
296- ("Thank you for your interest in" " contributing to OpenWISP! 🙏" ),
297266 ]
298- try :
299- pr .create_issue_comment ("\n " .join (close_lines ))
300- except Exception as comment_error :
301- print (
302- f"Warning: Could not post closing comment"
303- f" on PR #{ pr .number } : { comment_error } "
304- )
305- finally :
306- pr .edit (state = "closed" )
307- unassigned_count = self .unassign_linked_issues (pr )
308- print (
309- f"Closed PR #{ pr .number } after"
310- f" { days_inactive } days of inactivity,"
311- f" unassigned { unassigned_count } issues"
312- )
267+ pr .create_issue_comment ("\n " .join (followup_lines ))
268+ print (f"Sent final follow-up for PR #{ pr .number } " )
313269 return True
314270 except Exception as e :
315- print (f"Error closing PR #{ pr .number } : { e } " )
271+ print (f"Error sending final follow-up for PR #{ pr .number } : { e } " )
316272 return False
317273
318274 def mark_pr_stale (self , pr , days_inactive ):
@@ -353,14 +309,6 @@ def mark_pr_stale(self, pr, days_inactive):
353309 " let us know."
354310 " We're happy to help! 🤝"
355311 ),
356- "" ,
357- (
358- "If there's no further activity within"
359- f" **{ self .DAYS_BEFORE_CLOSE - days_inactive } "
360- " more days**, this PR will be"
361- " automatically closed"
362- " (but can be reopened anytime)."
363- ),
364312 ]
365313 pr .create_issue_comment ("\n " .join (unassign_lines ))
366314 unassigned_count = self .unassign_linked_issues (pr )
@@ -469,27 +417,40 @@ def process_stale_prs(self):
469417 " maintainer review, skipping"
470418 )
471419 continue
472- if days_inactive >= self .DAYS_BEFORE_CLOSE :
473- if self .close_stale_pr (pr , days_inactive ):
474- processed_count += 1
475- elif days_inactive >= self .DAYS_BEFORE_UNASSIGN :
476- if not self .has_bot_comment (
477- pr ,
420+ stages = (
421+ (
422+ self .DAYS_BEFORE_STALE_WARNING ,
423+ self .DAYS_BEFORE_UNASSIGN ,
424+ "stale_warning" ,
425+ self .send_stale_warning ,
426+ ),
427+ (
428+ self .DAYS_BEFORE_UNASSIGN ,
429+ None ,
478430 "stale" ,
479- after_date = last_changes_requested ,
480- issue_comments = issue_comments ,
481- ):
482- if self .mark_pr_stale (pr , days_inactive ):
483- processed_count += 1
484- elif days_inactive >= self .DAYS_BEFORE_STALE_WARNING :
485- if not self .has_bot_comment (
431+ self .mark_pr_stale ,
432+ ),
433+ (
434+ self .DAYS_BEFORE_FINAL_FOLLOWUP ,
435+ None ,
436+ "final_followup" ,
437+ self .send_final_followup ,
438+ ),
439+ )
440+ for low , high , marker , action in stages :
441+ if days_inactive < low :
442+ continue
443+ if high is not None and days_inactive >= high :
444+ continue
445+ if self .has_bot_comment (
486446 pr ,
487- "stale_warning" ,
447+ marker ,
488448 after_date = last_changes_requested ,
489449 issue_comments = issue_comments ,
490450 ):
491- if self .send_stale_warning (pr , days_inactive ):
492- processed_count += 1
451+ continue
452+ if action (pr , days_inactive ):
453+ processed_count += 1
493454 except Exception as e :
494455 print (f"Error processing" f" PR #{ pr .number } : { e } " )
495456 continue
0 commit comments