21eefd9824
- IssueTools.get_issue now returns IssueModel instead of JSON string - PRTools.get_pull_request now returns PullRequestModel instead of JSON string - PRTools.create_pull_request now returns PullRequestModel instead of JSON string - PRTools.update_pull_request now returns PullRequestModel instead of JSON string - All methods have proper return type hints and raise exceptions on error - Updated tests to verify model objects are returned directly - Marked issue 5.4 as resolved in bad_code.md
129 lines
4.7 KiB
Python
129 lines
4.7 KiB
Python
"""Tools for Gitea issue operations."""
|
||
|
||
import json
|
||
import logging
|
||
from typing import Any
|
||
from gitea.client import GiteaClient
|
||
from gitea.models import IssueModel, CommentModel, LabelModel
|
||
|
||
logger: logging.Logger = logging.getLogger("gitea.tools.issue_tools")
|
||
|
||
|
||
class IssueTools:
|
||
"""Tools for Gitea issue operations."""
|
||
|
||
def __init__(self, client: GiteaClient) -> None:
|
||
self._client = client
|
||
|
||
def get_issue(self, owner: str, repo: str, issue_number: int) -> IssueModel:
|
||
try:
|
||
return self._client.issues.get_issue(owner, repo, issue_number)
|
||
except Exception as e:
|
||
logger.error(f"Error getting issue #{issue_number}: {e}", exc_info=True)
|
||
raise
|
||
|
||
def close_issue(self, owner: str, repo: str, issue_number: int) -> str:
|
||
try:
|
||
self._client.issues.close_issue(owner, repo, issue_number)
|
||
return f"Issue #{issue_number} closed successfully."
|
||
except Exception as e:
|
||
return f"Error closing issue: {str(e)}"
|
||
|
||
def get_issue_comments(
|
||
self,
|
||
owner: str,
|
||
repo: str,
|
||
issue_number: int,
|
||
limit: int = 20,
|
||
offset: int = 0,
|
||
) -> str:
|
||
"""Get comments on an issue with optional paging.
|
||
|
||
Args:
|
||
limit: Maximum number of comments to return (default 20).
|
||
offset: Zero-based comment index to start from (default 0).
|
||
"""
|
||
try:
|
||
comments: list[CommentModel] = self._client.issues.get_issue_comments(
|
||
owner, repo, issue_number
|
||
)
|
||
total: int = len(comments)
|
||
page: list[CommentModel] = comments[offset : offset + limit]
|
||
result: str = json.dumps([c.model_dump() for c in page], indent=2)
|
||
if total > offset + limit:
|
||
next_offset: int = offset + limit
|
||
result += (
|
||
f"\n\n[{total} comments total — showing {offset}–{offset + len(page)}. "
|
||
f"Re-call with offset={next_offset} to see more.]"
|
||
)
|
||
return result
|
||
except Exception as e:
|
||
return f"Error getting issue comments: {str(e)}"
|
||
|
||
def list_assigned_issues(self) -> list[dict[str, Any]]:
|
||
try:
|
||
repos = self._client.repos.list_all_user_repos()
|
||
all_issues: list[dict[str, Any]] = []
|
||
for repo in repos:
|
||
owner = repo.owner
|
||
repo_name = repo.name
|
||
issues = self._client.issues.list_assigned_issues(owner, repo_name)
|
||
if issues:
|
||
all_issues.extend(
|
||
[
|
||
issue.model_dump()
|
||
if hasattr(issue, "model_dump")
|
||
else issue
|
||
for issue in issues
|
||
]
|
||
)
|
||
return all_issues
|
||
except Exception as e:
|
||
logger.error(f"Error listing assigned issues: {e}", exc_info=True)
|
||
return []
|
||
|
||
def list_issues(self, owner: str, repo: str, state: str = "open") -> str:
|
||
try:
|
||
issues = self._client.issues.list_repo_issues(owner, repo, state)
|
||
if not issues:
|
||
return f"No issues in {owner}/{repo}."
|
||
summary = [f"#{issue.number}: {issue.title}" for issue in issues]
|
||
return "\n".join(summary)
|
||
except Exception as e:
|
||
return f"Error listing issues: {str(e)}"
|
||
|
||
def create_issue(
|
||
self,
|
||
owner: str,
|
||
repo: str,
|
||
title: str,
|
||
body: str,
|
||
labels: list[str] | None = None,
|
||
assignees: list[str] | None = None,
|
||
) -> str:
|
||
try:
|
||
issue = self._client.issues.create_issue(
|
||
owner, repo, title, body, labels, assignees
|
||
)
|
||
return f"Issue #{issue.number} created successfully in {owner}/{repo}."
|
||
except Exception as e:
|
||
return f"Error creating issue: {str(e)}"
|
||
|
||
def add_label_to_issue(
|
||
self, owner: str, repo: str, issue_number: int, label: str
|
||
) -> str:
|
||
try:
|
||
self._client.issues.add_label(owner, repo, issue_number, label)
|
||
return f"Label '{label}' added to issue #{issue_number}."
|
||
except Exception as e:
|
||
return f"Error adding label to issue #{issue_number}: {e}"
|
||
|
||
def add_comment_to_issue(
|
||
self, owner: str, repo: str, issue_number: int, body: str
|
||
) -> str:
|
||
try:
|
||
self._client.issues.add_comment(owner, repo, issue_number, body)
|
||
return f"Comment added to issue #{issue_number}."
|
||
except Exception as e:
|
||
return f"Error adding comment to issue #{issue_number}: {e}"
|