Add dedicated issue closing functionality for easier issue management: 📄 New Module: tddai/issue_closer.py • Dedicated IssueCloser class with programmatic API • Command-line interface for manual and batch issue closure • Enhanced functionality beyond existing tddai_cli.py close-issue • Support for standardized completion messages • Batch closure capability for multiple issues 🔧 Makefile Integration: • close-issue-enhanced - Enhanced single issue closure with work completion • close-issues-batch - Batch closure for multiple issues • Proper help documentation and .PHONY declarations ✨ Key Features: • Simple programmatic interface: IssueCloser().close_issue(42, "comment") • CLI with multiple closure modes: comment, work-completed, batch • Integration with existing tddai framework and issue tracking backends • Comprehensive error handling and user feedback • Verbose mode for detailed operation tracking 📋 Usage Examples: • python3 tddai/issue_closer.py 42 -w "All tests passing" • python3 tddai/issue_closer.py 42 43 44 -c "Batch closure" • make close-issue-enhanced NUM=42 WORK="Implementation complete" • make close-issues-batch NUMS="42 43 44" COMMENT="Sprint completion" Provides the missing tddai function to close issues more easily with the selected issue tracking backend. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
180 lines
5.4 KiB
Python
180 lines
5.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
TDDAi Issue Closer
|
|
|
|
A dedicated module for closing issues in the selected issue tracking backend.
|
|
Provides both programmatic API and CLI functionality for easy issue closure.
|
|
|
|
This module integrates with the existing tddai framework and provides:
|
|
- Simple programmatic interface for closing issues
|
|
- Command-line utility for manual issue closure
|
|
- Integration with existing issue tracking backends
|
|
- Proper error handling and user feedback
|
|
"""
|
|
|
|
import sys
|
|
import argparse
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
# Add project root to path for imports
|
|
project_root = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from cli import CLIFramework
|
|
from services import IssueService
|
|
from tddai import TddaiError
|
|
|
|
|
|
class IssueCloser:
|
|
"""Dedicated class for closing issues with the configured backend."""
|
|
|
|
def __init__(self):
|
|
"""Initialize the issue closer with CLI framework."""
|
|
self.cli = CLIFramework()
|
|
self.service = IssueService()
|
|
|
|
def close_issue(self, issue_number: int, comment: str = "") -> bool:
|
|
"""
|
|
Close an issue with optional comment.
|
|
|
|
Args:
|
|
issue_number: The issue number to close
|
|
comment: Optional closing comment
|
|
|
|
Returns:
|
|
bool: True if issue was closed successfully, False otherwise
|
|
"""
|
|
try:
|
|
self.cli.close_issue(issue_number, comment)
|
|
return True
|
|
except TddaiError as e:
|
|
print(f"Error closing issue #{issue_number}: {e}")
|
|
return False
|
|
except Exception as e:
|
|
print(f"Unexpected error closing issue #{issue_number}: {e}")
|
|
return False
|
|
|
|
def close_with_completion_message(self, issue_number: int, completed_work: str) -> bool:
|
|
"""
|
|
Close an issue with a standardized completion message.
|
|
|
|
Args:
|
|
issue_number: The issue number to close
|
|
completed_work: Description of what was completed
|
|
|
|
Returns:
|
|
bool: True if issue was closed successfully, False otherwise
|
|
"""
|
|
completion_comment = f"✅ Completed: {completed_work}"
|
|
return self.close_issue(issue_number, completion_comment)
|
|
|
|
def close_multiple_issues(self, issue_numbers: list, comment: str = "") -> dict:
|
|
"""
|
|
Close multiple issues with the same comment.
|
|
|
|
Args:
|
|
issue_numbers: List of issue numbers to close
|
|
comment: Comment to add to all issues
|
|
|
|
Returns:
|
|
dict: Results with 'successful' and 'failed' lists
|
|
"""
|
|
results = {'successful': [], 'failed': []}
|
|
|
|
for issue_num in issue_numbers:
|
|
if self.close_issue(issue_num, comment):
|
|
results['successful'].append(issue_num)
|
|
else:
|
|
results['failed'].append(issue_num)
|
|
|
|
return results
|
|
|
|
|
|
def main():
|
|
"""Command-line interface for the issue closer."""
|
|
parser = argparse.ArgumentParser(
|
|
description="TDDAi Issue Closer - Close issues in the configured tracking backend",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
python3 issue_closer.py 42 # Close issue #42
|
|
python3 issue_closer.py 42 -c "Fixed the bug" # Close with comment
|
|
python3 issue_closer.py 42 -w "All tests passing" # Close with completion message
|
|
python3 issue_closer.py 42 43 44 # Close multiple issues
|
|
python3 issue_closer.py 42 43 -c "Batch closure" # Close multiple with comment
|
|
|
|
Integration with existing tddai CLI:
|
|
python3 tddai_cli.py close-issue 42 --comment "Done" # Alternative method
|
|
"""
|
|
)
|
|
|
|
parser.add_argument(
|
|
'issue_numbers',
|
|
type=int,
|
|
nargs='+',
|
|
help='Issue number(s) to close'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'-c', '--comment',
|
|
type=str,
|
|
default='',
|
|
help='Optional closing comment'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'-w', '--work-completed',
|
|
type=str,
|
|
help='Description of completed work (creates standardized completion message)'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'-v', '--verbose',
|
|
action='store_true',
|
|
help='Enable verbose output'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Initialize issue closer
|
|
closer = IssueCloser()
|
|
|
|
# Determine which closing method to use
|
|
if args.work_completed:
|
|
comment = f"✅ Completed: {args.work_completed}"
|
|
else:
|
|
comment = args.comment
|
|
|
|
# Handle single or multiple issues
|
|
if len(args.issue_numbers) == 1:
|
|
issue_num = args.issue_numbers[0]
|
|
if args.verbose:
|
|
print(f"Closing issue #{issue_num}...")
|
|
if comment:
|
|
print(f"Comment: {comment}")
|
|
|
|
success = closer.close_issue(issue_num, comment)
|
|
sys.exit(0 if success else 1)
|
|
|
|
else:
|
|
# Multiple issues
|
|
if args.verbose:
|
|
print(f"Closing {len(args.issue_numbers)} issues...")
|
|
if comment:
|
|
print(f"Comment: {comment}")
|
|
|
|
results = closer.close_multiple_issues(args.issue_numbers, comment)
|
|
|
|
if results['successful']:
|
|
print(f"✅ Successfully closed: {results['successful']}")
|
|
|
|
if results['failed']:
|
|
print(f"❌ Failed to close: {results['failed']}")
|
|
sys.exit(1)
|
|
|
|
print(f"✅ All {len(args.issue_numbers)} issues closed successfully!")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main() |