[Gap Analysis] Missing CRUD Operations for Issues and Pull Requests in gitea/dev.py #3

Closed
opened 2026-01-15 11:42:35 +00:00 by xcaliber · 0 comments
Owner

Summary

The gitea/dev.py tool provides partial Gitea API coverage but is missing critical CRUD operations for Issues and Pull Requests. This limits autonomous LLM workflows that require reading, updating, or commenting on artifacts.


Current Coverage Assessment

Implemented Functions (17 total)

Category Functions
Repos list_repos, get_repo
Files list_files, get_file, create_file, update_file, delete_file
Branches list_branches, create_branch
Commits list_commits, get_commit
Issues list_issues, create_issue
PRs list_pull_requests, create_pull_request
Context get_project_context

Missing Functions (16 total)

Issues (8 missing)

# READ - Single issue retrieval
async def get_issue(issue_number: int, repo: str = None) -> str

# UPDATE - Edit issue
async def update_issue(
    issue_number: int,
    title: str = None,
    body: str = None,
    state: str = None,  # "open" | "closed"
    repo: str = None,
    assignee: str = None,
) -> str

# UPDATE - State transitions
async def close_issue(issue_number: int, repo: str = None) -> str
async def reopen_issue(issue_number: int, repo: str = None) -> str

# DELETE
async def delete_issue(issue_number: int, repo: str = None) -> str

# COMMENTS - CRUD
async def list_issue_comments(issue_number: int, repo: str = None) -> str
async def create_issue_comment(issue_number: int, body: str, repo: str = None) -> str
async def update_issue_comment(comment_id: int, body: str, repo: str = None) -> str
async def delete_issue_comment(comment_id: int, repo: str = None) -> str

Pull Requests (8 missing)

# READ
async def get_pull_request(pr_number: int, repo: str = None) -> str

# UPDATE
async def update_pull_request(
    pr_number: int,
    title: str = None,
    body: str = None,
    repo: str = None,
) -> str

# ACTION
async def merge_pull_request(
    pr_number: int,
    merge_strategy: str = "merge",  # "merge" | "rebase" | "squash"
    repo: str = None,
) -> str

# COMMENTS - CRUD
async def list_pull_request_comments(pr_number: int, repo: str = None) -> str
async def create_pull_request_comment(pr_number: int, body: str, repo: str = None) -> str
async def update_pull_request_comment(comment_id: int, body: str, repo: str = None) -> str
async def delete_pull_request_comment(comment_id: int, repo: str = None) -> str

Gap Matrix

Resource Create Read (List) Read (One) Update Delete Comments
Issue
Pull Request

Impact on LLM Autonomy

Blocked Workflows

  1. Issue Triage Loop

    1. list_issues → find new issue
    2. get_issue → read full details ← MISSING
    3. update_issue → add labels/assignee ← MISSING
    4. create_issue_comment → request clarification ← MISSING
    
  2. PR Review Automation

    1. list_pull_requests → find PR
    2. get_pull_request → read diff/context ← MISSING
    3. create_pull_request_comment → add review comments ← MISSING
    
  3. Stale Issue Management

    1. list_issues (state="open", labels="stale")
    2. create_issue_comment → notify author ← MISSING
    3. close_issue → auto-close ← MISSING
    

Gitea API Endpoints Required

Operation Endpoint
Get issue GET /repos/{owner}/{repo}/issues/{index}
Update issue PATCH /repos/{owner}/{repo}/issues/{index}
Delete issue DELETE /repos/{owner}/{repo}/issues/{index}
List issue comments GET /repos/{owner}/{repo}/issues/{index}/comments
Create issue comment POST /repos/{owner}/{repo}/issues/{index}/comments
Get PR GET /repos/{owner}/{repo}/pulls/{index}
Update PR PATCH /repos/{owner}/{repo}/pulls/{index}
Merge PR POST /repos/{owner}/{repo}/pulls/{index}/merge
List PR reviews GET /repos/{owner}/{repo}/pulls/{index}/reviews

  1. High: get_issue, get_pull_request - Block reading individual items
  2. High: update_issue, update_pull_request - Block editing artifacts
  3. Medium: create_issue_comment, create_pull_request_comment - Block feedback loops
  4. Medium: close_issue, reopen_issue - State management
  5. Low: list_issue_comments, list_pull_request_comments - Read-only context
  6. Low: Delete operations - Destructive, lower priority

Reference Implementation Pattern

async def get_issue(
    self,
    issue_number: int,
    repo: Optional[str] = None,
    __user__: dict = None,
) -> str:
    """Get detailed issue information."""
    token = self._get_token(__user__)
    if not token:
        return "Error: GITEA_TOKEN not configured."

    owner, repo_name = self._resolve_repo(repo, __user__)

    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(
                self._api_url(f"/repos/{owner}/{repo_name}/issues/{issue_number}"),
                headers=self._headers(__user__),
            )
            response.raise_for_status()
            issue = response.json()

        # Format output (similar to existing patterns)
        output = f"# Issue #{issue_number}\n\n"
        output += f"**Title:** {issue.get('title')}\n"
        output += f"**State:** {issue.get('state')}\n"
        output += f"**Author:** {issue.get('user', {}).get('login')}\n"
        output += f"**Body:**\n{issue.get('body', 'No description')}\n"
        return output

    except httpx.HTTPStatusError as e:
        return self._format_error(e, f"issue {issue_number}")

Next Steps

Add the missing functions following the established patterns in gitea/dev.py:

  • Use same _resolve_repo, _headers, _format_error helpers
  • Match existing response formatting style
  • Include proper error handling for 404 (not found), 403 (forbidden), 401 (unauthorized)
  • Add pagination support for list operations
## Summary The `gitea/dev.py` tool provides partial Gitea API coverage but is missing critical CRUD operations for Issues and Pull Requests. This limits autonomous LLM workflows that require reading, updating, or commenting on artifacts. --- ## Current Coverage Assessment ### ✅ Implemented Functions (17 total) | Category | Functions | |----------|-----------| | **Repos** | `list_repos`, `get_repo` | | **Files** | `list_files`, `get_file`, `create_file`, `update_file`, `delete_file` | | **Branches** | `list_branches`, `create_branch` | | **Commits** | `list_commits`, `get_commit` | | **Issues** | `list_issues`, `create_issue` | | **PRs** | `list_pull_requests`, `create_pull_request` | | **Context** | `get_project_context` | ### ❌ Missing Functions (16 total) #### Issues (8 missing) ```python # READ - Single issue retrieval async def get_issue(issue_number: int, repo: str = None) -> str # UPDATE - Edit issue async def update_issue( issue_number: int, title: str = None, body: str = None, state: str = None, # "open" | "closed" repo: str = None, assignee: str = None, ) -> str # UPDATE - State transitions async def close_issue(issue_number: int, repo: str = None) -> str async def reopen_issue(issue_number: int, repo: str = None) -> str # DELETE async def delete_issue(issue_number: int, repo: str = None) -> str # COMMENTS - CRUD async def list_issue_comments(issue_number: int, repo: str = None) -> str async def create_issue_comment(issue_number: int, body: str, repo: str = None) -> str async def update_issue_comment(comment_id: int, body: str, repo: str = None) -> str async def delete_issue_comment(comment_id: int, repo: str = None) -> str ``` #### Pull Requests (8 missing) ```python # READ async def get_pull_request(pr_number: int, repo: str = None) -> str # UPDATE async def update_pull_request( pr_number: int, title: str = None, body: str = None, repo: str = None, ) -> str # ACTION async def merge_pull_request( pr_number: int, merge_strategy: str = "merge", # "merge" | "rebase" | "squash" repo: str = None, ) -> str # COMMENTS - CRUD async def list_pull_request_comments(pr_number: int, repo: str = None) -> str async def create_pull_request_comment(pr_number: int, body: str, repo: str = None) -> str async def update_pull_request_comment(comment_id: int, body: str, repo: str = None) -> str async def delete_pull_request_comment(comment_id: int, repo: str = None) -> str ``` --- ## Gap Matrix | Resource | Create | Read (List) | Read (One) | Update | Delete | Comments | |----------|--------|-------------|------------|--------|--------|----------| | Issue | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | | Pull Request | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | --- ## Impact on LLM Autonomy ### Blocked Workflows 1. **Issue Triage Loop** ``` 1. list_issues → find new issue 2. get_issue → read full details ← MISSING 3. update_issue → add labels/assignee ← MISSING 4. create_issue_comment → request clarification ← MISSING ``` 2. **PR Review Automation** ``` 1. list_pull_requests → find PR 2. get_pull_request → read diff/context ← MISSING 3. create_pull_request_comment → add review comments ← MISSING ``` 3. **Stale Issue Management** ``` 1. list_issues (state="open", labels="stale") 2. create_issue_comment → notify author ← MISSING 3. close_issue → auto-close ← MISSING ``` --- ## Gitea API Endpoints Required | Operation | Endpoint | |-----------|----------| | Get issue | `GET /repos/{owner}/{repo}/issues/{index}` | | Update issue | `PATCH /repos/{owner}/{repo}/issues/{index}` | | Delete issue | `DELETE /repos/{owner}/{repo}/issues/{index}` | | List issue comments | `GET /repos/{owner}/{repo}/issues/{index}/comments` | | Create issue comment | `POST /repos/{owner}/{repo}/issues/{index}/comments` | | Get PR | `GET /repos/{owner}/{repo}/pulls/{index}` | | Update PR | `PATCH /repos/{owner}/{repo}/pulls/{index}` | | Merge PR | `POST /repos/{owner}/{repo}/pulls/{index}/merge` | | List PR reviews | `GET /repos/{owner}/{repo}/pulls/{index}/reviews` | --- ## Recommended Priority 1. **High**: `get_issue`, `get_pull_request` - Block reading individual items 2. **High**: `update_issue`, `update_pull_request` - Block editing artifacts 3. **Medium**: `create_issue_comment`, `create_pull_request_comment` - Block feedback loops 4. **Medium**: `close_issue`, `reopen_issue` - State management 5. **Low**: `list_issue_comments`, `list_pull_request_comments` - Read-only context 6. **Low**: Delete operations - Destructive, lower priority --- ## Reference Implementation Pattern ```python async def get_issue( self, issue_number: int, repo: Optional[str] = None, __user__: dict = None, ) -> str: """Get detailed issue information.""" token = self._get_token(__user__) if not token: return "Error: GITEA_TOKEN not configured." owner, repo_name = self._resolve_repo(repo, __user__) try: async with httpx.AsyncClient(timeout=30.0) as client: response = await client.get( self._api_url(f"/repos/{owner}/{repo_name}/issues/{issue_number}"), headers=self._headers(__user__), ) response.raise_for_status() issue = response.json() # Format output (similar to existing patterns) output = f"# Issue #{issue_number}\n\n" output += f"**Title:** {issue.get('title')}\n" output += f"**State:** {issue.get('state')}\n" output += f"**Author:** {issue.get('user', {}).get('login')}\n" output += f"**Body:**\n{issue.get('body', 'No description')}\n" return output except httpx.HTTPStatusError as e: return self._format_error(e, f"issue {issue_number}") ``` --- ## Next Steps Add the missing functions following the established patterns in `gitea/dev.py`: - Use same `_resolve_repo`, `_headers`, `_format_error` helpers - Match existing response formatting style - Include proper error handling for 404 (not found), 403 (forbidden), 401 (unauthorized) - Add pagination support for list operations
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: open-webui-automation/tools#3
No description provided.