"""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) -> str: try: issue: IssueModel = self._client.issues.get_issue(owner, repo, issue_number) return issue.model_dump_json(indent=2) except Exception as e: return f"Error getting issue: {str(e)}" 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}"