180 lines
6.5 KiB
Python
180 lines
6.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Pure Issue Management CLI
|
||
|
|
|
||
|
|
Dedicated CLI interface for issue management operations, providing clean
|
||
|
|
separation from document processing and TDD workflow functionality.
|
||
|
|
|
||
|
|
This CLI focuses exclusively on issue operations:
|
||
|
|
- Listing and viewing issues
|
||
|
|
- Creating and closing issues
|
||
|
|
- Project management (milestones, priorities, states)
|
||
|
|
- Issue metadata and bulk operations
|
||
|
|
|
||
|
|
Architecture: Uses the unified cli/ framework for consistent command structure.
|
||
|
|
"""
|
||
|
|
|
||
|
|
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.core import CLIFramework
|
||
|
|
from tddai import TddaiError
|
||
|
|
|
||
|
|
|
||
|
|
def create_parser() -> argparse.ArgumentParser:
|
||
|
|
"""Create argument parser for issue CLI."""
|
||
|
|
parser = argparse.ArgumentParser(
|
||
|
|
prog='issue',
|
||
|
|
description='Pure Issue Management CLI - Dedicated interface for issue operations',
|
||
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
|
|
epilog="""
|
||
|
|
Examples:
|
||
|
|
issue list # List all issues
|
||
|
|
issue list --open # List only open issues
|
||
|
|
issue show 42 # Show issue details
|
||
|
|
issue create "Bug fix" "Description" # Create new issue
|
||
|
|
issue close 42 "Fixed the problem" # Close issue with comment
|
||
|
|
issue assign 42 milestone-1 # Assign to milestone
|
||
|
|
issue priority 42 high # Set priority
|
||
|
|
issue state 42 "In Progress" # Set project state
|
||
|
|
|
||
|
|
Focus Areas:
|
||
|
|
- Issue browsing and management
|
||
|
|
- Project organization (milestones, priorities)
|
||
|
|
- Bulk operations and metadata management
|
||
|
|
- Integration with various issue tracking backends
|
||
|
|
|
||
|
|
Related Commands:
|
||
|
|
tddai - TDD workflow management with issue context
|
||
|
|
markitect - Document processing and template operations
|
||
|
|
"""
|
||
|
|
)
|
||
|
|
|
||
|
|
subparsers = parser.add_subparsers(dest='command', help='Available issue commands')
|
||
|
|
|
||
|
|
# List issues
|
||
|
|
list_parser = subparsers.add_parser('list', help='List issues')
|
||
|
|
list_parser.add_argument('--open', action='store_true', help='Show only open issues')
|
||
|
|
list_parser.add_argument('--format', choices=['table', 'json', 'csv'], default='table', help='Output format')
|
||
|
|
|
||
|
|
# Show issue details
|
||
|
|
show_parser = subparsers.add_parser('show', help='Show issue details')
|
||
|
|
show_parser.add_argument('issue_number', type=int, help='Issue number')
|
||
|
|
|
||
|
|
# Create issue
|
||
|
|
create_parser = subparsers.add_parser('create', help='Create new issue')
|
||
|
|
create_parser.add_argument('title', help='Issue title')
|
||
|
|
create_parser.add_argument('description', help='Issue description')
|
||
|
|
create_parser.add_argument('--type', choices=['bug', 'enhancement', 'feature'], default='enhancement', help='Issue type')
|
||
|
|
create_parser.add_argument('--priority', choices=['low', 'medium', 'high', 'critical'], help='Issue priority')
|
||
|
|
|
||
|
|
# Close issue
|
||
|
|
close_parser = subparsers.add_parser('close', help='Close issue')
|
||
|
|
close_parser.add_argument('issue_number', type=int, help='Issue number')
|
||
|
|
close_parser.add_argument('comment', nargs='?', default='', help='Closing comment')
|
||
|
|
|
||
|
|
# Assign to milestone
|
||
|
|
assign_parser = subparsers.add_parser('assign', help='Assign issue to milestone')
|
||
|
|
assign_parser.add_argument('issue_number', type=int, help='Issue number')
|
||
|
|
assign_parser.add_argument('milestone_id', type=int, help='Milestone ID')
|
||
|
|
|
||
|
|
# Set priority
|
||
|
|
priority_parser = subparsers.add_parser('priority', help='Set issue priority')
|
||
|
|
priority_parser.add_argument('issue_number', type=int, help='Issue number')
|
||
|
|
priority_parser.add_argument('priority', choices=['low', 'medium', 'high', 'critical'], help='Priority level')
|
||
|
|
|
||
|
|
# Set state
|
||
|
|
state_parser = subparsers.add_parser('state', help='Set issue project state')
|
||
|
|
state_parser.add_argument('issue_number', type=int, help='Issue number')
|
||
|
|
state_parser.add_argument('state', help='Project state')
|
||
|
|
|
||
|
|
# Export/bulk operations
|
||
|
|
export_parser = subparsers.add_parser('export', help='Export issues in various formats')
|
||
|
|
export_parser.add_argument('--format', choices=['csv', 'json', 'tsv'], default='csv', help='Export format')
|
||
|
|
export_parser.add_argument('--output', help='Output file (default: stdout)')
|
||
|
|
export_parser.add_argument('--filter', choices=['open', 'closed', 'all'], default='all', help='Filter issues')
|
||
|
|
|
||
|
|
# Milestones
|
||
|
|
milestone_parser = subparsers.add_parser('milestones', help='List milestones')
|
||
|
|
|
||
|
|
return parser
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""Main entry point for issue CLI."""
|
||
|
|
parser = create_parser()
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
if not args.command:
|
||
|
|
parser.print_help()
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# Initialize CLI framework
|
||
|
|
try:
|
||
|
|
cli = CLIFramework()
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Error initializing CLI framework: {e}")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# Execute commands
|
||
|
|
try:
|
||
|
|
if args.command == 'list':
|
||
|
|
if args.open:
|
||
|
|
cli.list_open_issues()
|
||
|
|
else:
|
||
|
|
cli.list_issues()
|
||
|
|
|
||
|
|
elif args.command == 'show':
|
||
|
|
cli.show_issue(args.issue_number)
|
||
|
|
|
||
|
|
elif args.command == 'create':
|
||
|
|
kwargs = {}
|
||
|
|
if hasattr(args, 'priority') and args.priority:
|
||
|
|
kwargs['priority'] = args.priority
|
||
|
|
cli.create_issue(args.title, args.description, args.type, **kwargs)
|
||
|
|
|
||
|
|
elif args.command == 'close':
|
||
|
|
cli.close_issue(args.issue_number, args.comment)
|
||
|
|
|
||
|
|
elif args.command == 'assign':
|
||
|
|
cli.assign_issue_to_milestone(args.issue_number, args.milestone_id)
|
||
|
|
|
||
|
|
elif args.command == 'priority':
|
||
|
|
cli.set_issue_priority(args.issue_number, args.priority)
|
||
|
|
|
||
|
|
elif args.command == 'state':
|
||
|
|
cli.move_issue_to_state(args.issue_number, args.state)
|
||
|
|
|
||
|
|
elif args.command == 'export':
|
||
|
|
# Export functionality
|
||
|
|
if args.format == 'csv':
|
||
|
|
cli.export_issues_csv(args.output)
|
||
|
|
elif args.format == 'json':
|
||
|
|
cli.export_issues_json(args.output)
|
||
|
|
elif args.format == 'tsv':
|
||
|
|
cli.export_issue_index(args.output)
|
||
|
|
|
||
|
|
elif args.command == 'milestones':
|
||
|
|
cli.list_milestones()
|
||
|
|
|
||
|
|
else:
|
||
|
|
print(f"Unknown command: {args.command}")
|
||
|
|
parser.print_help()
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
except TddaiError as e:
|
||
|
|
print(f"Issue CLI Error: {e}")
|
||
|
|
sys.exit(1)
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Unexpected error: {e}")
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|