roadmap-cli 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- roadmap/__init__.py +27 -0
- roadmap/adapters/__init__.py +1 -0
- roadmap/adapters/base_paginated_adapter.py +117 -0
- roadmap/adapters/cli/__init__.py +249 -0
- roadmap/adapters/cli/analysis/__init__.py +5 -0
- roadmap/adapters/cli/analysis/commands.py +370 -0
- roadmap/adapters/cli/analysis/presenter.py +125 -0
- roadmap/adapters/cli/archive_operations.py +86 -0
- roadmap/adapters/cli/cli_command_helpers.py +109 -0
- roadmap/adapters/cli/cli_confirmations.py +74 -0
- roadmap/adapters/cli/cli_error_handlers.py +146 -0
- roadmap/adapters/cli/cli_validators.py +39 -0
- roadmap/adapters/cli/commands/sync_status.py +308 -0
- roadmap/adapters/cli/comment/__init__.py +5 -0
- roadmap/adapters/cli/comment/commands.py +106 -0
- roadmap/adapters/cli/config/__init__.py +5 -0
- roadmap/adapters/cli/config/commands.py +198 -0
- roadmap/adapters/cli/console_exports.py +10 -0
- roadmap/adapters/cli/core.py +26 -0
- roadmap/adapters/cli/crud/__init__.py +47 -0
- roadmap/adapters/cli/crud/base_archive.py +208 -0
- roadmap/adapters/cli/crud/base_create.py +154 -0
- roadmap/adapters/cli/crud/base_delete.py +155 -0
- roadmap/adapters/cli/crud/base_restore.py +283 -0
- roadmap/adapters/cli/crud/base_update.py +193 -0
- roadmap/adapters/cli/crud/crud_helpers.py +206 -0
- roadmap/adapters/cli/crud/crud_utils.py +152 -0
- roadmap/adapters/cli/crud/entity_builders.py +374 -0
- roadmap/adapters/cli/data/__init__.py +8 -0
- roadmap/adapters/cli/data/commands.py +149 -0
- roadmap/adapters/cli/decorators.py +208 -0
- roadmap/adapters/cli/dtos/__init__.py +155 -0
- roadmap/adapters/cli/exception_handler.py +105 -0
- roadmap/adapters/cli/git/__init__.py +8 -0
- roadmap/adapters/cli/git/commands.py +475 -0
- roadmap/adapters/cli/git/handlers/__init__.py +1 -0
- roadmap/adapters/cli/git/handlers/git_authentication_handler.py +124 -0
- roadmap/adapters/cli/git/handlers/git_branch_handler.py +238 -0
- roadmap/adapters/cli/git/handlers/git_connectivity_handler.py +122 -0
- roadmap/adapters/cli/git/handlers/git_hooks_handler.py +105 -0
- roadmap/adapters/cli/git/hooks_config.py +327 -0
- roadmap/adapters/cli/git/status_display.py +158 -0
- roadmap/adapters/cli/health/__init__.py +8 -0
- roadmap/adapters/cli/health/db_integrity.py +204 -0
- roadmap/adapters/cli/health/enhancer.py +227 -0
- roadmap/adapters/cli/health/fixer.py +295 -0
- roadmap/adapters/cli/health/fixers/__init__.py +10 -0
- roadmap/adapters/cli/health/fixers/corrupted_comments_fixer.py +231 -0
- roadmap/adapters/cli/health/fixers/data_integrity_fixer.py +137 -0
- roadmap/adapters/cli/health/fixers/duplicate_issues_fixer.py +138 -0
- roadmap/adapters/cli/health/fixers/folder_structure_fixer.py +114 -0
- roadmap/adapters/cli/health/fixers/label_normalization_fixer.py +162 -0
- roadmap/adapters/cli/health/fixers/milestone_name_normalization_fixer.py +181 -0
- roadmap/adapters/cli/health/fixers/milestone_naming_compliance_fixer.py +244 -0
- roadmap/adapters/cli/health/fixers/milestone_parse_error_fixer.py +162 -0
- roadmap/adapters/cli/health/fixers/milestone_validation_fixer.py +211 -0
- roadmap/adapters/cli/health/fixers/old_backups_fixer.py +135 -0
- roadmap/adapters/cli/health/fixers/orphaned_issues_fixer.py +252 -0
- roadmap/adapters/cli/health/formatter.py +250 -0
- roadmap/adapters/cli/health/formatters.py +427 -0
- roadmap/adapters/cli/health/scan.py +293 -0
- roadmap/adapters/cli/init/__init__.py +5 -0
- roadmap/adapters/cli/init/commands.py +587 -0
- roadmap/adapters/cli/init.py +9 -0
- roadmap/adapters/cli/issues/__init__.py +70 -0
- roadmap/adapters/cli/issues/archive.py +137 -0
- roadmap/adapters/cli/issues/archive_class.py +253 -0
- roadmap/adapters/cli/issues/block.py +39 -0
- roadmap/adapters/cli/issues/close.py +216 -0
- roadmap/adapters/cli/issues/comment.py +178 -0
- roadmap/adapters/cli/issues/create.py +162 -0
- roadmap/adapters/cli/issues/delete.py +31 -0
- roadmap/adapters/cli/issues/deps.py +161 -0
- roadmap/adapters/cli/issues/issue_status_helpers.py +111 -0
- roadmap/adapters/cli/issues/link.py +308 -0
- roadmap/adapters/cli/issues/list.py +402 -0
- roadmap/adapters/cli/issues/lookup.py +96 -0
- roadmap/adapters/cli/issues/progress.py +102 -0
- roadmap/adapters/cli/issues/restore.py +96 -0
- roadmap/adapters/cli/issues/restore_class.py +57 -0
- roadmap/adapters/cli/issues/start.py +165 -0
- roadmap/adapters/cli/issues/sync_status.py +374 -0
- roadmap/adapters/cli/issues/unblock.py +43 -0
- roadmap/adapters/cli/issues/unlink.py +104 -0
- roadmap/adapters/cli/issues/update.py +120 -0
- roadmap/adapters/cli/issues/view.py +36 -0
- roadmap/adapters/cli/layout.py +220 -0
- roadmap/adapters/cli/mappers.py +200 -0
- roadmap/adapters/cli/milestones/__init__.py +52 -0
- roadmap/adapters/cli/milestones/archive.py +125 -0
- roadmap/adapters/cli/milestones/archive_class.py +236 -0
- roadmap/adapters/cli/milestones/assign.py +62 -0
- roadmap/adapters/cli/milestones/close.py +177 -0
- roadmap/adapters/cli/milestones/create.py +131 -0
- roadmap/adapters/cli/milestones/delete.py +27 -0
- roadmap/adapters/cli/milestones/kanban.py +123 -0
- roadmap/adapters/cli/milestones/list.py +87 -0
- roadmap/adapters/cli/milestones/recalculate.py +79 -0
- roadmap/adapters/cli/milestones/restore.py +87 -0
- roadmap/adapters/cli/milestones/restore_class.py +99 -0
- roadmap/adapters/cli/milestones/update.py +61 -0
- roadmap/adapters/cli/milestones/view.py +142 -0
- roadmap/adapters/cli/output_manager.py +319 -0
- roadmap/adapters/cli/presentation/base_presenter.py +121 -0
- roadmap/adapters/cli/presentation/cleanup_presenter.py +235 -0
- roadmap/adapters/cli/presentation/core_initialization_presenter.py +277 -0
- roadmap/adapters/cli/presentation/crud_presenter.py +134 -0
- roadmap/adapters/cli/presentation/daily_summary_presenter.py +266 -0
- roadmap/adapters/cli/presentation/issue_presenter.py +258 -0
- roadmap/adapters/cli/presentation/milestone_list_presenter.py +135 -0
- roadmap/adapters/cli/presentation/milestone_presenter.py +297 -0
- roadmap/adapters/cli/presentation/project_presenter.py +233 -0
- roadmap/adapters/cli/presentation/project_status_presenter.py +186 -0
- roadmap/adapters/cli/presentation/table_builders.py +95 -0
- roadmap/adapters/cli/projects/__init__.py +42 -0
- roadmap/adapters/cli/projects/archive.py +127 -0
- roadmap/adapters/cli/projects/archive_class.py +96 -0
- roadmap/adapters/cli/projects/close.py +94 -0
- roadmap/adapters/cli/projects/create.py +50 -0
- roadmap/adapters/cli/projects/delete.py +27 -0
- roadmap/adapters/cli/projects/list.py +227 -0
- roadmap/adapters/cli/projects/restore.py +87 -0
- roadmap/adapters/cli/projects/restore_class.py +56 -0
- roadmap/adapters/cli/projects/update.py +57 -0
- roadmap/adapters/cli/projects/view.py +157 -0
- roadmap/adapters/cli/services/__init__.py +1 -0
- roadmap/adapters/cli/services/daily_summary_service.py +313 -0
- roadmap/adapters/cli/services/export_manager.py +268 -0
- roadmap/adapters/cli/services/milestone_list_service.py +266 -0
- roadmap/adapters/cli/services/project_initialization_service.py +29 -0
- roadmap/adapters/cli/services/project_status_service.py +462 -0
- roadmap/adapters/cli/services/sync_service.py +62 -0
- roadmap/adapters/cli/status.py +408 -0
- roadmap/adapters/cli/styling.py +21 -0
- roadmap/adapters/cli/sync.py +1117 -0
- roadmap/adapters/cli/sync_context.py +432 -0
- roadmap/adapters/cli/sync_handlers/__init__.py +77 -0
- roadmap/adapters/cli/sync_handlers/apply_ops.py +522 -0
- roadmap/adapters/cli/sync_handlers/baseline_ops.py +366 -0
- roadmap/adapters/cli/sync_handlers/conflict_ops.py +161 -0
- roadmap/adapters/cli/sync_handlers/dry_run_display.py +237 -0
- roadmap/adapters/cli/sync_handlers/interactive_resolver.py +396 -0
- roadmap/adapters/cli/sync_handlers/progress_tracker.py +128 -0
- roadmap/adapters/cli/sync_metrics_command.py +190 -0
- roadmap/adapters/cli/sync_presenter.py +58 -0
- roadmap/adapters/cli/sync_validation.py +295 -0
- roadmap/adapters/cli/today.py +52 -0
- roadmap/adapters/cli/utils/click_options.py +38 -0
- roadmap/adapters/git/__init__.py +1 -0
- roadmap/adapters/git/git.py +208 -0
- roadmap/adapters/git/git_branch_manager.py +400 -0
- roadmap/adapters/git/git_command_executor.py +56 -0
- roadmap/adapters/git/git_commit_analyzer.py +334 -0
- roadmap/adapters/git/git_hooks.py +22 -0
- roadmap/adapters/git/git_hooks_manager.py +455 -0
- roadmap/adapters/git/git_repository_info.py +65 -0
- roadmap/adapters/git/hook_installer.py +106 -0
- roadmap/adapters/git/hook_registry.py +97 -0
- roadmap/adapters/git/hook_script_generator.py +58 -0
- roadmap/adapters/git/sync_monitor.py +409 -0
- roadmap/adapters/git/workflow_automation.py +286 -0
- roadmap/adapters/github/__init__.py +1 -0
- roadmap/adapters/github/github.py +360 -0
- roadmap/adapters/github/handlers/__init__.py +17 -0
- roadmap/adapters/github/handlers/base.py +337 -0
- roadmap/adapters/github/handlers/collaborators.py +165 -0
- roadmap/adapters/github/handlers/comments.py +118 -0
- roadmap/adapters/github/handlers/issues.py +150 -0
- roadmap/adapters/github/handlers/labels.py +164 -0
- roadmap/adapters/github/handlers/milestones.py +104 -0
- roadmap/adapters/persistence/__init__.py +35 -0
- roadmap/adapters/persistence/conflict_resolver.py +190 -0
- roadmap/adapters/persistence/database_manager.py +492 -0
- roadmap/adapters/persistence/entity_sync_coordinators.py +672 -0
- roadmap/adapters/persistence/file_locking.py +348 -0
- roadmap/adapters/persistence/file_parser.py +92 -0
- roadmap/adapters/persistence/file_synchronizer.py +107 -0
- roadmap/adapters/persistence/focused_managers.py +140 -0
- roadmap/adapters/persistence/git_history.py +330 -0
- roadmap/adapters/persistence/parser/__init__.py +20 -0
- roadmap/adapters/persistence/parser/frontmatter.py +152 -0
- roadmap/adapters/persistence/parser/issue.py +245 -0
- roadmap/adapters/persistence/parser/milestone.py +146 -0
- roadmap/adapters/persistence/parser/project.py +106 -0
- roadmap/adapters/persistence/persistence.py +288 -0
- roadmap/adapters/persistence/repositories/__init__.py +15 -0
- roadmap/adapters/persistence/repositories/issue_repository.py +223 -0
- roadmap/adapters/persistence/repositories/milestone_repository.py +140 -0
- roadmap/adapters/persistence/repositories/project_repository.py +168 -0
- roadmap/adapters/persistence/repositories/remote_link_repository.py +355 -0
- roadmap/adapters/persistence/repositories/sync_state_repository.py +66 -0
- roadmap/adapters/persistence/storage/__init__.py +36 -0
- roadmap/adapters/persistence/storage/conflicts.py +101 -0
- roadmap/adapters/persistence/storage/connection_manager.py +79 -0
- roadmap/adapters/persistence/storage/issue_storage.py +89 -0
- roadmap/adapters/persistence/storage/milestone_storage.py +80 -0
- roadmap/adapters/persistence/storage/project_storage.py +102 -0
- roadmap/adapters/persistence/storage/queries.py +227 -0
- roadmap/adapters/persistence/storage/state_manager.py +652 -0
- roadmap/adapters/persistence/storage/sync_state_storage.py +207 -0
- roadmap/adapters/persistence/sync_metrics_repository.py +342 -0
- roadmap/adapters/persistence/sync_orchestrator.py +293 -0
- roadmap/adapters/persistence/sync_state_tracker.py +86 -0
- roadmap/adapters/persistence/yaml_repositories.py +711 -0
- roadmap/adapters/sync/__init__.py +21 -0
- roadmap/adapters/sync/backend_factory.py +108 -0
- roadmap/adapters/sync/backends/__init__.py +15 -0
- roadmap/adapters/sync/backends/converters.py +209 -0
- roadmap/adapters/sync/backends/github_backend_helpers.py +380 -0
- roadmap/adapters/sync/backends/github_client.py +99 -0
- roadmap/adapters/sync/backends/github_sync_backend.py +792 -0
- roadmap/adapters/sync/backends/github_sync_ops.py +908 -0
- roadmap/adapters/sync/backends/services/__init__.py +1 -0
- roadmap/adapters/sync/backends/services/github_authentication_service.py +105 -0
- roadmap/adapters/sync/backends/services/github_issue_delete_service.py +423 -0
- roadmap/adapters/sync/backends/services/github_issue_dependency_service.py +63 -0
- roadmap/adapters/sync/backends/services/github_issue_fetch_service.py +158 -0
- roadmap/adapters/sync/backends/services/github_label_sync_service.py +126 -0
- roadmap/adapters/sync/backends/services/github_local_issue_sync_service.py +229 -0
- roadmap/adapters/sync/backends/services/github_milestone_fetch_service.py +204 -0
- roadmap/adapters/sync/backends/vanilla_git_sync_backend.py +198 -0
- roadmap/adapters/sync/services/__init__.py +11 -0
- roadmap/adapters/sync/services/baseline_state_handler.py +83 -0
- roadmap/adapters/sync/services/conflict_converter.py +85 -0
- roadmap/adapters/sync/services/issue_persistence_service.py +263 -0
- roadmap/adapters/sync/services/issue_state_service.py +243 -0
- roadmap/adapters/sync/services/local_change_filter.py +129 -0
- roadmap/adapters/sync/services/pull_result_processor.py +71 -0
- roadmap/adapters/sync/services/remote_issue_creation_service.py +112 -0
- roadmap/adapters/sync/services/sync_analysis_service.py +250 -0
- roadmap/adapters/sync/services/sync_authentication_service.py +57 -0
- roadmap/adapters/sync/services/sync_data_fetch_service.py +212 -0
- roadmap/adapters/sync/services/sync_linking_service.py +329 -0
- roadmap/adapters/sync/services/sync_report_service.py +62 -0
- roadmap/adapters/sync/services/sync_state_update_service.py +51 -0
- roadmap/adapters/sync/sync_cache_orchestrator.py +454 -0
- roadmap/adapters/sync/sync_merge_engine.py +416 -0
- roadmap/adapters/sync/sync_merge_orchestrator.py +1313 -0
- roadmap/adapters/sync/sync_retrieval_orchestrator.py +810 -0
- roadmap/application/services/__init__.py +1 -0
- roadmap/application/services/deduplicate_service.py +517 -0
- roadmap/application/use_cases/__init__.py +1 -0
- roadmap/common/__init__.py +308 -0
- roadmap/common/cache.py +209 -0
- roadmap/common/cli_errors.py +147 -0
- roadmap/common/configuration/__init__.py +33 -0
- roadmap/common/configuration/config_loader.py +264 -0
- roadmap/common/configuration/config_manager.py +164 -0
- roadmap/common/configuration/config_schema.py +145 -0
- roadmap/common/configuration/github/__init__.py +9 -0
- roadmap/common/configuration/github/config_manager.py +154 -0
- roadmap/common/configuration/github/token_resolver.py +84 -0
- roadmap/common/console.py +184 -0
- roadmap/common/constants.py +134 -0
- roadmap/common/datetime_parser.py +319 -0
- roadmap/common/error_formatter.py +84 -0
- roadmap/common/errors/__init__.py +143 -0
- roadmap/common/errors/error_base.py +73 -0
- roadmap/common/errors/error_file.py +82 -0
- roadmap/common/errors/error_git.py +67 -0
- roadmap/common/errors/error_handler.py +166 -0
- roadmap/common/errors/error_network.py +90 -0
- roadmap/common/errors/error_security.py +78 -0
- roadmap/common/errors/error_standards.py +561 -0
- roadmap/common/errors/error_validation.py +111 -0
- roadmap/common/errors/exceptions.py +432 -0
- roadmap/common/formatters/__init__.py +29 -0
- roadmap/common/formatters/base_table_formatter.py +96 -0
- roadmap/common/formatters/export/__init__.py +7 -0
- roadmap/common/formatters/export/issue_exporter.py +97 -0
- roadmap/common/formatters/helpers.py +28 -0
- roadmap/common/formatters/kanban/__init__.py +9 -0
- roadmap/common/formatters/kanban/layout.py +48 -0
- roadmap/common/formatters/kanban/organizer.py +81 -0
- roadmap/common/formatters/output/__init__.py +15 -0
- roadmap/common/formatters/tables/__init__.py +11 -0
- roadmap/common/formatters/tables/column_factory.py +312 -0
- roadmap/common/formatters/tables/issue_table.py +276 -0
- roadmap/common/formatters/tables/milestone_table.py +247 -0
- roadmap/common/formatters/tables/project_table.py +195 -0
- roadmap/common/formatters/text/__init__.py +57 -0
- roadmap/common/formatters/text/basic.py +217 -0
- roadmap/common/formatters/text/display.py +42 -0
- roadmap/common/formatters/text/duration.py +36 -0
- roadmap/common/formatters/text/operations.py +325 -0
- roadmap/common/formatters/text/status_badges.py +57 -0
- roadmap/common/initialization/github/__init__.py +11 -0
- roadmap/common/initialization/github/setup_service.py +238 -0
- roadmap/common/initialization/github/setup_validator.py +78 -0
- roadmap/common/logging/__init__.py +113 -0
- roadmap/common/logging/audit_logging.py +5 -0
- roadmap/common/logging/correlation.py +45 -0
- roadmap/common/logging/decorators.py +267 -0
- roadmap/common/logging/error_logging.py +217 -0
- roadmap/common/logging/formatters.py +124 -0
- roadmap/common/logging/loggers.py +68 -0
- roadmap/common/logging/performance_tracking.py +267 -0
- roadmap/common/logging/utils.py +335 -0
- roadmap/common/models/__init__.py +44 -0
- roadmap/common/models/cli_models.py +118 -0
- roadmap/common/models/config_models.py +199 -0
- roadmap/common/models/output_models.py +381 -0
- roadmap/common/observability/__init__.py +28 -0
- roadmap/common/observability/instrumentation.py +103 -0
- roadmap/common/observability/observability.py +76 -0
- roadmap/common/observability/otel_init.py +109 -0
- roadmap/common/output_formatter.py +393 -0
- roadmap/common/progress.py +379 -0
- roadmap/common/result.py +396 -0
- roadmap/common/security/__init__.py +48 -0
- roadmap/common/security/exceptions.py +13 -0
- roadmap/common/security/export_cleanup.py +79 -0
- roadmap/common/security/file_operations.py +104 -0
- roadmap/common/security/filename_sanitization.py +54 -0
- roadmap/common/security/logging.py +27 -0
- roadmap/common/security/path_validation.py +137 -0
- roadmap/common/security/temp_files.py +41 -0
- roadmap/common/services/__init__.py +65 -0
- roadmap/common/services/decorators.py +183 -0
- roadmap/common/services/logging_utils.py +208 -0
- roadmap/common/services/metrics.py +161 -0
- roadmap/common/services/performance.py +219 -0
- roadmap/common/services/profiling.py +288 -0
- roadmap/common/services/retry.py +288 -0
- roadmap/common/status_style_manager.py +114 -0
- roadmap/common/union_find.py +88 -0
- roadmap/common/update_constants.py +13 -0
- roadmap/common/utils/__init__.py +65 -0
- roadmap/common/utils/cli_helpers.py +381 -0
- roadmap/common/utils/file_utils.py +440 -0
- roadmap/common/utils/path_utils.py +38 -0
- roadmap/common/utils/status_utils.py +130 -0
- roadmap/common/utils/timezone_utils.py +480 -0
- roadmap/common/validation/__init__.py +37 -0
- roadmap/common/validation/field_validator.py +104 -0
- roadmap/common/validation/result.py +37 -0
- roadmap/common/validation/roadmap_validator.py +310 -0
- roadmap/common/validation/schema_validator.py +36 -0
- roadmap/common/validation/validators.py +50 -0
- roadmap/core/__init__.py +1 -0
- roadmap/core/domain/__init__.py +30 -0
- roadmap/core/domain/comment.py +24 -0
- roadmap/core/domain/health.py +15 -0
- roadmap/core/domain/issue.py +274 -0
- roadmap/core/domain/milestone.py +173 -0
- roadmap/core/domain/ports/__init__.py +1 -0
- roadmap/core/domain/ports/baseline_repository.py +24 -0
- roadmap/core/domain/ports/issue_repository.py +34 -0
- roadmap/core/domain/ports/remote_backend_port.py +31 -0
- roadmap/core/domain/project.py +130 -0
- roadmap/core/interfaces/__init__.py +109 -0
- roadmap/core/interfaces/assignee_validator.py +40 -0
- roadmap/core/interfaces/backend_factory.py +175 -0
- roadmap/core/interfaces/github.py +102 -0
- roadmap/core/interfaces/parsers.py +140 -0
- roadmap/core/interfaces/persistence.py +45 -0
- roadmap/core/interfaces/repositories.py +174 -0
- roadmap/core/interfaces/state_managers.py +111 -0
- roadmap/core/interfaces/state_storage.py +64 -0
- roadmap/core/interfaces/sync_backend.py +275 -0
- roadmap/core/interfaces/sync_services.py +119 -0
- roadmap/core/interfaces/sync_validators.py +180 -0
- roadmap/core/models/__init__.py +31 -0
- roadmap/core/models/sync_models.py +162 -0
- roadmap/core/models.py +115 -0
- roadmap/core/observability/__init__.py +17 -0
- roadmap/core/observability/sync_metrics.py +699 -0
- roadmap/core/repositories.py +200 -0
- roadmap/core/services/__init__.py +313 -0
- roadmap/core/services/baseline/__init__.py +1 -0
- roadmap/core/services/baseline/baseline_builder_progress.py +274 -0
- roadmap/core/services/baseline/baseline_retriever.py +63 -0
- roadmap/core/services/baseline/baseline_selector.py +248 -0
- roadmap/core/services/baseline/baseline_state_retriever.py +284 -0
- roadmap/core/services/baseline/optimized_baseline_builder.py +425 -0
- roadmap/core/services/comment/__init__.py +1 -0
- roadmap/core/services/comment/comment_service.py +277 -0
- roadmap/core/services/git/__init__.py +1 -0
- roadmap/core/services/git/git_hook_auto_sync_service.py +403 -0
- roadmap/core/services/github/__init__.py +1 -0
- roadmap/core/services/github/github_change_detector.py +162 -0
- roadmap/core/services/github/github_config_validator.py +148 -0
- roadmap/core/services/github/github_conflict_detector.py +179 -0
- roadmap/core/services/github/github_entity_classifier.py +51 -0
- roadmap/core/services/github/github_integration_service.py +439 -0
- roadmap/core/services/github/github_issue_client.py +346 -0
- roadmap/core/services/health/__init__.py +1 -0
- roadmap/core/services/health/backup_cleanup_service.py +202 -0
- roadmap/core/services/health/data_integrity_validator_service.py +90 -0
- roadmap/core/services/health/entity_health_scanner.py +460 -0
- roadmap/core/services/health/file_repair_service.py +193 -0
- roadmap/core/services/health/health_check_service.py +166 -0
- roadmap/core/services/health/health_models.py +80 -0
- roadmap/core/services/health/infrastructure_validator_service.py +328 -0
- roadmap/core/services/health/issue_health_scanner.py +263 -0
- roadmap/core/services/helpers/__init__.py +18 -0
- roadmap/core/services/helpers/status_change_helpers.py +88 -0
- roadmap/core/services/initialization/__init__.py +19 -0
- roadmap/core/services/initialization/utils.py +104 -0
- roadmap/core/services/initialization/validator.py +78 -0
- roadmap/core/services/initialization/workflow.py +182 -0
- roadmap/core/services/initialization_service.py +111 -0
- roadmap/core/services/issue/__init__.py +1 -0
- roadmap/core/services/issue/assignee_validation_service.py +312 -0
- roadmap/core/services/issue/issue_creation_service.py +309 -0
- roadmap/core/services/issue/issue_filter_service.py +302 -0
- roadmap/core/services/issue/issue_matching_service.py +127 -0
- roadmap/core/services/issue/issue_service.py +765 -0
- roadmap/core/services/issue/issue_update_service.py +144 -0
- roadmap/core/services/issue/start_issue_service.py +174 -0
- roadmap/core/services/issue_helpers/__init__.py +18 -0
- roadmap/core/services/issue_helpers/issue_filters.py +296 -0
- roadmap/core/services/milestone_service.py +438 -0
- roadmap/core/services/project/__init__.py +1 -0
- roadmap/core/services/project/project_service.py +434 -0
- roadmap/core/services/project/project_status_service.py +125 -0
- roadmap/core/services/project_init/__init__.py +22 -0
- roadmap/core/services/project_init/context_detection.py +146 -0
- roadmap/core/services/project_init/creation.py +76 -0
- roadmap/core/services/project_init/detection.py +51 -0
- roadmap/core/services/project_init/template.py +228 -0
- roadmap/core/services/status_change_service.py +88 -0
- roadmap/core/services/sync/__init__.py +1 -0
- roadmap/core/services/sync/batch_processor.py +290 -0
- roadmap/core/services/sync/conflict_resolver.py +154 -0
- roadmap/core/services/sync/dependency_resolver.py +367 -0
- roadmap/core/services/sync/duplicate_detector.py +771 -0
- roadmap/core/services/sync/duplicate_resolver.py +315 -0
- roadmap/core/services/sync/error_classification.py +470 -0
- roadmap/core/services/sync/performance.py +263 -0
- roadmap/core/services/sync/sync_change_computer.py +211 -0
- roadmap/core/services/sync/sync_checkpoint.py +348 -0
- roadmap/core/services/sync/sync_conflict_detector.py +147 -0
- roadmap/core/services/sync/sync_conflict_resolver.py +448 -0
- roadmap/core/services/sync/sync_errors.py +383 -0
- roadmap/core/services/sync/sync_key_normalizer.py +222 -0
- roadmap/core/services/sync/sync_metadata_service.py +361 -0
- roadmap/core/services/sync/sync_plan.py +171 -0
- roadmap/core/services/sync/sync_plan_executor.py +447 -0
- roadmap/core/services/sync/sync_report.py +296 -0
- roadmap/core/services/sync/sync_state.py +173 -0
- roadmap/core/services/sync/sync_state_comparator.py +690 -0
- roadmap/core/services/sync/sync_state_manager.py +431 -0
- roadmap/core/services/sync/sync_state_normalizer.py +98 -0
- roadmap/core/services/sync/sync_three_way.py +78 -0
- roadmap/core/services/sync/three_way_merger.py +178 -0
- roadmap/core/services/utils/__init__.py +1 -0
- roadmap/core/services/utils/configuration_service.py +113 -0
- roadmap/core/services/utils/critical_path_calculator.py +418 -0
- roadmap/core/services/utils/dependency_analyzer.py +360 -0
- roadmap/core/services/utils/field_conflict_detector.py +126 -0
- roadmap/core/services/utils/remote_fetcher.py +202 -0
- roadmap/core/services/utils/remote_state_normalizer.py +110 -0
- roadmap/core/services/utils/retry_policy.py +51 -0
- roadmap/core/services/validator_base.py +130 -0
- roadmap/core/services/validators/__init__.py +28 -0
- roadmap/core/services/validators/_utils.py +20 -0
- roadmap/core/services/validators/archivable_issues_validator.py +71 -0
- roadmap/core/services/validators/archivable_milestones_validator.py +69 -0
- roadmap/core/services/validators/backup_validator.py +89 -0
- roadmap/core/services/validators/data_integrity_validator.py +84 -0
- roadmap/core/services/validators/duplicate_issues_validator.py +75 -0
- roadmap/core/services/validators/duplicate_milestones_validator.py +141 -0
- roadmap/core/services/validators/folder_structure_validator.py +165 -0
- roadmap/core/services/validators/health_status_utils.py +28 -0
- roadmap/core/services/validators/milestone_naming_validator.py +146 -0
- roadmap/core/services/validators/missing_headlines_validator.py +97 -0
- roadmap/core/services/validators/orphaned_issues_validator.py +142 -0
- roadmap/core/services/validators/orphaned_milestones_validator.py +85 -0
- roadmap/core/utils/git_remote_parser.py +83 -0
- roadmap/core/utils/github_urls.py +66 -0
- roadmap/domain/validation.py +30 -0
- roadmap/infrastructure/__init__.py +55 -0
- roadmap/infrastructure/coordination/__init__.py +8 -0
- roadmap/infrastructure/coordination/coordinator_params.py +82 -0
- roadmap/infrastructure/coordination/core.py +446 -0
- roadmap/infrastructure/coordination/git_coordinator.py +160 -0
- roadmap/infrastructure/coordination/initialization.py +348 -0
- roadmap/infrastructure/coordination/issue_coordinator.py +154 -0
- roadmap/infrastructure/coordination/issue_operations.py +456 -0
- roadmap/infrastructure/coordination/milestone_coordinator.py +135 -0
- roadmap/infrastructure/coordination/milestone_operations.py +201 -0
- roadmap/infrastructure/coordination/project_coordinator.py +113 -0
- roadmap/infrastructure/coordination/project_operations.py +144 -0
- roadmap/infrastructure/coordination/team_coordinator.py +107 -0
- roadmap/infrastructure/coordination/user_operations.py +150 -0
- roadmap/infrastructure/coordination/validation_coordinator.py +249 -0
- roadmap/infrastructure/coordination_gateway.py +152 -0
- roadmap/infrastructure/git/__init__.py +6 -0
- roadmap/infrastructure/git/git_integration_ops.py +234 -0
- roadmap/infrastructure/git_gateway.py +35 -0
- roadmap/infrastructure/github_gateway.py +52 -0
- roadmap/infrastructure/maintenance/__init__.py +5 -0
- roadmap/infrastructure/maintenance/cleanup.py +483 -0
- roadmap/infrastructure/observability/__init__.py +7 -0
- roadmap/infrastructure/observability/health.py +196 -0
- roadmap/infrastructure/observability/health_formatter.py +73 -0
- roadmap/infrastructure/observability/specialized_health_checkers.py +188 -0
- roadmap/infrastructure/persistence_gateway.py +164 -0
- roadmap/infrastructure/security/__init__.py +1 -0
- roadmap/infrastructure/security/credentials.py +489 -0
- roadmap/infrastructure/sync_gateway.py +94 -0
- roadmap/infrastructure/validation/__init__.py +7 -0
- roadmap/infrastructure/validation/file_enumeration.py +219 -0
- roadmap/infrastructure/validation/github_assignee_validator.py +47 -0
- roadmap/infrastructure/validation/github_validator.py +101 -0
- roadmap/infrastructure/validation/milestone_consistency_validator.py +96 -0
- roadmap/infrastructure/validation/vanilla_assignee_validator.py +37 -0
- roadmap/infrastructure/validation_gateway.py +96 -0
- roadmap/presentation/formatters/sync_metrics_formatter.py +355 -0
- roadmap/settings.py +345 -0
- roadmap/templates/github_workflows/ci-cd-roadmap.yml +241 -0
- roadmap/templates/github_workflows/issue-lifecycle.yml +236 -0
- roadmap/templates/github_workflows/roadmap-integration.yml +137 -0
- roadmap/templates/github_workflows/roadmap-starter.yml +59 -0
- roadmap/version.py +381 -0
- roadmap_cli-0.1.1.dist-info/METADATA +448 -0
- roadmap_cli-0.1.1.dist-info/RECORD +521 -0
- roadmap_cli-0.1.1.dist-info/WHEEL +4 -0
- roadmap_cli-0.1.1.dist-info/entry_points.txt +2 -0
- roadmap_cli-0.1.1.dist-info/licenses/LICENSE.md +21 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Click command decorators for structured output with filtering/sorting.
|
|
2
|
+
|
|
3
|
+
Provides @with_output_support decorator that adds:
|
|
4
|
+
- --format flag (rich, plain, json, csv, markdown)
|
|
5
|
+
- --columns flag (select columns)
|
|
6
|
+
- --sort-by flag (sort results)
|
|
7
|
+
- --filter flag (filter results)
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
@click.command()
|
|
11
|
+
@with_output_support(
|
|
12
|
+
available_columns=["id", "name", "status"],
|
|
13
|
+
column_types={"id": ColumnType.INTEGER, "status": ColumnType.ENUM, ...}
|
|
14
|
+
)
|
|
15
|
+
def list_issues(format, columns, sort_by, filter):
|
|
16
|
+
# Command logic returns TableData
|
|
17
|
+
return TableData(...)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from collections.abc import Callable
|
|
21
|
+
from functools import wraps
|
|
22
|
+
|
|
23
|
+
import click
|
|
24
|
+
|
|
25
|
+
from roadmap.adapters.cli.layout import SmartTableLayout
|
|
26
|
+
from roadmap.common.console import get_console
|
|
27
|
+
from roadmap.common.models import ColumnType, TableData
|
|
28
|
+
from roadmap.common.utils.cli_helpers import (
|
|
29
|
+
ColumnSelector,
|
|
30
|
+
FilterSpecParser,
|
|
31
|
+
OutputFormatHandler,
|
|
32
|
+
SortSpecParser,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def with_output_support(
|
|
37
|
+
available_columns: list[str] | None = None,
|
|
38
|
+
column_types: dict[str, ColumnType] | None = None,
|
|
39
|
+
):
|
|
40
|
+
"""Add output formatting support to Click commands.
|
|
41
|
+
|
|
42
|
+
Adds three flags to command:
|
|
43
|
+
- --format: Output format (rich, plain, json, csv, markdown)
|
|
44
|
+
- --columns: Columns to display (comma-separated)
|
|
45
|
+
- --sort-by: Sort specification (format: col:asc,col2:desc)
|
|
46
|
+
- --filter: Filter specification (format: col=value,col2>=5)
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
available_columns: List of valid column names for selection.
|
|
50
|
+
column_types: Dict mapping column names to ColumnType for filter validation.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
@click.command()
|
|
54
|
+
@with_output_support(
|
|
55
|
+
available_columns=["id", "title", "status", "created"],
|
|
56
|
+
column_types={
|
|
57
|
+
"id": ColumnType.INTEGER,
|
|
58
|
+
"status": ColumnType.ENUM,
|
|
59
|
+
"created": ColumnType.DATETIME,
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
def list_issues(format, columns, sort_by, filter):
|
|
63
|
+
issues = issue_service.list_all()
|
|
64
|
+
table = build_table_from_issues(issues)
|
|
65
|
+
return table
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Decorator function.
|
|
69
|
+
"""
|
|
70
|
+
available_columns = available_columns or []
|
|
71
|
+
column_types = column_types or {}
|
|
72
|
+
|
|
73
|
+
def decorator(func: Callable) -> Callable:
|
|
74
|
+
@wraps(func)
|
|
75
|
+
def wrapper(
|
|
76
|
+
*args, format=None, columns=None, sort_by=None, filter_spec=None, **kwargs
|
|
77
|
+
):
|
|
78
|
+
# Call original command with all non-format-related params
|
|
79
|
+
result = func(*args, **kwargs)
|
|
80
|
+
|
|
81
|
+
# If result is TableData, apply formatting/filtering/sorting
|
|
82
|
+
if isinstance(result, TableData):
|
|
83
|
+
# Parse and apply column selection
|
|
84
|
+
if columns:
|
|
85
|
+
selected_cols = ColumnSelector.parse(columns, available_columns)
|
|
86
|
+
if selected_cols:
|
|
87
|
+
result = result.select_columns(selected_cols)
|
|
88
|
+
|
|
89
|
+
# Parse and apply sorting
|
|
90
|
+
if sort_by:
|
|
91
|
+
sort_spec = SortSpecParser.parse(sort_by, available_columns)
|
|
92
|
+
if sort_spec:
|
|
93
|
+
result = result.sort(sort_spec)
|
|
94
|
+
|
|
95
|
+
# Parse and apply filtering
|
|
96
|
+
if filter_spec and column_types:
|
|
97
|
+
filters = FilterSpecParser.parse(filter_spec, column_types)
|
|
98
|
+
if filters:
|
|
99
|
+
for filt in filters:
|
|
100
|
+
# Simple equality filtering for now
|
|
101
|
+
if filt.operator == "=":
|
|
102
|
+
result = result.filter(filt.column, filt.value)
|
|
103
|
+
|
|
104
|
+
# Render in requested format
|
|
105
|
+
if format and format.lower() != "rich":
|
|
106
|
+
output = OutputFormatHandler.render(result, format.lower())
|
|
107
|
+
console = get_console()
|
|
108
|
+
console.print(output)
|
|
109
|
+
return # Don't return TableData, output already printed
|
|
110
|
+
elif format and format.lower() == "rich":
|
|
111
|
+
# Use smart responsive layout for 'rich' format
|
|
112
|
+
layout = SmartTableLayout()
|
|
113
|
+
renderable = layout.render(result)
|
|
114
|
+
console = get_console()
|
|
115
|
+
console.print(renderable)
|
|
116
|
+
return # Rich was printed directly
|
|
117
|
+
else:
|
|
118
|
+
# Default: return TableData (backwards compat)
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
return result
|
|
122
|
+
|
|
123
|
+
# Add Click options (decorators are applied bottom-up)
|
|
124
|
+
wrapper = click.option(
|
|
125
|
+
"--filter",
|
|
126
|
+
"filter_spec",
|
|
127
|
+
help=FilterSpecParser.get_help_text() if column_types else None,
|
|
128
|
+
)(wrapper)
|
|
129
|
+
|
|
130
|
+
wrapper = click.option(
|
|
131
|
+
"--sort-by",
|
|
132
|
+
help=SortSpecParser.get_help_text() if available_columns else None,
|
|
133
|
+
)(wrapper)
|
|
134
|
+
|
|
135
|
+
wrapper = click.option(
|
|
136
|
+
"--columns",
|
|
137
|
+
help=ColumnSelector.get_help_text(available_columns)
|
|
138
|
+
if available_columns
|
|
139
|
+
else None,
|
|
140
|
+
)(wrapper)
|
|
141
|
+
|
|
142
|
+
wrapper = click.option(
|
|
143
|
+
"--format",
|
|
144
|
+
type=click.Choice(
|
|
145
|
+
["rich", "plain", "json", "csv", "markdown"], case_sensitive=False
|
|
146
|
+
),
|
|
147
|
+
default="rich",
|
|
148
|
+
help="Output format (rich=default, plain=POSIX, json=machine-readable, csv=analysis)",
|
|
149
|
+
)(wrapper)
|
|
150
|
+
|
|
151
|
+
return wrapper
|
|
152
|
+
|
|
153
|
+
return decorator
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def add_output_flags(
|
|
157
|
+
available_columns: list[str] | None = None,
|
|
158
|
+
column_types: dict[str, ColumnType] | None = None,
|
|
159
|
+
) -> Callable:
|
|
160
|
+
"""Simpler decorator that just adds flags without automatic processing.
|
|
161
|
+
|
|
162
|
+
Use this if you want manual control over how formatting is applied.
|
|
163
|
+
The flags are added to the command, and you handle them manually.
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
@click.command()
|
|
167
|
+
@add_output_flags(available_columns=["id", "name"])
|
|
168
|
+
def my_command(format, columns, sort_by, filter):
|
|
169
|
+
# You handle the flags manually
|
|
170
|
+
...
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Decorator function.
|
|
174
|
+
"""
|
|
175
|
+
available_columns = available_columns or []
|
|
176
|
+
column_types = column_types or {}
|
|
177
|
+
|
|
178
|
+
def decorator(func: Callable) -> Callable:
|
|
179
|
+
func = click.option(
|
|
180
|
+
"--format",
|
|
181
|
+
type=click.Choice(
|
|
182
|
+
["rich", "plain", "json", "csv", "markdown"], case_sensitive=False
|
|
183
|
+
),
|
|
184
|
+
default="rich",
|
|
185
|
+
help="Output format",
|
|
186
|
+
)(func)
|
|
187
|
+
|
|
188
|
+
func = click.option(
|
|
189
|
+
"--columns",
|
|
190
|
+
help=ColumnSelector.get_help_text(available_columns)
|
|
191
|
+
if available_columns
|
|
192
|
+
else None,
|
|
193
|
+
)(func)
|
|
194
|
+
|
|
195
|
+
func = click.option(
|
|
196
|
+
"--sort-by",
|
|
197
|
+
help=SortSpecParser.get_help_text() if available_columns else None,
|
|
198
|
+
)(func)
|
|
199
|
+
|
|
200
|
+
func = click.option(
|
|
201
|
+
"--filter",
|
|
202
|
+
"filter_spec",
|
|
203
|
+
help=FilterSpecParser.get_help_text() if column_types else None,
|
|
204
|
+
)(func)
|
|
205
|
+
|
|
206
|
+
return func
|
|
207
|
+
|
|
208
|
+
return decorator
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""CLI Data Transfer Objects (DTOs).
|
|
2
|
+
|
|
3
|
+
This module provides lightweight data transfer objects for the CLI layer.
|
|
4
|
+
DTOs decouple the CLI presentation layer from domain models, enabling:
|
|
5
|
+
- Selective field exposure (hide implementation details)
|
|
6
|
+
- Type conversion to CLI-friendly formats
|
|
7
|
+
- Easier testing with mocks
|
|
8
|
+
- Cleaner separation of concerns
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class BaseDTO:
|
|
17
|
+
"""Base class for all DTOs with common functionality."""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_dict(cls, data: dict):
|
|
21
|
+
"""Create DTO from dictionary (flexible initialization)."""
|
|
22
|
+
# Filter to only include known fields
|
|
23
|
+
fields = {f.name for f in cls.__dataclass_fields__.values()}
|
|
24
|
+
filtered = {k: v for k, v in data.items() if k in fields}
|
|
25
|
+
return cls(**filtered)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class IssueDTO(BaseDTO):
|
|
30
|
+
"""CLI-level issue representation for presentation and commands.
|
|
31
|
+
|
|
32
|
+
This DTO provides a CLI-friendly view of issues, converting domain enums
|
|
33
|
+
to strings and hiding internal implementation details.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
id: Unique issue identifier
|
|
37
|
+
title: Issue title/summary
|
|
38
|
+
priority: Priority level (string, not enum)
|
|
39
|
+
status: Current status (string, not enum)
|
|
40
|
+
issue_type: Type of issue (string, not enum)
|
|
41
|
+
assignee: Assigned user, if any
|
|
42
|
+
milestone: Associated milestone name, if any
|
|
43
|
+
due_date: When issue should be completed
|
|
44
|
+
estimated_hours: Estimated time in hours
|
|
45
|
+
actual_end_date: When issue was completed
|
|
46
|
+
progress_percentage: Completion percentage (0-100)
|
|
47
|
+
created: When issue was created
|
|
48
|
+
updated: Last update time
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
id: str
|
|
52
|
+
title: str
|
|
53
|
+
priority: str # String, not enum (e.g., "high", "medium")
|
|
54
|
+
status: str # String, not enum (e.g., "todo", "in_progress")
|
|
55
|
+
headline: str = "" # Short summary for list views
|
|
56
|
+
issue_type: str = "other" # String, not enum
|
|
57
|
+
assignee: str | None = None
|
|
58
|
+
milestone: str | None = None
|
|
59
|
+
due_date: datetime | None = None
|
|
60
|
+
estimated_hours: float | None = None
|
|
61
|
+
actual_end_date: datetime | None = None
|
|
62
|
+
progress_percentage: float | None = None
|
|
63
|
+
created: datetime | None = None
|
|
64
|
+
updated: datetime | None = None
|
|
65
|
+
# Extended fields for detailed views
|
|
66
|
+
content: str | None = None
|
|
67
|
+
labels: list[str] = field(default_factory=list)
|
|
68
|
+
github_issue: str | None = None
|
|
69
|
+
comments: list["CommentDTO"] = field(default_factory=list)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class MilestoneDTO(BaseDTO):
|
|
74
|
+
"""CLI-level milestone representation.
|
|
75
|
+
|
|
76
|
+
Attributes:
|
|
77
|
+
id: Unique milestone identifier (usually name)
|
|
78
|
+
name: Milestone name
|
|
79
|
+
status: Status (string, not enum)
|
|
80
|
+
due_date: Target completion date
|
|
81
|
+
description: Milestone description
|
|
82
|
+
progress_percentage: Overall completion percentage
|
|
83
|
+
issue_count: Number of associated issues
|
|
84
|
+
completed_count: Number of completed issues
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
id: str
|
|
88
|
+
name: str
|
|
89
|
+
status: str # String, not enum
|
|
90
|
+
headline: str = "" # Short summary for list views
|
|
91
|
+
due_date: datetime | None = None
|
|
92
|
+
progress_percentage: float | None = None
|
|
93
|
+
issue_count: int = 0
|
|
94
|
+
completed_count: int = 0
|
|
95
|
+
created: datetime | None = None
|
|
96
|
+
updated: datetime | None = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class ProjectDTO(BaseDTO):
|
|
101
|
+
"""CLI-level project representation.
|
|
102
|
+
|
|
103
|
+
Attributes:
|
|
104
|
+
id: Unique project identifier
|
|
105
|
+
name: Project name
|
|
106
|
+
status: Status (string, not enum)
|
|
107
|
+
description: Project description
|
|
108
|
+
owner: Project owner/creator
|
|
109
|
+
target_end_date: Target completion date
|
|
110
|
+
actual_end_date: Actual completion date
|
|
111
|
+
milestone_count: Number of milestones
|
|
112
|
+
issue_count: Total number of issues
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
id: str
|
|
116
|
+
name: str
|
|
117
|
+
status: str # String, not enum
|
|
118
|
+
headline: str = "" # Short summary for list views
|
|
119
|
+
owner: str | None = None
|
|
120
|
+
target_end_date: datetime | None = None
|
|
121
|
+
actual_end_date: datetime | None = None
|
|
122
|
+
milestone_count: int = 0
|
|
123
|
+
issue_count: int = 0
|
|
124
|
+
created: datetime | None = None
|
|
125
|
+
updated: datetime | None = None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass
|
|
129
|
+
class CommentDTO(BaseDTO):
|
|
130
|
+
"""CLI-level comment representation.
|
|
131
|
+
|
|
132
|
+
Attributes:
|
|
133
|
+
id: Unique comment identifier
|
|
134
|
+
author: Comment author name/username
|
|
135
|
+
body: Comment content (markdown)
|
|
136
|
+
created_at: When comment was created
|
|
137
|
+
updated_at: Last update time
|
|
138
|
+
in_reply_to: Optional comment ID this is a reply to
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
id: int
|
|
142
|
+
author: str
|
|
143
|
+
body: str
|
|
144
|
+
created_at: datetime
|
|
145
|
+
updated_at: datetime
|
|
146
|
+
in_reply_to: int | None = None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
__all__ = [
|
|
150
|
+
"BaseDTO",
|
|
151
|
+
"CommentDTO",
|
|
152
|
+
"IssueDTO",
|
|
153
|
+
"MilestoneDTO",
|
|
154
|
+
"ProjectDTO",
|
|
155
|
+
]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Centralized exception handling for CLI commands.
|
|
2
|
+
|
|
3
|
+
This module provides error handling and formatting for all exceptions
|
|
4
|
+
raised by CLI commands, ensuring consistent user-facing error messages
|
|
5
|
+
and proper stderr output with correct exit codes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from roadmap.common.console import get_console_stderr
|
|
14
|
+
from roadmap.common.error_formatter import (
|
|
15
|
+
format_error_message,
|
|
16
|
+
)
|
|
17
|
+
from roadmap.common.errors.exceptions import RoadmapException
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def handle_cli_exception(
|
|
21
|
+
ctx: click.Context, error: Exception, show_traceback: bool = False
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Centralized exception handler for CLI commands.
|
|
24
|
+
|
|
25
|
+
Catches RoadmapException instances and formats them for user output,
|
|
26
|
+
directing errors to stderr with proper exit codes. Other exceptions
|
|
27
|
+
are re-raised or logged as needed.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
ctx: Click context
|
|
31
|
+
error: The exception to handle
|
|
32
|
+
show_traceback: Whether to show full traceback (for debugging)
|
|
33
|
+
"""
|
|
34
|
+
stderr_console = get_console_stderr()
|
|
35
|
+
|
|
36
|
+
if isinstance(error, RoadmapException):
|
|
37
|
+
# Format using our error formatter, which respects plain mode
|
|
38
|
+
error_msg = format_error_message(error)
|
|
39
|
+
stderr_console.print(error_msg)
|
|
40
|
+
ctx.exit(error.exit_code)
|
|
41
|
+
else:
|
|
42
|
+
# For non-roadmap exceptions, show generic error message
|
|
43
|
+
error_msg = format_error_message(error)
|
|
44
|
+
stderr_console.print(error_msg)
|
|
45
|
+
if show_traceback:
|
|
46
|
+
stderr_console.print_exception()
|
|
47
|
+
ctx.exit(1)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def with_exception_handler(
|
|
51
|
+
show_traceback: bool = False,
|
|
52
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
53
|
+
"""Wrap CLI commands with centralized exception handling.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
show_traceback: Whether to show full traceback on error
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Decorator function
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
63
|
+
"""Implement exception handling decorator."""
|
|
64
|
+
|
|
65
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
66
|
+
"""Execute wrapped function with exception handling."""
|
|
67
|
+
try:
|
|
68
|
+
return func(*args, **kwargs)
|
|
69
|
+
except click.Abort:
|
|
70
|
+
# Click.Abort is intentional, don't handle it
|
|
71
|
+
raise
|
|
72
|
+
except click.ClickException:
|
|
73
|
+
# Click exceptions are already formatted, re-raise
|
|
74
|
+
raise
|
|
75
|
+
except RoadmapException as e:
|
|
76
|
+
# Format roadmap exceptions for output
|
|
77
|
+
ctx = click.get_current_context()
|
|
78
|
+
handle_cli_exception(ctx, e, show_traceback=show_traceback)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
# Unexpected exceptions get generic handling
|
|
81
|
+
ctx = click.get_current_context()
|
|
82
|
+
handle_cli_exception(ctx, e, show_traceback=show_traceback)
|
|
83
|
+
|
|
84
|
+
return click.pass_context(wrapper)
|
|
85
|
+
|
|
86
|
+
return decorator
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def setup_cli_exception_handling() -> None:
|
|
90
|
+
"""Set up global exception handling for the CLI group.
|
|
91
|
+
|
|
92
|
+
This configures Click to use our custom exception handler for all
|
|
93
|
+
subcommands in the CLI group.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
main_group: The Click group (main CLI) to configure
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def handle_exception(ctx: click.Context, exc: Exception) -> None:
|
|
100
|
+
"""Click exception callback."""
|
|
101
|
+
handle_cli_exception(ctx, exc, show_traceback=False)
|
|
102
|
+
|
|
103
|
+
# Note: Click's exception handling is context-specific;
|
|
104
|
+
# individual commands should use the decorator for best results
|
|
105
|
+
# The group-level handling provides a fallback
|