feat: Implement comprehensive IssueCreator system and create CLI roadmap issues
IssueCreator Implementation: - Add tddai/issue_creator.py with full POST API functionality for issue creation - Support multiple creation methods: basic, enhancement, bug, template-based - Include structured issue formatting with acceptance criteria and dependencies - Template system with variable substitution for reusable issue creation Authentication Fix: - Fix critical authentication bug: use GITEA_API_TOKEN instead of GITEA_TOKEN - Update both IssueCreator and IssueWriter for consistency - Update all tests and documentation to reflect correct environment variable Comprehensive Test Suite: - Add 15 unit tests for IssueCreator (tests/test_issue_creator.py) - Add 5 integration tests for full API lifecycle (tests/test_issue_integration.py) - Create test_environment_variable_detection to prevent future auth issues - Total 33 tests covering complete issue handling workflow CLI Integration: - Enhance tddai_cli.py with 3 new commands: create-issue, create-enhancement, create-from-template - Add comprehensive argument parsing with optional fields and priority support - Include user-friendly output with next step guidance - Update package exports to include IssueCreator CLI Roadmap Execution: - Successfully create 8 CLI implementation issues (#12-#19) in Gitea - Resolve mismatch between NEXT.md roadmap and actual Gitea issues - Issues prioritized for core USPs: Database Query CLI and AST Query CLI - Remove local MISSING_ISSUES.md file after successful creation Framework Maturity: - Complete CRUD operations for issue management (Create, Read, Update, Delete) - Robust error handling and API integration patterns - Full authentication and environment variable management - Ready for production CLI implementation workflow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
139
tddai_cli.py
139
tddai_cli.py
@@ -14,6 +14,7 @@ from tddai import (
|
||||
WorkspaceManager, IssueFetcher, TestGenerator, CoverageAnalyzer,
|
||||
WorkspaceStatus, TddaiError
|
||||
)
|
||||
from tddai.issue_creator import IssueCreator
|
||||
|
||||
|
||||
def workspace_status():
|
||||
@@ -354,6 +355,111 @@ def show_issue(issue_number: int):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_issue(title: str, body: str, issue_type: str = "enhancement"):
|
||||
"""Create a new issue."""
|
||||
try:
|
||||
creator = IssueCreator()
|
||||
print(f"🚀 Creating {issue_type} issue: {title}")
|
||||
print()
|
||||
|
||||
if issue_type == "enhancement":
|
||||
# For enhancements, assume body contains structured content
|
||||
result = creator.create_issue(title, body, labels=[issue_type])
|
||||
elif issue_type == "bug":
|
||||
result = creator.create_issue(title, body, labels=[issue_type])
|
||||
else:
|
||||
result = creator.create_issue(title, body)
|
||||
|
||||
print("✅ Issue created successfully!")
|
||||
print(f" Number: #{result['number']}")
|
||||
print(f" Title: {result['title']}")
|
||||
print(f" Status: {result['state']}")
|
||||
|
||||
if 'html_url' in result:
|
||||
print(f" URL: {result['html_url']}")
|
||||
|
||||
print()
|
||||
print("💡 Next steps:")
|
||||
print(f" - Use 'make tdd-start NUM={result['number']}' to begin work")
|
||||
print(f" - Use 'make show-issue NUM={result['number']}' to view details")
|
||||
|
||||
except TddaiError as e:
|
||||
print(f"❌ Error creating issue: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_enhancement_issue(title: str, use_case: str, technical_requirements: str = "",
|
||||
acceptance_criteria: str = "", dependencies: str = "",
|
||||
priority: str = "Medium"):
|
||||
"""Create a structured enhancement issue."""
|
||||
try:
|
||||
creator = IssueCreator()
|
||||
print(f"🚀 Creating enhancement issue: {title}")
|
||||
print()
|
||||
|
||||
# Parse acceptance criteria if provided
|
||||
criteria_list = []
|
||||
if acceptance_criteria:
|
||||
criteria_list = [line.strip() for line in acceptance_criteria.split('\n') if line.strip()]
|
||||
|
||||
# Parse dependencies if provided
|
||||
deps_list = []
|
||||
if dependencies:
|
||||
deps_list = [line.strip() for line in dependencies.split('\n') if line.strip()]
|
||||
|
||||
result = creator.create_enhancement_issue(
|
||||
title=title,
|
||||
use_case=use_case,
|
||||
technical_requirements=technical_requirements,
|
||||
acceptance_criteria=criteria_list,
|
||||
dependencies=deps_list,
|
||||
priority=priority
|
||||
)
|
||||
|
||||
print("✅ Enhancement issue created successfully!")
|
||||
print(f" Number: #{result['number']}")
|
||||
print(f" Title: {result['title']}")
|
||||
print(f" Priority: {priority}")
|
||||
|
||||
if 'html_url' in result:
|
||||
print(f" URL: {result['html_url']}")
|
||||
|
||||
print()
|
||||
print("💡 Next steps:")
|
||||
print(f" - Use 'make tdd-start NUM={result['number']}' to begin work")
|
||||
print(f" - Use 'make show-issue NUM={result['number']}' to view details")
|
||||
|
||||
except TddaiError as e:
|
||||
print(f"❌ Error creating enhancement issue: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_from_template(template_file: str, **kwargs):
|
||||
"""Create issue from template file."""
|
||||
try:
|
||||
creator = IssueCreator()
|
||||
print(f"🚀 Creating issue from template: {template_file}")
|
||||
print()
|
||||
|
||||
result = creator.create_from_template(template_file, **kwargs)
|
||||
|
||||
print("✅ Issue created from template successfully!")
|
||||
print(f" Number: #{result['number']}")
|
||||
print(f" Title: {result['title']}")
|
||||
|
||||
if 'html_url' in result:
|
||||
print(f" URL: {result['html_url']}")
|
||||
|
||||
print()
|
||||
print("💡 Next steps:")
|
||||
print(f" - Use 'make tdd-start NUM={result['number']}' to begin work")
|
||||
print(f" - Use 'make show-issue NUM={result['number']}' to view details")
|
||||
|
||||
except TddaiError as e:
|
||||
print(f"❌ Error creating issue from template: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main CLI entry point."""
|
||||
parser = argparse.ArgumentParser(description="tddai CLI tool")
|
||||
@@ -378,6 +484,24 @@ def main():
|
||||
coverage_parser = subparsers.add_parser('analyze-coverage', help='Analyze test coverage for issue')
|
||||
coverage_parser.add_argument('issue_number', type=int, help='Issue number')
|
||||
|
||||
# Issue creation commands
|
||||
create_parser = subparsers.add_parser('create-issue', help='Create a new issue')
|
||||
create_parser.add_argument('title', help='Issue title')
|
||||
create_parser.add_argument('body', help='Issue body/description')
|
||||
create_parser.add_argument('--type', choices=['enhancement', 'bug'], default='enhancement', help='Issue type')
|
||||
|
||||
create_enh_parser = subparsers.add_parser('create-enhancement', help='Create a structured enhancement issue')
|
||||
create_enh_parser.add_argument('title', help='Issue title')
|
||||
create_enh_parser.add_argument('use_case', help='UseCase description')
|
||||
create_enh_parser.add_argument('--technical', help='Technical requirements', default='')
|
||||
create_enh_parser.add_argument('--criteria', help='Acceptance criteria (newline separated)', default='')
|
||||
create_enh_parser.add_argument('--dependencies', help='Dependencies (newline separated)', default='')
|
||||
create_enh_parser.add_argument('--priority', choices=['High', 'Medium', 'Low'], default='Medium', help='Priority level')
|
||||
|
||||
template_parser = subparsers.add_parser('create-from-template', help='Create issue from template')
|
||||
template_parser.add_argument('template_file', help='Template file path')
|
||||
template_parser.add_argument('--vars', help='Template variables in key=value format', nargs='*', default=[])
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
@@ -401,6 +525,21 @@ def main():
|
||||
show_issue(args.issue_number)
|
||||
elif args.command == 'analyze-coverage':
|
||||
analyze_coverage(args.issue_number)
|
||||
elif args.command == 'create-issue':
|
||||
create_issue(args.title, args.body, args.type)
|
||||
elif args.command == 'create-enhancement':
|
||||
create_enhancement_issue(
|
||||
args.title, args.use_case, args.technical,
|
||||
args.criteria, args.dependencies, args.priority
|
||||
)
|
||||
elif args.command == 'create-from-template':
|
||||
# Parse template variables
|
||||
template_vars = {}
|
||||
for var in args.vars:
|
||||
if '=' in var:
|
||||
key, value = var.split('=', 1)
|
||||
template_vars[key] = value
|
||||
create_from_template(args.template_file, **template_vars)
|
||||
except KeyboardInterrupt:
|
||||
print("\n⚠️ Operation cancelled")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user