From 87e7457cfd26ee4a064b9968e1bd398a141f67ed Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:02:11 -0500 Subject: [PATCH 01/13] Create pending_user_response.py Python script for Workflow automation for pending_user_response.yml based on the following: - If an issue or PR has 'needs-user-input' label, and it has been 30 days since the last comment, comment and tag the user asking them to take a look. - And 30 days after this comment from the workflow, if no response, close the issue with a comment stating the user did not respond and they can re-open if needed. - If the user responds, remove the 'needs-user-input' label. --- .github/workflows/pending_user_response.py | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/pending_user_response.py diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py new file mode 100644 index 00000000000..1395cc58255 --- /dev/null +++ b/.github/workflows/pending_user_response.py @@ -0,0 +1,64 @@ +import os +import datetime +from github import Github + +REPO_NAME = "pytorch/executorch" +LABEL = "need-user-input" +REMINDER_MARKER = "" +REMINDER_COMMENT = ( + f"{REMINDER_MARKER}\nHi @{0}, this issue/PR has been marked as 'need-user-input'. " + "Please respond or provide input. If we don't hear back in 30 days, this will be closed." +) +CLOSE_COMMENT = ( + f"{REMINDER_MARKER}\nClosing due to no response after 30 days. " + "If you still need help, feel free to re-open or comment again!" +) +DAYS_BEFORE_REMINDER = 30 +DAYS_BEFORE_CLOSE = 30 + +def main(): + g = Github(os.environ['GH_TOKEN']) + repo = g.get_repo(REPO_NAME) + + issues = repo.get_issues(state='open', labels=[LABEL]) + now = datetime.datetime.utcnow() + + for issue in issues: + comments = list(issue.get_comments()) + last_comment = comments[-1] if comments else None + + # Find automation comments + auto_comments = [c for c in comments if REMINDER_MARKER in c.body] + user_comments = [c for c in comments if REMINDER_MARKER not in c.body] + + # Case 1: No automation comment yet, and last comment > 30 days ago + if not auto_comments: + if last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER: + # Tag the issue author or PR author + user = issue.user.login + issue.create_comment(REMINDER_COMMENT.format(user)) + print(f"Reminded {user} on issue/PR #{issue.number}") + + # Case 2: Automation comment exists, but no user response after 30 more days + elif auto_comments: + last_auto = auto_comments[-1] + # Any user response after automation? + user_responded = any( + c.created_at > last_auto.created_at and c.user.login == issue.user.login + for c in user_comments + ) + + if not user_responded: + if (now - last_auto.created_at).days >= DAYS_BEFORE_CLOSE: + issue.create_comment(CLOSE_COMMENT) + issue.edit(state="closed") + print(f"Closed issue/PR #{issue.number} due to inactivity.") + + else: + # Remove label if user responded + labels = [l.name for l in issue.labels if l.name != LABEL] + issue.set_labels(*labels) + print(f"Removed label from issue/PR #{issue.number} after user response.") + +if __name__ == "__main__": + main() From 8d8713628c33860a933198267bdd62c4d0614be7 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 2 Sep 2025 16:15:08 -0500 Subject: [PATCH 02/13] Create pending_user_response.yml Workflow automation for addressing issues/PRs pending user response. - follows script in pending_user_response.py --- .github/workflows/pending_user_response.yml | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/pending_user_response.yml diff --git a/.github/workflows/pending_user_response.yml b/.github/workflows/pending_user_response.yml new file mode 100644 index 00000000000..298577360a3 --- /dev/null +++ b/.github/workflows/pending_user_response.yml @@ -0,0 +1,25 @@ +name: Needs User Input Automation + +on: + schedule: + - cron: '0 8 * * 1' # runs every Monday at 8:00 UTC + +jobs: + needs-user-input: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: pip install PyGithub + + - name: Run needs-user-input script + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python .github/scripts/pending_user_response.py From 440ffc81411f7564790575c72842fef820ae431d Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 2 Sep 2025 17:53:07 -0500 Subject: [PATCH 03/13] removed API calls in pending_user_response.py --- .github/workflows/pending_user_response.py | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index 1395cc58255..f0e8dd279a9 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -17,14 +17,22 @@ DAYS_BEFORE_CLOSE = 30 def main(): - g = Github(os.environ['GH_TOKEN']) - repo = g.get_repo(REPO_NAME) + # g = Github(os.environ['GH_TOKEN']) + # repo = g.get_repo(REPO_NAME) + + print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) + # issues = repo.get_issues(state='open', labels=[LABEL]) + print(f"[VALIDATION] Would fetch open issues with label '{LABEL}'.") - issues = repo.get_issues(state='open', labels=[LABEL]) now = datetime.datetime.utcnow() + # Simulate issues for validation workflow + issues = [] # Replace with mock issues if needed + for issue in issues: - comments = list(issue.get_comments()) + # comments = list(issue.get_comments()) + print(f"[VALIDATION] Would fetch comments for issue/PR #{issue.number}.") + comments = [] # Replace with mock comments if needed last_comment = comments[-1] if comments else None # Find automation comments @@ -36,8 +44,8 @@ def main(): if last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER: # Tag the issue author or PR author user = issue.user.login - issue.create_comment(REMINDER_COMMENT.format(user)) - print(f"Reminded {user} on issue/PR #{issue.number}") + # issue.create_comment(REMINDER_COMMENT.format(user)) + print(f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}") # Case 2: Automation comment exists, but no user response after 30 more days elif auto_comments: @@ -50,15 +58,15 @@ def main(): if not user_responded: if (now - last_auto.created_at).days >= DAYS_BEFORE_CLOSE: - issue.create_comment(CLOSE_COMMENT) - issue.edit(state="closed") - print(f"Closed issue/PR #{issue.number} due to inactivity.") + # issue.create_comment(CLOSE_COMMENT) + # issue.edit(state="closed") + print(f"[VALIDATION] Would close issue/PR #{issue.number} due to inactivity.") else: # Remove label if user responded labels = [l.name for l in issue.labels if l.name != LABEL] - issue.set_labels(*labels) - print(f"Removed label from issue/PR #{issue.number} after user response.") + # issue.set_labels(*labels) + print(f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response.") if __name__ == "__main__": main() From cd95949ee468ba9a71b00487c3147458bcaae152 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:47:58 -0500 Subject: [PATCH 04/13] re-enable API call to allow testing of fetching issues Uncommented start of main() [lines 21-25 impacted] --- .github/workflows/pending_user_response.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index f0e8dd279a9..e7295876132 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -17,11 +17,11 @@ DAYS_BEFORE_CLOSE = 30 def main(): - # g = Github(os.environ['GH_TOKEN']) - # repo = g.get_repo(REPO_NAME) + g = Github(os.environ['GH_TOKEN']) + repo = g.get_repo(REPO_NAME) print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) - # issues = repo.get_issues(state='open', labels=[LABEL]) + issues = repo.get_issues(state='open', labels=[LABEL]) print(f"[VALIDATION] Would fetch open issues with label '{LABEL}'.") now = datetime.datetime.utcnow() From 40eceb8a92f33f4249f4493cca9a027d32d97f46 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:52:29 -0500 Subject: [PATCH 05/13] Removed issue simulation in python script since we now fetch actual issues --- .github/workflows/pending_user_response.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index e7295876132..f71298318d0 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -26,9 +26,6 @@ def main(): now = datetime.datetime.utcnow() - # Simulate issues for validation workflow - issues = [] # Replace with mock issues if needed - for issue in issues: # comments = list(issue.get_comments()) print(f"[VALIDATION] Would fetch comments for issue/PR #{issue.number}.") From c209a62aef3bc5d2328e7a3e2fe3b659371e4a81 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:57:32 -0500 Subject: [PATCH 06/13] Update pending_user_response.py to prevent duplicate reminders Added a reminder logic to comment only if no reminder in last 7 days --- .github/workflows/pending_user_response.py | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index f71298318d0..9064a83e707 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -15,6 +15,7 @@ ) DAYS_BEFORE_REMINDER = 30 DAYS_BEFORE_CLOSE = 30 +REMINDER_COOLDOWN_DAYS = 7 # Don't post another reminder within 7 days def main(): g = Github(os.environ['GH_TOKEN']) @@ -27,7 +28,6 @@ def main(): now = datetime.datetime.utcnow() for issue in issues: - # comments = list(issue.get_comments()) print(f"[VALIDATION] Would fetch comments for issue/PR #{issue.number}.") comments = [] # Replace with mock comments if needed last_comment = comments[-1] if comments else None @@ -36,33 +36,37 @@ def main(): auto_comments = [c for c in comments if REMINDER_MARKER in c.body] user_comments = [c for c in comments if REMINDER_MARKER not in c.body] - # Case 1: No automation comment yet, and last comment > 30 days ago + # ---- REMINDER LOGIC ---- + # Only remind if NO reminder in last 7 days + recent_auto_reminder = any( + (now - c.created_at).days < REMINDER_COOLDOWN_DAYS + for c in auto_comments + ) + if not auto_comments: if last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER: - # Tag the issue author or PR author user = issue.user.login - # issue.create_comment(REMINDER_COMMENT.format(user)) print(f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}") - # Case 2: Automation comment exists, but no user response after 30 more days - elif auto_comments: + elif auto_comments and not recent_auto_reminder: + # Only post new reminder if last was > REMINDER_COOLDOWN_DAYS ago + last_auto = auto_comments[-1] + user = issue.user.login + if (now - last_auto.created_at).days >= REMINDER_COOLDOWN_DAYS: + print(f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}") + + # ---- EXISTING CLOSE/REMOVE LABEL LOGIC ---- + if auto_comments: last_auto = auto_comments[-1] - # Any user response after automation? user_responded = any( c.created_at > last_auto.created_at and c.user.login == issue.user.login for c in user_comments ) - if not user_responded: if (now - last_auto.created_at).days >= DAYS_BEFORE_CLOSE: - # issue.create_comment(CLOSE_COMMENT) - # issue.edit(state="closed") print(f"[VALIDATION] Would close issue/PR #{issue.number} due to inactivity.") - else: - # Remove label if user responded labels = [l.name for l in issue.labels if l.name != LABEL] - # issue.set_labels(*labels) print(f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response.") if __name__ == "__main__": From 78ca94068e9735e644dd6075475e27fdd15c3495 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:57:46 -0500 Subject: [PATCH 07/13] Update pending_user_response.yml to have workflow dispatch --- .github/workflows/pending_user_response.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pending_user_response.yml b/.github/workflows/pending_user_response.yml index 298577360a3..4c431c7d5cb 100644 --- a/.github/workflows/pending_user_response.yml +++ b/.github/workflows/pending_user_response.yml @@ -3,6 +3,7 @@ name: Needs User Input Automation on: schedule: - cron: '0 8 * * 1' # runs every Monday at 8:00 UTC + workflow_dispatch: jobs: needs-user-input: From 2b32d3a65e585e77b42637491c76d3677eea5f2b Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Wed, 10 Sep 2025 15:06:54 -0500 Subject: [PATCH 08/13] Update pending_user_response.py to fix lintrunner --- .github/workflows/pending_user_response.py | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index 9064a83e707..71070ca5e04 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -66,7 +66,6 @@ def main(): if (now - last_auto.created_at).days >= DAYS_BEFORE_CLOSE: print(f"[VALIDATION] Would close issue/PR #{issue.number} due to inactivity.") else: - labels = [l.name for l in issue.labels if l.name != LABEL] print(f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response.") if __name__ == "__main__": From 7fff2bff681737109fad283e62b474ae905ffe7a Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:02:57 -0500 Subject: [PATCH 09/13] Update pending_user_response.py to fix lintrunner --- .github/workflows/pending_user_response.py | 26 ++++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index 71070ca5e04..4a0e3f1e1e3 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -1,5 +1,6 @@ -import os import datetime +import os + from github import Github REPO_NAME = "pytorch/executorch" @@ -17,8 +18,9 @@ DAYS_BEFORE_CLOSE = 30 REMINDER_COOLDOWN_DAYS = 7 # Don't post another reminder within 7 days + def main(): - g = Github(os.environ['GH_TOKEN']) + g = Github(os.environ["GH_TOKEN"]) repo = g.get_repo(REPO_NAME) print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) @@ -44,16 +46,22 @@ def main(): ) if not auto_comments: - if last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER: + if ( + last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER + ): user = issue.user.login - print(f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}") + print( + f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}" + ) elif auto_comments and not recent_auto_reminder: # Only post new reminder if last was > REMINDER_COOLDOWN_DAYS ago last_auto = auto_comments[-1] user = issue.user.login if (now - last_auto.created_at).days >= REMINDER_COOLDOWN_DAYS: - print(f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}") + print( + f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}" + ) # ---- EXISTING CLOSE/REMOVE LABEL LOGIC ---- if auto_comments: @@ -64,9 +72,13 @@ def main(): ) if not user_responded: if (now - last_auto.created_at).days >= DAYS_BEFORE_CLOSE: - print(f"[VALIDATION] Would close issue/PR #{issue.number} due to inactivity.") + print( + f"[VALIDATION] Would close issue/PR #{issue.number} due to inactivity." + ) else: - print(f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response.") + print( + f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response." + ) if __name__ == "__main__": main() From 2fca973eba616a7891da7c25ab0fd2319dfe9885 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Thu, 11 Sep 2025 12:38:26 -0500 Subject: [PATCH 10/13] Update pending_user_response.py to fix lint runner --- .github/workflows/pending_user_response.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index 4a0e3f1e1e3..fe70947665f 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -24,6 +24,7 @@ def main(): repo = g.get_repo(REPO_NAME) print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) + issues = repo.get_issues(state='open', labels=[LABEL]) print(f"[VALIDATION] Would fetch open issues with label '{LABEL}'.") @@ -41,13 +42,13 @@ def main(): # ---- REMINDER LOGIC ---- # Only remind if NO reminder in last 7 days recent_auto_reminder = any( - (now - c.created_at).days < REMINDER_COOLDOWN_DAYS - for c in auto_comments + (now - c.created_at).days < REMINDER_COOLDOWN_DAYS for c in auto_comments ) if not auto_comments: if ( - last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER + last_comment + and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER ): user = issue.user.login print( From ab5b2fad5fb50397ac98da8a77e6a1b51358f11f Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:05:43 -0500 Subject: [PATCH 11/13] Update pending_user_response.py to fix lint runner --- .github/workflows/pending_user_response.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index fe70947665f..9824674bffd 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -25,7 +25,7 @@ def main(): print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) - issues = repo.get_issues(state='open', labels=[LABEL]) + issues = repo.get_issues(state="open", labels=[LABEL]) print(f"[VALIDATION] Would fetch open issues with label '{LABEL}'.") now = datetime.datetime.utcnow() @@ -60,9 +60,7 @@ def main(): last_auto = auto_comments[-1] user = issue.user.login if (now - last_auto.created_at).days >= REMINDER_COOLDOWN_DAYS: - print( - f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}" - ) + print(f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}") # ---- EXISTING CLOSE/REMOVE LABEL LOGIC ---- if auto_comments: @@ -81,5 +79,6 @@ def main(): f"[VALIDATION] Would remove label from issue/PR #{issue.number} after user response." ) + if __name__ == "__main__": main() From dc11a0e419024713150a8e092ca9837d4a3f62cc Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:37:21 -0500 Subject: [PATCH 12/13] Update pending_user_response.py to fix lintrunner --- .github/workflows/pending_user_response.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index 9824674bffd..fd49c617d7e 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -47,20 +47,19 @@ def main(): if not auto_comments: if ( - last_comment + last_comment and (now - last_comment.created_at).days >= DAYS_BEFORE_REMINDER ): user = issue.user.login - print( - f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}" - ) - + print(f"[VALIDATION] Would remind {user} on issue/PR #{issue.number}") elif auto_comments and not recent_auto_reminder: # Only post new reminder if last was > REMINDER_COOLDOWN_DAYS ago last_auto = auto_comments[-1] user = issue.user.login if (now - last_auto.created_at).days >= REMINDER_COOLDOWN_DAYS: - print(f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}") + print( + f"[VALIDATION] Would remind {user} again on issue/PR #{issue.number}" + ) # ---- EXISTING CLOSE/REMOVE LABEL LOGIC ---- if auto_comments: From 1292f326817898cd8d6f17b64e0ef59b0a9edd69 Mon Sep 17 00:00:00 2001 From: Nikhil Viswanath Sivakumar <68182521+nil-is-all@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:54:27 -0500 Subject: [PATCH 13/13] Update pending_user_response.py to fix lintrunner --- .github/workflows/pending_user_response.py | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pending_user_response.py b/.github/workflows/pending_user_response.py index fd49c617d7e..846e488e015 100644 --- a/.github/workflows/pending_user_response.py +++ b/.github/workflows/pending_user_response.py @@ -24,7 +24,6 @@ def main(): repo = g.get_repo(REPO_NAME) print("[VALIDATION] Would connect to Github and fetch repo:", REPO_NAME) - issues = repo.get_issues(state="open", labels=[LABEL]) print(f"[VALIDATION] Would fetch open issues with label '{LABEL}'.")