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,319 @@
|
|
|
1
|
+
"""Unified DateTime Parser for Roadmap CLI.
|
|
2
|
+
|
|
3
|
+
This module provides a single source of truth for all datetime parsing operations
|
|
4
|
+
across the roadmap CLI, eliminating duplication and ensuring consistent behavior.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from structlog import get_logger
|
|
12
|
+
|
|
13
|
+
# Import timezone utilities
|
|
14
|
+
from .utils.timezone_utils import (
|
|
15
|
+
ensure_timezone_aware,
|
|
16
|
+
get_timezone_manager,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = get_logger()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class UnifiedDateTimeParser:
|
|
23
|
+
"""Single source of truth for all datetime parsing in roadmap CLI."""
|
|
24
|
+
|
|
25
|
+
# Common datetime format patterns for parsing
|
|
26
|
+
DATETIME_FORMATS = [
|
|
27
|
+
"%Y-%m-%d %H:%M:%S",
|
|
28
|
+
"%Y-%m-%d %H:%M",
|
|
29
|
+
"%Y-%m-%d",
|
|
30
|
+
"%m/%d/%Y %H:%M:%S",
|
|
31
|
+
"%m/%d/%Y %H:%M",
|
|
32
|
+
"%m/%d/%Y",
|
|
33
|
+
"%d/%m/%Y %H:%M:%S",
|
|
34
|
+
"%d/%m/%Y %H:%M",
|
|
35
|
+
"%d/%m/%Y",
|
|
36
|
+
"%Y/%m/%d %H:%M:%S",
|
|
37
|
+
"%Y/%m/%d %H:%M",
|
|
38
|
+
"%Y/%m/%d",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def _handle_datetime_object(
|
|
43
|
+
cls, value: datetime, assumed_timezone: str | None
|
|
44
|
+
) -> datetime:
|
|
45
|
+
"""Handle datetime object input (ensure timezone awareness).
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
value: Datetime object
|
|
49
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Timezone-aware datetime in UTC
|
|
53
|
+
"""
|
|
54
|
+
return ensure_timezone_aware(value, assumed_timezone or "UTC")
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def _normalize_string_value(cls, value: str) -> str | None:
|
|
58
|
+
"""Normalize string input for parsing.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
value: String value to normalize
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Normalized string or None if empty
|
|
65
|
+
"""
|
|
66
|
+
if not isinstance(value, str):
|
|
67
|
+
value = str(value)
|
|
68
|
+
value = value.strip()
|
|
69
|
+
return value if value else None
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def _route_to_specialized_parser(
|
|
73
|
+
cls, value: str, source_type: str, assumed_timezone: str | None
|
|
74
|
+
) -> datetime | None:
|
|
75
|
+
"""Route value to appropriate specialized parser based on type and format.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
value: String value to parse
|
|
79
|
+
source_type: Hint for parsing behavior
|
|
80
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Parsed datetime or None
|
|
84
|
+
"""
|
|
85
|
+
if source_type == "github" or cls._is_github_format(value):
|
|
86
|
+
return cls.parse_github_timestamp(value)
|
|
87
|
+
elif source_type == "iso" or cls._is_iso_format(value):
|
|
88
|
+
return cls.parse_iso_datetime(value, assumed_timezone)
|
|
89
|
+
elif source_type == "file":
|
|
90
|
+
return cls.parse_file_datetime(value, assumed_timezone)
|
|
91
|
+
else:
|
|
92
|
+
return cls.parse_user_datetime(value, assumed_timezone)
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def parse_any_datetime(
|
|
96
|
+
cls, value: Any, source_type: str = "user", assumed_timezone: str | None = None
|
|
97
|
+
) -> datetime | None:
|
|
98
|
+
"""Universal datetime parser for all roadmap CLI needs.
|
|
99
|
+
|
|
100
|
+
This is the primary entry point for datetime parsing. It handles:
|
|
101
|
+
- String datetime values in various formats
|
|
102
|
+
- Existing datetime objects (ensures timezone awareness)
|
|
103
|
+
- None values (returns None)
|
|
104
|
+
- GitHub API timestamps (Z suffix)
|
|
105
|
+
- File frontmatter datetimes
|
|
106
|
+
- User input in multiple formats
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
value: Any datetime-like value (string, datetime, None)
|
|
110
|
+
source_type: Hint for parsing behavior ("user", "github", "file", "iso")
|
|
111
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Timezone-aware datetime in UTC, or None if value is None/invalid
|
|
115
|
+
"""
|
|
116
|
+
if value is None:
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
if isinstance(value, datetime):
|
|
120
|
+
return cls._handle_datetime_object(value, assumed_timezone)
|
|
121
|
+
|
|
122
|
+
# Normalize string value
|
|
123
|
+
normalized = cls._normalize_string_value(value)
|
|
124
|
+
if not normalized:
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
# Route to specialized parser
|
|
128
|
+
return cls._route_to_specialized_parser(
|
|
129
|
+
normalized, source_type, assumed_timezone
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def parse_github_timestamp(cls, github_timestamp: str) -> datetime:
|
|
134
|
+
"""Specialized GitHub API timestamp parsing.
|
|
135
|
+
|
|
136
|
+
Handles GitHub's ISO format timestamps which typically end with 'Z' (UTC).
|
|
137
|
+
Also handles malformed test timestamps with mixed timezone formats.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
github_timestamp: GitHub API timestamp string
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Timezone-aware datetime in UTC
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
ValueError: If timestamp cannot be parsed
|
|
147
|
+
"""
|
|
148
|
+
if not github_timestamp:
|
|
149
|
+
return datetime.min.replace(tzinfo=UTC)
|
|
150
|
+
|
|
151
|
+
# Handle malformed timestamps from tests (e.g., "2025-01-01T00:00:00+00:00Z")
|
|
152
|
+
if github_timestamp.endswith("Z") and "+00:00" in github_timestamp:
|
|
153
|
+
# Remove the trailing Z if there's already timezone info
|
|
154
|
+
github_timestamp = github_timestamp[:-1]
|
|
155
|
+
elif github_timestamp.endswith("Z"):
|
|
156
|
+
# Standard GitHub API format: replace Z with +00:00
|
|
157
|
+
github_timestamp = github_timestamp.replace("Z", "+00:00")
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
# Parse the timestamp and ensure it's in UTC
|
|
161
|
+
dt = datetime.fromisoformat(github_timestamp)
|
|
162
|
+
return ensure_timezone_aware(dt, "UTC")
|
|
163
|
+
except ValueError as e:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Invalid GitHub timestamp format: {github_timestamp}"
|
|
166
|
+
) from e
|
|
167
|
+
|
|
168
|
+
@classmethod
|
|
169
|
+
def parse_file_datetime(
|
|
170
|
+
cls, value: str, assumed_timezone: str | None = None
|
|
171
|
+
) -> datetime | None:
|
|
172
|
+
"""Parse datetime from markdown frontmatter or file content.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
value: Datetime string from file
|
|
176
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Timezone-aware datetime in UTC, or None if invalid
|
|
180
|
+
"""
|
|
181
|
+
if not value or not isinstance(value, str):
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
value = value.strip()
|
|
185
|
+
if not value:
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
# Try ISO format first (most common in files)
|
|
189
|
+
if cls._is_iso_format(value):
|
|
190
|
+
return cls.parse_iso_datetime(value, assumed_timezone)
|
|
191
|
+
|
|
192
|
+
# Try other common formats
|
|
193
|
+
return cls._parse_with_formats(value, cls.DATETIME_FORMATS, assumed_timezone)
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def parse_user_datetime(
|
|
197
|
+
cls, value: str, assumed_timezone: str | None = None
|
|
198
|
+
) -> datetime | None:
|
|
199
|
+
"""Parse datetime from user input with flexible format support.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
value: User input datetime string
|
|
203
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Timezone-aware datetime in UTC, or None if invalid
|
|
207
|
+
"""
|
|
208
|
+
if not value or not isinstance(value, str):
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
# Use the TimezoneManager for user input parsing
|
|
212
|
+
try:
|
|
213
|
+
timezone_manager = get_timezone_manager()
|
|
214
|
+
return timezone_manager.parse_user_input(value, assumed_timezone)
|
|
215
|
+
except Exception as e:
|
|
216
|
+
logger.debug("timezone_manager_parsing_failed", value=value, error=str(e))
|
|
217
|
+
# Fallback to manual parsing
|
|
218
|
+
return cls._parse_with_formats(
|
|
219
|
+
value, cls.DATETIME_FORMATS, assumed_timezone
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
@classmethod
|
|
223
|
+
def parse_iso_datetime(
|
|
224
|
+
cls, value: str, assumed_timezone: str | None = None
|
|
225
|
+
) -> datetime | None:
|
|
226
|
+
"""Parse ISO format datetime string.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
value: ISO format datetime string
|
|
230
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Timezone-aware datetime in UTC, or None if invalid
|
|
234
|
+
"""
|
|
235
|
+
if not value:
|
|
236
|
+
return None
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
# Handle Z suffix (UTC indicator)
|
|
240
|
+
if value.endswith("Z"):
|
|
241
|
+
value = value.replace("Z", "+00:00")
|
|
242
|
+
|
|
243
|
+
# Parse with fromisoformat
|
|
244
|
+
dt = datetime.fromisoformat(value)
|
|
245
|
+
return ensure_timezone_aware(dt, assumed_timezone or "UTC")
|
|
246
|
+
|
|
247
|
+
except ValueError as e:
|
|
248
|
+
logger.debug("iso_datetime_parse_failed", value=value, error=str(e))
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def _is_github_format(cls, value: str) -> bool:
|
|
253
|
+
"""Check if string looks like a GitHub API timestamp."""
|
|
254
|
+
return value.endswith("Z") or (
|
|
255
|
+
"T" in value and (":" in value) and ("+" in value or "Z" in value)
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
@classmethod
|
|
259
|
+
def _is_iso_format(cls, value: str) -> bool:
|
|
260
|
+
"""Check if string looks like ISO format."""
|
|
261
|
+
iso_pattern = r"^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}"
|
|
262
|
+
return bool(re.match(iso_pattern, value))
|
|
263
|
+
|
|
264
|
+
@classmethod
|
|
265
|
+
def _parse_with_formats(
|
|
266
|
+
cls, value: str, formats: list, assumed_timezone: str | None = None
|
|
267
|
+
) -> datetime | None:
|
|
268
|
+
"""Try parsing with multiple datetime formats.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
value: Datetime string to parse
|
|
272
|
+
formats: List of strptime format strings to try
|
|
273
|
+
assumed_timezone: Timezone to assume for naive datetimes
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
Timezone-aware datetime in UTC, or None if no format works
|
|
277
|
+
"""
|
|
278
|
+
for fmt in formats:
|
|
279
|
+
try:
|
|
280
|
+
dt = datetime.strptime(value, fmt)
|
|
281
|
+
return ensure_timezone_aware(dt, assumed_timezone or "UTC")
|
|
282
|
+
except ValueError as e:
|
|
283
|
+
logger.debug(
|
|
284
|
+
"format_datetime_parse_failed",
|
|
285
|
+
value=value,
|
|
286
|
+
format=fmt,
|
|
287
|
+
error=str(e),
|
|
288
|
+
)
|
|
289
|
+
continue
|
|
290
|
+
return None
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
# Convenience functions for backward compatibility and ease of use
|
|
294
|
+
def parse_datetime(
|
|
295
|
+
value: Any, source_type: str = "user", assumed_timezone: str | None = None
|
|
296
|
+
) -> datetime | None:
|
|
297
|
+
"""Parse datetime from various input formats."""
|
|
298
|
+
return UnifiedDateTimeParser.parse_any_datetime(
|
|
299
|
+
value, source_type, assumed_timezone
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def parse_github_datetime(github_timestamp: str) -> datetime:
|
|
304
|
+
"""Parse GitHub timestamp format."""
|
|
305
|
+
return UnifiedDateTimeParser.parse_github_timestamp(github_timestamp)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def parse_file_datetime(
|
|
309
|
+
value: str, assumed_timezone: str | None = None
|
|
310
|
+
) -> datetime | None:
|
|
311
|
+
"""Parse datetime from file path format."""
|
|
312
|
+
return UnifiedDateTimeParser.parse_file_datetime(value, assumed_timezone)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def parse_user_datetime(
|
|
316
|
+
value: str, assumed_timezone: str | None = None
|
|
317
|
+
) -> datetime | None:
|
|
318
|
+
"""Parse user-input datetime string."""
|
|
319
|
+
return UnifiedDateTimeParser.parse_user_datetime(value, assumed_timezone)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Error formatting utilities for CLI output.
|
|
2
|
+
|
|
3
|
+
Provides consistent error message formatting for both plain and rich output modes.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from roadmap.common.console import is_plain_mode
|
|
7
|
+
from roadmap.common.errors.exceptions import RoadmapException
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def format_error_message(exc: RoadmapException | Exception) -> str:
|
|
11
|
+
"""Format an exception for user-friendly CLI output.
|
|
12
|
+
|
|
13
|
+
For RoadmapException: Uses user_message with appropriate styling
|
|
14
|
+
For other exceptions: Uses generic fallback message
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
exc: Exception to format
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Formatted error message suitable for stderr output
|
|
21
|
+
"""
|
|
22
|
+
plain = is_plain_mode()
|
|
23
|
+
|
|
24
|
+
if isinstance(exc, RoadmapException):
|
|
25
|
+
message = exc.user_message
|
|
26
|
+
else:
|
|
27
|
+
message = str(exc)
|
|
28
|
+
|
|
29
|
+
# Add prefix based on mode
|
|
30
|
+
if plain:
|
|
31
|
+
return f"[ERROR] {message}"
|
|
32
|
+
else:
|
|
33
|
+
return f"❌ {message}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def format_warning_message(message: str) -> str:
|
|
37
|
+
"""Format a warning message for CLI output.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
message: Warning message text
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Formatted warning message
|
|
44
|
+
"""
|
|
45
|
+
plain = is_plain_mode()
|
|
46
|
+
|
|
47
|
+
if plain:
|
|
48
|
+
return f"[WARN] {message}"
|
|
49
|
+
else:
|
|
50
|
+
return f"⚠️ {message}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def format_info_message(message: str) -> str:
|
|
54
|
+
"""Format an info message for CLI output.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
message: Info message text
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Formatted info message
|
|
61
|
+
"""
|
|
62
|
+
plain = is_plain_mode()
|
|
63
|
+
|
|
64
|
+
if plain:
|
|
65
|
+
return f"[INFO] {message}"
|
|
66
|
+
else:
|
|
67
|
+
return f"ℹ️ {message}"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def format_success_message(message: str) -> str:
|
|
71
|
+
"""Format a success message for CLI output.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
message: Success message text
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Formatted success message
|
|
78
|
+
"""
|
|
79
|
+
plain = is_plain_mode()
|
|
80
|
+
|
|
81
|
+
if plain:
|
|
82
|
+
return f"[OK] {message}"
|
|
83
|
+
else:
|
|
84
|
+
return f"✅ {message}"
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Error handling and exception definitions for Roadmap.
|
|
2
|
+
|
|
3
|
+
This package provides organized error classes, categorized by concern:
|
|
4
|
+
- exceptions: High-level exceptions with domain and user messages (NEW)
|
|
5
|
+
- error_base: Core exception classes and enums
|
|
6
|
+
- error_file: File and I/O related errors
|
|
7
|
+
- error_validation: Data validation errors
|
|
8
|
+
- error_network: Network and GitHub API errors
|
|
9
|
+
- error_git: Git operation errors and configuration errors
|
|
10
|
+
- error_security: Security and parsing errors
|
|
11
|
+
- error_handler: Error handling utilities
|
|
12
|
+
- error_standards: Standardized error handling decorators and context managers (NEW)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# Legacy error hierarchy (backwards compatibility)
|
|
16
|
+
from roadmap.common.errors.error_base import (
|
|
17
|
+
ErrorCategory,
|
|
18
|
+
ErrorSeverity,
|
|
19
|
+
RoadmapError,
|
|
20
|
+
)
|
|
21
|
+
from roadmap.common.errors.error_file import (
|
|
22
|
+
DirectoryCreationError,
|
|
23
|
+
ExportError,
|
|
24
|
+
FileLockError,
|
|
25
|
+
FileOperationError,
|
|
26
|
+
FileReadError,
|
|
27
|
+
FileWriteError,
|
|
28
|
+
ImportError,
|
|
29
|
+
PersistenceError,
|
|
30
|
+
)
|
|
31
|
+
from roadmap.common.errors.error_git import ConfigurationError, GitOperationError
|
|
32
|
+
from roadmap.common.errors.error_handler import ErrorHandler, handle_errors
|
|
33
|
+
from roadmap.common.errors.error_network import (
|
|
34
|
+
AuthenticationError,
|
|
35
|
+
GitHubAPIError,
|
|
36
|
+
NetworkError,
|
|
37
|
+
)
|
|
38
|
+
from roadmap.common.errors.error_security import (
|
|
39
|
+
ParseError,
|
|
40
|
+
PathValidationError,
|
|
41
|
+
SecurityError,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Standardized error handling decorators and utilities
|
|
45
|
+
from roadmap.common.errors.error_standards import (
|
|
46
|
+
ErrorContext,
|
|
47
|
+
OperationType,
|
|
48
|
+
RecoveryAction,
|
|
49
|
+
log_operation,
|
|
50
|
+
safe_operation,
|
|
51
|
+
with_error_handling,
|
|
52
|
+
)
|
|
53
|
+
from roadmap.common.errors.error_validation import (
|
|
54
|
+
IssueNotFoundError,
|
|
55
|
+
MilestoneNotFoundError,
|
|
56
|
+
StateError,
|
|
57
|
+
ValidationError,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# New exception hierarchy (recommended for future use)
|
|
61
|
+
from roadmap.common.errors.exceptions import (
|
|
62
|
+
AlreadyInitializedError,
|
|
63
|
+
CreateError,
|
|
64
|
+
DatabaseError,
|
|
65
|
+
DeleteError,
|
|
66
|
+
EntityNotFoundError,
|
|
67
|
+
GitConfigError,
|
|
68
|
+
GitError,
|
|
69
|
+
GitHubError,
|
|
70
|
+
InvalidPriorityError,
|
|
71
|
+
InvalidStatusError,
|
|
72
|
+
NoGitRepositoryError,
|
|
73
|
+
NotInitializedError,
|
|
74
|
+
OperationError,
|
|
75
|
+
ProjectNotFoundError,
|
|
76
|
+
RoadmapException,
|
|
77
|
+
UpdateError,
|
|
78
|
+
)
|
|
79
|
+
from roadmap.common.errors.exceptions import (
|
|
80
|
+
IssueNotFoundError as NewIssueNotFoundError,
|
|
81
|
+
)
|
|
82
|
+
from roadmap.common.errors.exceptions import (
|
|
83
|
+
MilestoneNotFoundError as NewMilestoneNotFoundError,
|
|
84
|
+
)
|
|
85
|
+
from roadmap.common.errors.exceptions import (
|
|
86
|
+
ValidationError as NewValidationError,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
__all__ = [
|
|
90
|
+
# Legacy (backwards compatibility)
|
|
91
|
+
"ErrorSeverity",
|
|
92
|
+
"ErrorCategory",
|
|
93
|
+
"RoadmapError",
|
|
94
|
+
"FileOperationError",
|
|
95
|
+
"DirectoryCreationError",
|
|
96
|
+
"FileReadError",
|
|
97
|
+
"FileWriteError",
|
|
98
|
+
"ExportError",
|
|
99
|
+
"ImportError",
|
|
100
|
+
"PersistenceError",
|
|
101
|
+
"FileLockError",
|
|
102
|
+
"ValidationError",
|
|
103
|
+
"NetworkError",
|
|
104
|
+
"AuthenticationError",
|
|
105
|
+
"GitHubAPIError",
|
|
106
|
+
"GitOperationError",
|
|
107
|
+
"SecurityError",
|
|
108
|
+
"PathValidationError",
|
|
109
|
+
"ParseError",
|
|
110
|
+
"ErrorHandler",
|
|
111
|
+
"handle_errors",
|
|
112
|
+
"StateError",
|
|
113
|
+
"IssueNotFoundError",
|
|
114
|
+
"MilestoneNotFoundError",
|
|
115
|
+
"ConfigurationError",
|
|
116
|
+
# New exceptions (recommended)
|
|
117
|
+
"RoadmapException",
|
|
118
|
+
"NotInitializedError",
|
|
119
|
+
"AlreadyInitializedError",
|
|
120
|
+
"EntityNotFoundError",
|
|
121
|
+
"NewIssueNotFoundError",
|
|
122
|
+
"NewMilestoneNotFoundError",
|
|
123
|
+
"ProjectNotFoundError",
|
|
124
|
+
"NewValidationError",
|
|
125
|
+
"InvalidStatusError",
|
|
126
|
+
"InvalidPriorityError",
|
|
127
|
+
"OperationError",
|
|
128
|
+
"CreateError",
|
|
129
|
+
"UpdateError",
|
|
130
|
+
"DeleteError",
|
|
131
|
+
"DatabaseError",
|
|
132
|
+
"GitError",
|
|
133
|
+
"GitHubError",
|
|
134
|
+
"GitConfigError",
|
|
135
|
+
"NoGitRepositoryError",
|
|
136
|
+
# Standardized error handling decorators and utilities
|
|
137
|
+
"safe_operation",
|
|
138
|
+
"log_operation",
|
|
139
|
+
"with_error_handling",
|
|
140
|
+
"ErrorContext",
|
|
141
|
+
"OperationType",
|
|
142
|
+
"RecoveryAction",
|
|
143
|
+
]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Base error classes and enums for Roadmap."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ErrorSeverity(Enum):
|
|
8
|
+
"""Error severity levels for consistent classification."""
|
|
9
|
+
|
|
10
|
+
CRITICAL = "critical"
|
|
11
|
+
HIGH = "high"
|
|
12
|
+
MEDIUM = "medium"
|
|
13
|
+
LOW = "low"
|
|
14
|
+
WARNING = "warning"
|
|
15
|
+
INFO = "info"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ErrorCategory(Enum):
|
|
19
|
+
"""Error categories for better organization and handling."""
|
|
20
|
+
|
|
21
|
+
FILE_OPERATION = "file_operation"
|
|
22
|
+
VALIDATION = "validation"
|
|
23
|
+
NETWORK = "network"
|
|
24
|
+
GIT_OPERATION = "git_operation"
|
|
25
|
+
GITHUB_API = "github_api"
|
|
26
|
+
PARSING = "parsing"
|
|
27
|
+
CONFIGURATION = "configuration"
|
|
28
|
+
PERMISSION = "permission"
|
|
29
|
+
DEPENDENCY = "dependency"
|
|
30
|
+
USER_INPUT = "user_input"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RoadmapError(Exception):
|
|
34
|
+
"""Base exception for all roadmap-specific errors."""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
message: str,
|
|
39
|
+
severity: ErrorSeverity = ErrorSeverity.MEDIUM,
|
|
40
|
+
category: ErrorCategory = ErrorCategory.VALIDATION,
|
|
41
|
+
context: dict[str, Any] | None = None,
|
|
42
|
+
cause: Exception | None = None,
|
|
43
|
+
):
|
|
44
|
+
"""Initialize RoadmapError.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
message: Error message.
|
|
48
|
+
severity: Error severity level.
|
|
49
|
+
category: Error category.
|
|
50
|
+
context: Additional context dictionary.
|
|
51
|
+
cause: Underlying exception that caused this error.
|
|
52
|
+
"""
|
|
53
|
+
super().__init__(message)
|
|
54
|
+
self.message = message
|
|
55
|
+
self.severity = severity
|
|
56
|
+
self.category = category
|
|
57
|
+
self.context = context or {}
|
|
58
|
+
self.cause = cause
|
|
59
|
+
|
|
60
|
+
def __str__(self) -> str:
|
|
61
|
+
"""Return string representation of error."""
|
|
62
|
+
return self.message
|
|
63
|
+
|
|
64
|
+
def get_context_info(self) -> str:
|
|
65
|
+
"""Get formatted context information."""
|
|
66
|
+
if not self.context:
|
|
67
|
+
return ""
|
|
68
|
+
|
|
69
|
+
context_parts = []
|
|
70
|
+
for key, value in self.context.items():
|
|
71
|
+
context_parts.append(f"{key}: {value}")
|
|
72
|
+
|
|
73
|
+
return f" ({', '.join(context_parts)})"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""File and I/O related error classes."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from roadmap.common.errors.error_base import ErrorCategory, ErrorSeverity, RoadmapError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileOperationError(RoadmapError):
|
|
9
|
+
"""Errors related to file operations."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
message: str,
|
|
14
|
+
file_path: Path | None = None,
|
|
15
|
+
operation: str | None = None,
|
|
16
|
+
**kwargs,
|
|
17
|
+
):
|
|
18
|
+
"""Initialize FileOperationError.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
message: Error message.
|
|
22
|
+
file_path: Path to the file involved in the error.
|
|
23
|
+
operation: Name of the file operation that failed.
|
|
24
|
+
**kwargs: Additional arguments passed to parent class.
|
|
25
|
+
"""
|
|
26
|
+
context = kwargs.get("context", {})
|
|
27
|
+
if file_path:
|
|
28
|
+
context["file_path"] = str(file_path)
|
|
29
|
+
if operation:
|
|
30
|
+
context["operation"] = operation
|
|
31
|
+
|
|
32
|
+
super().__init__(
|
|
33
|
+
message,
|
|
34
|
+
severity=kwargs.get("severity", ErrorSeverity.HIGH),
|
|
35
|
+
category=ErrorCategory.FILE_OPERATION,
|
|
36
|
+
context=context,
|
|
37
|
+
cause=kwargs.get("cause"),
|
|
38
|
+
)
|
|
39
|
+
self.file_path = file_path
|
|
40
|
+
self.operation = operation
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PersistenceError(FileOperationError):
|
|
44
|
+
"""Raised when database or file persistence operations fail."""
|
|
45
|
+
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FileLockError(FileOperationError):
|
|
50
|
+
"""Raised when file locking operations fail."""
|
|
51
|
+
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class DirectoryCreationError(FileOperationError):
|
|
56
|
+
"""Raised when directory creation fails."""
|
|
57
|
+
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class FileReadError(FileOperationError):
|
|
62
|
+
"""Raised when file reading fails."""
|
|
63
|
+
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FileWriteError(FileOperationError):
|
|
68
|
+
"""Raised when file writing fails."""
|
|
69
|
+
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ExportError(FileOperationError):
|
|
74
|
+
"""Raised when data export fails."""
|
|
75
|
+
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ImportError(FileOperationError):
|
|
80
|
+
"""Raised when data import fails."""
|
|
81
|
+
|
|
82
|
+
pass
|