PyGithub MCP Server

"""Issue comments integration tests. This module tests the issue comment operations using the real GitHub API. """ import pytest from datetime import datetime, timedelta from pygithub_mcp_server.operations.issues import ( create_issue, update_issue, add_issue_comment, list_issue_comments, update_issue_comment, delete_issue_comment, ) from pygithub_mcp_server.schemas.issues import ( CreateIssueParams, UpdateIssueParams, IssueCommentParams, ListIssueCommentsParams, UpdateIssueCommentParams, DeleteIssueCommentParams, ) @pytest.mark.integration def test_add_issue_comment(test_owner, test_repo_name, unique_id, with_retry): """Test adding a comment to an issue.""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (Add Comment) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Test comment at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() # Verify assert comment["body"] == comment_body assert "id" in comment assert "user" in comment assert "created_at" in comment finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}") @pytest.mark.integration def test_list_issue_comments(test_owner, test_repo_name, unique_id, with_retry): """Test listing comments on an issue.""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (List Comments) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Test comment for listing at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() # List comments @with_retry def list_test_comments(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments = list_test_comments() # Verify assert isinstance(comments, list) assert len(comments) >= 1 # Verify our comment is in the list found = False for c in comments: if c["id"] == comment["id"]: found = True assert c["body"] == comment_body break assert found, "Test comment not found in list_issue_comments results" finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}") @pytest.mark.integration def test_update_issue_comment(test_owner, test_repo_name, unique_id, with_retry): """Test updating a comment on an issue.""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (Update Comment) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Initial comment at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() # Update the comment updated_body = f"Updated comment at {datetime.now().isoformat()}" @with_retry def update_test_comment(): return update_issue_comment(UpdateIssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], comment_id=comment["id"], body=updated_body )) updated = update_test_comment() # Verify assert updated["id"] == comment["id"] assert updated["body"] == updated_body assert updated["body"] != comment_body # List comments to verify update @with_retry def list_test_comments(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments = list_test_comments() # Verify our updated comment is in the list found = False for c in comments: if c["id"] == comment["id"]: found = True assert c["body"] == updated_body break assert found, "Updated comment not found in list_issue_comments results" finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}") @pytest.mark.integration def test_delete_issue_comment(test_owner, test_repo_name, unique_id, with_retry): """Test deleting a comment from an issue.""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (Delete Comment) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Comment to delete at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() # Verify comment exists @with_retry def list_test_comments_before(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments_before = list_test_comments_before() found_before = False for c in comments_before: if c["id"] == comment["id"]: found_before = True break assert found_before, "Comment not found before deletion" # Delete the comment @with_retry def delete_test_comment(): return delete_issue_comment(DeleteIssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], comment_id=comment["id"] )) delete_test_comment() # Verify comment is deleted @with_retry def list_test_comments_after(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments_after = list_test_comments_after() for c in comments_after: assert c["id"] != comment["id"], "Comment still exists after deletion" finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}") @pytest.mark.integration def test_list_issue_comments_since(test_owner, test_repo_name, unique_id, with_retry): """Test listing comments on an issue with since parameter.""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (List Comments Since) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Test comment for since filter at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() # Get the current time now = datetime.now() # Set since to 1 hour ago since = now - timedelta(hours=1) # List comments since 1 hour ago @with_retry def list_test_comments_since(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"], since=since.isoformat() + "Z" # Add UTC timezone indicator )) recent_comments = list_test_comments_since() # Verify our comment is in the list found = False for c in recent_comments: if c["id"] == comment["id"]: found = True assert c["body"] == comment_body break assert found, "Test comment not found in since filter results" # Set since to 24 hours in the future to ensure timezone differences are covered future = now + timedelta(hours=24) # List comments since 1 hour in the future @with_retry def list_test_comments_future(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"], since=future.isoformat() + "Z" # Add UTC timezone indicator )) future_comments = list_test_comments_future() # Verify our comment is not in the list for c in future_comments: assert c["id"] != comment["id"], "Comment found with future since filter" finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}") @pytest.mark.integration def test_comment_lifecycle(test_owner, test_repo_name, unique_id, with_retry): """Test complete comment lifecycle (add → list → update → delete).""" # Setup owner = test_owner repo = test_repo_name title = f"Test Issue (Comment Lifecycle) {unique_id}" # Create an issue @with_retry def create_test_issue(): return create_issue(CreateIssueParams( owner=owner, repo=repo, title=title )) issue = create_test_issue() try: # Add a comment comment_body = f"Initial comment at {datetime.now().isoformat()}" @with_retry def add_test_comment(): return add_issue_comment(IssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], body=comment_body )) comment = add_test_comment() assert comment["body"] == comment_body # List comments @with_retry def list_test_comments(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments = list_test_comments() found = False for c in comments: if c["id"] == comment["id"]: found = True break assert found, "Comment not found in list after adding" # Update comment updated_body = f"Updated comment at {datetime.now().isoformat()}" @with_retry def update_test_comment(): return update_issue_comment(UpdateIssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], comment_id=comment["id"], body=updated_body )) updated = update_test_comment() assert updated["body"] == updated_body # List comments again to verify update @with_retry def list_test_comments_after_update(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments_after_update = list_test_comments_after_update() found_updated = False for c in comments_after_update: if c["id"] == comment["id"]: found_updated = True assert c["body"] == updated_body break assert found_updated, "Updated comment not found in list" # Delete comment @with_retry def delete_test_comment(): return delete_issue_comment(DeleteIssueCommentParams( owner=owner, repo=repo, issue_number=issue["issue_number"], comment_id=comment["id"] )) delete_test_comment() # List comments again to verify deletion @with_retry def list_test_comments_after_delete(): return list_issue_comments(ListIssueCommentsParams( owner=owner, repo=repo, issue_number=issue["issue_number"] )) comments_after_delete = list_test_comments_after_delete() for c in comments_after_delete: assert c["id"] != comment["id"], "Comment still exists after deletion" finally: # Cleanup try: @with_retry def close_issue(): return update_issue(UpdateIssueParams( owner=owner, repo=repo, issue_number=issue["issue_number"], state="closed" )) close_issue() except Exception as e: print(f"Failed to close issue during cleanup: {e}")