Skip to content

/wait github command#302

Open
itayd wants to merge 2 commits intomainfrom
itay/wait
Open

/wait github command#302
itayd wants to merge 2 commits intomainfrom
itay/wait

Conversation

@itayd
Copy link
Member

@itayd itayd commented Dec 9, 2025

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new GitHub bot that helps reviewers track PRs and issues that are waiting for author updates. The bot responds to /wait and /wait-any slash commands to add labels, and automatically removes these labels when the author pushes code or adds comments.

Key Changes

  • Implements two wait modes: /wait (removed on code push only) and /wait-any (removed on push or comment)
  • Automatically manages "waiting" and "waiting:any" labels based on PR/issue activity
  • Provides visual feedback via emoji reactions on command execution

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

File Description
github_wait/handlers.py Core event handlers for slash commands, PR sync, and comment events with automatic label management
github_wait/autokitteh.yaml Configuration defining GitHub connection, event triggers, and filtering logic
github_wait/README.md Comprehensive documentation covering features, usage, deployment, and implementation details
github_wait/Makefile Build tooling for linting, formatting, type checking, and deployment

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +38 to +40
issue: _IssueOrPR = repo.get_issue(number=data.issue.number)
elif data.get("pull_request"):
issue = repo.get_pull(number=data.pull_request.number)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name issue is used for both issues and pull requests, which can be confusing. Consider using a more generic name like item, target, or issue_or_pr to better reflect that it can hold either type. The type alias _IssueOrPR already exists and could inform a better name.

Copilot uses AI. Check for mistakes.
if data.get("issue"):
issue: _IssueOrPR = repo.get_issue(number=data.issue.number)
elif data.get("pull_request"):
issue = repo.get_pull(number=data.pull_request.number)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue variable may be undefined if neither data.get("issue") nor data.get("pull_request") is truthy. This would cause a NameError when _label(issue, ...) is called on line 42. Consider adding an else clause to handle this case or ensure that at least one condition is always met based on the event filter.

Suggested change
issue = repo.get_pull(number=data.pull_request.number)
issue = repo.get_pull(number=data.pull_request.number)
else:
print("Error: neither issue nor pull_request found in event data")
return

Copilot uses AI. Check for mistakes.
call: handlers.py:on_pull_request_review_comment
filter: "data.action == 'created'"

- # On a new review , remove wait-any labels unless the comment is a command.
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space before comma. Should be "review," not "review ,".

Suggested change
- # On a new review , remove wait-any labels unless the comment is a command.
- # On a new review, remove wait-any labels unless the comment is a command.

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +126
def on_issue_comment(event: Event) -> None:
data = event.data

if not any(
label["name"] in [_waiting_any_label, _waiting_push_label]
for label in data.issue.labels
):
print("not waiting, ignored")
return

if data.slash_commands and any(
cmd["name"] in ["wait", "wait-any"] for cmd in data.slash_commands
):
# Don't remove labels if this comment is a command.
print("comment contains wait command, ignored")
return

repo = github.get_repo(data.repository.full_name)
issue = repo.get_issue(data.issue.number)

# Remove only wait-any label on new comment.
_label(issue, adds=[], removes=[_waiting_any_label])


def on_pull_request_review_comment(event: Event) -> None:
data = event.data

if not any(
label["name"] in [_waiting_any_label, _waiting_push_label]
for label in data.pull_request.labels
):
print("not waiting, ignored")
return

if data.slash_commands and any(
cmd["name"] in ["wait", "wait-any"] for cmd in data.slash_commands
):
# Don't remove labels if this comment is a command.
print("comment contains wait command, ignored")
return

repo = github.get_repo(data.repository.full_name)
pr = repo.get_pull(data.pull_request.number)

# Remove only wait-any label on new comment.
_label(pr, adds=[], removes=[_waiting_any_label])


def on_pull_request_review(event: Event) -> None:
data = event.data

if not any(
label["name"] in [_waiting_any_label, _waiting_push_label]
for label in data.pull_request.labels
):
print("not waiting, ignored")
return

if data.slash_commands and any(
cmd["name"] in ["wait", "wait-any"] for cmd in data.slash_commands
):
# Don't remove labels if this comment is a command.
print("comment contains wait command, ignored")
return

repo = github.get_repo(data.repository.full_name)
pr = repo.get_pull(data.pull_request.number)

# Remove only wait-any label on new comment.
_label(pr, adds=[], removes=[_waiting_any_label])
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions on_issue_comment, on_pull_request_review_comment, and on_pull_request_review contain nearly identical logic (lines 57-78, 81-102, and 105-126). Consider extracting the common logic into a helper function that accepts the event data and the appropriate data field accessor (e.g., data.issue vs data.pull_request) to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
- **`waiting`**: Indicates waiting for code changes (push events only)
- **`waiting:any`**: Indicates waiting for any activity (comments or code changes)

These labels should be created in your repository. The bot will create them automatically on first use if they don't exist.
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states "The bot will create them automatically on first use if they don't exist." However, the code in handlers.py uses issue.add_to_labels(add) without explicit label creation logic. Verify that PyGithub's add_to_labels() method automatically creates non-existent labels, or update the documentation to clarify that labels should be pre-created in the repository.

Suggested change
These labels should be created in your repository. The bot will create them automatically on first use if they don't exist.
**Important:** These labels must be created manually in your repository before using the bot. The bot does not create labels automatically.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to +181
- **Reviewer Comments**: When reviewers add more comments (including wait commands), labels stay in place
- **Author Comments**: Comments from the author remove the `waiting:any` label (but not `waiting`)
- **Code Pushes**: New commits from the author remove both `waiting` and `waiting:any` labels
- **Reviews**: New review submissions remove the `waiting:any` label

This means reviewers can continue discussing without accidentally removing the waiting state - only author activity triggers label removal.
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states that "Reviewer Comments" keep labels in place and only "Author Comments" remove the waiting:any label. However, the implementation in handlers.py (lines 57-78, 81-102, 105-126) removes the waiting:any label on ANY comment (unless it contains a wait command), regardless of who posted it. The code does not differentiate between reviewer and author comments. Either the documentation should be updated to reflect the actual behavior, or the code should be modified to check the comment author and only remove labels for author comments.

Suggested change
- **Reviewer Comments**: When reviewers add more comments (including wait commands), labels stay in place
- **Author Comments**: Comments from the author remove the `waiting:any` label (but not `waiting`)
- **Code Pushes**: New commits from the author remove both `waiting` and `waiting:any` labels
- **Reviews**: New review submissions remove the `waiting:any` label
This means reviewers can continue discussing without accidentally removing the waiting state - only author activity triggers label removal.
- **Comments**: Any new comment (unless it contains a wait command) removes the `waiting:any` label, regardless of whether it is from the author or a reviewer.
- **Code Pushes**: New commits from the author remove both `waiting` and `waiting:any` labels
- **Reviews**: New review submissions remove the `waiting:any` label
This means that any activity in the form of a comment will remove the `waiting:any` label, so reviewers and authors alike can trigger label removal.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants