Close an issue with optional comment.
(
self,
issue_number: int,
reason: str = "completed",
comment: str | None = None,
)
| 447 | return {"success": False, "error": str(e)} |
| 448 | |
| 449 | async def close_issue( |
| 450 | self, |
| 451 | issue_number: int, |
| 452 | reason: str = "completed", |
| 453 | comment: str | None = None, |
| 454 | ) -> dict: |
| 455 | """Close an issue with optional comment.""" |
| 456 | if not self._has_auth(): |
| 457 | return {"success": False, "error": "GitHub token not configured"} |
| 458 | |
| 459 | url = f"https://api.github.com/repos/{config.github_repo}/issues/{issue_number}" |
| 460 | |
| 461 | # Map reason to GitHub's state_reason |
| 462 | state_reason = "completed" if reason == "completed" else "not_planned" |
| 463 | |
| 464 | try: |
| 465 | session = await self.get_session() |
| 466 | |
| 467 | # Add comment first if provided |
| 468 | if comment: |
| 469 | await self.add_comment(issue_number, comment, "Admin") |
| 470 | |
| 471 | # Close the issue |
| 472 | async with session.patch( |
| 473 | url, |
| 474 | json={"state": "closed", "state_reason": state_reason}, |
| 475 | headers=await self._get_headers(), |
| 476 | timeout=aiohttp.ClientTimeout(total=10), |
| 477 | ) as response: |
| 478 | if response.status == 200: |
| 479 | logger.info(f"Closed issue #{issue_number} ({reason})") |
| 480 | return { |
| 481 | "success": True, |
| 482 | "issue_number": issue_number, |
| 483 | "issue_url": f"https://github.com/{config.github_repo}/issues/{issue_number}", |
| 484 | } |
| 485 | else: |
| 486 | return { |
| 487 | "success": False, |
| 488 | "error": f"GitHub API error: {response.status}", |
| 489 | } |
| 490 | except Exception as e: |
| 491 | logger.error(f"Error closing issue: {e}") |
| 492 | return {"success": False, "error": str(e)} |
| 493 | |
| 494 | async def reopen_issue(self, issue_number: int, comment: str | None = None) -> dict: |
| 495 | """Reopen a closed issue.""" |
no test coverage detected