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,374 @@
|
|
|
1
|
+
"""Entity-specific builders for CRUD operations.
|
|
2
|
+
|
|
3
|
+
This module provides builders for each entity type (Issue, Milestone, Project)
|
|
4
|
+
that handle validation and dict building for create/update operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from roadmap.common.errors.exceptions import ValidationError
|
|
11
|
+
from roadmap.core.domain import IssueType, Priority
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IssueBuilder:
|
|
15
|
+
"""Builder for issue creation and updates."""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def validate_issue_exists(core: Any, issue_id: str) -> bool:
|
|
19
|
+
"""Check if an issue exists.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
core: The core application context
|
|
23
|
+
issue_id: Issue ID to check
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
True if issue exists, False otherwise
|
|
27
|
+
"""
|
|
28
|
+
return core.issues.get(issue_id) is not None
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
def validate_priority(priority: str) -> Priority:
|
|
32
|
+
"""Validate and convert priority string.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
priority: Priority string (critical, high, medium, low)
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Priority enum value
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValidationError: If priority is invalid
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
priority_map = {
|
|
45
|
+
"critical": Priority.CRITICAL,
|
|
46
|
+
"high": Priority.HIGH,
|
|
47
|
+
"medium": Priority.MEDIUM,
|
|
48
|
+
"low": Priority.LOW,
|
|
49
|
+
}
|
|
50
|
+
return priority_map[priority.lower()]
|
|
51
|
+
except KeyError as e:
|
|
52
|
+
raise ValidationError(
|
|
53
|
+
domain_message=f"Invalid priority: {priority}",
|
|
54
|
+
user_message=f"Invalid priority: {priority}. Valid values: critical, high, medium, low",
|
|
55
|
+
) from e
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def validate_issue_type(issue_type: str) -> IssueType:
|
|
59
|
+
"""Validate and convert issue type string.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
issue_type: Issue type string (feature, bug, other)
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
IssueType enum value
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
ValidationError: If type is invalid
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
type_map = {
|
|
72
|
+
"feature": IssueType.FEATURE,
|
|
73
|
+
"bug": IssueType.BUG,
|
|
74
|
+
"other": IssueType.OTHER,
|
|
75
|
+
}
|
|
76
|
+
return type_map[issue_type.lower()]
|
|
77
|
+
except KeyError as e:
|
|
78
|
+
raise ValidationError(
|
|
79
|
+
domain_message=f"Invalid issue type: {issue_type}",
|
|
80
|
+
user_message=f"Invalid issue type: {issue_type}. Valid values: feature, bug, other",
|
|
81
|
+
) from e
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def build_create_dict(
|
|
85
|
+
title: str,
|
|
86
|
+
priority: str | None = None,
|
|
87
|
+
issue_type: str | None = None,
|
|
88
|
+
milestone: str | None = None,
|
|
89
|
+
assignee: str | None = None,
|
|
90
|
+
labels: list[str] | None = None,
|
|
91
|
+
estimate: float | None = None,
|
|
92
|
+
depends_on: list[str] | None = None,
|
|
93
|
+
blocks: list[str] | None = None,
|
|
94
|
+
description: str | None = None,
|
|
95
|
+
) -> dict[str, Any]:
|
|
96
|
+
"""Build create dictionary for issue.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
title: Issue title (required)
|
|
100
|
+
priority: Priority level
|
|
101
|
+
issue_type: Type of issue
|
|
102
|
+
milestone: Milestone ID to assign
|
|
103
|
+
assignee: Assignee name/email
|
|
104
|
+
labels: List of labels
|
|
105
|
+
estimate: Estimated hours
|
|
106
|
+
depends_on: Issue IDs this depends on
|
|
107
|
+
blocks: Issue IDs this blocks
|
|
108
|
+
description: Markdown content/description
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
Dictionary ready for core.issues.create()
|
|
112
|
+
"""
|
|
113
|
+
create_dict: dict[str, Any] = {"title": title, "status": "todo"}
|
|
114
|
+
|
|
115
|
+
if priority:
|
|
116
|
+
create_dict["priority"] = IssueBuilder.validate_priority(priority)
|
|
117
|
+
|
|
118
|
+
if issue_type:
|
|
119
|
+
create_dict["issue_type"] = IssueBuilder.validate_issue_type(issue_type)
|
|
120
|
+
|
|
121
|
+
if milestone:
|
|
122
|
+
create_dict["milestone"] = milestone
|
|
123
|
+
|
|
124
|
+
if assignee:
|
|
125
|
+
create_dict["assignee"] = assignee
|
|
126
|
+
|
|
127
|
+
if labels:
|
|
128
|
+
create_dict["labels"] = labels
|
|
129
|
+
|
|
130
|
+
if estimate is not None:
|
|
131
|
+
create_dict["estimated_hours"] = estimate
|
|
132
|
+
|
|
133
|
+
if depends_on:
|
|
134
|
+
create_dict["depends_on"] = depends_on
|
|
135
|
+
|
|
136
|
+
if blocks:
|
|
137
|
+
create_dict["blocks"] = blocks
|
|
138
|
+
|
|
139
|
+
if description:
|
|
140
|
+
create_dict["content"] = description
|
|
141
|
+
|
|
142
|
+
return create_dict
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def build_update_dict(
|
|
146
|
+
title: str | None = None,
|
|
147
|
+
priority: str | None = None,
|
|
148
|
+
status: str | None = None,
|
|
149
|
+
assignee: str | None = None,
|
|
150
|
+
milestone: str | None = None,
|
|
151
|
+
description: str | None = None,
|
|
152
|
+
estimate: float | None = None,
|
|
153
|
+
) -> dict[str, Any]:
|
|
154
|
+
"""Build update dictionary for issue.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
title: New title
|
|
158
|
+
priority: New priority
|
|
159
|
+
status: New status
|
|
160
|
+
assignee: New assignee
|
|
161
|
+
milestone: New milestone
|
|
162
|
+
description: New description
|
|
163
|
+
estimate: New estimate
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Dictionary ready for core.issues.update()
|
|
167
|
+
"""
|
|
168
|
+
update_dict = {}
|
|
169
|
+
|
|
170
|
+
if title is not None:
|
|
171
|
+
update_dict["title"] = title
|
|
172
|
+
|
|
173
|
+
if priority is not None:
|
|
174
|
+
update_dict["priority"] = IssueBuilder.validate_priority(priority)
|
|
175
|
+
|
|
176
|
+
if status is not None:
|
|
177
|
+
update_dict["status"] = status
|
|
178
|
+
|
|
179
|
+
if assignee is not None:
|
|
180
|
+
update_dict["assignee"] = assignee
|
|
181
|
+
|
|
182
|
+
if milestone is not None:
|
|
183
|
+
update_dict["milestone"] = milestone
|
|
184
|
+
|
|
185
|
+
if description is not None:
|
|
186
|
+
update_dict["content"] = description
|
|
187
|
+
|
|
188
|
+
if estimate is not None:
|
|
189
|
+
update_dict["estimated_hours"] = estimate
|
|
190
|
+
|
|
191
|
+
return update_dict
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class MilestoneBuilder:
|
|
195
|
+
"""Builder for milestone creation and updates."""
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def validate_milestone_exists(core: Any, milestone_id: str) -> bool:
|
|
199
|
+
"""Check if a milestone exists.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
core: The core application context
|
|
203
|
+
milestone_id: Milestone ID to check
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
True if milestone exists, False otherwise
|
|
207
|
+
"""
|
|
208
|
+
return core.milestones.get(milestone_id) is not None
|
|
209
|
+
|
|
210
|
+
@staticmethod
|
|
211
|
+
def validate_due_date(due_date: str | None) -> datetime | None:
|
|
212
|
+
"""Validate and parse due date.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
due_date: Due date string (YYYY-MM-DD format)
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Parsed datetime or None
|
|
219
|
+
|
|
220
|
+
Raises:
|
|
221
|
+
ValidationError: If date format is invalid
|
|
222
|
+
"""
|
|
223
|
+
if not due_date:
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
return datetime.strptime(due_date, "%Y-%m-%d")
|
|
228
|
+
except ValueError as e:
|
|
229
|
+
raise ValidationError(
|
|
230
|
+
domain_message="Invalid due date format: expected YYYY-MM-DD",
|
|
231
|
+
user_message=f"Invalid due date format: {due_date}. Expected format: YYYY-MM-DD (example: 2024-12-31)",
|
|
232
|
+
) from e
|
|
233
|
+
|
|
234
|
+
@staticmethod
|
|
235
|
+
def build_create_dict(
|
|
236
|
+
name: str,
|
|
237
|
+
description: str | None = None,
|
|
238
|
+
due_date: str | None = None,
|
|
239
|
+
) -> dict[str, Any]:
|
|
240
|
+
"""Build create dictionary for milestone.
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
name: Milestone name (required)
|
|
244
|
+
description: Milestone content/description
|
|
245
|
+
due_date: Due date (YYYY-MM-DD format)
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Dictionary ready for core.milestones.create()
|
|
249
|
+
"""
|
|
250
|
+
create_dict: dict[str, Any] = {"name": name, "status": "open"}
|
|
251
|
+
|
|
252
|
+
if description:
|
|
253
|
+
create_dict["headline"] = description
|
|
254
|
+
|
|
255
|
+
if due_date:
|
|
256
|
+
create_dict["due_date"] = MilestoneBuilder.validate_due_date(due_date)
|
|
257
|
+
|
|
258
|
+
return create_dict
|
|
259
|
+
|
|
260
|
+
@staticmethod
|
|
261
|
+
def build_update_dict(
|
|
262
|
+
name: str | None = None,
|
|
263
|
+
description: str | None = None,
|
|
264
|
+
due_date: str | None = None,
|
|
265
|
+
status: str | None = None,
|
|
266
|
+
project_id: str | None = None,
|
|
267
|
+
) -> dict[str, Any]:
|
|
268
|
+
"""Build update dictionary for milestone.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
name: New name
|
|
272
|
+
description: New content/description
|
|
273
|
+
due_date: New due date (YYYY-MM-DD format)
|
|
274
|
+
status: New status
|
|
275
|
+
project_id: Project ID to assign milestone to
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Dictionary ready for core.milestones.update()
|
|
279
|
+
"""
|
|
280
|
+
update_dict = {}
|
|
281
|
+
|
|
282
|
+
if name is not None:
|
|
283
|
+
update_dict["name"] = name
|
|
284
|
+
|
|
285
|
+
if description is not None:
|
|
286
|
+
update_dict["headline"] = description
|
|
287
|
+
|
|
288
|
+
if due_date is not None:
|
|
289
|
+
update_dict["due_date"] = MilestoneBuilder.validate_due_date(due_date)
|
|
290
|
+
|
|
291
|
+
if status is not None:
|
|
292
|
+
update_dict["status"] = status
|
|
293
|
+
|
|
294
|
+
if project_id is not None:
|
|
295
|
+
update_dict["project_id"] = project_id
|
|
296
|
+
|
|
297
|
+
return update_dict
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class ProjectBuilder:
|
|
301
|
+
"""Builder for project creation and updates."""
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def validate_project_exists(core: Any, project_id: str) -> bool:
|
|
305
|
+
"""Check if a project exists.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
core: The core application context
|
|
309
|
+
project_id: Project ID to check
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
True if project exists, False otherwise
|
|
313
|
+
"""
|
|
314
|
+
return core.projects.get(project_id) is not None
|
|
315
|
+
|
|
316
|
+
@staticmethod
|
|
317
|
+
def build_create_dict(
|
|
318
|
+
name: str,
|
|
319
|
+
description: str | None = None,
|
|
320
|
+
repository: str | None = None,
|
|
321
|
+
) -> dict[str, Any]:
|
|
322
|
+
"""Build create dictionary for project.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
name: Project name (required)
|
|
326
|
+
description: Project content
|
|
327
|
+
repository: Repository URL
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Dictionary ready for core.projects.create()
|
|
331
|
+
"""
|
|
332
|
+
create_dict = {"name": name, "status": "planning"}
|
|
333
|
+
|
|
334
|
+
if description:
|
|
335
|
+
create_dict["headline"] = description
|
|
336
|
+
|
|
337
|
+
if repository:
|
|
338
|
+
create_dict["repository"] = repository
|
|
339
|
+
|
|
340
|
+
return create_dict
|
|
341
|
+
|
|
342
|
+
@staticmethod
|
|
343
|
+
def build_update_dict(
|
|
344
|
+
name: str | None = None,
|
|
345
|
+
description: str | None = None,
|
|
346
|
+
repository: str | None = None,
|
|
347
|
+
status: str | None = None,
|
|
348
|
+
) -> dict[str, Any]:
|
|
349
|
+
"""Build update dictionary for project.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
name: New name
|
|
353
|
+
description: New description
|
|
354
|
+
repository: New repository URL
|
|
355
|
+
status: New status
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Dictionary ready for core.projects.update()
|
|
359
|
+
"""
|
|
360
|
+
update_dict = {}
|
|
361
|
+
|
|
362
|
+
if name is not None:
|
|
363
|
+
update_dict["name"] = name
|
|
364
|
+
|
|
365
|
+
if description is not None:
|
|
366
|
+
update_dict["headline"] = description
|
|
367
|
+
|
|
368
|
+
if repository is not None:
|
|
369
|
+
update_dict["repository"] = repository
|
|
370
|
+
|
|
371
|
+
if status is not None:
|
|
372
|
+
update_dict["status"] = status
|
|
373
|
+
|
|
374
|
+
return update_dict
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Data management commands for export and reporting."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from roadmap.common.console import get_console
|
|
6
|
+
from roadmap.common.logging import verbose_output
|
|
7
|
+
from roadmap.core.domain import Issue
|
|
8
|
+
|
|
9
|
+
console = get_console()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _serialize_issue(issue: Issue) -> dict:
|
|
13
|
+
"""Convert an Issue model to a JSON-serializable dict."""
|
|
14
|
+
# Use pydantic's dict but convert datetimes to isoformat strings
|
|
15
|
+
d = issue.model_dump()
|
|
16
|
+
for k, v in d.items():
|
|
17
|
+
if hasattr(v, "isoformat"):
|
|
18
|
+
try:
|
|
19
|
+
d[k] = v.isoformat()
|
|
20
|
+
except Exception:
|
|
21
|
+
d[k] = str(v)
|
|
22
|
+
return d
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@click.group()
|
|
26
|
+
def data():
|
|
27
|
+
"""Export, import, and analyze roadmap data."""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@data.command("export")
|
|
32
|
+
@click.option(
|
|
33
|
+
"--format",
|
|
34
|
+
type=click.Choice(["json", "csv", "markdown"]),
|
|
35
|
+
default="json",
|
|
36
|
+
help="Export format",
|
|
37
|
+
)
|
|
38
|
+
@click.option("--output", "-o", help="Output file path")
|
|
39
|
+
@click.option("--filter", help="Filter criteria (simple key=value)")
|
|
40
|
+
@click.pass_context
|
|
41
|
+
@verbose_output
|
|
42
|
+
def export(ctx: click.Context, format: str, output: str, filter: str):
|
|
43
|
+
"""Export roadmap issues to JSON, CSV or Markdown.
|
|
44
|
+
|
|
45
|
+
The --filter argument supports a simple key=value filter (e.g. assignee=alice).
|
|
46
|
+
"""
|
|
47
|
+
console.print(f"đ Exporting issues in {format} format...", style="bold blue")
|
|
48
|
+
|
|
49
|
+
# Get core and issues
|
|
50
|
+
core = _get_core(ctx)
|
|
51
|
+
if not core or not core.is_initialized():
|
|
52
|
+
console.print(
|
|
53
|
+
"â Roadmap not initialized. Run 'roadmap init' first or run this command inside a roadmap.",
|
|
54
|
+
style="bold red",
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
issues = _load_and_filter_issues(core, filter)
|
|
59
|
+
if not issues:
|
|
60
|
+
console.print("âšī¸ No issues to export.", style="yellow")
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
# Format and output
|
|
64
|
+
_export_and_write(issues, format, output)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _get_core(ctx: click.Context):
|
|
68
|
+
"""Get RoadmapCore from context or discover existing roadmap."""
|
|
69
|
+
try:
|
|
70
|
+
core = ctx.obj.get("core") if ctx.obj else None
|
|
71
|
+
except Exception:
|
|
72
|
+
core = None
|
|
73
|
+
|
|
74
|
+
if core is None:
|
|
75
|
+
try:
|
|
76
|
+
from roadmap.infrastructure.coordination.core import RoadmapCore
|
|
77
|
+
|
|
78
|
+
core = RoadmapCore.find_existing_roadmap()
|
|
79
|
+
except Exception:
|
|
80
|
+
core = None
|
|
81
|
+
|
|
82
|
+
return core
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _load_and_filter_issues(core, filter_str: str):
|
|
86
|
+
"""Load issues and apply filter if provided."""
|
|
87
|
+
try:
|
|
88
|
+
issues = core.issues.list()
|
|
89
|
+
except Exception as e:
|
|
90
|
+
console.print(f"â Failed to list issues: {e}", style="bold red")
|
|
91
|
+
return []
|
|
92
|
+
|
|
93
|
+
if filter_str:
|
|
94
|
+
try:
|
|
95
|
+
key, val = filter_str.split("=", 1)
|
|
96
|
+
key = key.strip()
|
|
97
|
+
val = val.strip()
|
|
98
|
+
issues = [
|
|
99
|
+
i for i in issues if str(getattr(i, key, "")).lower() == val.lower()
|
|
100
|
+
]
|
|
101
|
+
except Exception:
|
|
102
|
+
console.print("â ī¸ Unable to parse filter, ignoring.", style="yellow")
|
|
103
|
+
|
|
104
|
+
return issues
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _export_and_write(issues, format_type: str, output_path: str):
|
|
108
|
+
"""Format issues and write to file or stdout."""
|
|
109
|
+
from roadmap.common.formatters import IssueExporter
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
if format_type == "json":
|
|
113
|
+
out_text = IssueExporter.to_json(issues, _serialize_issue)
|
|
114
|
+
elif format_type == "csv":
|
|
115
|
+
out_text = IssueExporter.to_csv(issues, _serialize_issue)
|
|
116
|
+
else: # markdown
|
|
117
|
+
out_text = IssueExporter.to_markdown(issues)
|
|
118
|
+
|
|
119
|
+
# Write to file or print
|
|
120
|
+
if output_path:
|
|
121
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
|
122
|
+
f.write(out_text)
|
|
123
|
+
console.print(
|
|
124
|
+
f"â
Exported {len(issues)} issues to {output_path}", style="bold green"
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
console.print(out_text)
|
|
128
|
+
|
|
129
|
+
except Exception as e:
|
|
130
|
+
console.print(f"â Failed to export issues: {e}", style="bold red")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@data.command("generate-report")
|
|
134
|
+
@click.option(
|
|
135
|
+
"--type",
|
|
136
|
+
type=click.Choice(["summary", "detailed", "analytics"]),
|
|
137
|
+
default="summary",
|
|
138
|
+
help="Report type",
|
|
139
|
+
)
|
|
140
|
+
@click.option("--output", "-o", help="Output file path")
|
|
141
|
+
@click.pass_context
|
|
142
|
+
@verbose_output
|
|
143
|
+
def generate_report(ctx: click.Context, type: str, output: str):
|
|
144
|
+
"""Generate detailed reports and analytics."""
|
|
145
|
+
console.print(f"đ Generating {type} report...", style="bold blue")
|
|
146
|
+
# Implementation would go here
|
|
147
|
+
console.print(
|
|
148
|
+
"â
Report generation functionality will be implemented", style="green"
|
|
149
|
+
)
|