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,325 @@
|
|
|
1
|
+
"""CLI operation feedback formatting.
|
|
2
|
+
|
|
3
|
+
This module provides both functional and class-based formatters for operation results.
|
|
4
|
+
Use OperationFormatter class for new code. Legacy functions remain for backward compatibility.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OperationFormatter:
|
|
9
|
+
"""Unified formatter for all operation results.
|
|
10
|
+
|
|
11
|
+
Provides a consistent interface for formatting operation successes, failures,
|
|
12
|
+
and entity details across the CLI. This class consolidates all formatting logic
|
|
13
|
+
that was previously scattered across multiple functions.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def success(
|
|
18
|
+
emoji: str,
|
|
19
|
+
action: str,
|
|
20
|
+
entity_title: str | None = None,
|
|
21
|
+
entity_id: str | None = None,
|
|
22
|
+
details: dict[str, str] | None = None,
|
|
23
|
+
) -> str:
|
|
24
|
+
"""Format a successful operation as a string.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
emoji: Emoji to display (e.g., "✅", "🚫", "📊")
|
|
28
|
+
action: Action verb (e.g., "Blocked", "Closed", "Updated")
|
|
29
|
+
entity_title: Title/name of the entity affected (e.g., issue title)
|
|
30
|
+
entity_id: ID of the entity (displayed separately as cyan)
|
|
31
|
+
details: Optional dict of additional details to display
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Formatted string for console output
|
|
35
|
+
"""
|
|
36
|
+
lines = []
|
|
37
|
+
|
|
38
|
+
# Main success line: emoji + action + title
|
|
39
|
+
if entity_title:
|
|
40
|
+
lines.append(f"{emoji} {action} issue: {entity_title}")
|
|
41
|
+
else:
|
|
42
|
+
lines.append(f"{emoji} {action}")
|
|
43
|
+
|
|
44
|
+
# Entity ID line (if provided)
|
|
45
|
+
if entity_id:
|
|
46
|
+
lines.append(f" ID: {entity_id}")
|
|
47
|
+
|
|
48
|
+
# Extra details (if provided)
|
|
49
|
+
if details:
|
|
50
|
+
for key, value in details.items():
|
|
51
|
+
lines.append(f" {key}: {value}")
|
|
52
|
+
|
|
53
|
+
return "\n".join(lines)
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def failure(
|
|
57
|
+
action: str,
|
|
58
|
+
entity_id: str | None = None,
|
|
59
|
+
error: str | None = None,
|
|
60
|
+
suggestion: str | None = None,
|
|
61
|
+
) -> str:
|
|
62
|
+
"""Format a failed operation as a string.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
action: Action that failed (e.g., "block", "close", "update")
|
|
66
|
+
entity_id: ID of the entity that failed (optional)
|
|
67
|
+
error: Error message/reason for failure
|
|
68
|
+
suggestion: Suggested recovery action
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Formatted string for console output
|
|
72
|
+
"""
|
|
73
|
+
lines = []
|
|
74
|
+
|
|
75
|
+
# Main failure line
|
|
76
|
+
if entity_id:
|
|
77
|
+
lines.append(f"❌ Failed to {action} issue: {entity_id}")
|
|
78
|
+
else:
|
|
79
|
+
lines.append(f"❌ Failed to {action}")
|
|
80
|
+
|
|
81
|
+
# Error details (if provided)
|
|
82
|
+
if error:
|
|
83
|
+
lines.append(f" Error: {error}")
|
|
84
|
+
|
|
85
|
+
# Suggestion (if provided)
|
|
86
|
+
if suggestion:
|
|
87
|
+
lines.append(f" 💡 {suggestion}")
|
|
88
|
+
|
|
89
|
+
return "\n".join(lines)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def entity(
|
|
93
|
+
entity_id: str,
|
|
94
|
+
entity_title: str | None = None,
|
|
95
|
+
entity_type: str = "item",
|
|
96
|
+
status: str | None = None,
|
|
97
|
+
details: dict[str, str] | None = None,
|
|
98
|
+
) -> str:
|
|
99
|
+
"""Format entity details as a string.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
entity_id: ID of the entity
|
|
103
|
+
entity_title: Title/name of the entity
|
|
104
|
+
entity_type: Type of entity (e.g., "issue", "milestone")
|
|
105
|
+
status: Current status of entity
|
|
106
|
+
details: Additional details dict
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Formatted string for console output
|
|
110
|
+
"""
|
|
111
|
+
lines = []
|
|
112
|
+
|
|
113
|
+
# ID and title
|
|
114
|
+
if entity_title:
|
|
115
|
+
lines.append(f"📋 {entity_type.title()}: {entity_title}")
|
|
116
|
+
lines.append(f" ID: {entity_id}")
|
|
117
|
+
|
|
118
|
+
# Status
|
|
119
|
+
if status:
|
|
120
|
+
lines.append(f" Status: {status}")
|
|
121
|
+
|
|
122
|
+
# Additional details
|
|
123
|
+
if details:
|
|
124
|
+
for key, value in details.items():
|
|
125
|
+
lines.append(f" {key}: {value}")
|
|
126
|
+
|
|
127
|
+
return "\n".join(lines)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
131
|
+
# Legacy Functions (Backward Compatibility)
|
|
132
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
133
|
+
# These functions are deprecated. Use OperationFormatter class instead.
|
|
134
|
+
# They are retained for backward compatibility with existing code.
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def format_operation_success(
|
|
138
|
+
emoji: str,
|
|
139
|
+
action: str,
|
|
140
|
+
entity_title: str | None = None,
|
|
141
|
+
entity_id: str | None = None,
|
|
142
|
+
reason: str | None = None,
|
|
143
|
+
extra_details: dict[str, str] | None = None,
|
|
144
|
+
) -> list[str]:
|
|
145
|
+
"""Format a successful operation message with consistent styling.
|
|
146
|
+
|
|
147
|
+
Returns a list of formatted lines for console output.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
emoji: Emoji to display (e.g., "✅", "🚫", "📊")
|
|
151
|
+
action: Action verb (e.g., "Blocked", "Closed", "Updated")
|
|
152
|
+
entity_title: Title/name of the entity affected (e.g., issue title)
|
|
153
|
+
entity_id: ID of the entity (displayed separately as cyan)
|
|
154
|
+
reason: Optional reason for the operation
|
|
155
|
+
extra_details: Optional dict of additional details to display
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
List of formatted output lines
|
|
159
|
+
"""
|
|
160
|
+
lines = []
|
|
161
|
+
|
|
162
|
+
# Main success line: emoji + action + title
|
|
163
|
+
if entity_title:
|
|
164
|
+
lines.append(f"{emoji} {action} issue: {entity_title}")
|
|
165
|
+
else:
|
|
166
|
+
lines.append(f"{emoji} {action}")
|
|
167
|
+
|
|
168
|
+
# Entity ID line (if provided)
|
|
169
|
+
if entity_id:
|
|
170
|
+
lines.append(f" ID: {entity_id}")
|
|
171
|
+
|
|
172
|
+
# Reason line (if provided)
|
|
173
|
+
if reason:
|
|
174
|
+
lines.append(f" Reason: {reason}")
|
|
175
|
+
|
|
176
|
+
# Extra details (if provided)
|
|
177
|
+
if extra_details:
|
|
178
|
+
for key, value in extra_details.items():
|
|
179
|
+
lines.append(f" {key}: {value}")
|
|
180
|
+
|
|
181
|
+
return lines
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def format_operation_failure(
|
|
185
|
+
action: str,
|
|
186
|
+
entity_id: str | None = None,
|
|
187
|
+
error: str | None = None,
|
|
188
|
+
suggestion: str | None = None,
|
|
189
|
+
) -> list[str]:
|
|
190
|
+
"""Format a failed operation message with consistent styling.
|
|
191
|
+
|
|
192
|
+
Returns a list of formatted lines for console output.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
action: Action that failed (e.g., "block", "close", "update")
|
|
196
|
+
entity_id: ID of the entity that failed (optional)
|
|
197
|
+
error: Error message/reason for failure
|
|
198
|
+
suggestion: Suggested recovery action
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of formatted output lines
|
|
202
|
+
"""
|
|
203
|
+
lines = []
|
|
204
|
+
|
|
205
|
+
# Main failure line
|
|
206
|
+
if entity_id:
|
|
207
|
+
lines.append(f"❌ Failed to {action} issue: {entity_id}")
|
|
208
|
+
else:
|
|
209
|
+
lines.append(f"❌ Failed to {action}")
|
|
210
|
+
|
|
211
|
+
# Error details (if provided)
|
|
212
|
+
if error:
|
|
213
|
+
lines.append(f" Error: {error}")
|
|
214
|
+
|
|
215
|
+
# Suggestion (if provided)
|
|
216
|
+
if suggestion:
|
|
217
|
+
lines.append(f" 💡 {suggestion}")
|
|
218
|
+
|
|
219
|
+
return lines
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def format_entity_details(
|
|
223
|
+
entity_id: str,
|
|
224
|
+
entity_title: str | None = None,
|
|
225
|
+
entity_type: str = "item",
|
|
226
|
+
status: str | None = None,
|
|
227
|
+
details: dict[str, str] | None = None,
|
|
228
|
+
) -> list[str]:
|
|
229
|
+
"""Format entity details for consistent display across commands.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
entity_id: ID of the entity
|
|
233
|
+
entity_title: Title/name of the entity
|
|
234
|
+
entity_type: Type of entity (e.g., "issue", "milestone")
|
|
235
|
+
status: Current status of entity
|
|
236
|
+
details: Additional details dict
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
List of formatted output lines
|
|
240
|
+
"""
|
|
241
|
+
lines = []
|
|
242
|
+
|
|
243
|
+
# ID and title
|
|
244
|
+
if entity_title:
|
|
245
|
+
lines.append(f"📋 {entity_type.title()}: {entity_title}")
|
|
246
|
+
lines.append(f" ID: {entity_id}")
|
|
247
|
+
|
|
248
|
+
# Status
|
|
249
|
+
if status:
|
|
250
|
+
lines.append(f" Status: {status}")
|
|
251
|
+
|
|
252
|
+
# Additional details
|
|
253
|
+
if details:
|
|
254
|
+
for key, value in details.items():
|
|
255
|
+
lines.append(f" {key}: {value}")
|
|
256
|
+
|
|
257
|
+
return lines
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def format_list_items(
|
|
261
|
+
items: list[dict[str, str]],
|
|
262
|
+
show_count: int | None = None,
|
|
263
|
+
more_suffix: str = "... and {count} more",
|
|
264
|
+
) -> list[str]:
|
|
265
|
+
"""Format a list of items consistently.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
items: List of dicts with 'id' and 'title' keys minimum
|
|
269
|
+
show_count: Maximum items to show (None = show all)
|
|
270
|
+
more_suffix: Format string for "... and X more" suffix
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
List of formatted output lines
|
|
274
|
+
"""
|
|
275
|
+
lines = []
|
|
276
|
+
|
|
277
|
+
# Determine how many to show
|
|
278
|
+
items_to_show = items
|
|
279
|
+
remaining = 0
|
|
280
|
+
if show_count and len(items) > show_count:
|
|
281
|
+
items_to_show = items[:show_count]
|
|
282
|
+
remaining = len(items) - show_count
|
|
283
|
+
|
|
284
|
+
# Format each item
|
|
285
|
+
for item in items_to_show:
|
|
286
|
+
item_id = item.get("id", "")[:8] # Show first 8 chars of ID
|
|
287
|
+
title = item.get("title", "")
|
|
288
|
+
lines.append(f" • {item_id} - {title}")
|
|
289
|
+
|
|
290
|
+
# Add "... and X more" if truncated
|
|
291
|
+
if remaining > 0:
|
|
292
|
+
lines.append(more_suffix.format(count=remaining))
|
|
293
|
+
|
|
294
|
+
return lines
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# Console wrapper functions for CLI commands that need to print and potentially exit
|
|
298
|
+
def print_operation_success(
|
|
299
|
+
console,
|
|
300
|
+
emoji: str,
|
|
301
|
+
action: str,
|
|
302
|
+
entity_title: str | None = None,
|
|
303
|
+
entity_id: str | None = None,
|
|
304
|
+
reason: str | None = None,
|
|
305
|
+
extra_details: dict[str, str] | None = None,
|
|
306
|
+
) -> None:
|
|
307
|
+
"""Print a successful operation message to console."""
|
|
308
|
+
lines = format_operation_success(
|
|
309
|
+
emoji, action, entity_title, entity_id, reason, extra_details
|
|
310
|
+
)
|
|
311
|
+
for line in lines:
|
|
312
|
+
console.print(line)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def print_operation_failure(
|
|
316
|
+
console,
|
|
317
|
+
action: str,
|
|
318
|
+
entity_id: str | None = None,
|
|
319
|
+
error: str | None = None,
|
|
320
|
+
suggestion: str | None = None,
|
|
321
|
+
) -> None:
|
|
322
|
+
"""Print a failed operation message to console."""
|
|
323
|
+
lines = format_operation_failure(action, entity_id, error, suggestion)
|
|
324
|
+
for line in lines:
|
|
325
|
+
console.print(line)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Status badge and percentage formatting."""
|
|
2
|
+
|
|
3
|
+
from rich.text import Text
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def format_status_badge(status: str) -> Text:
|
|
7
|
+
"""Format a status as a colored badge.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
status: Status value
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Styled Text badge
|
|
14
|
+
"""
|
|
15
|
+
status_lower = str(status).lower()
|
|
16
|
+
|
|
17
|
+
# Map status values to colors
|
|
18
|
+
status_colors = {
|
|
19
|
+
"closed": "bold green",
|
|
20
|
+
"in-progress": "bold blue",
|
|
21
|
+
"in_progress": "bold blue",
|
|
22
|
+
"todo": "bold yellow",
|
|
23
|
+
"blocked": "bold red",
|
|
24
|
+
"review": "bold magenta",
|
|
25
|
+
"open": "bold green",
|
|
26
|
+
"active": "bold green",
|
|
27
|
+
"on-hold": "bold yellow",
|
|
28
|
+
"on_hold": "bold yellow",
|
|
29
|
+
"planning": "bold blue",
|
|
30
|
+
"completed": "bold green",
|
|
31
|
+
"cancelled": "bold red",
|
|
32
|
+
"critical": "bold red",
|
|
33
|
+
"high": "bold yellow",
|
|
34
|
+
"medium": "bold blue",
|
|
35
|
+
"low": "bold green",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
style = status_colors.get(status_lower, "white")
|
|
39
|
+
return Text(f"[{status}]", style=style)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def format_percentage(value: float, decimals: int = 1) -> str:
|
|
43
|
+
"""Format a numeric value as a percentage.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
value: Decimal value (0.0-1.0 or 0-100)
|
|
47
|
+
decimals: Number of decimal places
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Formatted percentage string
|
|
51
|
+
"""
|
|
52
|
+
if value <= 1.0:
|
|
53
|
+
value = value * 100
|
|
54
|
+
return f"{value:.{decimals}f}%"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = ["format_status_badge", "format_percentage"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""GitHub initialization services."""
|
|
2
|
+
|
|
3
|
+
from roadmap.common.initialization.github.setup_service import (
|
|
4
|
+
GitHubInitializationService,
|
|
5
|
+
)
|
|
6
|
+
from roadmap.common.initialization.github.setup_validator import GitHubSetupValidator
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"GitHubSetupValidator",
|
|
10
|
+
"GitHubInitializationService",
|
|
11
|
+
]
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""GitHub initialization service for setup workflow orchestration."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from structlog import get_logger
|
|
5
|
+
|
|
6
|
+
from roadmap.adapters.github.github import GitHubClient
|
|
7
|
+
from roadmap.common.configuration.github.config_manager import GitHubConfigManager
|
|
8
|
+
from roadmap.common.configuration.github.token_resolver import GitHubTokenResolver
|
|
9
|
+
from roadmap.common.console import get_console
|
|
10
|
+
from roadmap.common.constants import SyncBackend
|
|
11
|
+
from roadmap.common.initialization.github.setup_validator import GitHubSetupValidator
|
|
12
|
+
from roadmap.infrastructure.coordination.core import RoadmapCore
|
|
13
|
+
from roadmap.infrastructure.security.credentials import CredentialManager
|
|
14
|
+
|
|
15
|
+
logger = get_logger()
|
|
16
|
+
console = get_console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def show_github_setup_instructions(github_repo: str, yes: bool) -> bool:
|
|
20
|
+
"""Show GitHub setup instructions and get user confirmation.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
True if user wants to continue, False to skip
|
|
24
|
+
"""
|
|
25
|
+
console.print("🔗 GitHub Integration Setup", style="bold blue")
|
|
26
|
+
console.print(f"\nRepository: {github_repo}")
|
|
27
|
+
console.print("\nTo sync with GitHub, you'll need a personal access token.")
|
|
28
|
+
console.print("→ Open: https://github.com/settings/tokens")
|
|
29
|
+
console.print(
|
|
30
|
+
"→ Create token with 'repo' scope (or 'public_repo' for public repos)"
|
|
31
|
+
)
|
|
32
|
+
console.print("→ Required permissions: Issues, Pull requests, Repository metadata")
|
|
33
|
+
console.print()
|
|
34
|
+
|
|
35
|
+
if not yes and not click.confirm("Do you want to set up GitHub integration now?"):
|
|
36
|
+
console.print(
|
|
37
|
+
"⏭️ Skipping GitHub integration (you can set this up later with 'roadmap sync setup')"
|
|
38
|
+
)
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class GitHubInitializationService:
|
|
45
|
+
"""Orchestrates GitHub integration setup during initialization."""
|
|
46
|
+
|
|
47
|
+
def __init__(self, core: RoadmapCore):
|
|
48
|
+
"""Initialize GitHubInitializationService.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
core: Core roadmap instance.
|
|
52
|
+
"""
|
|
53
|
+
self.core = core
|
|
54
|
+
self.presenter = None # Set by caller if needed
|
|
55
|
+
|
|
56
|
+
def setup(
|
|
57
|
+
self,
|
|
58
|
+
skip_github: bool,
|
|
59
|
+
github_repo: str | None,
|
|
60
|
+
detected_info: dict,
|
|
61
|
+
interactive: bool,
|
|
62
|
+
yes: bool,
|
|
63
|
+
github_token: str | None,
|
|
64
|
+
presenter=None,
|
|
65
|
+
sync_backend: SyncBackend = SyncBackend.GITHUB,
|
|
66
|
+
) -> bool:
|
|
67
|
+
"""Set up GitHub integration if requested.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
skip_github: If True, skip GitHub setup
|
|
71
|
+
github_repo: GitHub repository (owner/repo)
|
|
72
|
+
detected_info: Auto-detected project information
|
|
73
|
+
interactive: If True, prompt user for input
|
|
74
|
+
yes: If True, answer yes to all prompts
|
|
75
|
+
github_token: GitHub personal access token
|
|
76
|
+
presenter: UI presenter for output
|
|
77
|
+
sync_backend: Backend to use (SyncBackend.GITHUB or SyncBackend.GIT)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
True if configured, False if skipped or failed
|
|
81
|
+
"""
|
|
82
|
+
self.presenter = presenter
|
|
83
|
+
|
|
84
|
+
if skip_github:
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
repo_name = github_repo or detected_info.get("git_repo")
|
|
88
|
+
if not repo_name:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
return self._configure_integration(
|
|
92
|
+
repo_name, interactive, yes, token=github_token, sync_backend=sync_backend
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def _validate_setup_conditions(self, github_repo, interactive, yes, token):
|
|
96
|
+
"""Validate prerequisites for GitHub integration setup.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
True if setup should proceed, False if user wants to skip
|
|
100
|
+
"""
|
|
101
|
+
if GitHubClient is None or CredentialManager is None:
|
|
102
|
+
raise ImportError("GitHub integration dependencies not available")
|
|
103
|
+
|
|
104
|
+
if interactive and not yes:
|
|
105
|
+
if not show_github_setup_instructions(github_repo, yes):
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def _resolve_and_test_token(self, token, interactive, yes):
|
|
111
|
+
"""Resolve token and test GitHub connection."""
|
|
112
|
+
cred_manager = CredentialManager() # type: ignore[call-arg]
|
|
113
|
+
token_resolver = GitHubTokenResolver(cred_manager)
|
|
114
|
+
|
|
115
|
+
existing_token = token_resolver.get_existing_token()
|
|
116
|
+
use_token, should_continue = token_resolver.resolve_token(
|
|
117
|
+
token, interactive, yes, existing_token
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if not should_continue or not use_token:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
if self.presenter:
|
|
124
|
+
self.presenter.present_github_testing()
|
|
125
|
+
else:
|
|
126
|
+
console.print("🧪 Testing GitHub connection...", style="cyan")
|
|
127
|
+
|
|
128
|
+
return use_token
|
|
129
|
+
|
|
130
|
+
def _validate_github_access(self, use_token, github_repo, interactive, yes):
|
|
131
|
+
"""Validate authentication and repository access."""
|
|
132
|
+
github_client = GitHubClient(use_token) # type: ignore[call-arg]
|
|
133
|
+
validator = GitHubSetupValidator(github_client)
|
|
134
|
+
|
|
135
|
+
auth_success, _ = validator.validate_authentication()
|
|
136
|
+
if not auth_success:
|
|
137
|
+
if interactive and not yes:
|
|
138
|
+
if not click.confirm(
|
|
139
|
+
"Continue without GitHub integration? (recommended to skip until token is fixed)"
|
|
140
|
+
):
|
|
141
|
+
return False
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
repo_success, _ = validator.validate_repository_access(github_repo)
|
|
145
|
+
if not repo_success:
|
|
146
|
+
if interactive and not yes:
|
|
147
|
+
if not click.confirm("Continue with GitHub integration anyway?"):
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
def _store_credentials_and_config(
|
|
153
|
+
self,
|
|
154
|
+
use_token: str,
|
|
155
|
+
existing_token: str | None,
|
|
156
|
+
github_repo: str,
|
|
157
|
+
sync_backend: SyncBackend = SyncBackend.GITHUB,
|
|
158
|
+
) -> None:
|
|
159
|
+
"""Store credentials and save configuration.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
use_token: Token to store
|
|
163
|
+
existing_token: Previously stored token
|
|
164
|
+
github_repo: GitHub repository (owner/repo)
|
|
165
|
+
sync_backend: Backend to use (SyncBackend.GITHUB or SyncBackend.GIT)
|
|
166
|
+
"""
|
|
167
|
+
if use_token != existing_token:
|
|
168
|
+
cred_manager = CredentialManager() # type: ignore[call-arg]
|
|
169
|
+
cred_manager.store_token(use_token)
|
|
170
|
+
if self.presenter:
|
|
171
|
+
self.presenter.present_github_credentials_stored()
|
|
172
|
+
else:
|
|
173
|
+
console.print("✅ GitHub credentials stored", style="green")
|
|
174
|
+
|
|
175
|
+
config_manager = GitHubConfigManager(self.core)
|
|
176
|
+
# Always pass sync_backend explicitly for consistency and clarity
|
|
177
|
+
config_manager.save_github_config(github_repo, sync_backend=sync_backend)
|
|
178
|
+
|
|
179
|
+
def _configure_integration(
|
|
180
|
+
self,
|
|
181
|
+
github_repo: str,
|
|
182
|
+
interactive: bool,
|
|
183
|
+
yes: bool = False,
|
|
184
|
+
token: str | None = None,
|
|
185
|
+
sync_backend: SyncBackend = SyncBackend.GITHUB,
|
|
186
|
+
) -> bool:
|
|
187
|
+
"""Set up GitHub integration with credential flow.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
github_repo: GitHub repository (owner/repo)
|
|
191
|
+
interactive: If True, prompt user for input
|
|
192
|
+
yes: If True, answer yes to all prompts
|
|
193
|
+
token: GitHub personal access token
|
|
194
|
+
sync_backend: Backend to use (SyncBackend.GITHUB or SyncBackend.GIT)
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
True if setup successful, False otherwise
|
|
198
|
+
"""
|
|
199
|
+
try:
|
|
200
|
+
# Validate setup conditions - this will prompt user if they want to proceed
|
|
201
|
+
setup_result = self._validate_setup_conditions(
|
|
202
|
+
github_repo, interactive, yes, token
|
|
203
|
+
)
|
|
204
|
+
if not setup_result:
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
# Resolve and test token
|
|
208
|
+
use_token = self._resolve_and_test_token(token, interactive, yes)
|
|
209
|
+
if use_token is None:
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
# Validate GitHub access
|
|
213
|
+
if not self._validate_github_access(
|
|
214
|
+
use_token, github_repo, interactive, yes
|
|
215
|
+
):
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
# Store credentials and config
|
|
219
|
+
cred_manager = CredentialManager() # type: ignore[call-arg]
|
|
220
|
+
existing_token = GitHubTokenResolver(cred_manager).get_existing_token()
|
|
221
|
+
self._store_credentials_and_config(
|
|
222
|
+
use_token, existing_token, github_repo, sync_backend=sync_backend
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
except ImportError:
|
|
228
|
+
if self.presenter:
|
|
229
|
+
self.presenter.present_github_unavailable("Dependencies not installed")
|
|
230
|
+
else:
|
|
231
|
+
console.print("⚠️ GitHub dependencies not installed", style="yellow")
|
|
232
|
+
return False
|
|
233
|
+
except Exception as e:
|
|
234
|
+
if self.presenter:
|
|
235
|
+
self.presenter.present_github_setup_failed(str(e))
|
|
236
|
+
else:
|
|
237
|
+
console.print(f"❌ GitHub setup failed: {e}", style="red")
|
|
238
|
+
return False
|