feat: Complete Issue #79 - Provide tddai issue_closer.py
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>
This commit is contained in:
47
Makefile
47
Makefile
@@ -1,7 +1,7 @@
|
||||
# MarkiTect - Advanced Markdown Engine
|
||||
# Makefile for common development tasks
|
||||
|
||||
.PHONY: help setup install test build clean update status dev lint format check-deps venv-status update-digest add-diary-entry list-issues show-issue list-open-issues close-issue test-from-issue tdd-start tdd-add-test tdd-finish tdd-status test-status test-new test-coverage test-arch test-foundation test-infrastructure test-integration test-domain test-service test-application test-presentation test-quick test-layers test-random test-random-seed test-random-repeat test-install-randomly test-clean test-tdd test-changed test-module test-cache-clean test-efficient cli-help
|
||||
.PHONY: help setup install test build clean update status dev lint format check-deps venv-status update-digest add-diary-entry list-issues show-issue list-open-issues close-issue close-issue-enhanced close-issues-batch test-from-issue tdd-start tdd-add-test tdd-finish tdd-status test-status test-new test-coverage test-arch test-foundation test-infrastructure test-integration test-domain test-service test-application test-presentation test-quick test-layers test-random test-random-seed test-random-repeat test-install-randomly test-clean test-tdd test-changed test-module test-cache-clean test-efficient cli-help
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@@ -66,7 +66,9 @@ help:
|
||||
@echo " list-issues - Show all gitea issues with status and priority"
|
||||
@echo " list-open-issues - Show only open issues (active backlog)"
|
||||
@echo " show-issue NUM=X - Show detailed view of specific issue"
|
||||
@echo " close-issue NUM=X - Close an issue and mark as completed"
|
||||
@echo " close-issue NUM=X [COMMENT='reason'] - Close an issue and mark as completed"
|
||||
@echo " close-issue-enhanced NUM=X [WORK='description'] - Close issue with enhanced tddai/issue_closer.py"
|
||||
@echo " close-issues-batch NUMS='X Y Z' [COMMENT='reason'] - Close multiple issues at once"
|
||||
@echo " issues-get - Export compact issue index to ISSUES.index"
|
||||
@echo " issues-csv - Export issues as CSV for spreadsheet processing"
|
||||
@echo " issues-json - Export issues as JSON for programmatic processing"
|
||||
@@ -343,11 +345,46 @@ close-issue: $(VENV)/bin/activate
|
||||
echo "❌ Please specify issue number: make close-issue NUM=5"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "🔄 Closing issue #$(NUM)..."
|
||||
@echo " Setting issue state to 'done'..."
|
||||
@PYTHONPATH=. $(VENV_PYTHON) tddai_cli.py set-issue-state $(NUM) done
|
||||
@if [ -n "$(COMMENT)" ]; then \
|
||||
echo "🔄 Closing issue #$(NUM) with comment..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai_cli.py close-issue $(NUM) --comment "$(COMMENT)"; \
|
||||
else \
|
||||
echo "🔄 Closing issue #$(NUM)..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai_cli.py close-issue $(NUM); \
|
||||
fi
|
||||
@echo "✅ Issue #$(NUM) closed successfully!"
|
||||
|
||||
# Close issue using dedicated issue_closer.py script (enhanced functionality)
|
||||
close-issue-enhanced: $(VENV)/bin/activate
|
||||
@if [ -z "$(NUM)" ]; then \
|
||||
echo "❌ Please specify issue number: make close-issue-enhanced NUM=5"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if [ -n "$(WORK)" ]; then \
|
||||
echo "🔄 Closing issue #$(NUM) with completion message..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai/issue_closer.py $(NUM) --work-completed "$(WORK)"; \
|
||||
elif [ -n "$(COMMENT)" ]; then \
|
||||
echo "🔄 Closing issue #$(NUM) with comment..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai/issue_closer.py $(NUM) --comment "$(COMMENT)"; \
|
||||
else \
|
||||
echo "🔄 Closing issue #$(NUM)..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai/issue_closer.py $(NUM); \
|
||||
fi
|
||||
|
||||
# Close multiple issues at once using issue_closer.py
|
||||
close-issues-batch: $(VENV)/bin/activate
|
||||
@if [ -z "$(NUMS)" ]; then \
|
||||
echo "❌ Please specify issue numbers: make close-issues-batch NUMS='42 43 44'"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if [ -n "$(COMMENT)" ]; then \
|
||||
echo "🔄 Closing issues $(NUMS) with comment..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai/issue_closer.py $(NUMS) --comment "$(COMMENT)"; \
|
||||
else \
|
||||
echo "🔄 Closing issues $(NUMS)..."; \
|
||||
PYTHONPATH=. $(VENV_PYTHON) tddai/issue_closer.py $(NUMS); \
|
||||
fi
|
||||
|
||||
# Export compact issue index to ISSUES.index file (TSV format)
|
||||
issues-get: $(VENV)/bin/activate
|
||||
@echo "📋 Fetching issue index from gitea..."
|
||||
|
||||
180
tddai/issue_closer.py
Normal file
180
tddai/issue_closer.py
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user