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,587 @@
|
|
|
1
|
+
"""Initialize a new roadmap directory structure."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from structlog import get_logger
|
|
8
|
+
|
|
9
|
+
from roadmap.adapters.cli.presentation.core_initialization_presenter import (
|
|
10
|
+
CoreInitializationPresenter,
|
|
11
|
+
)
|
|
12
|
+
from roadmap.adapters.cli.services.project_initialization_service import (
|
|
13
|
+
ProjectContextDetectionService,
|
|
14
|
+
ProjectCreationService,
|
|
15
|
+
ProjectDetectionService,
|
|
16
|
+
)
|
|
17
|
+
from roadmap.common.constants import SyncBackend
|
|
18
|
+
from roadmap.common.initialization.github import GitHubInitializationService
|
|
19
|
+
from roadmap.core.services.initialization import (
|
|
20
|
+
InitializationLock,
|
|
21
|
+
InitializationManifest,
|
|
22
|
+
InitializationValidator,
|
|
23
|
+
InitializationWorkflow,
|
|
24
|
+
)
|
|
25
|
+
from roadmap.infrastructure.coordination.core import RoadmapCore
|
|
26
|
+
|
|
27
|
+
logger = get_logger()
|
|
28
|
+
presenter = CoreInitializationPresenter()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def show_dry_run_info(
|
|
32
|
+
name: str, is_initialized: bool, force: bool, skip_project: bool, skip_github: bool
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Display dry-run information without making changes."""
|
|
35
|
+
click.secho("🚀 Roadmap CLI Initialization", fg="cyan", bold=True)
|
|
36
|
+
click.echo()
|
|
37
|
+
click.secho("ℹ️ Dry run mode enabled - no changes will be made.", fg="yellow")
|
|
38
|
+
|
|
39
|
+
if is_initialized and force:
|
|
40
|
+
click.secho(f"🟡 Would remove existing {name}/ and reinitialize", fg="yellow")
|
|
41
|
+
elif is_initialized:
|
|
42
|
+
click.secho(
|
|
43
|
+
f"❌ Roadmap already initialized in {name}/ directory", fg="red", bold=True
|
|
44
|
+
)
|
|
45
|
+
click.secho("Tip: use --force to reinitialize", fg="yellow")
|
|
46
|
+
else:
|
|
47
|
+
actions = [
|
|
48
|
+
f"Create roadmap directory: {name}/",
|
|
49
|
+
"Create default templates and config",
|
|
50
|
+
]
|
|
51
|
+
if not skip_project:
|
|
52
|
+
actions.append("Create main project")
|
|
53
|
+
if not skip_github:
|
|
54
|
+
actions.append("Optionally configure GitHub")
|
|
55
|
+
|
|
56
|
+
click.echo("Planned actions:")
|
|
57
|
+
for action in actions:
|
|
58
|
+
click.echo(f" - {action}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _validate_initialization(custom_core, lock_path, force):
|
|
62
|
+
"""Validate initialization prerequisites."""
|
|
63
|
+
is_valid, error_msg = InitializationValidator.validate_lockfile(lock_path)
|
|
64
|
+
if not is_valid:
|
|
65
|
+
presenter.present_error(error_msg or "Unknown error")
|
|
66
|
+
presenter.present_initialization_tip()
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
is_valid, error_msg = InitializationValidator.check_existing_roadmap(
|
|
70
|
+
custom_core, force
|
|
71
|
+
)
|
|
72
|
+
if not is_valid:
|
|
73
|
+
presenter.present_error(error_msg or "Unknown error")
|
|
74
|
+
presenter.present_initialization_tip()
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _setup_project(
|
|
81
|
+
custom_core,
|
|
82
|
+
skip_project,
|
|
83
|
+
detected_info,
|
|
84
|
+
project_name,
|
|
85
|
+
description,
|
|
86
|
+
template,
|
|
87
|
+
template_path,
|
|
88
|
+
interactive,
|
|
89
|
+
):
|
|
90
|
+
"""Set up project if not skipped."""
|
|
91
|
+
if skip_project:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
existing_projects = ProjectDetectionService.detect_existing_projects(
|
|
95
|
+
custom_core.projects_dir
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if existing_projects:
|
|
99
|
+
if len(existing_projects) > 1 and interactive:
|
|
100
|
+
presenter.present_existing_projects_found(len(existing_projects))
|
|
101
|
+
return {
|
|
102
|
+
"name": existing_projects[0]["name"],
|
|
103
|
+
"id": existing_projects[0]["id"],
|
|
104
|
+
"action": "joined",
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
project_info = ProjectCreationService.create_project(
|
|
108
|
+
custom_core,
|
|
109
|
+
project_name or detected_info.get("project_name", Path.cwd().name),
|
|
110
|
+
description or "A project managed with Roadmap CLI",
|
|
111
|
+
detected_info,
|
|
112
|
+
template or "basic",
|
|
113
|
+
template_path,
|
|
114
|
+
)
|
|
115
|
+
if project_info:
|
|
116
|
+
project_info["action"] = "created"
|
|
117
|
+
|
|
118
|
+
return project_info
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _create_roadmap_structure(workflow, manifest, name):
|
|
122
|
+
"""Create roadmap directory structure."""
|
|
123
|
+
presenter.present_creating_structure(name)
|
|
124
|
+
if not workflow.create_structure_preserve_data():
|
|
125
|
+
return False
|
|
126
|
+
workflow.generate_config_file()
|
|
127
|
+
workflow.record_created_paths(manifest)
|
|
128
|
+
workflow.ensure_gitignore_entry()
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _handle_force_reinitialization(custom_core, workflow, name):
|
|
133
|
+
"""Handle force re-initialization of existing roadmap."""
|
|
134
|
+
if custom_core.is_initialized():
|
|
135
|
+
presenter.present_force_reinitialize_warning(name)
|
|
136
|
+
if not workflow.cleanup_existing():
|
|
137
|
+
return False
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _handle_init_dry_run(
|
|
142
|
+
name: str, force: bool, skip_project: bool, skip_github: bool, log
|
|
143
|
+
) -> bool:
|
|
144
|
+
"""Handle dry-run mode for init.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
name: Roadmap name
|
|
148
|
+
force: Force flag
|
|
149
|
+
skip_project: Skip project setup
|
|
150
|
+
skip_github: Skip GitHub setup
|
|
151
|
+
log: Logger instance
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
True if should continue (not dry-run), False if dry-run was handled
|
|
155
|
+
"""
|
|
156
|
+
roadmap_dir = Path.cwd() / name
|
|
157
|
+
config_file = roadmap_dir / "config.yaml"
|
|
158
|
+
is_initialized = roadmap_dir.exists() and config_file.exists()
|
|
159
|
+
log.info("dry_run_mode", is_initialized=is_initialized)
|
|
160
|
+
show_dry_run_info(name, is_initialized, force, skip_project, skip_github)
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _setup_init_environment(custom_core, name: str, force: bool, log):
|
|
165
|
+
"""Set up lock and manifest for initialization.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
custom_core: RoadmapCore instance
|
|
169
|
+
name: Roadmap name
|
|
170
|
+
force: Force flag
|
|
171
|
+
log: Logger instance
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
Tuple of (lock, manifest, workflow) or (None, None, None) on error
|
|
175
|
+
"""
|
|
176
|
+
lock_path = Path.cwd() / ".roadmap_init.lock"
|
|
177
|
+
if not _validate_initialization(custom_core, lock_path, force):
|
|
178
|
+
return None, None, None
|
|
179
|
+
|
|
180
|
+
lock = InitializationLock(lock_path)
|
|
181
|
+
if not lock.acquire():
|
|
182
|
+
presenter.present_already_in_progress_error()
|
|
183
|
+
return None, None, None
|
|
184
|
+
|
|
185
|
+
manifest = InitializationManifest(custom_core.roadmap_dir / ".init_manifest.json")
|
|
186
|
+
workflow = InitializationWorkflow(custom_core)
|
|
187
|
+
|
|
188
|
+
return lock, manifest, workflow
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _handle_already_initialized(
|
|
192
|
+
custom_core, force: bool, workflow, name: str
|
|
193
|
+
) -> tuple[bool, bool]:
|
|
194
|
+
"""Handle case where roadmap is already initialized.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
custom_core: RoadmapCore instance
|
|
198
|
+
force: Force re-initialization flag
|
|
199
|
+
workflow: InitializationWorkflow instance
|
|
200
|
+
name: Roadmap name
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Tuple of (should_continue, should_create_structure)
|
|
204
|
+
- should_continue: Whether to proceed with initialization
|
|
205
|
+
- should_create_structure: Whether to call _create_roadmap_structure
|
|
206
|
+
"""
|
|
207
|
+
if force:
|
|
208
|
+
success = _handle_force_reinitialization(custom_core, workflow, name)
|
|
209
|
+
# If force succeeded, we need to create structure (roadmap was cleaned)
|
|
210
|
+
return success, success
|
|
211
|
+
elif custom_core.is_initialized():
|
|
212
|
+
# Show info message but continue - allow team members to join existing projects
|
|
213
|
+
# Do NOT create structure since roadmap already exists
|
|
214
|
+
presenter.present_already_initialized_info(name)
|
|
215
|
+
return True, False
|
|
216
|
+
# Roadmap doesn't exist, so we need to create structure
|
|
217
|
+
return True, True
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _setup_project_and_context(
|
|
221
|
+
custom_core: RoadmapCore,
|
|
222
|
+
skip_project: bool,
|
|
223
|
+
detected_info: dict,
|
|
224
|
+
project_name: str | None,
|
|
225
|
+
description: str | None,
|
|
226
|
+
template: str | None,
|
|
227
|
+
template_path: str | None,
|
|
228
|
+
interactive: bool,
|
|
229
|
+
) -> dict | None:
|
|
230
|
+
"""Set up project and save configuration.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
custom_core: The roadmap core instance
|
|
234
|
+
skip_project: Whether to skip project setup
|
|
235
|
+
detected_info: Detected project context
|
|
236
|
+
project_name: Optional project name
|
|
237
|
+
description: Optional project description
|
|
238
|
+
template: Optional template name
|
|
239
|
+
template_path: Optional path to template
|
|
240
|
+
interactive: Whether interactive mode is enabled
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
Project info dict or None
|
|
244
|
+
"""
|
|
245
|
+
project_info = _setup_project(
|
|
246
|
+
custom_core,
|
|
247
|
+
skip_project,
|
|
248
|
+
detected_info,
|
|
249
|
+
project_name,
|
|
250
|
+
description,
|
|
251
|
+
template,
|
|
252
|
+
template_path,
|
|
253
|
+
interactive,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Save default project ID if created
|
|
257
|
+
if project_info and project_info.get("action") == "created":
|
|
258
|
+
from roadmap.common.configuration import ConfigManager
|
|
259
|
+
|
|
260
|
+
config_manager = ConfigManager(custom_core.config_file)
|
|
261
|
+
config = config_manager.load()
|
|
262
|
+
config.behavior.default_project_id = project_info.get("id")
|
|
263
|
+
config_manager.save(config)
|
|
264
|
+
|
|
265
|
+
return project_info
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _present_project_results(project_info: dict | None) -> None:
|
|
269
|
+
"""Display project setup results to user.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
project_info: Information about the created/joined project
|
|
273
|
+
"""
|
|
274
|
+
if not project_info:
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
if project_info.get("action") == "created":
|
|
278
|
+
presenter.present_project_created(project_info.get("name", "Main Project"))
|
|
279
|
+
elif project_info.get("action") == "joined":
|
|
280
|
+
count = project_info.get("count", 1)
|
|
281
|
+
if count > 1:
|
|
282
|
+
presenter.present_projects_joined(project_info.get("name", ""), count)
|
|
283
|
+
else:
|
|
284
|
+
presenter.present_project_joined(project_info.get("name", ""))
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def _persist_sync_backend_config(
|
|
288
|
+
custom_core: RoadmapCore, sync_backend: str, log
|
|
289
|
+
) -> None:
|
|
290
|
+
"""Persist sync backend selection to configuration.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
custom_core: The roadmap core instance
|
|
294
|
+
sync_backend: The sync backend to persist
|
|
295
|
+
log: Logger instance for recording operations
|
|
296
|
+
"""
|
|
297
|
+
if sync_backend == "github":
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
from roadmap.common.configuration import ConfigManager
|
|
302
|
+
|
|
303
|
+
config_manager = ConfigManager(custom_core.config_file)
|
|
304
|
+
config = config_manager.load()
|
|
305
|
+
|
|
306
|
+
if not config.github:
|
|
307
|
+
log.warning("github_config_not_initialized", sync_backend=sync_backend)
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
log.info(
|
|
311
|
+
"persisting_sync_backend",
|
|
312
|
+
sync_backend=sync_backend,
|
|
313
|
+
config_file=str(custom_core.config_file),
|
|
314
|
+
)
|
|
315
|
+
config.github.sync_backend = sync_backend
|
|
316
|
+
config_manager.save(config)
|
|
317
|
+
|
|
318
|
+
# Verify persistence
|
|
319
|
+
verify_config = config_manager.load()
|
|
320
|
+
persisted_backend = verify_config.github.sync_backend
|
|
321
|
+
if persisted_backend == sync_backend:
|
|
322
|
+
log.info("sync_backend_persisted_verified", sync_backend=sync_backend)
|
|
323
|
+
else:
|
|
324
|
+
log.warning(
|
|
325
|
+
"sync_backend_persistence_mismatch",
|
|
326
|
+
expected=sync_backend,
|
|
327
|
+
actual=persisted_backend,
|
|
328
|
+
)
|
|
329
|
+
except Exception as e:
|
|
330
|
+
log.error(
|
|
331
|
+
"sync_backend_persistence_failed",
|
|
332
|
+
sync_backend=sync_backend,
|
|
333
|
+
error=str(e),
|
|
334
|
+
error_type=type(e).__name__,
|
|
335
|
+
)
|
|
336
|
+
presenter.present_initialization_warning(
|
|
337
|
+
f"⚠️ Could not persist sync backend selection: {str(e)}"
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _finalize_initialization(
|
|
342
|
+
custom_core: RoadmapCore,
|
|
343
|
+
name: str,
|
|
344
|
+
project_info: dict | None,
|
|
345
|
+
should_create_structure: bool,
|
|
346
|
+
) -> None:
|
|
347
|
+
"""Finalize initialization with validation and summary.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
custom_core: The roadmap core instance
|
|
351
|
+
name: The roadmap name
|
|
352
|
+
project_info: Information about the setup project
|
|
353
|
+
should_create_structure: Whether new structure was created
|
|
354
|
+
"""
|
|
355
|
+
# Validate and show summary
|
|
356
|
+
validation_ok = InitializationValidator.post_init_validate(
|
|
357
|
+
custom_core, name, project_info
|
|
358
|
+
)
|
|
359
|
+
if not validation_ok:
|
|
360
|
+
presenter.present_initialization_warning("Some validation checks failed")
|
|
361
|
+
|
|
362
|
+
# Show completion message with next steps
|
|
363
|
+
presenter.present_initialization_complete(created_new=should_create_structure)
|
|
364
|
+
|
|
365
|
+
# If we joined existing projects (not created), show them
|
|
366
|
+
if project_info and project_info.get("action") == "joined":
|
|
367
|
+
all_projects = ProjectDetectionService.detect_existing_projects(
|
|
368
|
+
custom_core.projects_dir
|
|
369
|
+
)
|
|
370
|
+
if all_projects:
|
|
371
|
+
project_names = [p.get("name", "Unknown") for p in all_projects]
|
|
372
|
+
presenter.present_existing_projects_info(project_names)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
@click.command()
|
|
376
|
+
@click.option(
|
|
377
|
+
"--name",
|
|
378
|
+
"-n",
|
|
379
|
+
default=".roadmap",
|
|
380
|
+
help="Name of the roadmap directory (default: .roadmap)",
|
|
381
|
+
)
|
|
382
|
+
@click.option(
|
|
383
|
+
"--project-name",
|
|
384
|
+
"-p",
|
|
385
|
+
default=None,
|
|
386
|
+
help="Name for the initial project",
|
|
387
|
+
)
|
|
388
|
+
@click.option(
|
|
389
|
+
"--description",
|
|
390
|
+
"-d",
|
|
391
|
+
default=None,
|
|
392
|
+
help="Description for the initial project",
|
|
393
|
+
)
|
|
394
|
+
@click.option(
|
|
395
|
+
"--skip-project",
|
|
396
|
+
is_flag=True,
|
|
397
|
+
help="Skip project creation",
|
|
398
|
+
)
|
|
399
|
+
@click.option(
|
|
400
|
+
"--skip-github",
|
|
401
|
+
is_flag=True,
|
|
402
|
+
help="Skip GitHub integration setup",
|
|
403
|
+
)
|
|
404
|
+
@click.option(
|
|
405
|
+
"--sync-backend",
|
|
406
|
+
type=click.Choice(["github", "git"]),
|
|
407
|
+
default="github",
|
|
408
|
+
help="Sync backend to use: 'github' for GitHub API, 'git' for vanilla Git push/pull",
|
|
409
|
+
)
|
|
410
|
+
@click.option(
|
|
411
|
+
"--github-repo",
|
|
412
|
+
default=None,
|
|
413
|
+
help="GitHub repository (owner/repo)",
|
|
414
|
+
)
|
|
415
|
+
@click.option(
|
|
416
|
+
"--github-token",
|
|
417
|
+
default=None,
|
|
418
|
+
help="GitHub personal access token",
|
|
419
|
+
)
|
|
420
|
+
@click.option(
|
|
421
|
+
"--interactive/--non-interactive",
|
|
422
|
+
default=True,
|
|
423
|
+
help="Run in interactive mode with prompts (default: interactive)",
|
|
424
|
+
)
|
|
425
|
+
@click.option(
|
|
426
|
+
"--yes",
|
|
427
|
+
"-y",
|
|
428
|
+
is_flag=True,
|
|
429
|
+
help="Answer yes to all prompts",
|
|
430
|
+
)
|
|
431
|
+
@click.option(
|
|
432
|
+
"--dry-run",
|
|
433
|
+
is_flag=True,
|
|
434
|
+
help="Show what would be initialized without making changes",
|
|
435
|
+
)
|
|
436
|
+
@click.option(
|
|
437
|
+
"--force",
|
|
438
|
+
"-f",
|
|
439
|
+
is_flag=True,
|
|
440
|
+
help="Force reinitialize existing roadmap",
|
|
441
|
+
)
|
|
442
|
+
@click.option(
|
|
443
|
+
"--template",
|
|
444
|
+
"-t",
|
|
445
|
+
default=None,
|
|
446
|
+
help="Template to use for project initialization",
|
|
447
|
+
)
|
|
448
|
+
@click.option(
|
|
449
|
+
"--template-path",
|
|
450
|
+
default=None,
|
|
451
|
+
help="Path to custom template file",
|
|
452
|
+
)
|
|
453
|
+
@click.pass_context
|
|
454
|
+
def init(
|
|
455
|
+
ctx: click.Context,
|
|
456
|
+
name: str,
|
|
457
|
+
project_name: str | None,
|
|
458
|
+
description: str | None,
|
|
459
|
+
skip_project: bool,
|
|
460
|
+
skip_github: bool,
|
|
461
|
+
sync_backend: str,
|
|
462
|
+
github_repo: str | None,
|
|
463
|
+
github_token: str | None,
|
|
464
|
+
interactive: bool,
|
|
465
|
+
yes: bool,
|
|
466
|
+
dry_run: bool,
|
|
467
|
+
force: bool,
|
|
468
|
+
template: str | None,
|
|
469
|
+
template_path: str | None,
|
|
470
|
+
) -> None:
|
|
471
|
+
"""Initialize a new roadmap structure."""
|
|
472
|
+
from roadmap.common.models import InitParams
|
|
473
|
+
|
|
474
|
+
# Create structured parameter object
|
|
475
|
+
params = InitParams(
|
|
476
|
+
name=name,
|
|
477
|
+
project_name=project_name,
|
|
478
|
+
description=description,
|
|
479
|
+
skip_project=skip_project,
|
|
480
|
+
skip_github=skip_github,
|
|
481
|
+
sync_backend=sync_backend,
|
|
482
|
+
github_repo=github_repo,
|
|
483
|
+
github_token=github_token,
|
|
484
|
+
interactive=interactive,
|
|
485
|
+
yes=yes,
|
|
486
|
+
dry_run=dry_run,
|
|
487
|
+
force=force,
|
|
488
|
+
template=template,
|
|
489
|
+
template_path=template_path,
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
log = logger.bind(
|
|
493
|
+
operation="init",
|
|
494
|
+
roadmap_name=params.name,
|
|
495
|
+
skip_github=params.skip_github,
|
|
496
|
+
interactive=params.interactive,
|
|
497
|
+
dry_run=params.dry_run,
|
|
498
|
+
force=params.force,
|
|
499
|
+
)
|
|
500
|
+
log.info("starting_init")
|
|
501
|
+
|
|
502
|
+
custom_core = RoadmapCore(roadmap_dir_name=params.name)
|
|
503
|
+
|
|
504
|
+
# Handle dry-run mode
|
|
505
|
+
if params.dry_run:
|
|
506
|
+
_handle_init_dry_run(
|
|
507
|
+
params.name, params.force, params.skip_project, params.skip_github, log
|
|
508
|
+
)
|
|
509
|
+
return
|
|
510
|
+
|
|
511
|
+
# Setup environment
|
|
512
|
+
lock, manifest, workflow = _setup_init_environment(
|
|
513
|
+
custom_core, params.name, params.force, log
|
|
514
|
+
)
|
|
515
|
+
if not lock:
|
|
516
|
+
sys.exit(1)
|
|
517
|
+
|
|
518
|
+
presenter.present_initialization_header()
|
|
519
|
+
|
|
520
|
+
try:
|
|
521
|
+
# Handle already initialized or force re-init
|
|
522
|
+
should_continue, should_create_structure = _handle_already_initialized(
|
|
523
|
+
custom_core, params.force, workflow, params.name
|
|
524
|
+
)
|
|
525
|
+
if not should_continue:
|
|
526
|
+
return
|
|
527
|
+
|
|
528
|
+
# Detect context (needed for project setup regardless)
|
|
529
|
+
detected_info = ProjectContextDetectionService.detect_project_context()
|
|
530
|
+
|
|
531
|
+
# Create structure only if needed (not already initialized or was force-cleaned)
|
|
532
|
+
if should_create_structure:
|
|
533
|
+
if not _create_roadmap_structure(workflow, manifest, params.name):
|
|
534
|
+
return
|
|
535
|
+
|
|
536
|
+
# Initialize ctx.obj if not already done (can happen in tests)
|
|
537
|
+
if ctx.obj is None:
|
|
538
|
+
ctx.obj = {}
|
|
539
|
+
|
|
540
|
+
ctx.obj["core"] = custom_core
|
|
541
|
+
|
|
542
|
+
# Setup project and context
|
|
543
|
+
project_info = _setup_project_and_context(
|
|
544
|
+
custom_core,
|
|
545
|
+
params.skip_project,
|
|
546
|
+
detected_info,
|
|
547
|
+
params.project_name,
|
|
548
|
+
params.description,
|
|
549
|
+
params.template,
|
|
550
|
+
params.template_path,
|
|
551
|
+
params.interactive,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
# Present project results
|
|
555
|
+
_present_project_results(project_info)
|
|
556
|
+
|
|
557
|
+
# Configure GitHub
|
|
558
|
+
github_service = GitHubInitializationService(custom_core)
|
|
559
|
+
sync_backend_enum = SyncBackend(params.sync_backend)
|
|
560
|
+
github_service.setup(
|
|
561
|
+
params.skip_github,
|
|
562
|
+
params.github_repo,
|
|
563
|
+
detected_info,
|
|
564
|
+
params.interactive,
|
|
565
|
+
params.yes,
|
|
566
|
+
github_token,
|
|
567
|
+
presenter,
|
|
568
|
+
sync_backend=sync_backend_enum,
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
# Persist sync backend configuration
|
|
572
|
+
_persist_sync_backend_config(custom_core, params.sync_backend, log)
|
|
573
|
+
|
|
574
|
+
# Finalize and validate
|
|
575
|
+
_finalize_initialization(
|
|
576
|
+
custom_core, name, project_info, should_create_structure
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
except Exception as e:
|
|
580
|
+
log.error("init_failed", error=str(e))
|
|
581
|
+
presenter.present_initialization_failed(str(e))
|
|
582
|
+
if manifest:
|
|
583
|
+
manifest.rollback()
|
|
584
|
+
if workflow:
|
|
585
|
+
workflow.rollback_on_error()
|
|
586
|
+
finally:
|
|
587
|
+
lock.release()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Initialize a new roadmap directory structure.
|
|
2
|
+
|
|
3
|
+
This module re-exports the init command from the init package.
|
|
4
|
+
The actual implementation is in adapters/cli/init/commands.py
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from roadmap.adapters.cli.init.commands import init
|
|
8
|
+
|
|
9
|
+
__all__ = ["init"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Issue commands module.
|
|
2
|
+
|
|
3
|
+
Provides all issue management commands:
|
|
4
|
+
- list: List issues with various filters
|
|
5
|
+
- create: Create a new issue
|
|
6
|
+
- update: Update an existing issue
|
|
7
|
+
- close: Close an issue (Git-aligned terminology)
|
|
8
|
+
- start: Start work on an issue
|
|
9
|
+
- progress: Update issue progress percentage
|
|
10
|
+
- block: Mark an issue as blocked
|
|
11
|
+
- unblock: Unblock a blocked issue
|
|
12
|
+
- delete: Delete an issue
|
|
13
|
+
- deps: Manage issue dependencies
|
|
14
|
+
- view: View detailed information about an issue
|
|
15
|
+
- archive: Archive an issue to .roadmap/archive/issues/
|
|
16
|
+
- comment: Manage comments and discussions on issues
|
|
17
|
+
- link: Link internal issue to GitHub issue
|
|
18
|
+
- lookup-github: Look up internal issue by GitHub issue number
|
|
19
|
+
- sync-status: View sync history and statistics for GitHub-linked issues
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import click
|
|
23
|
+
|
|
24
|
+
from roadmap.adapters.cli.issues.archive import archive_issue
|
|
25
|
+
from roadmap.adapters.cli.issues.block import block_issue
|
|
26
|
+
from roadmap.adapters.cli.issues.close import close_issue
|
|
27
|
+
from roadmap.adapters.cli.issues.comment import comment_group
|
|
28
|
+
from roadmap.adapters.cli.issues.create import create_issue
|
|
29
|
+
from roadmap.adapters.cli.issues.delete import delete_issue
|
|
30
|
+
from roadmap.adapters.cli.issues.deps import deps
|
|
31
|
+
from roadmap.adapters.cli.issues.link import link_github_issue
|
|
32
|
+
from roadmap.adapters.cli.issues.list import list_issues
|
|
33
|
+
from roadmap.adapters.cli.issues.lookup import lookup_github_issue
|
|
34
|
+
from roadmap.adapters.cli.issues.progress import update_progress
|
|
35
|
+
from roadmap.adapters.cli.issues.restore import restore_issue
|
|
36
|
+
from roadmap.adapters.cli.issues.start import start_issue
|
|
37
|
+
from roadmap.adapters.cli.issues.sync_status import sync_status
|
|
38
|
+
from roadmap.adapters.cli.issues.unblock import unblock_issue
|
|
39
|
+
from roadmap.adapters.cli.issues.unlink import unlink_github_issue
|
|
40
|
+
from roadmap.adapters.cli.issues.update import update_issue
|
|
41
|
+
from roadmap.adapters.cli.issues.view import view_issue
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@click.group()
|
|
45
|
+
def issue():
|
|
46
|
+
"""Manage issues."""
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Register all commands
|
|
51
|
+
issue.add_command(list_issues, name="list")
|
|
52
|
+
issue.add_command(create_issue, name="create")
|
|
53
|
+
issue.add_command(update_issue, name="update")
|
|
54
|
+
issue.add_command(close_issue, name="close")
|
|
55
|
+
issue.add_command(start_issue, name="start")
|
|
56
|
+
issue.add_command(update_progress, name="progress")
|
|
57
|
+
issue.add_command(block_issue, name="block")
|
|
58
|
+
issue.add_command(unblock_issue, name="unblock")
|
|
59
|
+
issue.add_command(delete_issue, name="delete")
|
|
60
|
+
issue.add_command(deps, name="deps")
|
|
61
|
+
issue.add_command(view_issue, name="view")
|
|
62
|
+
issue.add_command(archive_issue, name="archive")
|
|
63
|
+
issue.add_command(restore_issue, name="restore")
|
|
64
|
+
issue.add_command(comment_group, name="comment")
|
|
65
|
+
issue.add_command(link_github_issue, name="link-github")
|
|
66
|
+
issue.add_command(unlink_github_issue, name="unlink-github")
|
|
67
|
+
issue.add_command(lookup_github_issue, name="lookup-github")
|
|
68
|
+
issue.add_command(sync_status, name="sync-status")
|
|
69
|
+
|
|
70
|
+
__all__ = ["issue"]
|