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,21 @@
|
|
|
1
|
+
"""Sync infrastructure for integrating local roadmap with remote repositories.
|
|
2
|
+
|
|
3
|
+
Provides pluggable backend architecture supporting multiple sync targets.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .backend_factory import (
|
|
7
|
+
detect_backend_from_config,
|
|
8
|
+
get_backend_for_config,
|
|
9
|
+
get_sync_backend,
|
|
10
|
+
)
|
|
11
|
+
from .backends import GitHubSyncBackend, VanillaGitSyncBackend
|
|
12
|
+
from .sync_merge_orchestrator import SyncMergeOrchestrator
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"GitHubSyncBackend",
|
|
16
|
+
"VanillaGitSyncBackend",
|
|
17
|
+
"get_sync_backend",
|
|
18
|
+
"get_backend_for_config",
|
|
19
|
+
"detect_backend_from_config",
|
|
20
|
+
"SyncMergeOrchestrator",
|
|
21
|
+
]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Factory for creating sync backend instances based on configuration."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
import structlog
|
|
6
|
+
|
|
7
|
+
from roadmap.adapters.sync.backends.github_sync_backend import GitHubSyncBackend
|
|
8
|
+
from roadmap.adapters.sync.backends.vanilla_git_sync_backend import (
|
|
9
|
+
VanillaGitSyncBackend,
|
|
10
|
+
)
|
|
11
|
+
from roadmap.core.interfaces.sync_backend import SyncBackendInterface
|
|
12
|
+
from roadmap.infrastructure.coordination.core import RoadmapCore
|
|
13
|
+
|
|
14
|
+
log = structlog.get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_sync_backend(
|
|
18
|
+
backend_type: Literal["github", "git"],
|
|
19
|
+
core: RoadmapCore,
|
|
20
|
+
config: dict | None = None,
|
|
21
|
+
) -> SyncBackendInterface | None:
|
|
22
|
+
"""Create and return a sync backend instance.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
backend_type: Type of backend to create ('github' or 'git')
|
|
26
|
+
core: RoadmapCore instance
|
|
27
|
+
config: Configuration dict for the backend
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Backend instance implementing SyncBackendInterface, or None if creation fails
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
ValueError: If backend_type is invalid
|
|
34
|
+
"""
|
|
35
|
+
config_dict = config or {}
|
|
36
|
+
|
|
37
|
+
if backend_type == "github":
|
|
38
|
+
log.info("sync_backend_creating", backend_type="github")
|
|
39
|
+
return GitHubSyncBackend(core, config_dict)
|
|
40
|
+
elif backend_type == "git":
|
|
41
|
+
try:
|
|
42
|
+
log.info("sync_backend_creating", backend_type="git")
|
|
43
|
+
return VanillaGitSyncBackend(core, config_dict)
|
|
44
|
+
except (ValueError, RuntimeError) as e:
|
|
45
|
+
# VanillaGitSyncBackend raises on init failure (not in git repo, etc.)
|
|
46
|
+
log.warning(
|
|
47
|
+
"sync_backend_creation_failed",
|
|
48
|
+
backend_type="git",
|
|
49
|
+
error=str(e),
|
|
50
|
+
error_type=type(e).__name__,
|
|
51
|
+
)
|
|
52
|
+
return None
|
|
53
|
+
else:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"Invalid backend type: {backend_type}. Must be 'github' or 'git'"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def detect_backend_from_config(config: dict) -> Literal["github", "git"]:
|
|
60
|
+
"""Detect the appropriate backend from configuration.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
config: Configuration dict from .roadmap/config.json or .github/config.json
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Backend type to use ('github' or 'git')
|
|
67
|
+
"""
|
|
68
|
+
# If explicitly specified in config, use that
|
|
69
|
+
if config.get("backend") in ("github", "git"):
|
|
70
|
+
backend = config["backend"]
|
|
71
|
+
log.info("backend_detected_explicit", backend=backend)
|
|
72
|
+
return backend
|
|
73
|
+
|
|
74
|
+
# If GitHub config present, prefer GitHub backend
|
|
75
|
+
if config.get("github") and (
|
|
76
|
+
config["github"].get("owner") and config["github"].get("repo")
|
|
77
|
+
):
|
|
78
|
+
log.info(
|
|
79
|
+
"backend_detected_github_config",
|
|
80
|
+
has_owner=bool(config["github"].get("owner")),
|
|
81
|
+
has_repo=bool(config["github"].get("repo")),
|
|
82
|
+
)
|
|
83
|
+
return "github"
|
|
84
|
+
|
|
85
|
+
# Default to vanilla git backend
|
|
86
|
+
log.info("backend_detected_default", backend="git")
|
|
87
|
+
return "git"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_backend_for_config(
|
|
91
|
+
core: RoadmapCore, config: dict | None = None
|
|
92
|
+
) -> SyncBackendInterface | None:
|
|
93
|
+
"""Create backend based on auto-detected config.
|
|
94
|
+
|
|
95
|
+
Convenience function that detects the appropriate backend type
|
|
96
|
+
and creates an instance.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
core: RoadmapCore instance
|
|
100
|
+
config: Configuration dict (optional)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Backend instance, or None if creation fails
|
|
104
|
+
"""
|
|
105
|
+
config = config or {}
|
|
106
|
+
backend_type = detect_backend_from_config(config)
|
|
107
|
+
log.debug("backend_factory_creating_instance", backend_type=backend_type)
|
|
108
|
+
return get_sync_backend(backend_type, core, config)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Sync backend implementations.
|
|
2
|
+
|
|
3
|
+
Provides pluggable sync backends for integrating with various platforms:
|
|
4
|
+
- GitHub: GitHub API-based sync
|
|
5
|
+
- Vanilla Git: Git push/pull-based sync
|
|
6
|
+
- Other: Extensible for GitLab, Jira, etc.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .github_sync_backend import GitHubSyncBackend
|
|
10
|
+
from .vanilla_git_sync_backend import VanillaGitSyncBackend
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"GitHubSyncBackend",
|
|
14
|
+
"VanillaGitSyncBackend",
|
|
15
|
+
]
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""Converters between Issue domain objects and GitHub API payloads.
|
|
2
|
+
|
|
3
|
+
This module handles bidirectional conversion:
|
|
4
|
+
- Issue → GitHub API payload (for push)
|
|
5
|
+
- GitHub API response → Issue (for pull)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from structlog import get_logger
|
|
11
|
+
|
|
12
|
+
from roadmap.common.constants import Status
|
|
13
|
+
from roadmap.core.domain.issue import Issue
|
|
14
|
+
from roadmap.core.models.sync_models import SyncIssue
|
|
15
|
+
|
|
16
|
+
logger = get_logger()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IssueToGitHubPayloadConverter:
|
|
20
|
+
"""Convert Issue domain object to GitHub API payload."""
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def to_create_payload(issue: Issue) -> dict[str, Any]:
|
|
24
|
+
"""Convert Issue to GitHub API payload for create_issue().
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
issue: The Issue domain object
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Dictionary suitable for GitHub API create_issue() call
|
|
31
|
+
(does NOT include 'state' - that's only for updates)
|
|
32
|
+
"""
|
|
33
|
+
payload: dict[str, Any] = {
|
|
34
|
+
"title": issue.title,
|
|
35
|
+
"body": issue.content or "", # Use content as description
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
labels = [
|
|
39
|
+
label
|
|
40
|
+
for label in (issue.labels or [])
|
|
41
|
+
if isinstance(label, str) and label.strip()
|
|
42
|
+
]
|
|
43
|
+
if labels:
|
|
44
|
+
payload["labels"] = labels
|
|
45
|
+
|
|
46
|
+
if isinstance(issue.assignee, str) and issue.assignee.strip():
|
|
47
|
+
payload["assignees"] = [issue.assignee.strip()]
|
|
48
|
+
|
|
49
|
+
# NOTE: milestone field requires a milestone number/ID, not a string name
|
|
50
|
+
# GitHub API validation fails if we send milestone names instead of numbers
|
|
51
|
+
# Skip milestone for now until we have proper milestone mapping
|
|
52
|
+
# if issue.milestone:
|
|
53
|
+
# payload["milestone"] = issue.milestone
|
|
54
|
+
|
|
55
|
+
return payload
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def to_update_payload(issue: Issue) -> dict[str, Any]:
|
|
59
|
+
"""Convert Issue to GitHub API payload for update_issue().
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
issue: The Issue domain object
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dictionary suitable for GitHub API update_issue() call
|
|
66
|
+
"""
|
|
67
|
+
payload: dict[str, Any] = {
|
|
68
|
+
"title": issue.title,
|
|
69
|
+
"body": issue.content or "", # Use content as description
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Map roadmap status to GitHub state (only on update)
|
|
73
|
+
# GitHub only has open/closed, so we map our status accordingly
|
|
74
|
+
if issue.status == Status.CLOSED:
|
|
75
|
+
payload["state"] = "closed"
|
|
76
|
+
else:
|
|
77
|
+
payload["state"] = "open"
|
|
78
|
+
|
|
79
|
+
labels = [
|
|
80
|
+
label
|
|
81
|
+
for label in (issue.labels or [])
|
|
82
|
+
if isinstance(label, str) and label.strip()
|
|
83
|
+
]
|
|
84
|
+
if labels:
|
|
85
|
+
payload["labels"] = labels
|
|
86
|
+
|
|
87
|
+
if isinstance(issue.assignee, str) and issue.assignee.strip():
|
|
88
|
+
payload["assignees"] = [issue.assignee.strip()]
|
|
89
|
+
|
|
90
|
+
# NOTE: milestone field requires a milestone number/ID, not a string name
|
|
91
|
+
# GitHub API validation fails if we send milestone names instead of numbers
|
|
92
|
+
# Skip milestone for now until we have proper milestone mapping
|
|
93
|
+
# if issue.milestone:
|
|
94
|
+
# payload["milestone"] = issue.milestone
|
|
95
|
+
|
|
96
|
+
return payload
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def to_payload(issue: Issue, github_number: int | None = None) -> dict[str, Any]:
|
|
100
|
+
"""Convert Issue to GitHub API payload for create or update.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
issue: The Issue domain object
|
|
104
|
+
github_number: Optional GitHub issue number for update (None for create)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Dictionary suitable for GitHub API create_issue or update_issue call
|
|
108
|
+
"""
|
|
109
|
+
# Delegate to specific methods based on whether this is create or update
|
|
110
|
+
if github_number:
|
|
111
|
+
return IssueToGitHubPayloadConverter.to_update_payload(issue)
|
|
112
|
+
else:
|
|
113
|
+
return IssueToGitHubPayloadConverter.to_create_payload(issue)
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def get_github_number(issue: Issue) -> int | None:
|
|
117
|
+
"""Extract GitHub issue number from Issue's remote_ids.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
issue: The Issue domain object
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
GitHub issue number if linked, None otherwise
|
|
124
|
+
"""
|
|
125
|
+
if issue.remote_ids and "github" in issue.remote_ids:
|
|
126
|
+
github_id = issue.remote_ids["github"]
|
|
127
|
+
# Convert to int if needed
|
|
128
|
+
if isinstance(github_id, str):
|
|
129
|
+
try:
|
|
130
|
+
return int(github_id)
|
|
131
|
+
except ValueError:
|
|
132
|
+
logger.debug(
|
|
133
|
+
"failed_to_convert_github_id_to_int",
|
|
134
|
+
github_id=github_id,
|
|
135
|
+
)
|
|
136
|
+
return None
|
|
137
|
+
return github_id
|
|
138
|
+
return None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class GitHubPayloadToIssueConverter:
|
|
142
|
+
"""Convert GitHub API response to Issue domain object."""
|
|
143
|
+
|
|
144
|
+
@staticmethod
|
|
145
|
+
def from_sync_issue(sync_issue: SyncIssue) -> Issue:
|
|
146
|
+
"""Convert SyncIssue to Issue domain object.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
sync_issue: The SyncIssue from GitHub fetch
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Issue domain object
|
|
153
|
+
"""
|
|
154
|
+
# Map GitHub state to roadmap status
|
|
155
|
+
# SyncIssue.status is already normalized: "open" or "closed"
|
|
156
|
+
status = Status.CLOSED if sync_issue.status == "closed" else Status.TODO
|
|
157
|
+
|
|
158
|
+
issue = Issue(
|
|
159
|
+
title=sync_issue.title,
|
|
160
|
+
content=sync_issue.headline or "", # headline is the content in SyncIssue
|
|
161
|
+
status=status,
|
|
162
|
+
labels=sync_issue.labels or [],
|
|
163
|
+
assignee=sync_issue.assignee,
|
|
164
|
+
milestone=sync_issue.milestone,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Store the GitHub issue number as remote_id
|
|
168
|
+
# Use backend_id if available, or look in remote_ids dict
|
|
169
|
+
github_number = sync_issue.backend_id or sync_issue.remote_ids.get("github")
|
|
170
|
+
if github_number:
|
|
171
|
+
issue.remote_ids["github"] = (
|
|
172
|
+
int(github_number) if isinstance(github_number, str) else github_number
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return issue
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def from_github_dict(github_dict: dict[str, Any]) -> Issue:
|
|
179
|
+
"""Convert GitHub API issue dict to Issue domain object.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
github_dict: Dictionary from GitHub API response
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Issue domain object
|
|
186
|
+
"""
|
|
187
|
+
# Map GitHub state to roadmap status
|
|
188
|
+
status = Status.CLOSED if github_dict.get("state") == "closed" else Status.TODO
|
|
189
|
+
|
|
190
|
+
# Extract assignee (GitHub returns list)
|
|
191
|
+
assignees = github_dict.get("assignees") or []
|
|
192
|
+
assignee = assignees[0]["login"] if assignees else None
|
|
193
|
+
|
|
194
|
+
issue = Issue(
|
|
195
|
+
title=github_dict.get("title", ""),
|
|
196
|
+
content=github_dict.get("body") or "",
|
|
197
|
+
status=status,
|
|
198
|
+
labels=[label["name"] for label in (github_dict.get("labels") or [])],
|
|
199
|
+
assignee=assignee,
|
|
200
|
+
milestone=github_dict.get("milestone", {}).get("title")
|
|
201
|
+
if github_dict.get("milestone")
|
|
202
|
+
else None,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Store GitHub issue number
|
|
206
|
+
if "number" in github_dict:
|
|
207
|
+
issue.remote_ids["github"] = github_dict["number"]
|
|
208
|
+
|
|
209
|
+
return issue
|