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,220 @@
|
|
|
1
|
+
"""Smart table layout system with responsive formatting.
|
|
2
|
+
|
|
3
|
+
Automatically detects terminal width and switches to vertical layout
|
|
4
|
+
when horizontal table is too wide.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import shutil
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
from roadmap.common.models import TableData
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class LayoutConfig:
|
|
19
|
+
"""Configuration for smart table layouts."""
|
|
20
|
+
|
|
21
|
+
min_column_width: int = 15
|
|
22
|
+
max_horizontal_width: int = 120
|
|
23
|
+
vertical_threshold: float = (
|
|
24
|
+
0.8 # Switch to vertical if table > 80% of terminal width
|
|
25
|
+
)
|
|
26
|
+
responsive_enabled: bool = True
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SmartTableLayout:
|
|
30
|
+
"""Renders tables with responsive layout based on terminal width."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, config: LayoutConfig | None = None):
|
|
33
|
+
"""Initialize layout system.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config: Layout configuration
|
|
37
|
+
"""
|
|
38
|
+
self.config = config or LayoutConfig()
|
|
39
|
+
|
|
40
|
+
def get_terminal_width(self) -> int:
|
|
41
|
+
"""Get terminal width in columns.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Terminal width, defaults to 80 if unable to detect
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
width = shutil.get_terminal_size().columns
|
|
48
|
+
return max(width, 40) # Minimum 40 columns
|
|
49
|
+
except Exception as e:
|
|
50
|
+
from roadmap.common.logging import get_logger
|
|
51
|
+
|
|
52
|
+
logger = get_logger(__name__)
|
|
53
|
+
logger.debug(
|
|
54
|
+
"terminal_width_detection_failed",
|
|
55
|
+
error=str(e),
|
|
56
|
+
action="get_terminal_width",
|
|
57
|
+
)
|
|
58
|
+
return 80 # Default fallback
|
|
59
|
+
|
|
60
|
+
def calculate_table_width(self, table_data: TableData) -> int:
|
|
61
|
+
"""Calculate estimated table width based on column headers and data.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
table_data: Table data to measure
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Estimated table width in columns
|
|
68
|
+
"""
|
|
69
|
+
if not table_data.columns or not table_data.rows:
|
|
70
|
+
return 20
|
|
71
|
+
|
|
72
|
+
# Estimate based on column headers and sample data
|
|
73
|
+
total_width = 0
|
|
74
|
+
max_samples = min(5, len(table_data.rows))
|
|
75
|
+
|
|
76
|
+
for i, column in enumerate(table_data.columns):
|
|
77
|
+
# Start with header width
|
|
78
|
+
col_width = len(column.display_name) + 2
|
|
79
|
+
|
|
80
|
+
# Check sample data for this column
|
|
81
|
+
for row_idx in range(max_samples):
|
|
82
|
+
if row_idx < len(table_data.rows) and i < len(table_data.rows[row_idx]):
|
|
83
|
+
value = table_data.rows[row_idx][i]
|
|
84
|
+
col_width = max(col_width, len(str(value)))
|
|
85
|
+
|
|
86
|
+
# Add padding and separators
|
|
87
|
+
col_width = min(col_width + 2, 30) # Cap at 30 per column
|
|
88
|
+
total_width += col_width
|
|
89
|
+
|
|
90
|
+
# Add separators and padding
|
|
91
|
+
total_width += len(table_data.columns) + 4
|
|
92
|
+
|
|
93
|
+
return total_width
|
|
94
|
+
|
|
95
|
+
def should_use_vertical_layout(self, table_data: TableData) -> bool:
|
|
96
|
+
"""Determine if vertical layout should be used.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
table_data: Table data to evaluate
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
True if vertical layout is recommended
|
|
103
|
+
"""
|
|
104
|
+
if not self.config.responsive_enabled:
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
terminal_width = self.get_terminal_width()
|
|
108
|
+
table_width = self.calculate_table_width(table_data)
|
|
109
|
+
|
|
110
|
+
# Use vertical if table would take > threshold of terminal width
|
|
111
|
+
return table_width > (terminal_width * self.config.vertical_threshold)
|
|
112
|
+
|
|
113
|
+
def render_horizontal(self, table_data: TableData) -> Table:
|
|
114
|
+
"""Render table in horizontal layout.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
table_data: Table data to render
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
Rich Table object
|
|
121
|
+
"""
|
|
122
|
+
table = Table(
|
|
123
|
+
title=table_data.title,
|
|
124
|
+
show_header=True,
|
|
125
|
+
header_style="bold cyan",
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Add columns
|
|
129
|
+
for column in table_data.columns:
|
|
130
|
+
table.add_column(column.display_name, style=column.display_style or "")
|
|
131
|
+
|
|
132
|
+
# Add rows
|
|
133
|
+
for row in table_data.rows:
|
|
134
|
+
values = [str(val) if val is not None else "" for val in row]
|
|
135
|
+
table.add_row(*values)
|
|
136
|
+
|
|
137
|
+
return table
|
|
138
|
+
|
|
139
|
+
def render_vertical(self, table_data: TableData) -> Panel:
|
|
140
|
+
"""Render table in vertical layout (one field per line).
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
table_data: Table data to render
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Rich Panel with vertical layout
|
|
147
|
+
"""
|
|
148
|
+
from rich.text import Text
|
|
149
|
+
|
|
150
|
+
panels_content = []
|
|
151
|
+
|
|
152
|
+
for row_idx, row in enumerate(table_data.rows):
|
|
153
|
+
# Create header for this row
|
|
154
|
+
row_header = f"Entry {row_idx + 1}"
|
|
155
|
+
|
|
156
|
+
# Build content for this row
|
|
157
|
+
row_text = Text()
|
|
158
|
+
row_text.append(row_header + "\n", style="bold cyan")
|
|
159
|
+
|
|
160
|
+
for col_idx, column in enumerate(table_data.columns):
|
|
161
|
+
value = row[col_idx] if col_idx < len(row) else ""
|
|
162
|
+
row_text.append(f" {column.display_name}: ", style="bold")
|
|
163
|
+
row_text.append(f"{value}\n")
|
|
164
|
+
|
|
165
|
+
panels_content.append(row_text)
|
|
166
|
+
|
|
167
|
+
# Combine all panels
|
|
168
|
+
combined = Text()
|
|
169
|
+
for i, text in enumerate(panels_content):
|
|
170
|
+
combined.append(text)
|
|
171
|
+
if i < len(panels_content) - 1:
|
|
172
|
+
combined.append("\n" + "ā" * 40 + "\n\n")
|
|
173
|
+
|
|
174
|
+
return Panel(
|
|
175
|
+
combined,
|
|
176
|
+
title=table_data.title,
|
|
177
|
+
expand=False,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def render(self, table_data: TableData) -> Table | Panel:
|
|
181
|
+
"""Render table with appropriate layout based on terminal width.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
table_data: Table data to render
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Rich Table or Panel object
|
|
188
|
+
"""
|
|
189
|
+
if self.should_use_vertical_layout(table_data):
|
|
190
|
+
return self.render_vertical(table_data)
|
|
191
|
+
else:
|
|
192
|
+
return self.render_horizontal(table_data)
|
|
193
|
+
|
|
194
|
+
def render_as_string(self, table_data: TableData, width: int | None = None) -> str:
|
|
195
|
+
"""Render table to string representation.
|
|
196
|
+
|
|
197
|
+
Useful for testing and non-interactive environments.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
table_data: Table data to render
|
|
201
|
+
width: Override terminal width
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
String representation of table
|
|
205
|
+
"""
|
|
206
|
+
# Temporarily override terminal width for testing
|
|
207
|
+
original_get_width = self.get_terminal_width
|
|
208
|
+
if width is not None:
|
|
209
|
+
self.get_terminal_width = lambda: width
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
renderable = self.render(table_data)
|
|
213
|
+
from io import StringIO
|
|
214
|
+
|
|
215
|
+
string_io = StringIO()
|
|
216
|
+
temp_console = Console(file=string_io)
|
|
217
|
+
temp_console.print(renderable)
|
|
218
|
+
return string_io.getvalue()
|
|
219
|
+
finally:
|
|
220
|
+
self.get_terminal_width = original_get_width
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Mappers for converting between domain models and CLI DTOs.
|
|
2
|
+
|
|
3
|
+
Mappers handle the conversion logic between domain models (internal representation)
|
|
4
|
+
and DTOs (CLI presentation representation). They ensure DTOs don't leak domain
|
|
5
|
+
implementation details.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from roadmap.adapters.cli.dtos import CommentDTO, IssueDTO, MilestoneDTO, ProjectDTO
|
|
9
|
+
from roadmap.core.domain.issue import Issue
|
|
10
|
+
from roadmap.core.domain.milestone import Milestone
|
|
11
|
+
from roadmap.core.domain.project import Project
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IssueMapper:
|
|
15
|
+
"""Maps between Issue domain model and IssueDTO."""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def domain_to_dto(issue: Issue) -> IssueDTO:
|
|
19
|
+
"""Convert domain Issue to CLI DTO.
|
|
20
|
+
|
|
21
|
+
Converts enums to strings and selects only CLI-relevant fields.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
issue: Domain model Issue instance
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
IssueDTO instance ready for CLI display
|
|
28
|
+
"""
|
|
29
|
+
# Convert comments to DTOs
|
|
30
|
+
comments = []
|
|
31
|
+
if hasattr(issue, "comments") and issue.comments:
|
|
32
|
+
comments = [
|
|
33
|
+
CommentDTO(
|
|
34
|
+
id=comment.id,
|
|
35
|
+
author=comment.author,
|
|
36
|
+
body=comment.body,
|
|
37
|
+
created_at=comment.created_at,
|
|
38
|
+
updated_at=comment.updated_at,
|
|
39
|
+
in_reply_to=comment.in_reply_to,
|
|
40
|
+
)
|
|
41
|
+
for comment in issue.comments
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
return IssueDTO(
|
|
45
|
+
id=issue.id,
|
|
46
|
+
title=issue.title,
|
|
47
|
+
headline=issue.headline or "",
|
|
48
|
+
priority=issue.priority.value, # Convert enum to string
|
|
49
|
+
status=issue.status.value, # Convert enum to string
|
|
50
|
+
issue_type=issue.issue_type.value, # Convert enum to string
|
|
51
|
+
assignee=issue.assignee,
|
|
52
|
+
milestone=issue.milestone,
|
|
53
|
+
due_date=issue.due_date,
|
|
54
|
+
estimated_hours=issue.estimated_hours,
|
|
55
|
+
actual_end_date=issue.actual_end_date,
|
|
56
|
+
progress_percentage=issue.progress_percentage,
|
|
57
|
+
created=issue.created,
|
|
58
|
+
updated=issue.updated,
|
|
59
|
+
content=issue.content,
|
|
60
|
+
labels=issue.labels.copy() if issue.labels else [],
|
|
61
|
+
github_issue=str(issue.github_issue) if issue.github_issue else None,
|
|
62
|
+
comments=comments,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def dto_to_domain(dto: IssueDTO) -> Issue:
|
|
67
|
+
"""Convert CLI DTO to domain Issue.
|
|
68
|
+
|
|
69
|
+
Converts string fields back to appropriate enums.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
dto: IssueDTO instance from CLI
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Domain model Issue instance
|
|
76
|
+
"""
|
|
77
|
+
from roadmap.common.constants import IssueType, Priority, Status
|
|
78
|
+
|
|
79
|
+
return Issue(
|
|
80
|
+
id=dto.id,
|
|
81
|
+
title=dto.title,
|
|
82
|
+
headline=dto.headline or "",
|
|
83
|
+
priority=Priority(dto.priority),
|
|
84
|
+
status=Status(dto.status),
|
|
85
|
+
issue_type=IssueType(dto.issue_type),
|
|
86
|
+
assignee=dto.assignee,
|
|
87
|
+
milestone=dto.milestone,
|
|
88
|
+
due_date=dto.due_date,
|
|
89
|
+
estimated_hours=dto.estimated_hours,
|
|
90
|
+
actual_end_date=dto.actual_end_date,
|
|
91
|
+
progress_percentage=dto.progress_percentage,
|
|
92
|
+
content=dto.content or "",
|
|
93
|
+
labels=dto.labels.copy() if dto.labels else [],
|
|
94
|
+
remote_ids=(
|
|
95
|
+
{"github": int(dto.github_issue)}
|
|
96
|
+
if dto.github_issue and dto.github_issue.isdigit()
|
|
97
|
+
else {}
|
|
98
|
+
),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MilestoneMapper:
|
|
103
|
+
"""Maps between Milestone domain model and MilestoneDTO."""
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def domain_to_dto(milestone: Milestone) -> MilestoneDTO:
|
|
107
|
+
"""Convert domain Milestone to CLI DTO.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
milestone: Domain model Milestone instance
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
MilestoneDTO instance ready for CLI display
|
|
114
|
+
"""
|
|
115
|
+
return MilestoneDTO(
|
|
116
|
+
id=milestone.name, # Use name as ID
|
|
117
|
+
name=milestone.name,
|
|
118
|
+
status=milestone.status.value, # Convert enum to string
|
|
119
|
+
headline=milestone.headline or "",
|
|
120
|
+
due_date=milestone.due_date,
|
|
121
|
+
progress_percentage=milestone.calculated_progress,
|
|
122
|
+
created=milestone.created,
|
|
123
|
+
updated=milestone.updated,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def dto_to_domain(dto: MilestoneDTO) -> Milestone:
|
|
128
|
+
"""Convert CLI DTO to domain Milestone.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
dto: MilestoneDTO instance from CLI
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Domain model Milestone instance
|
|
135
|
+
"""
|
|
136
|
+
from roadmap.common.constants import MilestoneStatus
|
|
137
|
+
|
|
138
|
+
return Milestone(
|
|
139
|
+
name=dto.name,
|
|
140
|
+
headline=dto.headline or "",
|
|
141
|
+
status=MilestoneStatus(dto.status),
|
|
142
|
+
due_date=dto.due_date,
|
|
143
|
+
content="",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ProjectMapper:
|
|
148
|
+
"""Maps between Project domain model and ProjectDTO."""
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def domain_to_dto(project: Project) -> ProjectDTO:
|
|
152
|
+
"""Convert domain Project to CLI DTO.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
project: Domain model Project instance
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
ProjectDTO instance ready for CLI display
|
|
159
|
+
"""
|
|
160
|
+
return ProjectDTO(
|
|
161
|
+
id=project.id,
|
|
162
|
+
name=project.name,
|
|
163
|
+
status=project.status.value, # Convert enum to string
|
|
164
|
+
headline=project.headline or "",
|
|
165
|
+
owner=project.owner,
|
|
166
|
+
target_end_date=project.target_end_date,
|
|
167
|
+
actual_end_date=project.actual_end_date,
|
|
168
|
+
created=project.created,
|
|
169
|
+
updated=project.updated,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def dto_to_domain(dto: ProjectDTO) -> Project:
|
|
174
|
+
"""Convert CLI DTO to domain Project.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
dto: ProjectDTO instance from CLI
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
Domain model Project instance
|
|
181
|
+
"""
|
|
182
|
+
from roadmap.common.constants import ProjectStatus
|
|
183
|
+
|
|
184
|
+
return Project(
|
|
185
|
+
id=dto.id,
|
|
186
|
+
name=dto.name,
|
|
187
|
+
headline=dto.headline or "",
|
|
188
|
+
status=ProjectStatus(dto.status),
|
|
189
|
+
content="",
|
|
190
|
+
owner=dto.owner,
|
|
191
|
+
target_end_date=dto.target_end_date,
|
|
192
|
+
actual_end_date=dto.actual_end_date,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
__all__ = [
|
|
197
|
+
"IssueMapper",
|
|
198
|
+
"MilestoneMapper",
|
|
199
|
+
"ProjectMapper",
|
|
200
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Milestone commands module.
|
|
2
|
+
|
|
3
|
+
Provides all milestone management commands:
|
|
4
|
+
- create: Create a new milestone
|
|
5
|
+
- list: List all milestones
|
|
6
|
+
- assign: Assign an issue to a milestone
|
|
7
|
+
- delete: Delete a milestone
|
|
8
|
+
- close: Close a milestone
|
|
9
|
+
- update: Update milestone properties
|
|
10
|
+
- recalculate: Recalculate milestone progress
|
|
11
|
+
- kanban: Display milestone in kanban board layout
|
|
12
|
+
- view: View detailed information about a milestone
|
|
13
|
+
- archive: Archive a milestone to .roadmap/archive/milestones/
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
|
|
18
|
+
from roadmap.adapters.cli.milestones.archive import archive_milestone
|
|
19
|
+
from roadmap.adapters.cli.milestones.assign import assign_milestone
|
|
20
|
+
from roadmap.adapters.cli.milestones.close import close_milestone
|
|
21
|
+
from roadmap.adapters.cli.milestones.create import create_milestone
|
|
22
|
+
from roadmap.adapters.cli.milestones.delete import delete_milestone
|
|
23
|
+
from roadmap.adapters.cli.milestones.kanban import milestone_kanban
|
|
24
|
+
from roadmap.adapters.cli.milestones.list import list_milestones
|
|
25
|
+
from roadmap.adapters.cli.milestones.recalculate import (
|
|
26
|
+
recalculate_milestone_progress,
|
|
27
|
+
)
|
|
28
|
+
from roadmap.adapters.cli.milestones.restore import restore_milestone
|
|
29
|
+
from roadmap.adapters.cli.milestones.update import update_milestone
|
|
30
|
+
from roadmap.adapters.cli.milestones.view import view_milestone
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.group()
|
|
34
|
+
def milestone():
|
|
35
|
+
"""Manage milestones."""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Register all commands
|
|
40
|
+
milestone.add_command(create_milestone, name="create")
|
|
41
|
+
milestone.add_command(list_milestones, name="list")
|
|
42
|
+
milestone.add_command(assign_milestone, name="assign")
|
|
43
|
+
milestone.add_command(update_milestone, name="update")
|
|
44
|
+
milestone.add_command(delete_milestone, name="delete")
|
|
45
|
+
milestone.add_command(close_milestone, name="close")
|
|
46
|
+
milestone.add_command(recalculate_milestone_progress, name="recalculate")
|
|
47
|
+
milestone.add_command(milestone_kanban, name="kanban")
|
|
48
|
+
milestone.add_command(view_milestone, name="view")
|
|
49
|
+
milestone.add_command(archive_milestone, name="archive")
|
|
50
|
+
milestone.add_command(restore_milestone, name="restore")
|
|
51
|
+
|
|
52
|
+
__all__ = ["milestone"]
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Archive milestone command - move closed milestones to archive."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from roadmap.adapters.cli.cli_command_helpers import require_initialized
|
|
6
|
+
from roadmap.adapters.cli.milestones.archive_class import MilestoneArchive
|
|
7
|
+
from roadmap.common.console import get_console
|
|
8
|
+
from roadmap.common.logging import (
|
|
9
|
+
log_command,
|
|
10
|
+
verbose_output,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.argument("milestone_name", required=False)
|
|
16
|
+
@click.option(
|
|
17
|
+
"--all-closed",
|
|
18
|
+
is_flag=True,
|
|
19
|
+
help="Archive all closed milestones",
|
|
20
|
+
)
|
|
21
|
+
@click.option(
|
|
22
|
+
"--list",
|
|
23
|
+
"list_archived",
|
|
24
|
+
is_flag=True,
|
|
25
|
+
help="List archived milestones",
|
|
26
|
+
)
|
|
27
|
+
@click.option(
|
|
28
|
+
"--dry-run",
|
|
29
|
+
is_flag=True,
|
|
30
|
+
help="Preview what would be archived without actually doing it",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--force",
|
|
34
|
+
is_flag=True,
|
|
35
|
+
help="Skip confirmation prompt",
|
|
36
|
+
)
|
|
37
|
+
@click.option(
|
|
38
|
+
"--verbose",
|
|
39
|
+
"-v",
|
|
40
|
+
is_flag=True,
|
|
41
|
+
help="Show detailed debug information",
|
|
42
|
+
)
|
|
43
|
+
@click.pass_context
|
|
44
|
+
@verbose_output
|
|
45
|
+
@log_command("milestone_archive", entity_type="milestone", track_duration=True)
|
|
46
|
+
@require_initialized
|
|
47
|
+
def archive_milestone(
|
|
48
|
+
ctx: click.Context,
|
|
49
|
+
milestone_name: str | None,
|
|
50
|
+
all_closed: bool,
|
|
51
|
+
list_archived: bool,
|
|
52
|
+
dry_run: bool,
|
|
53
|
+
force: bool,
|
|
54
|
+
verbose: bool, # noqa: F841
|
|
55
|
+
):
|
|
56
|
+
"""Archive a milestone by moving it to .roadmap/archive/milestones/.
|
|
57
|
+
|
|
58
|
+
This is a non-destructive operation that preserves milestone data while
|
|
59
|
+
cleaning up the active workspace.
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
roadmap milestone archive "v1.0"
|
|
63
|
+
roadmap milestone archive --all-closed
|
|
64
|
+
roadmap milestone archive --list
|
|
65
|
+
"""
|
|
66
|
+
core = ctx.obj["core"]
|
|
67
|
+
console = get_console()
|
|
68
|
+
|
|
69
|
+
archive = MilestoneArchive(core, console)
|
|
70
|
+
|
|
71
|
+
if list_archived:
|
|
72
|
+
from pathlib import Path
|
|
73
|
+
|
|
74
|
+
from roadmap.adapters.persistence.parser import MilestoneParser
|
|
75
|
+
|
|
76
|
+
roadmap_dir = Path.cwd() / ".roadmap"
|
|
77
|
+
archive_dir = roadmap_dir / "archive" / "milestones"
|
|
78
|
+
|
|
79
|
+
if not archive_dir.exists():
|
|
80
|
+
console.print("š No archived milestones.", style="yellow")
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
archived_files = list(archive_dir.glob("*.md"))
|
|
84
|
+
if not archived_files:
|
|
85
|
+
console.print("š No archived milestones.", style="yellow")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
console.print("\nš¦ Archived Milestones:\n", style="bold blue")
|
|
89
|
+
for file_path in sorted(archived_files):
|
|
90
|
+
try:
|
|
91
|
+
milestone = MilestoneParser.parse_milestone_file(file_path)
|
|
92
|
+
console.print(
|
|
93
|
+
f" ⢠{milestone.name} ({milestone.status.value})", style="cyan"
|
|
94
|
+
)
|
|
95
|
+
except Exception:
|
|
96
|
+
console.print(
|
|
97
|
+
f" ⢠{file_path.name} (error reading file)", style="yellow"
|
|
98
|
+
)
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
# Validate arguments
|
|
102
|
+
if not milestone_name and not all_closed:
|
|
103
|
+
console.print(
|
|
104
|
+
"ā Error: Specify a milestone name or use --all-closed",
|
|
105
|
+
style="bold red",
|
|
106
|
+
)
|
|
107
|
+
ctx.exit(1)
|
|
108
|
+
|
|
109
|
+
if milestone_name and all_closed:
|
|
110
|
+
console.print(
|
|
111
|
+
"ā Error: Specify only one of: milestone name or --all-closed",
|
|
112
|
+
style="bold red",
|
|
113
|
+
)
|
|
114
|
+
ctx.exit(1)
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
archive.execute(
|
|
118
|
+
entity_id=milestone_name,
|
|
119
|
+
all_closed=all_closed,
|
|
120
|
+
dry_run=dry_run,
|
|
121
|
+
force=force,
|
|
122
|
+
)
|
|
123
|
+
except Exception as e:
|
|
124
|
+
console.print(f"ā Archive operation failed: {str(e)}", style="bold red")
|
|
125
|
+
ctx.exit(1)
|