Files
markitect-main/markitect/issues/commands.py
tegwick 3af6fb9935 feat: Integrate Requirements Engineering Agent and fix Issue #59 test failures
## Major Integration

-  Integrated Requirements Engineering Agent into development workflow
-  Enhanced Makefile with requirements validation targets
-  Added pre-commit validation with mock compatibility checking
-  Enhanced TDD workflow to include foundation analysis

## Test Fixes

-  Fixed GiteaPlugin missing _add_comment_async method
-  Fixed LocalPlugin config.yml file not found errors in tests
-  Enhanced mock objects in CLI tests with proper domain model attributes
-  All Issue #59 tests now passing (38/38 tests pass)

## New Capabilities

- `make validate-requirements` - Foundation analysis before development
- `make check-interface-compatibility INTERFACE=Name` - Interface compatibility checking
- `make generate-dev-checklist FEATURE='Name'` - Development checklist generation
- `make validate-mocks` - Mock object compatibility validation
- `make pre-commit-validate` - Complete pre-commit validation workflow

## Problem Prevention

This integration prevents the exact interface compatibility issues and mock object
mismatches that caused hours of debugging in Issue #59. The Requirements Engineering
Agent provides proactive foundation analysis and catches problems before they occur.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-02 00:45:06 +02:00

165 lines
5.7 KiB
Python

"""
CLI commands for issue management.
This module provides Click commands for the unified issue management interface.
"""
import click
from typing import Optional
from .manager import IssuePluginManager
from .exceptions import PluginNotFoundError, ConfigurationError
from cli.presenters.views import IssueView
@click.group()
def issues():
"""Issue management with multiple backend support."""
pass
@issues.command()
@click.option('--state', type=click.Choice(['open', 'closed', 'all']), default='all',
help='Filter issues by state')
@click.option('--backend', help='Override configured backend')
def list(state: str, backend: Optional[str]):
"""List issues from configured backend."""
try:
manager = IssuePluginManager()
backend_instance = manager.get_backend(backend)
issues_list = backend_instance.list_issues(state=state)
if state == 'open':
IssueView.show_open_issues(issues_list)
else:
IssueView.show_list(issues_list, f"Issues ({state})")
except (PluginNotFoundError, ConfigurationError) as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except Exception as e:
click.echo(f"Unexpected error: {e}", err=True)
raise click.Abort()
@issues.command()
@click.argument('issue_id')
@click.option('--backend', help='Override configured backend')
def show(issue_id: str, backend: Optional[str]):
"""Show details of a specific issue."""
try:
manager = IssuePluginManager()
backend_instance = manager.get_backend(backend)
issue = backend_instance.get_issue(issue_id)
# Convert issue to dict for display
issue_data = {
'number': issue.number,
'title': issue.title,
'body': getattr(issue, '_body', ''),
'state': issue.state.value if hasattr(issue.state, 'value') else str(issue.state),
'created_at': issue.created_at,
'updated_at': getattr(issue, 'updated_at', issue.created_at),
'labels': [label.name if hasattr(label, 'name') else str(label) for label in issue.labels],
'assignees': getattr(issue, 'assignees', []) or [],
'assignee': getattr(issue, 'assignee', None),
'milestone': getattr(issue, 'milestone', None),
'html_url': getattr(issue, 'html_url', ''),
'state_label': getattr(issue, 'state_label', issue.state.value if hasattr(issue.state, 'value') else str(issue.state)),
'priority_label': getattr(issue, 'priority_label', 'Normal'),
'type_labels': getattr(issue, 'type_labels', []),
'other_labels': getattr(issue, 'other_labels', []),
'kanban_column': getattr(issue, 'kanban_column', 'To Do')
}
IssueView.show_issue_details(issue_data)
except FileNotFoundError:
click.echo(f"Error: Issue {issue_id} not found", err=True)
raise click.Abort()
except (PluginNotFoundError, ConfigurationError) as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except Exception as e:
click.echo(f"Unexpected error: {e}", err=True)
raise click.Abort()
@issues.command()
@click.argument('title')
@click.argument('body')
@click.option('--backend', help='Override configured backend')
def create(title: str, body: str, backend: Optional[str]):
"""Create a new issue."""
try:
manager = IssuePluginManager()
backend_instance = manager.get_backend(backend)
issue = backend_instance.create_issue(title, body)
# Convert issue to dict for display
result = {
'number': issue.number,
'title': issue.title,
'state': issue.state.value if hasattr(issue.state, 'value') else str(issue.state)
}
IssueView.show_creation_success(result, "issue")
click.echo(f"Issue #{issue.number} created successfully")
except (PluginNotFoundError, ConfigurationError) as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except Exception as e:
click.echo(f"Unexpected error: {e}", err=True)
raise click.Abort()
@issues.command()
@click.argument('issue_id')
@click.argument('comment')
@click.option('--backend', help='Override configured backend')
def comment(issue_id: str, comment: str, backend: Optional[str]):
"""Add a comment to an issue."""
try:
manager = IssuePluginManager()
backend_instance = manager.get_backend(backend)
result = backend_instance.add_comment(issue_id, comment)
click.echo(f"Comment added to issue #{issue_id}")
except ValueError as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except (PluginNotFoundError, ConfigurationError) as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except Exception as e:
click.echo(f"Unexpected error: {e}", err=True)
raise click.Abort()
@issues.command()
@click.argument('issue_id')
@click.option('--backend', help='Override configured backend')
def close(issue_id: str, backend: Optional[str]):
"""Close an issue."""
try:
manager = IssuePluginManager()
backend_instance = manager.get_backend(backend)
issue = backend_instance.close_issue(issue_id)
click.echo(f"Issue #{issue_id} closed successfully")
except FileNotFoundError:
click.echo(f"Error: Issue {issue_id} not found", err=True)
raise click.Abort()
except (PluginNotFoundError, ConfigurationError) as e:
click.echo(f"Error: {e}", err=True)
raise click.Abort()
except Exception as e:
click.echo(f"Unexpected error: {e}", err=True)
raise click.Abort()
# Make issues_group available for import
issues_group = issues