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,78 @@
|
|
|
1
|
+
"""GitHub setup validation utilities."""
|
|
2
|
+
|
|
3
|
+
from roadmap.common.console import get_console
|
|
4
|
+
|
|
5
|
+
console = get_console()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GitHubSetupValidator:
|
|
9
|
+
"""Validates GitHub connectivity and permissions during setup."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, github_client): # type: ignore
|
|
12
|
+
"""Initialize GitHubSetupValidator.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
github_client: GitHub client instance.
|
|
16
|
+
"""
|
|
17
|
+
self.client = github_client
|
|
18
|
+
|
|
19
|
+
def validate_authentication(self) -> tuple[bool, str | None]:
|
|
20
|
+
"""Validate user authentication.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Tuple of (success, username or error)
|
|
24
|
+
"""
|
|
25
|
+
try:
|
|
26
|
+
user_response = self.client._make_request("GET", "/user")
|
|
27
|
+
user_info = user_response.json()
|
|
28
|
+
username = user_info.get("login", "unknown")
|
|
29
|
+
console.print(f"✅ Authenticated as: {username}")
|
|
30
|
+
return True, username
|
|
31
|
+
except Exception as e:
|
|
32
|
+
console.print(f"❌ Authentication failed: {e}", style="red")
|
|
33
|
+
return False, str(e)
|
|
34
|
+
|
|
35
|
+
def validate_repository_access(self, github_repo: str) -> tuple[bool, dict | None]:
|
|
36
|
+
"""Validate repository access and permissions.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Tuple of (success, repo_info or error_message)
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
owner, repo = github_repo.split("/")
|
|
43
|
+
self.client.set_repository(owner, repo)
|
|
44
|
+
repo_info = self.client.test_repository_access()
|
|
45
|
+
|
|
46
|
+
repo_name = repo_info.get("full_name", github_repo)
|
|
47
|
+
console.print(f"✅ Repository access: {repo_name}")
|
|
48
|
+
|
|
49
|
+
# Check permissions
|
|
50
|
+
permissions = repo_info.get("permissions", {})
|
|
51
|
+
if permissions.get("admin") or permissions.get("push"):
|
|
52
|
+
console.print("✅ Write access: Available")
|
|
53
|
+
elif permissions.get("pull"):
|
|
54
|
+
console.print(
|
|
55
|
+
"⚠️ Read-only access: Limited sync capabilities", style="yellow"
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
console.print("❌ No repository access detected", style="red")
|
|
59
|
+
|
|
60
|
+
return True, repo_info
|
|
61
|
+
except Exception as e:
|
|
62
|
+
console.print(f"⚠️ Repository validation warning: {e}", style="yellow")
|
|
63
|
+
return False, {"error": str(e)}
|
|
64
|
+
|
|
65
|
+
def test_api_access(self, github_repo: str) -> bool:
|
|
66
|
+
"""Test basic API calls."""
|
|
67
|
+
try:
|
|
68
|
+
issues_response = self.client._make_request(
|
|
69
|
+
"GET",
|
|
70
|
+
f"/repos/{github_repo}/issues",
|
|
71
|
+
params={"state": "open", "per_page": 1},
|
|
72
|
+
)
|
|
73
|
+
issues = issues_response.json()
|
|
74
|
+
console.print(f"✅ API test successful ({len(issues)} issue(s) found)")
|
|
75
|
+
return True
|
|
76
|
+
except Exception as e:
|
|
77
|
+
console.print(f"⚠️ API test warning: {e}", style="yellow")
|
|
78
|
+
return False
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Structured logging for roadmap CLI application."""
|
|
2
|
+
|
|
3
|
+
import structlog # noqa: F401
|
|
4
|
+
|
|
5
|
+
from roadmap.common.logging.correlation import (
|
|
6
|
+
add_correlation_id,
|
|
7
|
+
clear_correlation_id,
|
|
8
|
+
correlation_id_var,
|
|
9
|
+
get_correlation_id,
|
|
10
|
+
set_correlation_id,
|
|
11
|
+
)
|
|
12
|
+
from roadmap.common.logging.decorators import (
|
|
13
|
+
get_current_user,
|
|
14
|
+
log_audit_event,
|
|
15
|
+
log_command,
|
|
16
|
+
log_operation_duration,
|
|
17
|
+
verbose_output,
|
|
18
|
+
)
|
|
19
|
+
from roadmap.common.logging.error_logging import (
|
|
20
|
+
ErrorClassification,
|
|
21
|
+
classify_error,
|
|
22
|
+
is_error_recoverable,
|
|
23
|
+
log_database_error,
|
|
24
|
+
log_error_with_context,
|
|
25
|
+
log_external_service_error,
|
|
26
|
+
log_validation_error,
|
|
27
|
+
suggest_recovery,
|
|
28
|
+
)
|
|
29
|
+
from roadmap.common.logging.formatters import (
|
|
30
|
+
SENSITIVE_KEYS,
|
|
31
|
+
StructuredFormatter,
|
|
32
|
+
include_structured_fields_in_message,
|
|
33
|
+
scrub_sensitive_data,
|
|
34
|
+
)
|
|
35
|
+
from roadmap.common.logging.loggers import (
|
|
36
|
+
get_application_logger,
|
|
37
|
+
get_domain_logger,
|
|
38
|
+
get_infrastructure_logger,
|
|
39
|
+
get_logger,
|
|
40
|
+
get_presentation_logger,
|
|
41
|
+
get_security_logger,
|
|
42
|
+
)
|
|
43
|
+
from roadmap.common.logging.performance_tracking import (
|
|
44
|
+
OperationTimer,
|
|
45
|
+
track_database_operation,
|
|
46
|
+
track_file_operation,
|
|
47
|
+
track_operation_time,
|
|
48
|
+
track_sync_operation,
|
|
49
|
+
)
|
|
50
|
+
from roadmap.common.logging.utils import (
|
|
51
|
+
configure_for_testing,
|
|
52
|
+
get_stack_trace,
|
|
53
|
+
log_operation,
|
|
54
|
+
log_operation_timing,
|
|
55
|
+
setup_logging,
|
|
56
|
+
should_sample,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
# Formatters and scrubbing
|
|
61
|
+
"StructuredFormatter",
|
|
62
|
+
"scrub_sensitive_data",
|
|
63
|
+
"include_structured_fields_in_message",
|
|
64
|
+
"SENSITIVE_KEYS",
|
|
65
|
+
# Correlation ID
|
|
66
|
+
"correlation_id_var",
|
|
67
|
+
"set_correlation_id",
|
|
68
|
+
"get_correlation_id",
|
|
69
|
+
"clear_correlation_id",
|
|
70
|
+
"add_correlation_id",
|
|
71
|
+
# Logger factories
|
|
72
|
+
"get_logger",
|
|
73
|
+
"get_domain_logger",
|
|
74
|
+
"get_application_logger",
|
|
75
|
+
"get_infrastructure_logger",
|
|
76
|
+
"get_presentation_logger",
|
|
77
|
+
"get_security_logger",
|
|
78
|
+
# Setup and utilities
|
|
79
|
+
"setup_logging",
|
|
80
|
+
"get_stack_trace",
|
|
81
|
+
"log_operation_timing",
|
|
82
|
+
"log_operation",
|
|
83
|
+
"should_sample",
|
|
84
|
+
"configure_for_testing",
|
|
85
|
+
# Decorators
|
|
86
|
+
"log_command",
|
|
87
|
+
"verbose_output",
|
|
88
|
+
"get_current_user",
|
|
89
|
+
"log_audit_event",
|
|
90
|
+
"log_operation_duration",
|
|
91
|
+
# Error logging
|
|
92
|
+
"ErrorClassification",
|
|
93
|
+
"classify_error",
|
|
94
|
+
"is_error_recoverable",
|
|
95
|
+
"log_database_error",
|
|
96
|
+
"log_error_with_context",
|
|
97
|
+
"log_external_service_error",
|
|
98
|
+
"log_validation_error",
|
|
99
|
+
"suggest_recovery",
|
|
100
|
+
# Performance tracking
|
|
101
|
+
"OperationTimer",
|
|
102
|
+
"track_database_operation",
|
|
103
|
+
"track_file_operation",
|
|
104
|
+
"track_operation_time",
|
|
105
|
+
"track_sync_operation",
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
# Initialize logging at module load time
|
|
109
|
+
# This is the single source of truth for production logging configuration
|
|
110
|
+
setup_logging(log_level="INFO", debug_mode=False, log_to_file=True)
|
|
111
|
+
|
|
112
|
+
# Get default logger instance
|
|
113
|
+
logger = get_logger("roadmap")
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Correlation ID tracking for distributed tracing across operations."""
|
|
2
|
+
|
|
3
|
+
import contextvars
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
# Context variable for correlation ID tracking across async operations
|
|
7
|
+
correlation_id_var: contextvars.ContextVar[str | None] = contextvars.ContextVar(
|
|
8
|
+
"correlation_id", default=None
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def add_correlation_id(logger, _method_name, event_dict):
|
|
13
|
+
"""Structlog processor to add correlation ID to all log entries."""
|
|
14
|
+
cid = correlation_id_var.get()
|
|
15
|
+
if cid:
|
|
16
|
+
event_dict["correlation_id"] = cid
|
|
17
|
+
return event_dict
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def set_correlation_id(correlation_id: str | None = None) -> str:
|
|
21
|
+
"""Set correlation ID for current context.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
correlation_id: Optional correlation ID (generates UUID if None)
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The correlation ID that was set
|
|
28
|
+
"""
|
|
29
|
+
cid = correlation_id or str(uuid.uuid4())
|
|
30
|
+
correlation_id_var.set(cid)
|
|
31
|
+
return cid
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_correlation_id() -> str | None:
|
|
35
|
+
"""Get correlation ID from current context.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Current correlation ID or None
|
|
39
|
+
"""
|
|
40
|
+
return correlation_id_var.get()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def clear_correlation_id() -> None:
|
|
44
|
+
"""Clear correlation ID from current context."""
|
|
45
|
+
correlation_id_var.set(None)
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""CLI command logging decorators for audit trail and observability.
|
|
2
|
+
|
|
3
|
+
Provides decorators to automatically log CLI command execution, timing,
|
|
4
|
+
user actions, and outcomes for comprehensive audit trail and debugging.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import click # type: ignore[import-not-found]
|
|
15
|
+
|
|
16
|
+
from roadmap.common.logging.loggers import get_logger
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_current_user() -> str:
|
|
22
|
+
"""Get current user from environment."""
|
|
23
|
+
user = os.environ.get("USER") or os.environ.get("USERNAME")
|
|
24
|
+
return user if user else "unknown"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def log_command(
|
|
28
|
+
command_name: str,
|
|
29
|
+
entity_type: str | None = None,
|
|
30
|
+
track_duration: bool = True,
|
|
31
|
+
log_args: bool = False,
|
|
32
|
+
) -> Callable:
|
|
33
|
+
"""Log CLI command execution with audit trail.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
command_name: Name of the command (e.g., "issue_create")
|
|
37
|
+
entity_type: Type of entity affected (e.g., "issue", "milestone")
|
|
38
|
+
track_duration: Whether to track and log command execution time
|
|
39
|
+
log_args: Whether to log command arguments (use with caution for sensitive data)
|
|
40
|
+
|
|
41
|
+
Example:
|
|
42
|
+
@log_command("issue_create", entity_type="issue")
|
|
43
|
+
@click.command()
|
|
44
|
+
def create_issue(title, priority):
|
|
45
|
+
...
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def decorator(func: Callable) -> Callable:
|
|
49
|
+
@functools.wraps(func)
|
|
50
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
51
|
+
user = get_current_user()
|
|
52
|
+
start_time = time.time()
|
|
53
|
+
|
|
54
|
+
# Log command initiation
|
|
55
|
+
logger.info(
|
|
56
|
+
"command_initiated",
|
|
57
|
+
command_name=command_name,
|
|
58
|
+
user=user,
|
|
59
|
+
entity_type=entity_type,
|
|
60
|
+
args_logged=log_args,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
if log_args:
|
|
64
|
+
logger.debug(
|
|
65
|
+
"command_received_with_arguments",
|
|
66
|
+
command=command_name,
|
|
67
|
+
kwargs=kwargs,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
result = func(*args, **kwargs)
|
|
72
|
+
|
|
73
|
+
# Log successful completion
|
|
74
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
75
|
+
logger.info(
|
|
76
|
+
"command_completed",
|
|
77
|
+
command_name=command_name,
|
|
78
|
+
user=user,
|
|
79
|
+
entity_type=entity_type,
|
|
80
|
+
duration_ms=duration_ms if track_duration else None,
|
|
81
|
+
status="success",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
except click.Abort:
|
|
87
|
+
# User cancelled (Ctrl+C or declined prompt)
|
|
88
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
89
|
+
logger.info(
|
|
90
|
+
"command_cancelled",
|
|
91
|
+
command_name=command_name,
|
|
92
|
+
user=user,
|
|
93
|
+
entity_type=entity_type,
|
|
94
|
+
duration_ms=duration_ms if track_duration else None,
|
|
95
|
+
)
|
|
96
|
+
raise
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
# Log error with context
|
|
100
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
101
|
+
logger.error(
|
|
102
|
+
"command_failed",
|
|
103
|
+
command_name=command_name,
|
|
104
|
+
user=user,
|
|
105
|
+
entity_type=entity_type,
|
|
106
|
+
error_type=type(e).__name__,
|
|
107
|
+
error_message=str(e),
|
|
108
|
+
duration_ms=duration_ms if track_duration else None,
|
|
109
|
+
is_user_error=isinstance(e, click.BadParameter | ValueError),
|
|
110
|
+
)
|
|
111
|
+
raise
|
|
112
|
+
|
|
113
|
+
return wrapper
|
|
114
|
+
|
|
115
|
+
return decorator
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def verbose_output(func: Callable) -> Callable:
|
|
119
|
+
"""Add --verbose flag for controlling debug output visibility.
|
|
120
|
+
|
|
121
|
+
Suppresses debug logs by default for clean output.
|
|
122
|
+
When --verbose/-v is passed, all debug information is shown.
|
|
123
|
+
|
|
124
|
+
Works by disabling the console handler unless verbose is True.
|
|
125
|
+
|
|
126
|
+
Requires the decorated function to have a 'verbose' parameter.
|
|
127
|
+
Works with Click commands using @click.pass_context.
|
|
128
|
+
|
|
129
|
+
The decorator should be placed BEFORE @click.pass_context in the decorator stack.
|
|
130
|
+
|
|
131
|
+
Example:
|
|
132
|
+
@verbose_output
|
|
133
|
+
@click.pass_context
|
|
134
|
+
@click.command()
|
|
135
|
+
@click.option("--verbose", "-v", is_flag=True, ...)
|
|
136
|
+
def my_command(ctx, verbose):
|
|
137
|
+
# debug logs output suppressed unless verbose=True
|
|
138
|
+
...
|
|
139
|
+
"""
|
|
140
|
+
import logging
|
|
141
|
+
|
|
142
|
+
@functools.wraps(func)
|
|
143
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
144
|
+
# Extract verbose flag from kwargs (it's passed as a Click option)
|
|
145
|
+
# Click passes options as keyword arguments after ctx
|
|
146
|
+
verbose = kwargs.get("verbose", False)
|
|
147
|
+
|
|
148
|
+
# Adjust console logging based on verbose flag
|
|
149
|
+
# Handler management requires standard logging API
|
|
150
|
+
# nosemgrep
|
|
151
|
+
roadmap_logger = logging.getLogger("roadmap")
|
|
152
|
+
original_levels = {}
|
|
153
|
+
|
|
154
|
+
# Find and adjust the console handler
|
|
155
|
+
for handler in roadmap_logger.handlers[:]:
|
|
156
|
+
if (
|
|
157
|
+
isinstance(handler, logging.StreamHandler)
|
|
158
|
+
and handler.stream == sys.stderr
|
|
159
|
+
):
|
|
160
|
+
# Store original level for restoration later
|
|
161
|
+
original_levels[id(handler)] = handler.level
|
|
162
|
+
|
|
163
|
+
if verbose:
|
|
164
|
+
# With --verbose, show INFO and above
|
|
165
|
+
handler.setLevel(logging.INFO)
|
|
166
|
+
else:
|
|
167
|
+
# Without --verbose, suppress to CRITICAL (effectively disable console output)
|
|
168
|
+
handler.setLevel(logging.CRITICAL)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
return func(*args, **kwargs)
|
|
172
|
+
finally:
|
|
173
|
+
# Restore handler levels
|
|
174
|
+
for handler in roadmap_logger.handlers[:]:
|
|
175
|
+
if id(handler) in original_levels:
|
|
176
|
+
handler.setLevel(original_levels[id(handler)])
|
|
177
|
+
|
|
178
|
+
return wrapper
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def log_audit_event(
|
|
182
|
+
action: str,
|
|
183
|
+
entity_type: str,
|
|
184
|
+
entity_id: str | None = None,
|
|
185
|
+
before: dict | None = None,
|
|
186
|
+
after: dict | None = None,
|
|
187
|
+
reason: str | None = None,
|
|
188
|
+
) -> None:
|
|
189
|
+
"""Log an auditable user action with before/after state.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
action: Action performed (create, update, delete, archive, restore)
|
|
193
|
+
entity_type: Type of entity (issue, milestone, project)
|
|
194
|
+
entity_id: ID of the entity
|
|
195
|
+
before: Entity state before the action
|
|
196
|
+
after: Entity state after the action
|
|
197
|
+
reason: Reason for the action (if applicable)
|
|
198
|
+
"""
|
|
199
|
+
user = get_current_user()
|
|
200
|
+
logger.info(
|
|
201
|
+
"audit_event",
|
|
202
|
+
action=action,
|
|
203
|
+
entity_type=entity_type,
|
|
204
|
+
entity_id=entity_id,
|
|
205
|
+
user=user,
|
|
206
|
+
before=before,
|
|
207
|
+
after=after,
|
|
208
|
+
reason=reason,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def log_operation_duration(
|
|
213
|
+
operation_name: str,
|
|
214
|
+
warn_threshold_ms: int = 5000,
|
|
215
|
+
) -> Callable:
|
|
216
|
+
"""Log operation duration and identify slow operations.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
operation_name: Name of the operation
|
|
220
|
+
warn_threshold_ms: Threshold in milliseconds to warn about slow ops
|
|
221
|
+
|
|
222
|
+
Example:
|
|
223
|
+
@log_operation_duration("sync_issues", warn_threshold_ms=5000)
|
|
224
|
+
def sync_to_github():
|
|
225
|
+
...
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def decorator(func: Callable) -> Callable:
|
|
229
|
+
@functools.wraps(func)
|
|
230
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
231
|
+
start_time = time.time()
|
|
232
|
+
|
|
233
|
+
try:
|
|
234
|
+
result = func(*args, **kwargs)
|
|
235
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
236
|
+
|
|
237
|
+
# Log at appropriate level based on duration
|
|
238
|
+
if duration_ms > warn_threshold_ms:
|
|
239
|
+
logger.warning(
|
|
240
|
+
"operation_slow",
|
|
241
|
+
operation_name=operation_name,
|
|
242
|
+
duration_ms=duration_ms,
|
|
243
|
+
threshold_ms=warn_threshold_ms,
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
logger.debug(
|
|
247
|
+
"operation_completed",
|
|
248
|
+
operation_name=operation_name,
|
|
249
|
+
duration_ms=duration_ms,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
return result
|
|
253
|
+
|
|
254
|
+
except Exception as e:
|
|
255
|
+
duration_ms = (time.time() - start_time) * 1000
|
|
256
|
+
logger.error(
|
|
257
|
+
"operation_failed",
|
|
258
|
+
operation_name=operation_name,
|
|
259
|
+
error_type=type(e).__name__,
|
|
260
|
+
error_message=str(e),
|
|
261
|
+
duration_ms=duration_ms,
|
|
262
|
+
)
|
|
263
|
+
raise
|
|
264
|
+
|
|
265
|
+
return wrapper
|
|
266
|
+
|
|
267
|
+
return decorator
|