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,381 @@
|
|
|
1
|
+
"""CLI helpers for structured output formatting and filtering.
|
|
2
|
+
|
|
3
|
+
Provides decorators, utilities, and helpers for commands to support
|
|
4
|
+
--format, --columns, and --sort-by flags for consistent user experience.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from functools import wraps
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
from roadmap.common.models import ColumnType, TableData
|
|
15
|
+
from roadmap.common.output_formatter import OutputFormatter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OutputFormatHandler:
|
|
19
|
+
"""Handles output format selection and rendering.
|
|
20
|
+
|
|
21
|
+
Supports: rich (default), plain-text, json, csv, markdown
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
SUPPORTED_FORMATS = {
|
|
25
|
+
"rich": "Interactive terminal output with colors",
|
|
26
|
+
"plain": "POSIX-safe ASCII tables",
|
|
27
|
+
"json": "Machine-readable JSON format",
|
|
28
|
+
"csv": "Comma-separated values for analysis",
|
|
29
|
+
"markdown": "Markdown tables for documentation",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def render(table_data: TableData, format_name: str = "rich") -> str | Table:
|
|
34
|
+
"""Render table data in specified format.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
table_data: TableData object to render.
|
|
38
|
+
format_name: Output format (rich, plain, json, csv, markdown).
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Formatted string output or Rich Table object for rich format.
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
ValueError: If format_name is not supported.
|
|
45
|
+
"""
|
|
46
|
+
if format_name not in OutputFormatHandler.SUPPORTED_FORMATS:
|
|
47
|
+
raise ValueError(f"Unknown format: {format_name}")
|
|
48
|
+
|
|
49
|
+
formatter = OutputFormatter(table_data)
|
|
50
|
+
|
|
51
|
+
if format_name == "plain":
|
|
52
|
+
return formatter.to_plain_text()
|
|
53
|
+
elif format_name == "json":
|
|
54
|
+
return formatter.to_json()
|
|
55
|
+
elif format_name == "csv":
|
|
56
|
+
return formatter.to_csv()
|
|
57
|
+
elif format_name == "markdown":
|
|
58
|
+
return formatter.to_markdown()
|
|
59
|
+
else: # rich (default)
|
|
60
|
+
# Rich returns a Table object, needs console.print()
|
|
61
|
+
return formatter.to_rich()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ColumnSelector:
|
|
65
|
+
"""Smart column selection utility.
|
|
66
|
+
|
|
67
|
+
Handles --columns flag parsing and validation:
|
|
68
|
+
- Comma-separated column names
|
|
69
|
+
- Validates columns exist
|
|
70
|
+
- Respects column order
|
|
71
|
+
- Case-insensitive matching
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def parse(
|
|
76
|
+
columns_str: str | None, available_columns: list[str]
|
|
77
|
+
) -> list[str] | None:
|
|
78
|
+
"""Parse --columns flag value.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
columns_str: Raw --columns value (comma-separated).
|
|
82
|
+
available_columns: List of valid column names.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Normalized list of column names or None if not specified.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
click.BadParameter: If column name doesn't exist.
|
|
89
|
+
"""
|
|
90
|
+
if not columns_str:
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
# Parse comma-separated list
|
|
94
|
+
requested = [col.strip() for col in columns_str.split(",")]
|
|
95
|
+
|
|
96
|
+
# Validate all columns exist (case-insensitive)
|
|
97
|
+
column_map = {col.lower(): col for col in available_columns}
|
|
98
|
+
normalized = []
|
|
99
|
+
|
|
100
|
+
for col in requested:
|
|
101
|
+
col_lower = col.lower()
|
|
102
|
+
if col_lower not in column_map:
|
|
103
|
+
available_str = ", ".join(available_columns)
|
|
104
|
+
raise click.BadParameter(
|
|
105
|
+
f"Unknown column: {col}. Available columns: {available_str}"
|
|
106
|
+
)
|
|
107
|
+
normalized.append(column_map[col_lower])
|
|
108
|
+
|
|
109
|
+
return normalized
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def get_help_text(available_columns: list[str]) -> str:
|
|
113
|
+
"""Get help text for --columns flag."""
|
|
114
|
+
cols = ", ".join(available_columns)
|
|
115
|
+
return f"Columns to display (comma-separated). Available: {cols}"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class SortSpecParser:
|
|
119
|
+
"""Parse and validate --sort-by flag.
|
|
120
|
+
|
|
121
|
+
Handles:
|
|
122
|
+
- Single column: --sort-by name
|
|
123
|
+
- Multiple columns: --sort-by name,age
|
|
124
|
+
- Direction: --sort-by name:asc,age:desc
|
|
125
|
+
- Validates columns exist
|
|
126
|
+
- Respects direction (asc/desc, default asc)
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def parse(sort_str: str | None, available_columns: list[str]) -> list[tuple] | None:
|
|
131
|
+
"""Parse --sort-by flag value.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
sort_str: Raw --sort-by value (format: col1:asc,col2:desc).
|
|
135
|
+
available_columns: List of valid column names.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
List of (column_name, direction) tuples or None if not specified.
|
|
139
|
+
|
|
140
|
+
Raises:
|
|
141
|
+
click.BadParameter: If column name doesn't exist or direction invalid.
|
|
142
|
+
"""
|
|
143
|
+
if not sort_str:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
# Parse comma-separated sort specs
|
|
147
|
+
specs = []
|
|
148
|
+
column_map = {col.lower(): col for col in available_columns}
|
|
149
|
+
|
|
150
|
+
for item in sort_str.split(","):
|
|
151
|
+
item = item.strip()
|
|
152
|
+
|
|
153
|
+
# Split on colon (column:direction)
|
|
154
|
+
if ":" in item:
|
|
155
|
+
col_name, direction = item.split(":", 1)
|
|
156
|
+
col_name = col_name.strip()
|
|
157
|
+
direction = direction.strip().lower()
|
|
158
|
+
else:
|
|
159
|
+
col_name = item
|
|
160
|
+
direction = "asc"
|
|
161
|
+
|
|
162
|
+
# Validate column exists
|
|
163
|
+
col_lower = col_name.lower()
|
|
164
|
+
if col_lower not in column_map:
|
|
165
|
+
available_str = ", ".join(available_columns)
|
|
166
|
+
raise click.BadParameter(
|
|
167
|
+
f"Unknown sort column: {col_name}. Available: {available_str}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Validate direction
|
|
171
|
+
if direction not in ("asc", "desc"):
|
|
172
|
+
raise click.BadParameter(
|
|
173
|
+
f"Invalid sort direction '{direction}' for column {col_name}. "
|
|
174
|
+
"Use 'asc' or 'desc'."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
specs.append((column_map[col_lower], direction))
|
|
178
|
+
|
|
179
|
+
return specs if specs else None
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
def get_help_text() -> str:
|
|
183
|
+
"""Get help text for --sort-by flag."""
|
|
184
|
+
return (
|
|
185
|
+
"Sort by columns (format: col1:asc,col2:desc). "
|
|
186
|
+
"Direction defaults to 'asc' if omitted."
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class FilterSpec:
|
|
191
|
+
"""Represents a single filter specification.
|
|
192
|
+
|
|
193
|
+
Used internally for parsed --filter arguments.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
def __init__(self, column: str, operator: str, value: Any):
|
|
197
|
+
"""Initialize filter spec.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
column: Column name to filter.
|
|
201
|
+
operator: Comparison operator (=, !=, <, >, <=, >=, ~).
|
|
202
|
+
value: Filter value (type-aware parsing).
|
|
203
|
+
"""
|
|
204
|
+
self.column = column
|
|
205
|
+
self.operator = operator
|
|
206
|
+
self.value = value
|
|
207
|
+
|
|
208
|
+
def __repr__(self):
|
|
209
|
+
"""Return string representation of FilterSpec."""
|
|
210
|
+
return f"FilterSpec({self.column}{self.operator}{self.value})"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class FilterSpecParser:
|
|
214
|
+
"""Parse and validate --filter flags.
|
|
215
|
+
|
|
216
|
+
Handles:
|
|
217
|
+
- Simple equality: --filter status=open
|
|
218
|
+
- Negation: --filter status!=closed
|
|
219
|
+
- Comparisons: --filter count>=5
|
|
220
|
+
- Regex: --filter title~bug
|
|
221
|
+
- Case-insensitive matching
|
|
222
|
+
- Type-aware value conversion (string, int, bool)
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
# Order matters: longer operators first to avoid partial matches
|
|
226
|
+
VALID_OPERATORS = ["!=", "<=", ">=", "=", "~", "<", ">"]
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def parse(
|
|
230
|
+
filter_str: str | None, column_types: dict[str, ColumnType]
|
|
231
|
+
) -> list[FilterSpec] | None:
|
|
232
|
+
"""Parse --filter flag value(s).
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
filter_str: Raw --filter value(s).
|
|
236
|
+
column_types: Dict mapping column name to ColumnType.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
List of FilterSpec objects or None if not specified.
|
|
240
|
+
|
|
241
|
+
Raises:
|
|
242
|
+
click.BadParameter: If column or operator invalid.
|
|
243
|
+
"""
|
|
244
|
+
if not filter_str:
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
specs = []
|
|
248
|
+
column_map = {col.lower(): col for col in column_types.keys()}
|
|
249
|
+
|
|
250
|
+
# Parse space-separated filter specs
|
|
251
|
+
for item in filter_str.split(","):
|
|
252
|
+
item = item.strip()
|
|
253
|
+
if not item:
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
# Find operator
|
|
257
|
+
operator = None
|
|
258
|
+
for op in FilterSpecParser.VALID_OPERATORS:
|
|
259
|
+
if op in item:
|
|
260
|
+
operator = op
|
|
261
|
+
break
|
|
262
|
+
|
|
263
|
+
if not operator:
|
|
264
|
+
raise click.BadParameter(
|
|
265
|
+
f"Invalid filter syntax: {item}. Use format: column=value"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
col_name, value_str = item.split(operator, 1)
|
|
269
|
+
col_name = col_name.strip()
|
|
270
|
+
value_str = value_str.strip()
|
|
271
|
+
|
|
272
|
+
# Validate column exists
|
|
273
|
+
col_lower = col_name.lower()
|
|
274
|
+
if col_lower not in column_map:
|
|
275
|
+
available = ", ".join(column_types.keys())
|
|
276
|
+
raise click.BadParameter(
|
|
277
|
+
f"Unknown filter column: {col_name}. Available: {available}"
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
col_name = column_map[col_lower]
|
|
281
|
+
col_type = column_types[col_name]
|
|
282
|
+
|
|
283
|
+
# Parse value with type awareness
|
|
284
|
+
value = FilterSpecParser._parse_value(value_str, col_type)
|
|
285
|
+
|
|
286
|
+
specs.append(FilterSpec(col_name, operator, value))
|
|
287
|
+
|
|
288
|
+
return specs if specs else None
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def _parse_value(value_str: str, col_type: ColumnType) -> Any:
|
|
292
|
+
"""Parse filter value with type awareness."""
|
|
293
|
+
if col_type == ColumnType.INTEGER:
|
|
294
|
+
try:
|
|
295
|
+
return int(value_str)
|
|
296
|
+
except ValueError as err:
|
|
297
|
+
raise click.BadParameter(
|
|
298
|
+
f"Expected integer value, got: {value_str}"
|
|
299
|
+
) from err
|
|
300
|
+
|
|
301
|
+
elif col_type == ColumnType.FLOAT:
|
|
302
|
+
try:
|
|
303
|
+
return float(value_str)
|
|
304
|
+
except ValueError as err:
|
|
305
|
+
raise click.BadParameter(
|
|
306
|
+
f"Expected float value, got: {value_str}"
|
|
307
|
+
) from err
|
|
308
|
+
|
|
309
|
+
elif col_type == ColumnType.BOOLEAN:
|
|
310
|
+
if value_str.lower() in ("true", "yes", "1", "on"):
|
|
311
|
+
return True
|
|
312
|
+
elif value_str.lower() in ("false", "no", "0", "off"):
|
|
313
|
+
return False
|
|
314
|
+
else:
|
|
315
|
+
raise click.BadParameter(
|
|
316
|
+
f"Expected boolean value, got: {value_str}. Use: true/false, yes/no"
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
else: # STRING, DATE, DATETIME, ENUM
|
|
320
|
+
return value_str
|
|
321
|
+
|
|
322
|
+
@staticmethod
|
|
323
|
+
def get_help_text() -> str:
|
|
324
|
+
"""Get help text for --filter flag."""
|
|
325
|
+
return (
|
|
326
|
+
"Filter rows (format: column=value). "
|
|
327
|
+
"Operators: = != < > <= >= ~ (regex). "
|
|
328
|
+
"Example: --filter status=todo --filter priority=high"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def format_output(
|
|
333
|
+
format_choice: str = "rich", columns: list[str] | None = None
|
|
334
|
+
) -> Callable:
|
|
335
|
+
"""Handle output formatting for command results.
|
|
336
|
+
|
|
337
|
+
Wraps command functions to:
|
|
338
|
+
1. Convert returned TableData to formatted output
|
|
339
|
+
2. Apply column selection
|
|
340
|
+
3. Render in specified format
|
|
341
|
+
|
|
342
|
+
Usage:
|
|
343
|
+
@click.command()
|
|
344
|
+
@click.option("--format", type=click.Choice(["rich", "plain", "json", "csv"]))
|
|
345
|
+
@click.option("--columns", help="Columns to display")
|
|
346
|
+
@format_output()
|
|
347
|
+
def my_command(format, columns, ...):
|
|
348
|
+
return TableData(...)
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
format_choice: Output format (rich, plain, json, csv, markdown).
|
|
352
|
+
columns: Column names to select (None = all).
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Decorator function.
|
|
356
|
+
"""
|
|
357
|
+
|
|
358
|
+
def decorator(func: Callable) -> Callable:
|
|
359
|
+
@wraps(func)
|
|
360
|
+
def wrapper(*args, **kwargs):
|
|
361
|
+
# Call original function
|
|
362
|
+
result = func(*args, **kwargs)
|
|
363
|
+
|
|
364
|
+
# If result is TableData, format it
|
|
365
|
+
if isinstance(result, TableData):
|
|
366
|
+
# Apply column selection if specified
|
|
367
|
+
if columns:
|
|
368
|
+
result = result.select_columns(columns)
|
|
369
|
+
|
|
370
|
+
# Render in requested format
|
|
371
|
+
if format_choice == "rich":
|
|
372
|
+
# For rich, return Table object for console.print()
|
|
373
|
+
return OutputFormatter(result).to_rich()
|
|
374
|
+
else:
|
|
375
|
+
return OutputFormatHandler.render(result, format_choice)
|
|
376
|
+
|
|
377
|
+
return result
|
|
378
|
+
|
|
379
|
+
return wrapper
|
|
380
|
+
|
|
381
|
+
return decorator
|