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,335 @@
|
|
|
1
|
+
"""Logging setup and utility functions."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import logging.config
|
|
5
|
+
import logging.handlers
|
|
6
|
+
import random
|
|
7
|
+
import time
|
|
8
|
+
import traceback
|
|
9
|
+
from contextlib import contextmanager
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import structlog
|
|
14
|
+
|
|
15
|
+
from roadmap.common.logging.correlation import add_correlation_id
|
|
16
|
+
from roadmap.common.logging.formatters import (
|
|
17
|
+
include_structured_fields_in_message,
|
|
18
|
+
scrub_sensitive_data,
|
|
19
|
+
)
|
|
20
|
+
from roadmap.common.observability.instrumentation import span_context_processor
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def setup_logging(
|
|
24
|
+
log_level: str = "INFO",
|
|
25
|
+
log_to_file: bool = True,
|
|
26
|
+
log_dir: str | Path | None = None,
|
|
27
|
+
debug_mode: bool = False,
|
|
28
|
+
console_level: str | None = None,
|
|
29
|
+
custom_levels: dict[str, str] | None = None,
|
|
30
|
+
) -> structlog.stdlib.BoundLogger:
|
|
31
|
+
"""Set up structured logging for the roadmap application.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
log_level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|
35
|
+
log_to_file: Whether to log to file in addition to console
|
|
36
|
+
log_dir: Directory for log files (defaults to .roadmap/logs in current working directory)
|
|
37
|
+
debug_mode: Enable debug mode with verbose output
|
|
38
|
+
console_level: Override console handler level (e.g., "INFO" for --verbose)
|
|
39
|
+
If None, defaults to DEBUG if debug_mode else WARNING
|
|
40
|
+
custom_levels: Dict of logger_name: level for per-component log levels
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Configured structlog logger
|
|
44
|
+
"""
|
|
45
|
+
if log_dir is None:
|
|
46
|
+
log_dir = Path.cwd() / ".roadmap" / "logs"
|
|
47
|
+
else:
|
|
48
|
+
log_dir = Path(log_dir)
|
|
49
|
+
|
|
50
|
+
# Ensure log directory exists
|
|
51
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
log_file = log_dir / "roadmap.log"
|
|
53
|
+
|
|
54
|
+
# Configure standard library logging
|
|
55
|
+
# Use explicit sys.stderr for console to ensure logs go to stderr, not stdout
|
|
56
|
+
# Determine console level: explicit override > debug_mode > default WARNING
|
|
57
|
+
if console_level is None:
|
|
58
|
+
console_level = "DEBUG" if debug_mode else "WARNING"
|
|
59
|
+
|
|
60
|
+
handlers: dict[str, Any] = {
|
|
61
|
+
"console": {
|
|
62
|
+
"class": "logging.StreamHandler",
|
|
63
|
+
"level": console_level,
|
|
64
|
+
"formatter": "console",
|
|
65
|
+
"stream": "ext://sys.stderr", # Explicitly use stderr
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
formatters = {
|
|
70
|
+
"console": {
|
|
71
|
+
"format": "%(asctime)s [%(levelname)8s] %(name)s: %(message)s",
|
|
72
|
+
"datefmt": "%Y-%m-%dT%H:%M:%SZ",
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if log_to_file:
|
|
77
|
+
handlers["file"] = {
|
|
78
|
+
"class": "logging.handlers.RotatingFileHandler",
|
|
79
|
+
"level": "DEBUG",
|
|
80
|
+
"formatter": "structured",
|
|
81
|
+
"filename": str(log_file),
|
|
82
|
+
"maxBytes": 10485760, # 10MB
|
|
83
|
+
"backupCount": 5,
|
|
84
|
+
"encoding": "utf-8",
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
formatters["structured"] = {
|
|
88
|
+
"format": "%(asctime)s [%(levelname)8s] %(name)s: %(message)s",
|
|
89
|
+
"datefmt": "%Y-%m-%d %H:%M:%S",
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Build logger configuration with custom levels support
|
|
93
|
+
loggers_config = {
|
|
94
|
+
"roadmap": {
|
|
95
|
+
"level": log_level,
|
|
96
|
+
"handlers": list(handlers.keys()),
|
|
97
|
+
"propagate": False,
|
|
98
|
+
},
|
|
99
|
+
"roadmap.security": {
|
|
100
|
+
"level": "INFO",
|
|
101
|
+
"handlers": list(handlers.keys()),
|
|
102
|
+
"propagate": False,
|
|
103
|
+
},
|
|
104
|
+
# Suppress noisy third-party loggers
|
|
105
|
+
"urllib3": {"level": "WARNING"},
|
|
106
|
+
"requests": {"level": "WARNING"},
|
|
107
|
+
"aiohttp": {"level": "WARNING"},
|
|
108
|
+
"git": {"level": "WARNING"},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Add custom per-component log levels
|
|
112
|
+
if custom_levels:
|
|
113
|
+
for logger_name, level in custom_levels.items():
|
|
114
|
+
full_name = (
|
|
115
|
+
f"roadmap.{logger_name}"
|
|
116
|
+
if not logger_name.startswith("roadmap.")
|
|
117
|
+
else logger_name
|
|
118
|
+
)
|
|
119
|
+
loggers_config[full_name] = {
|
|
120
|
+
"level": level.upper(),
|
|
121
|
+
"handlers": list(handlers.keys()),
|
|
122
|
+
"propagate": False,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
config = {
|
|
126
|
+
"version": 1,
|
|
127
|
+
"disable_existing_loggers": False,
|
|
128
|
+
"formatters": formatters,
|
|
129
|
+
"handlers": handlers,
|
|
130
|
+
"loggers": loggers_config,
|
|
131
|
+
"root": {
|
|
132
|
+
"level": "WARNING",
|
|
133
|
+
"handlers": list(handlers.keys()), # Use all configured handlers
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
logging.config.dictConfig(config)
|
|
138
|
+
|
|
139
|
+
# Configure structlog with enhanced processors
|
|
140
|
+
# Route through stdlib logging handlers (console → stderr, file → JSON)
|
|
141
|
+
processors: list = [
|
|
142
|
+
# Add correlation ID first (before any filtering)
|
|
143
|
+
add_correlation_id,
|
|
144
|
+
# Add span context for tracing
|
|
145
|
+
span_context_processor,
|
|
146
|
+
# Scrub sensitive data early in pipeline
|
|
147
|
+
scrub_sensitive_data,
|
|
148
|
+
# Add standard metadata
|
|
149
|
+
structlog.stdlib.add_log_level,
|
|
150
|
+
# NOTE: Do NOT use add_logger_name when using render_to_log_kwargs
|
|
151
|
+
# because it creates a "logger" key that becomes "name" kwarg in LogRecord,
|
|
152
|
+
# causing: KeyError: "Attempt to overwrite 'name' in LogRecord"
|
|
153
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
154
|
+
structlog.processors.StackInfoRenderer(),
|
|
155
|
+
# Include structured fields in message for visibility
|
|
156
|
+
include_structured_fields_in_message,
|
|
157
|
+
# Convert to stdlib logging kwargs and pass through to handlers
|
|
158
|
+
structlog.stdlib.render_to_log_kwargs,
|
|
159
|
+
]
|
|
160
|
+
structlog.configure(
|
|
161
|
+
processors=processors,
|
|
162
|
+
wrapper_class=structlog.stdlib.BoundLogger,
|
|
163
|
+
logger_factory=structlog.stdlib.LoggerFactory(),
|
|
164
|
+
context_class=dict,
|
|
165
|
+
cache_logger_on_first_use=True,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
return structlog.get_logger("roadmap")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def get_stack_trace(depth: int = 5) -> str:
|
|
172
|
+
"""Get a formatted stack trace for DEBUG logging.
|
|
173
|
+
|
|
174
|
+
This utility makes it easy to add rich context to DEBUG logs without
|
|
175
|
+
cluttering the normal code path. Stack traces help with troubleshooting
|
|
176
|
+
unexpected behavior and finding where operations are triggered from.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
depth: Number of stack frames to include (default 5)
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Formatted multi-line stack trace suitable for log output
|
|
183
|
+
|
|
184
|
+
Example:
|
|
185
|
+
logger = get_logger(__name__)
|
|
186
|
+
logger.debug(
|
|
187
|
+
"operation_triggered",
|
|
188
|
+
operation="sync",
|
|
189
|
+
stack=get_stack_trace()
|
|
190
|
+
)
|
|
191
|
+
"""
|
|
192
|
+
stack_lines = traceback.format_stack()[:-1] # Exclude this function
|
|
193
|
+
# Get the last 'depth' frames
|
|
194
|
+
relevant_lines = stack_lines[-depth:]
|
|
195
|
+
formatted = "\n ".join([line.strip() for line in relevant_lines])
|
|
196
|
+
return formatted
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@contextmanager
|
|
200
|
+
def log_operation_timing(operation: str, logger=None, **context):
|
|
201
|
+
"""Context manager for timing and logging operations.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
operation: Operation name
|
|
205
|
+
logger: Optional logger (uses default if None)
|
|
206
|
+
**context: Additional context to log
|
|
207
|
+
|
|
208
|
+
Usage:
|
|
209
|
+
with log_operation_timing("create_issue", issue_id="123"):
|
|
210
|
+
core.create_issue(...)
|
|
211
|
+
|
|
212
|
+
This will log:
|
|
213
|
+
- Starting {operation} with context
|
|
214
|
+
- Completed {operation} with duration and success status
|
|
215
|
+
- Failed {operation} with duration and error details (on exception)
|
|
216
|
+
"""
|
|
217
|
+
from roadmap.common.logging.loggers import get_logger
|
|
218
|
+
|
|
219
|
+
logger = logger or get_logger()
|
|
220
|
+
start_time = time.perf_counter()
|
|
221
|
+
|
|
222
|
+
logger.info(
|
|
223
|
+
"operation_started",
|
|
224
|
+
operation=operation,
|
|
225
|
+
**context,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
yield
|
|
230
|
+
duration = time.perf_counter() - start_time
|
|
231
|
+
logger.info(
|
|
232
|
+
"operation_completed",
|
|
233
|
+
operation=operation,
|
|
234
|
+
duration_ms=round(duration * 1000, 2),
|
|
235
|
+
success=True,
|
|
236
|
+
**context,
|
|
237
|
+
)
|
|
238
|
+
except Exception as e:
|
|
239
|
+
duration = time.perf_counter() - start_time
|
|
240
|
+
logger.error(
|
|
241
|
+
"operation_failed",
|
|
242
|
+
operation=operation,
|
|
243
|
+
duration_ms=round(duration * 1000, 2),
|
|
244
|
+
success=False,
|
|
245
|
+
error_type=type(e).__name__,
|
|
246
|
+
error_message=str(e),
|
|
247
|
+
**context,
|
|
248
|
+
)
|
|
249
|
+
raise
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def log_operation(operation: str, **context):
|
|
253
|
+
"""Log operation start/end with context and timing.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
operation: Operation name
|
|
257
|
+
**context: Additional context to log
|
|
258
|
+
|
|
259
|
+
Usage:
|
|
260
|
+
@log_operation("create_issue", issue_type="bug")
|
|
261
|
+
def create_issue(...):
|
|
262
|
+
...
|
|
263
|
+
"""
|
|
264
|
+
from roadmap.common.logging.loggers import get_logger
|
|
265
|
+
|
|
266
|
+
def decorator(func):
|
|
267
|
+
def wrapper(*args, **kwargs):
|
|
268
|
+
logger = get_logger()
|
|
269
|
+
start_time = time.perf_counter()
|
|
270
|
+
|
|
271
|
+
logger.info(
|
|
272
|
+
"operation_started",
|
|
273
|
+
operation=operation,
|
|
274
|
+
**context,
|
|
275
|
+
)
|
|
276
|
+
try:
|
|
277
|
+
result = func(*args, **kwargs)
|
|
278
|
+
duration = time.perf_counter() - start_time
|
|
279
|
+
logger.info(
|
|
280
|
+
"operation_completed",
|
|
281
|
+
operation=operation,
|
|
282
|
+
duration_ms=round(duration * 1000, 2),
|
|
283
|
+
success=True,
|
|
284
|
+
**context,
|
|
285
|
+
)
|
|
286
|
+
return result
|
|
287
|
+
except Exception as e:
|
|
288
|
+
duration = time.perf_counter() - start_time
|
|
289
|
+
logger.error(
|
|
290
|
+
"operation_failed",
|
|
291
|
+
operation=operation,
|
|
292
|
+
duration_ms=round(duration * 1000, 2),
|
|
293
|
+
success=False,
|
|
294
|
+
error_type=type(e).__name__,
|
|
295
|
+
error_message=str(e),
|
|
296
|
+
**context,
|
|
297
|
+
)
|
|
298
|
+
raise
|
|
299
|
+
|
|
300
|
+
return wrapper
|
|
301
|
+
|
|
302
|
+
return decorator
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def should_sample(sample_rate: float = 0.1) -> bool:
|
|
306
|
+
"""Determine if this log entry should be sampled.
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
sample_rate: Probability of sampling (0.0 to 1.0)
|
|
310
|
+
0.1 = 10% sampling, 0.01 = 1% sampling
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
True if this entry should be logged
|
|
314
|
+
|
|
315
|
+
Usage:
|
|
316
|
+
if should_sample(sample_rate=0.01): # 1% sampling
|
|
317
|
+
logger.debug("Detailed operation info", ...)
|
|
318
|
+
"""
|
|
319
|
+
return random.random() < sample_rate
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def configure_for_testing():
|
|
323
|
+
"""Configure minimal logging for tests."""
|
|
324
|
+
structlog.configure(
|
|
325
|
+
processors=[
|
|
326
|
+
# Minimal processors for testing
|
|
327
|
+
structlog.stdlib.add_log_level,
|
|
328
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
329
|
+
# Use PrintLogger for simple output
|
|
330
|
+
structlog.dev.ConsoleRenderer(),
|
|
331
|
+
],
|
|
332
|
+
wrapper_class=structlog.stdlib.BoundLogger,
|
|
333
|
+
logger_factory=structlog.PrintLoggerFactory(),
|
|
334
|
+
cache_logger_on_first_use=True,
|
|
335
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Common data models."""
|
|
2
|
+
|
|
3
|
+
from .cli_models import ( # noqa: F401
|
|
4
|
+
CleanupParams,
|
|
5
|
+
InitParams,
|
|
6
|
+
IssueCreateParams,
|
|
7
|
+
IssueGitParams,
|
|
8
|
+
IssueListParams,
|
|
9
|
+
IssueUpdateParams,
|
|
10
|
+
)
|
|
11
|
+
from .config_models import ( # noqa: F401
|
|
12
|
+
BehaviorConfig,
|
|
13
|
+
ExportConfig,
|
|
14
|
+
GitConfig,
|
|
15
|
+
GitHubConfig,
|
|
16
|
+
OutputConfig,
|
|
17
|
+
RoadmapConfig,
|
|
18
|
+
)
|
|
19
|
+
from .output_models import ( # noqa: F401
|
|
20
|
+
ColumnDef,
|
|
21
|
+
ColumnType,
|
|
22
|
+
TableData,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# CLI models
|
|
27
|
+
"CleanupParams",
|
|
28
|
+
"InitParams",
|
|
29
|
+
"IssueCreateParams",
|
|
30
|
+
"IssueGitParams",
|
|
31
|
+
"IssueListParams",
|
|
32
|
+
"IssueUpdateParams",
|
|
33
|
+
# Config models
|
|
34
|
+
"BehaviorConfig",
|
|
35
|
+
"ExportConfig",
|
|
36
|
+
"GitConfig",
|
|
37
|
+
"GitHubConfig",
|
|
38
|
+
"OutputConfig",
|
|
39
|
+
"RoadmapConfig",
|
|
40
|
+
# Output models
|
|
41
|
+
"ColumnDef",
|
|
42
|
+
"ColumnType",
|
|
43
|
+
"TableData",
|
|
44
|
+
]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Dataclasses for clean CLI parameter passing.
|
|
2
|
+
|
|
3
|
+
These models provide structured, documented parameter groups for complex CLI commands.
|
|
4
|
+
Benefits:
|
|
5
|
+
- Reduces cognitive load on function signatures
|
|
6
|
+
- Self-documenting API with field descriptions
|
|
7
|
+
- Easy to extend without breaking changes
|
|
8
|
+
- Type-safe parameter handling
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class IssueCreateParams:
|
|
16
|
+
"""Parameters for creating an issue."""
|
|
17
|
+
|
|
18
|
+
title: str
|
|
19
|
+
priority: str | None = None
|
|
20
|
+
issue_type: str | None = None
|
|
21
|
+
milestone: str | None = None
|
|
22
|
+
assignee: str | None = None
|
|
23
|
+
labels: tuple = field(default_factory=tuple)
|
|
24
|
+
estimate: float | None = None
|
|
25
|
+
depends_on: tuple = field(default_factory=tuple)
|
|
26
|
+
blocks: tuple = field(default_factory=tuple)
|
|
27
|
+
content: str | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class IssueUpdateParams:
|
|
32
|
+
"""Parameters for updating an issue."""
|
|
33
|
+
|
|
34
|
+
issue_id: str
|
|
35
|
+
title: str | None = None
|
|
36
|
+
priority: str | None = None
|
|
37
|
+
status: str | None = None
|
|
38
|
+
assignee: str | None = None
|
|
39
|
+
milestone: str | None = None
|
|
40
|
+
content: str | None = None
|
|
41
|
+
estimate: float | None = None
|
|
42
|
+
reason: str | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class IssueGitParams:
|
|
47
|
+
"""Git-related parameters for issues."""
|
|
48
|
+
|
|
49
|
+
git_branch: bool = False
|
|
50
|
+
checkout: bool = False
|
|
51
|
+
branch_name: str | None = None
|
|
52
|
+
force: bool = False
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class IssueListParams:
|
|
57
|
+
"""Parameters for listing issues."""
|
|
58
|
+
|
|
59
|
+
filter_type: str | None = None
|
|
60
|
+
milestone: str | None = None
|
|
61
|
+
backlog: bool = False
|
|
62
|
+
unassigned: bool = False
|
|
63
|
+
open: bool = False
|
|
64
|
+
blocked: bool = False
|
|
65
|
+
next_milestone: bool = False
|
|
66
|
+
assignee: str | None = None
|
|
67
|
+
my_issues: bool = False
|
|
68
|
+
status: str | None = None
|
|
69
|
+
priority: str | None = None
|
|
70
|
+
issue_type: str | None = None
|
|
71
|
+
overdue: bool = False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class InitParams:
|
|
76
|
+
"""Parameters for initialization command."""
|
|
77
|
+
|
|
78
|
+
name: str
|
|
79
|
+
project_name: str | None = None
|
|
80
|
+
description: str | None = None
|
|
81
|
+
skip_project: bool = False
|
|
82
|
+
skip_github: bool = False
|
|
83
|
+
sync_backend: str = "github"
|
|
84
|
+
github_repo: str | None = None
|
|
85
|
+
github_token: str | None = None
|
|
86
|
+
interactive: bool = True
|
|
87
|
+
yes: bool = False
|
|
88
|
+
dry_run: bool = False
|
|
89
|
+
force: bool = False
|
|
90
|
+
template: str | None = None
|
|
91
|
+
template_path: str | None = None
|
|
92
|
+
|
|
93
|
+
def __post_init__(self):
|
|
94
|
+
"""Validate parameters after initialization."""
|
|
95
|
+
from roadmap.common.constants import SyncBackend
|
|
96
|
+
|
|
97
|
+
# Validate sync_backend matches enum values
|
|
98
|
+
valid_backends = {backend.value for backend in SyncBackend}
|
|
99
|
+
if self.sync_backend not in valid_backends:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f"Invalid sync_backend '{self.sync_backend}'. "
|
|
102
|
+
f"Must be one of: {', '.join(sorted(valid_backends))}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class CleanupParams:
|
|
108
|
+
"""Parameters for cleanup command."""
|
|
109
|
+
|
|
110
|
+
keep: int = 10
|
|
111
|
+
days: int | None = None
|
|
112
|
+
dry_run: bool = False
|
|
113
|
+
force: bool = False
|
|
114
|
+
backups_only: bool = False
|
|
115
|
+
check_folders: bool = False
|
|
116
|
+
check_duplicates: bool = False
|
|
117
|
+
check_malformed: bool = False
|
|
118
|
+
verbose: bool = False
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Configuration models and schemas for roadmap CLI.
|
|
2
|
+
|
|
3
|
+
Provides Pydantic models for user-level and project-level configuration
|
|
4
|
+
with validation and sensible defaults.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OutputConfig(BaseModel):
|
|
11
|
+
"""Output formatting preferences."""
|
|
12
|
+
|
|
13
|
+
format: str = Field(
|
|
14
|
+
default="rich",
|
|
15
|
+
description="Default output format (rich, plain, json, csv, markdown, html)",
|
|
16
|
+
)
|
|
17
|
+
columns: list[str] = Field(
|
|
18
|
+
default_factory=list,
|
|
19
|
+
description="Default columns to display (empty = all)",
|
|
20
|
+
)
|
|
21
|
+
sort_by: str = Field(
|
|
22
|
+
default="",
|
|
23
|
+
description="Default sort specification (e.g., 'status:asc')",
|
|
24
|
+
)
|
|
25
|
+
model_config = ConfigDict(extra="allow")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ExportConfig(BaseModel):
|
|
29
|
+
"""Export settings and behavior."""
|
|
30
|
+
|
|
31
|
+
directory: str = Field(
|
|
32
|
+
default=".roadmap/exports",
|
|
33
|
+
description="Directory for exported files (relative to project root)",
|
|
34
|
+
)
|
|
35
|
+
format: str = Field(
|
|
36
|
+
default="json",
|
|
37
|
+
description="Default export format (json, csv, markdown)",
|
|
38
|
+
)
|
|
39
|
+
include_metadata: bool = Field(
|
|
40
|
+
default=True,
|
|
41
|
+
description="Include metadata in exports",
|
|
42
|
+
)
|
|
43
|
+
auto_gitignore: bool = Field(
|
|
44
|
+
default=True,
|
|
45
|
+
description="Automatically add exports directory to .gitignore",
|
|
46
|
+
)
|
|
47
|
+
model_config = ConfigDict(extra="allow")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BehaviorConfig(BaseModel):
|
|
51
|
+
"""Application behavior preferences."""
|
|
52
|
+
|
|
53
|
+
auto_branch_on_start: bool = Field(
|
|
54
|
+
default=False,
|
|
55
|
+
description="Automatically create git branch when starting work on issue",
|
|
56
|
+
)
|
|
57
|
+
confirm_destructive: bool = Field(
|
|
58
|
+
default=True,
|
|
59
|
+
description="Prompt before delete/archive operations",
|
|
60
|
+
)
|
|
61
|
+
show_tips: bool = Field(
|
|
62
|
+
default=True,
|
|
63
|
+
description="Show helpful tips in output",
|
|
64
|
+
)
|
|
65
|
+
include_closed_in_critical_path: bool = Field(
|
|
66
|
+
default=False,
|
|
67
|
+
description="Include closed issues in critical path analysis by default",
|
|
68
|
+
)
|
|
69
|
+
default_project_id: str | None = Field(
|
|
70
|
+
default=None,
|
|
71
|
+
description="Default project ID to use when creating milestones (auto-detected during init)",
|
|
72
|
+
)
|
|
73
|
+
model_config = ConfigDict(extra="allow")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class GitConfig(BaseModel):
|
|
77
|
+
"""Git integration settings."""
|
|
78
|
+
|
|
79
|
+
auto_commit: bool = Field(
|
|
80
|
+
default=False,
|
|
81
|
+
description="Automatically commit changes after operations",
|
|
82
|
+
)
|
|
83
|
+
commit_template: str = Field(
|
|
84
|
+
default="roadmap: {operation} {entity_id}",
|
|
85
|
+
description="Template for auto-generated commit messages",
|
|
86
|
+
)
|
|
87
|
+
model_config = ConfigDict(extra="allow")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class GitHubConfig(BaseModel):
|
|
91
|
+
"""GitHub integration settings."""
|
|
92
|
+
|
|
93
|
+
repository: str | None = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
description="GitHub repository in format owner/repo",
|
|
96
|
+
)
|
|
97
|
+
owner: str | None = Field(
|
|
98
|
+
default=None,
|
|
99
|
+
description="GitHub repository owner",
|
|
100
|
+
)
|
|
101
|
+
repo: str | None = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="GitHub repository name",
|
|
104
|
+
)
|
|
105
|
+
enabled: bool = Field(
|
|
106
|
+
default=False,
|
|
107
|
+
description="Whether GitHub integration is enabled",
|
|
108
|
+
)
|
|
109
|
+
sync_enabled: bool = Field(
|
|
110
|
+
default=False,
|
|
111
|
+
description="Whether GitHub sync is enabled",
|
|
112
|
+
)
|
|
113
|
+
sync_backend: str = Field(
|
|
114
|
+
default="github",
|
|
115
|
+
description="Sync backend to use (github or git)",
|
|
116
|
+
)
|
|
117
|
+
webhook_secret: str | None = Field(
|
|
118
|
+
default=None,
|
|
119
|
+
description="Webhook secret for GitHub events",
|
|
120
|
+
)
|
|
121
|
+
sync_settings: dict = Field(
|
|
122
|
+
default_factory=lambda: {
|
|
123
|
+
"bidirectional": True,
|
|
124
|
+
"auto_close": True,
|
|
125
|
+
"sync_labels": True,
|
|
126
|
+
"sync_milestones": True,
|
|
127
|
+
"auto_detect_from_git": True, # Auto-detect owner/repo from git remote
|
|
128
|
+
"retry_attempts": 5, # Number of retry attempts for API failures
|
|
129
|
+
"retry_delay": 1.0, # Initial delay between retries (seconds)
|
|
130
|
+
"retry_backoff": 2.0, # Exponential backoff multiplier
|
|
131
|
+
"batch_size": 50, # Number of issues to process in parallel
|
|
132
|
+
"conflict_resolution": "prompt", # Default: prompt, local, remote
|
|
133
|
+
"milestone_filter": {
|
|
134
|
+
"enabled": False, # Enable milestone filtering
|
|
135
|
+
"states": ["open", "closed"], # Filter by state
|
|
136
|
+
"names": [], # Filter by milestone name patterns
|
|
137
|
+
"since": None, # Filter by date (ISO format)
|
|
138
|
+
"until": None, # Filter by date (ISO format)
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
description="Sync settings",
|
|
142
|
+
)
|
|
143
|
+
model_config = ConfigDict(extra="allow")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class RoadmapConfig(BaseModel):
|
|
147
|
+
"""Complete roadmap configuration schema."""
|
|
148
|
+
|
|
149
|
+
output: OutputConfig = Field(default_factory=OutputConfig)
|
|
150
|
+
export: ExportConfig = Field(default_factory=ExportConfig)
|
|
151
|
+
behavior: BehaviorConfig = Field(default_factory=BehaviorConfig)
|
|
152
|
+
git: GitConfig = Field(default_factory=GitConfig)
|
|
153
|
+
github: GitHubConfig = Field(default_factory=GitHubConfig)
|
|
154
|
+
model_config = ConfigDict(extra="allow")
|
|
155
|
+
|
|
156
|
+
def merge(self, other: "RoadmapConfig") -> "RoadmapConfig":
|
|
157
|
+
"""Merge another config into this one (other takes precedence).
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
other: Config to merge (takes precedence)
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
New RoadmapConfig with merged values
|
|
164
|
+
"""
|
|
165
|
+
if other is None:
|
|
166
|
+
return self
|
|
167
|
+
|
|
168
|
+
return RoadmapConfig(
|
|
169
|
+
output=OutputConfig(
|
|
170
|
+
**{
|
|
171
|
+
**self.output.model_dump(),
|
|
172
|
+
**other.output.model_dump(exclude_unset=True),
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
export=ExportConfig(
|
|
176
|
+
**{
|
|
177
|
+
**self.export.model_dump(),
|
|
178
|
+
**other.export.model_dump(exclude_unset=True),
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
behavior=BehaviorConfig(
|
|
182
|
+
**{
|
|
183
|
+
**self.behavior.model_dump(),
|
|
184
|
+
**other.behavior.model_dump(exclude_unset=True),
|
|
185
|
+
}
|
|
186
|
+
),
|
|
187
|
+
git=GitConfig(
|
|
188
|
+
**{
|
|
189
|
+
**self.git.model_dump(),
|
|
190
|
+
**other.git.model_dump(exclude_unset=True),
|
|
191
|
+
}
|
|
192
|
+
),
|
|
193
|
+
github=GitHubConfig(
|
|
194
|
+
**{
|
|
195
|
+
**self.github.model_dump(),
|
|
196
|
+
**other.github.model_dump(exclude_unset=True),
|
|
197
|
+
}
|
|
198
|
+
),
|
|
199
|
+
)
|