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,310 @@
|
|
|
1
|
+
"""Main roadmap entity validators."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from structlog import get_logger
|
|
9
|
+
|
|
10
|
+
from roadmap.common.constants import IssueType, MilestoneStatus, Priority, Status
|
|
11
|
+
|
|
12
|
+
from .field_validator import FieldValidator
|
|
13
|
+
from .result import ValidationResult
|
|
14
|
+
from .schema_validator import SchemaValidator
|
|
15
|
+
|
|
16
|
+
logger = get_logger()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RoadmapValidator:
|
|
20
|
+
"""Main validation class with predefined validators for roadmap entities."""
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
"""Initialize RoadmapValidator."""
|
|
24
|
+
self._setup_predefined_validators()
|
|
25
|
+
|
|
26
|
+
def _setup_predefined_validators(self):
|
|
27
|
+
"""Set up predefined validators for common roadmap entities."""
|
|
28
|
+
# Issue validation schema
|
|
29
|
+
self.issue_schema = SchemaValidator("issue")
|
|
30
|
+
self.issue_schema.add_field(
|
|
31
|
+
FieldValidator("id", required=True, pattern=r"^[a-f0-9]{8}$")
|
|
32
|
+
).add_field(
|
|
33
|
+
FieldValidator("title", required=True, min_length=1, max_length=200)
|
|
34
|
+
).add_field(
|
|
35
|
+
FieldValidator(
|
|
36
|
+
"priority", required=True, enum_values=[p.value for p in Priority]
|
|
37
|
+
)
|
|
38
|
+
).add_field(
|
|
39
|
+
FieldValidator(
|
|
40
|
+
"status", required=True, enum_values=[s.value for s in Status]
|
|
41
|
+
)
|
|
42
|
+
).add_field(
|
|
43
|
+
FieldValidator("issue_type", enum_values=[t.value for t in IssueType])
|
|
44
|
+
).add_field(
|
|
45
|
+
FieldValidator(
|
|
46
|
+
"assignee", max_length=100, custom_validator=self._validate_assignee
|
|
47
|
+
)
|
|
48
|
+
).add_field(FieldValidator("milestone", max_length=100)).add_field(
|
|
49
|
+
FieldValidator(
|
|
50
|
+
"estimated_hours", custom_validator=self._validate_positive_number
|
|
51
|
+
)
|
|
52
|
+
).add_field(
|
|
53
|
+
FieldValidator(
|
|
54
|
+
"progress_percentage", custom_validator=self._validate_percentage
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Milestone validation schema
|
|
59
|
+
self.milestone_schema = SchemaValidator("milestone")
|
|
60
|
+
self.milestone_schema.add_field(
|
|
61
|
+
FieldValidator("name", required=True, min_length=1, max_length=100)
|
|
62
|
+
).add_field(
|
|
63
|
+
FieldValidator(
|
|
64
|
+
"status", required=True, enum_values=[s.value for s in MilestoneStatus]
|
|
65
|
+
)
|
|
66
|
+
).add_field(FieldValidator("description", max_length=1000)).add_field(
|
|
67
|
+
FieldValidator("due_date", custom_validator=self._validate_datetime)
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Project validation schema
|
|
71
|
+
self.project_schema = SchemaValidator("project")
|
|
72
|
+
self.project_schema.add_field(
|
|
73
|
+
FieldValidator("id", required=True, pattern=r"^[a-f0-9-]+$")
|
|
74
|
+
).add_field(
|
|
75
|
+
FieldValidator("name", required=True, min_length=1, max_length=200)
|
|
76
|
+
).add_field(FieldValidator("description", max_length=2000)).add_field(
|
|
77
|
+
FieldValidator("owner", max_length=100)
|
|
78
|
+
).add_field(
|
|
79
|
+
FieldValidator(
|
|
80
|
+
"estimated_hours", custom_validator=self._validate_positive_number
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def _validate_assignee(self, value: Any) -> tuple[bool, str]:
|
|
85
|
+
"""Validate assignee format."""
|
|
86
|
+
if value is None:
|
|
87
|
+
return True, ""
|
|
88
|
+
|
|
89
|
+
str_value = str(value)
|
|
90
|
+
if not str_value:
|
|
91
|
+
return True, ""
|
|
92
|
+
|
|
93
|
+
# Basic username format validation
|
|
94
|
+
if not re.match(r"^[a-zA-Z0-9_-]+$", str_value):
|
|
95
|
+
return (
|
|
96
|
+
False,
|
|
97
|
+
"must contain only alphanumeric characters, hyphens, and underscores",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if len(str_value) > 39: # GitHub username limit
|
|
101
|
+
return False, "must be 39 characters or less"
|
|
102
|
+
|
|
103
|
+
return True, ""
|
|
104
|
+
|
|
105
|
+
def _validate_positive_number(self, value: Any) -> tuple[bool, str]:
|
|
106
|
+
"""Validate that a number is positive."""
|
|
107
|
+
if value is None:
|
|
108
|
+
return True, ""
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
num_value = float(value)
|
|
112
|
+
if num_value < 0:
|
|
113
|
+
return False, "must be a positive number"
|
|
114
|
+
return True, ""
|
|
115
|
+
except (ValueError, TypeError) as e:
|
|
116
|
+
logger.debug("number_validation_failed", value=value, error=str(e))
|
|
117
|
+
return False, "must be a valid number"
|
|
118
|
+
|
|
119
|
+
def _validate_percentage(self, value: Any) -> tuple[bool, str]:
|
|
120
|
+
"""Validate percentage value (0-100)."""
|
|
121
|
+
if value is None:
|
|
122
|
+
return True, ""
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
num_value = float(value)
|
|
126
|
+
if not 0 <= num_value <= 100:
|
|
127
|
+
return False, "must be between 0 and 100"
|
|
128
|
+
return True, ""
|
|
129
|
+
except (ValueError, TypeError) as e:
|
|
130
|
+
logger.debug("percentage_validation_failed", value=value, error=str(e))
|
|
131
|
+
return False, "must be a valid number"
|
|
132
|
+
|
|
133
|
+
def _validate_datetime(self, value: Any) -> tuple[bool, str]:
|
|
134
|
+
"""Validate datetime format."""
|
|
135
|
+
if value is None:
|
|
136
|
+
return True, ""
|
|
137
|
+
|
|
138
|
+
if isinstance(value, datetime):
|
|
139
|
+
return True, ""
|
|
140
|
+
|
|
141
|
+
# Try to parse string as datetime
|
|
142
|
+
if isinstance(value, str):
|
|
143
|
+
try:
|
|
144
|
+
from roadmap.common.datetime_parser import parse_datetime
|
|
145
|
+
|
|
146
|
+
parse_datetime(value, "flexible")
|
|
147
|
+
return True, ""
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.debug("datetime_parsing_failed", value=value, error=str(e))
|
|
150
|
+
return False, "must be a valid datetime format"
|
|
151
|
+
|
|
152
|
+
return False, "must be a datetime or valid datetime string"
|
|
153
|
+
|
|
154
|
+
def validate_issue(self, issue_data: dict[str, Any]) -> ValidationResult:
|
|
155
|
+
"""Validate issue data."""
|
|
156
|
+
return self.issue_schema.validate(issue_data)
|
|
157
|
+
|
|
158
|
+
def validate_milestone(self, milestone_data: dict[str, Any]) -> ValidationResult:
|
|
159
|
+
"""Validate milestone data."""
|
|
160
|
+
return self.milestone_schema.validate(milestone_data)
|
|
161
|
+
|
|
162
|
+
def validate_project(self, project_data: dict[str, Any]) -> ValidationResult:
|
|
163
|
+
"""Validate project data."""
|
|
164
|
+
return self.project_schema.validate(project_data)
|
|
165
|
+
|
|
166
|
+
def validate_required_fields(
|
|
167
|
+
self, data: dict[str, Any], required_fields: list[str]
|
|
168
|
+
) -> ValidationResult:
|
|
169
|
+
"""Validate that required fields are present."""
|
|
170
|
+
result = ValidationResult()
|
|
171
|
+
missing_fields = []
|
|
172
|
+
|
|
173
|
+
for field in required_fields:
|
|
174
|
+
if field not in data or data[field] is None or data[field] == "":
|
|
175
|
+
missing_fields.append(field)
|
|
176
|
+
|
|
177
|
+
if missing_fields:
|
|
178
|
+
result.add_error(f"Missing required fields: {', '.join(missing_fields)}")
|
|
179
|
+
|
|
180
|
+
return result
|
|
181
|
+
|
|
182
|
+
def validate_enum_field(
|
|
183
|
+
self, value: Any, field_name: str, enum_class: Any
|
|
184
|
+
) -> ValidationResult:
|
|
185
|
+
"""Validate an enum field."""
|
|
186
|
+
result = ValidationResult(field=field_name)
|
|
187
|
+
|
|
188
|
+
if value is None:
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
valid_values = [e.value for e in enum_class]
|
|
192
|
+
check_value = value.value if hasattr(value, "value") else value
|
|
193
|
+
|
|
194
|
+
if check_value not in valid_values:
|
|
195
|
+
result.add_error(
|
|
196
|
+
f"Invalid {field_name}: {check_value}. Valid values: {', '.join(valid_values)}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return result
|
|
200
|
+
|
|
201
|
+
def validate_string_length(
|
|
202
|
+
self,
|
|
203
|
+
value: str,
|
|
204
|
+
field_name: str,
|
|
205
|
+
min_length: int = 0,
|
|
206
|
+
max_length: int | None = None,
|
|
207
|
+
) -> ValidationResult:
|
|
208
|
+
"""Validate string length constraints."""
|
|
209
|
+
result = ValidationResult(field=field_name)
|
|
210
|
+
|
|
211
|
+
if value is None:
|
|
212
|
+
return result
|
|
213
|
+
|
|
214
|
+
if len(value) < min_length:
|
|
215
|
+
result.add_error(f"{field_name} must be at least {min_length} characters")
|
|
216
|
+
|
|
217
|
+
if max_length and len(value) > max_length:
|
|
218
|
+
result.add_error(
|
|
219
|
+
f"{field_name} must be no more than {max_length} characters"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return result
|
|
223
|
+
|
|
224
|
+
def validate_id_format(
|
|
225
|
+
self, id_value: str, field_name: str = "id"
|
|
226
|
+
) -> ValidationResult:
|
|
227
|
+
"""Validate ID format (8-character hex for issues, UUID-like for projects)."""
|
|
228
|
+
result = ValidationResult(field=field_name)
|
|
229
|
+
|
|
230
|
+
if not id_value:
|
|
231
|
+
result.add_error(f"{field_name} is required")
|
|
232
|
+
return result
|
|
233
|
+
|
|
234
|
+
# For issue IDs (8-character hex)
|
|
235
|
+
if len(id_value) == 8 and re.match(r"^[a-f0-9]{8}$", id_value):
|
|
236
|
+
return result
|
|
237
|
+
|
|
238
|
+
# For project IDs (UUID-like format)
|
|
239
|
+
if re.match(r"^[a-f0-9-]+$", id_value):
|
|
240
|
+
return result
|
|
241
|
+
|
|
242
|
+
result.add_error(f"{field_name} must be a valid ID format")
|
|
243
|
+
return result
|
|
244
|
+
|
|
245
|
+
def validate_path(
|
|
246
|
+
self, path_value: str | Path, field_name: str = "path"
|
|
247
|
+
) -> ValidationResult:
|
|
248
|
+
"""Validate file path."""
|
|
249
|
+
result = ValidationResult(field=field_name)
|
|
250
|
+
|
|
251
|
+
if path_value is None:
|
|
252
|
+
return result
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
path = Path(path_value)
|
|
256
|
+
|
|
257
|
+
# Check for path traversal attempts
|
|
258
|
+
if ".." in str(path):
|
|
259
|
+
result.add_error(f"{field_name} cannot contain '..' (path traversal)")
|
|
260
|
+
|
|
261
|
+
# Check for absolute paths when relative expected
|
|
262
|
+
if path.is_absolute() and field_name in ["filename", "relative_path"]:
|
|
263
|
+
result.add_error(f"{field_name} should be a relative path")
|
|
264
|
+
|
|
265
|
+
except Exception as e:
|
|
266
|
+
logger.error("path_validation_failed", path=str(path_value), error=str(e))
|
|
267
|
+
result.add_error(f"Invalid {field_name}: {str(e)}")
|
|
268
|
+
|
|
269
|
+
return result
|
|
270
|
+
|
|
271
|
+
def validate_github_issue_number(
|
|
272
|
+
self, issue_number: Any, field_name: str = "github_issue"
|
|
273
|
+
) -> ValidationResult:
|
|
274
|
+
"""Validate GitHub issue number."""
|
|
275
|
+
result = ValidationResult(field=field_name)
|
|
276
|
+
|
|
277
|
+
if issue_number is None:
|
|
278
|
+
return result
|
|
279
|
+
|
|
280
|
+
try:
|
|
281
|
+
num = int(issue_number)
|
|
282
|
+
if num <= 0:
|
|
283
|
+
result.add_error(f"{field_name} must be a positive integer")
|
|
284
|
+
except (ValueError, TypeError):
|
|
285
|
+
result.add_error(f"{field_name} must be a valid integer")
|
|
286
|
+
|
|
287
|
+
return result
|
|
288
|
+
|
|
289
|
+
def validate_labels(
|
|
290
|
+
self, labels: Any, field_name: str = "labels"
|
|
291
|
+
) -> ValidationResult:
|
|
292
|
+
"""Validate labels list."""
|
|
293
|
+
result = ValidationResult(field=field_name)
|
|
294
|
+
|
|
295
|
+
if labels is None:
|
|
296
|
+
return result
|
|
297
|
+
|
|
298
|
+
if not isinstance(labels, list):
|
|
299
|
+
result.add_error(f"{field_name} must be a list")
|
|
300
|
+
return result
|
|
301
|
+
|
|
302
|
+
for i, label in enumerate(labels):
|
|
303
|
+
if not isinstance(label, str):
|
|
304
|
+
result.add_error(f"{field_name}[{i}] must be a string")
|
|
305
|
+
elif len(label) > 50:
|
|
306
|
+
result.add_error(f"{field_name}[{i}] must be 50 characters or less")
|
|
307
|
+
elif not label.strip():
|
|
308
|
+
result.add_error(f"{field_name}[{i}] cannot be empty")
|
|
309
|
+
|
|
310
|
+
return result
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Schema-based validator for complex data structures."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .field_validator import FieldValidator
|
|
6
|
+
from .result import ValidationResult
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SchemaValidator:
|
|
10
|
+
"""Schema-based validator for complex data structures."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, schema_name: str):
|
|
13
|
+
"""Initialize SchemaValidator.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
schema_name: Name of the schema being validated.
|
|
17
|
+
"""
|
|
18
|
+
self.schema_name = schema_name
|
|
19
|
+
self.validators: dict[str, FieldValidator] = {}
|
|
20
|
+
|
|
21
|
+
def add_field(self, validator: FieldValidator) -> "SchemaValidator":
|
|
22
|
+
"""Add a field validator to the schema."""
|
|
23
|
+
self.validators[validator.field_name] = validator
|
|
24
|
+
return self
|
|
25
|
+
|
|
26
|
+
def validate(self, data: dict[str, Any]) -> ValidationResult:
|
|
27
|
+
"""Validate data against the schema."""
|
|
28
|
+
result = ValidationResult()
|
|
29
|
+
|
|
30
|
+
# Validate each field
|
|
31
|
+
for field_name, validator in self.validators.items():
|
|
32
|
+
value = data.get(field_name)
|
|
33
|
+
field_result = validator.validate(value)
|
|
34
|
+
result.merge(field_result)
|
|
35
|
+
|
|
36
|
+
return result
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Validation utility functions and helpers."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from roadmap.common.errors.exceptions import ValidationError
|
|
7
|
+
|
|
8
|
+
from .result import ValidationResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ValidationType(Enum):
|
|
12
|
+
"""Types of validation checks."""
|
|
13
|
+
|
|
14
|
+
REQUIRED = "required"
|
|
15
|
+
FORMAT = "format"
|
|
16
|
+
RANGE = "range"
|
|
17
|
+
ENUM = "enum"
|
|
18
|
+
LENGTH = "length"
|
|
19
|
+
PATTERN = "pattern"
|
|
20
|
+
CUSTOM = "custom"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def validate_and_raise(validation_result: ValidationResult, context: str | None = None):
|
|
24
|
+
"""Validate result and raise ValidationError if invalid."""
|
|
25
|
+
if not validation_result.is_valid:
|
|
26
|
+
error_message = "; ".join(validation_result.errors)
|
|
27
|
+
if context:
|
|
28
|
+
error_message = f"{context}: {error_message}"
|
|
29
|
+
|
|
30
|
+
raise ValidationError(domain_message=error_message, user_message=error_message)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def validate_frontmatter_structure(
|
|
34
|
+
frontmatter: dict[str, Any], expected_type: str
|
|
35
|
+
) -> tuple[bool, list[str]]:
|
|
36
|
+
"""Validate frontmatter structure for backward compatibility."""
|
|
37
|
+
from .roadmap_validator import RoadmapValidator
|
|
38
|
+
|
|
39
|
+
validator = RoadmapValidator()
|
|
40
|
+
|
|
41
|
+
if expected_type == "issue":
|
|
42
|
+
result = validator.validate_issue(frontmatter)
|
|
43
|
+
elif expected_type == "milestone":
|
|
44
|
+
result = validator.validate_milestone(frontmatter)
|
|
45
|
+
elif expected_type == "project":
|
|
46
|
+
result = validator.validate_project(frontmatter)
|
|
47
|
+
else:
|
|
48
|
+
return False, [f"Unknown type: {expected_type}"]
|
|
49
|
+
|
|
50
|
+
return result.is_valid, result.errors
|
roadmap/core/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core domain models and services for roadmap management."""
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Domain Layer - Pure Business Logic & Models.
|
|
2
|
+
|
|
3
|
+
This layer contains the core business models and domain logic that are
|
|
4
|
+
independent of any framework or external system. Models here should:
|
|
5
|
+
|
|
6
|
+
- Have no dependencies on infrastructure or presentation layers
|
|
7
|
+
- Contain only business rules and validation
|
|
8
|
+
- Be fully testable in isolation
|
|
9
|
+
- Represent core concepts of the problem domain
|
|
10
|
+
|
|
11
|
+
Models: Issue, Milestone, Project, Comment
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .comment import Comment
|
|
15
|
+
from .issue import Issue, IssueType, Priority, Status
|
|
16
|
+
from .milestone import Milestone, MilestoneStatus, RiskLevel
|
|
17
|
+
from .project import Project, ProjectStatus
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Issue",
|
|
21
|
+
"IssueType",
|
|
22
|
+
"Priority",
|
|
23
|
+
"Status",
|
|
24
|
+
"Milestone",
|
|
25
|
+
"MilestoneStatus",
|
|
26
|
+
"RiskLevel",
|
|
27
|
+
"Project",
|
|
28
|
+
"ProjectStatus",
|
|
29
|
+
"Comment",
|
|
30
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Comment model for issue discussions."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Comment:
|
|
9
|
+
"""Comment data model for issues."""
|
|
10
|
+
|
|
11
|
+
id: int # GitHub comment ID
|
|
12
|
+
issue_id: str # Local issue ID or GitHub issue number
|
|
13
|
+
author: str # GitHub username
|
|
14
|
+
body: str # Comment content (markdown)
|
|
15
|
+
created_at: datetime
|
|
16
|
+
updated_at: datetime
|
|
17
|
+
github_url: str | None = None # GitHub comment URL
|
|
18
|
+
in_reply_to: int | None = None # Comment ID this is a reply to (for threading)
|
|
19
|
+
|
|
20
|
+
def __str__(self) -> str:
|
|
21
|
+
"""Return string representation."""
|
|
22
|
+
return (
|
|
23
|
+
f"Comment by {self.author} on {self.created_at.strftime('%Y-%m-%d %H:%M')}"
|
|
24
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Health status domain models.
|
|
2
|
+
|
|
3
|
+
This module defines health status enumerations used across the application
|
|
4
|
+
for reporting system and component health states.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HealthStatus(Enum):
|
|
11
|
+
"""Health status levels for system components."""
|
|
12
|
+
|
|
13
|
+
HEALTHY = "healthy"
|
|
14
|
+
DEGRADED = "degraded"
|
|
15
|
+
UNHEALTHY = "unhealthy"
|