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
|
# MarkiTect - Advanced Markdown Engine
|
||||||
# Makefile for common development tasks
|
# 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
|
# Default target
|
||||||
help:
|
help:
|
||||||
@@ -66,7 +66,9 @@ help:
|
|||||||
@echo " list-issues - Show all gitea issues with status and priority"
|
@echo " list-issues - Show all gitea issues with status and priority"
|
||||||
@echo " list-open-issues - Show only open issues (active backlog)"
|
@echo " list-open-issues - Show only open issues (active backlog)"
|
||||||
@echo " show-issue NUM=X - Show detailed view of specific issue"
|
@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-get - Export compact issue index to ISSUES.index"
|
||||||
@echo " issues-csv - Export issues as CSV for spreadsheet processing"
|
@echo " issues-csv - Export issues as CSV for spreadsheet processing"
|
||||||
@echo " issues-json - Export issues as JSON for programmatic 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"; \
|
echo "❌ Please specify issue number: make close-issue NUM=5"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "🔄 Closing issue #$(NUM)..."
|
@if [ -n "$(COMMENT)" ]; then \
|
||||||
@echo " Setting issue state to 'done'..."
|
echo "🔄 Closing issue #$(NUM) with comment..."; \
|
||||||
@PYTHONPATH=. $(VENV_PYTHON) tddai_cli.py set-issue-state $(NUM) done
|
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!"
|
@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)
|
# Export compact issue index to ISSUES.index file (TSV format)
|
||||||
issues-get: $(VENV)/bin/activate
|
issues-get: $(VENV)/bin/activate
|
||||||
@echo "📋 Fetching issue index from gitea..."
|
@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