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.
Files changed (521) hide show
  1. roadmap/__init__.py +27 -0
  2. roadmap/adapters/__init__.py +1 -0
  3. roadmap/adapters/base_paginated_adapter.py +117 -0
  4. roadmap/adapters/cli/__init__.py +249 -0
  5. roadmap/adapters/cli/analysis/__init__.py +5 -0
  6. roadmap/adapters/cli/analysis/commands.py +370 -0
  7. roadmap/adapters/cli/analysis/presenter.py +125 -0
  8. roadmap/adapters/cli/archive_operations.py +86 -0
  9. roadmap/adapters/cli/cli_command_helpers.py +109 -0
  10. roadmap/adapters/cli/cli_confirmations.py +74 -0
  11. roadmap/adapters/cli/cli_error_handlers.py +146 -0
  12. roadmap/adapters/cli/cli_validators.py +39 -0
  13. roadmap/adapters/cli/commands/sync_status.py +308 -0
  14. roadmap/adapters/cli/comment/__init__.py +5 -0
  15. roadmap/adapters/cli/comment/commands.py +106 -0
  16. roadmap/adapters/cli/config/__init__.py +5 -0
  17. roadmap/adapters/cli/config/commands.py +198 -0
  18. roadmap/adapters/cli/console_exports.py +10 -0
  19. roadmap/adapters/cli/core.py +26 -0
  20. roadmap/adapters/cli/crud/__init__.py +47 -0
  21. roadmap/adapters/cli/crud/base_archive.py +208 -0
  22. roadmap/adapters/cli/crud/base_create.py +154 -0
  23. roadmap/adapters/cli/crud/base_delete.py +155 -0
  24. roadmap/adapters/cli/crud/base_restore.py +283 -0
  25. roadmap/adapters/cli/crud/base_update.py +193 -0
  26. roadmap/adapters/cli/crud/crud_helpers.py +206 -0
  27. roadmap/adapters/cli/crud/crud_utils.py +152 -0
  28. roadmap/adapters/cli/crud/entity_builders.py +374 -0
  29. roadmap/adapters/cli/data/__init__.py +8 -0
  30. roadmap/adapters/cli/data/commands.py +149 -0
  31. roadmap/adapters/cli/decorators.py +208 -0
  32. roadmap/adapters/cli/dtos/__init__.py +155 -0
  33. roadmap/adapters/cli/exception_handler.py +105 -0
  34. roadmap/adapters/cli/git/__init__.py +8 -0
  35. roadmap/adapters/cli/git/commands.py +475 -0
  36. roadmap/adapters/cli/git/handlers/__init__.py +1 -0
  37. roadmap/adapters/cli/git/handlers/git_authentication_handler.py +124 -0
  38. roadmap/adapters/cli/git/handlers/git_branch_handler.py +238 -0
  39. roadmap/adapters/cli/git/handlers/git_connectivity_handler.py +122 -0
  40. roadmap/adapters/cli/git/handlers/git_hooks_handler.py +105 -0
  41. roadmap/adapters/cli/git/hooks_config.py +327 -0
  42. roadmap/adapters/cli/git/status_display.py +158 -0
  43. roadmap/adapters/cli/health/__init__.py +8 -0
  44. roadmap/adapters/cli/health/db_integrity.py +204 -0
  45. roadmap/adapters/cli/health/enhancer.py +227 -0
  46. roadmap/adapters/cli/health/fixer.py +295 -0
  47. roadmap/adapters/cli/health/fixers/__init__.py +10 -0
  48. roadmap/adapters/cli/health/fixers/corrupted_comments_fixer.py +231 -0
  49. roadmap/adapters/cli/health/fixers/data_integrity_fixer.py +137 -0
  50. roadmap/adapters/cli/health/fixers/duplicate_issues_fixer.py +138 -0
  51. roadmap/adapters/cli/health/fixers/folder_structure_fixer.py +114 -0
  52. roadmap/adapters/cli/health/fixers/label_normalization_fixer.py +162 -0
  53. roadmap/adapters/cli/health/fixers/milestone_name_normalization_fixer.py +181 -0
  54. roadmap/adapters/cli/health/fixers/milestone_naming_compliance_fixer.py +244 -0
  55. roadmap/adapters/cli/health/fixers/milestone_parse_error_fixer.py +162 -0
  56. roadmap/adapters/cli/health/fixers/milestone_validation_fixer.py +211 -0
  57. roadmap/adapters/cli/health/fixers/old_backups_fixer.py +135 -0
  58. roadmap/adapters/cli/health/fixers/orphaned_issues_fixer.py +252 -0
  59. roadmap/adapters/cli/health/formatter.py +250 -0
  60. roadmap/adapters/cli/health/formatters.py +427 -0
  61. roadmap/adapters/cli/health/scan.py +293 -0
  62. roadmap/adapters/cli/init/__init__.py +5 -0
  63. roadmap/adapters/cli/init/commands.py +587 -0
  64. roadmap/adapters/cli/init.py +9 -0
  65. roadmap/adapters/cli/issues/__init__.py +70 -0
  66. roadmap/adapters/cli/issues/archive.py +137 -0
  67. roadmap/adapters/cli/issues/archive_class.py +253 -0
  68. roadmap/adapters/cli/issues/block.py +39 -0
  69. roadmap/adapters/cli/issues/close.py +216 -0
  70. roadmap/adapters/cli/issues/comment.py +178 -0
  71. roadmap/adapters/cli/issues/create.py +162 -0
  72. roadmap/adapters/cli/issues/delete.py +31 -0
  73. roadmap/adapters/cli/issues/deps.py +161 -0
  74. roadmap/adapters/cli/issues/issue_status_helpers.py +111 -0
  75. roadmap/adapters/cli/issues/link.py +308 -0
  76. roadmap/adapters/cli/issues/list.py +402 -0
  77. roadmap/adapters/cli/issues/lookup.py +96 -0
  78. roadmap/adapters/cli/issues/progress.py +102 -0
  79. roadmap/adapters/cli/issues/restore.py +96 -0
  80. roadmap/adapters/cli/issues/restore_class.py +57 -0
  81. roadmap/adapters/cli/issues/start.py +165 -0
  82. roadmap/adapters/cli/issues/sync_status.py +374 -0
  83. roadmap/adapters/cli/issues/unblock.py +43 -0
  84. roadmap/adapters/cli/issues/unlink.py +104 -0
  85. roadmap/adapters/cli/issues/update.py +120 -0
  86. roadmap/adapters/cli/issues/view.py +36 -0
  87. roadmap/adapters/cli/layout.py +220 -0
  88. roadmap/adapters/cli/mappers.py +200 -0
  89. roadmap/adapters/cli/milestones/__init__.py +52 -0
  90. roadmap/adapters/cli/milestones/archive.py +125 -0
  91. roadmap/adapters/cli/milestones/archive_class.py +236 -0
  92. roadmap/adapters/cli/milestones/assign.py +62 -0
  93. roadmap/adapters/cli/milestones/close.py +177 -0
  94. roadmap/adapters/cli/milestones/create.py +131 -0
  95. roadmap/adapters/cli/milestones/delete.py +27 -0
  96. roadmap/adapters/cli/milestones/kanban.py +123 -0
  97. roadmap/adapters/cli/milestones/list.py +87 -0
  98. roadmap/adapters/cli/milestones/recalculate.py +79 -0
  99. roadmap/adapters/cli/milestones/restore.py +87 -0
  100. roadmap/adapters/cli/milestones/restore_class.py +99 -0
  101. roadmap/adapters/cli/milestones/update.py +61 -0
  102. roadmap/adapters/cli/milestones/view.py +142 -0
  103. roadmap/adapters/cli/output_manager.py +319 -0
  104. roadmap/adapters/cli/presentation/base_presenter.py +121 -0
  105. roadmap/adapters/cli/presentation/cleanup_presenter.py +235 -0
  106. roadmap/adapters/cli/presentation/core_initialization_presenter.py +277 -0
  107. roadmap/adapters/cli/presentation/crud_presenter.py +134 -0
  108. roadmap/adapters/cli/presentation/daily_summary_presenter.py +266 -0
  109. roadmap/adapters/cli/presentation/issue_presenter.py +258 -0
  110. roadmap/adapters/cli/presentation/milestone_list_presenter.py +135 -0
  111. roadmap/adapters/cli/presentation/milestone_presenter.py +297 -0
  112. roadmap/adapters/cli/presentation/project_presenter.py +233 -0
  113. roadmap/adapters/cli/presentation/project_status_presenter.py +186 -0
  114. roadmap/adapters/cli/presentation/table_builders.py +95 -0
  115. roadmap/adapters/cli/projects/__init__.py +42 -0
  116. roadmap/adapters/cli/projects/archive.py +127 -0
  117. roadmap/adapters/cli/projects/archive_class.py +96 -0
  118. roadmap/adapters/cli/projects/close.py +94 -0
  119. roadmap/adapters/cli/projects/create.py +50 -0
  120. roadmap/adapters/cli/projects/delete.py +27 -0
  121. roadmap/adapters/cli/projects/list.py +227 -0
  122. roadmap/adapters/cli/projects/restore.py +87 -0
  123. roadmap/adapters/cli/projects/restore_class.py +56 -0
  124. roadmap/adapters/cli/projects/update.py +57 -0
  125. roadmap/adapters/cli/projects/view.py +157 -0
  126. roadmap/adapters/cli/services/__init__.py +1 -0
  127. roadmap/adapters/cli/services/daily_summary_service.py +313 -0
  128. roadmap/adapters/cli/services/export_manager.py +268 -0
  129. roadmap/adapters/cli/services/milestone_list_service.py +266 -0
  130. roadmap/adapters/cli/services/project_initialization_service.py +29 -0
  131. roadmap/adapters/cli/services/project_status_service.py +462 -0
  132. roadmap/adapters/cli/services/sync_service.py +62 -0
  133. roadmap/adapters/cli/status.py +408 -0
  134. roadmap/adapters/cli/styling.py +21 -0
  135. roadmap/adapters/cli/sync.py +1117 -0
  136. roadmap/adapters/cli/sync_context.py +432 -0
  137. roadmap/adapters/cli/sync_handlers/__init__.py +77 -0
  138. roadmap/adapters/cli/sync_handlers/apply_ops.py +522 -0
  139. roadmap/adapters/cli/sync_handlers/baseline_ops.py +366 -0
  140. roadmap/adapters/cli/sync_handlers/conflict_ops.py +161 -0
  141. roadmap/adapters/cli/sync_handlers/dry_run_display.py +237 -0
  142. roadmap/adapters/cli/sync_handlers/interactive_resolver.py +396 -0
  143. roadmap/adapters/cli/sync_handlers/progress_tracker.py +128 -0
  144. roadmap/adapters/cli/sync_metrics_command.py +190 -0
  145. roadmap/adapters/cli/sync_presenter.py +58 -0
  146. roadmap/adapters/cli/sync_validation.py +295 -0
  147. roadmap/adapters/cli/today.py +52 -0
  148. roadmap/adapters/cli/utils/click_options.py +38 -0
  149. roadmap/adapters/git/__init__.py +1 -0
  150. roadmap/adapters/git/git.py +208 -0
  151. roadmap/adapters/git/git_branch_manager.py +400 -0
  152. roadmap/adapters/git/git_command_executor.py +56 -0
  153. roadmap/adapters/git/git_commit_analyzer.py +334 -0
  154. roadmap/adapters/git/git_hooks.py +22 -0
  155. roadmap/adapters/git/git_hooks_manager.py +455 -0
  156. roadmap/adapters/git/git_repository_info.py +65 -0
  157. roadmap/adapters/git/hook_installer.py +106 -0
  158. roadmap/adapters/git/hook_registry.py +97 -0
  159. roadmap/adapters/git/hook_script_generator.py +58 -0
  160. roadmap/adapters/git/sync_monitor.py +409 -0
  161. roadmap/adapters/git/workflow_automation.py +286 -0
  162. roadmap/adapters/github/__init__.py +1 -0
  163. roadmap/adapters/github/github.py +360 -0
  164. roadmap/adapters/github/handlers/__init__.py +17 -0
  165. roadmap/adapters/github/handlers/base.py +337 -0
  166. roadmap/adapters/github/handlers/collaborators.py +165 -0
  167. roadmap/adapters/github/handlers/comments.py +118 -0
  168. roadmap/adapters/github/handlers/issues.py +150 -0
  169. roadmap/adapters/github/handlers/labels.py +164 -0
  170. roadmap/adapters/github/handlers/milestones.py +104 -0
  171. roadmap/adapters/persistence/__init__.py +35 -0
  172. roadmap/adapters/persistence/conflict_resolver.py +190 -0
  173. roadmap/adapters/persistence/database_manager.py +492 -0
  174. roadmap/adapters/persistence/entity_sync_coordinators.py +672 -0
  175. roadmap/adapters/persistence/file_locking.py +348 -0
  176. roadmap/adapters/persistence/file_parser.py +92 -0
  177. roadmap/adapters/persistence/file_synchronizer.py +107 -0
  178. roadmap/adapters/persistence/focused_managers.py +140 -0
  179. roadmap/adapters/persistence/git_history.py +330 -0
  180. roadmap/adapters/persistence/parser/__init__.py +20 -0
  181. roadmap/adapters/persistence/parser/frontmatter.py +152 -0
  182. roadmap/adapters/persistence/parser/issue.py +245 -0
  183. roadmap/adapters/persistence/parser/milestone.py +146 -0
  184. roadmap/adapters/persistence/parser/project.py +106 -0
  185. roadmap/adapters/persistence/persistence.py +288 -0
  186. roadmap/adapters/persistence/repositories/__init__.py +15 -0
  187. roadmap/adapters/persistence/repositories/issue_repository.py +223 -0
  188. roadmap/adapters/persistence/repositories/milestone_repository.py +140 -0
  189. roadmap/adapters/persistence/repositories/project_repository.py +168 -0
  190. roadmap/adapters/persistence/repositories/remote_link_repository.py +355 -0
  191. roadmap/adapters/persistence/repositories/sync_state_repository.py +66 -0
  192. roadmap/adapters/persistence/storage/__init__.py +36 -0
  193. roadmap/adapters/persistence/storage/conflicts.py +101 -0
  194. roadmap/adapters/persistence/storage/connection_manager.py +79 -0
  195. roadmap/adapters/persistence/storage/issue_storage.py +89 -0
  196. roadmap/adapters/persistence/storage/milestone_storage.py +80 -0
  197. roadmap/adapters/persistence/storage/project_storage.py +102 -0
  198. roadmap/adapters/persistence/storage/queries.py +227 -0
  199. roadmap/adapters/persistence/storage/state_manager.py +652 -0
  200. roadmap/adapters/persistence/storage/sync_state_storage.py +207 -0
  201. roadmap/adapters/persistence/sync_metrics_repository.py +342 -0
  202. roadmap/adapters/persistence/sync_orchestrator.py +293 -0
  203. roadmap/adapters/persistence/sync_state_tracker.py +86 -0
  204. roadmap/adapters/persistence/yaml_repositories.py +711 -0
  205. roadmap/adapters/sync/__init__.py +21 -0
  206. roadmap/adapters/sync/backend_factory.py +108 -0
  207. roadmap/adapters/sync/backends/__init__.py +15 -0
  208. roadmap/adapters/sync/backends/converters.py +209 -0
  209. roadmap/adapters/sync/backends/github_backend_helpers.py +380 -0
  210. roadmap/adapters/sync/backends/github_client.py +99 -0
  211. roadmap/adapters/sync/backends/github_sync_backend.py +792 -0
  212. roadmap/adapters/sync/backends/github_sync_ops.py +908 -0
  213. roadmap/adapters/sync/backends/services/__init__.py +1 -0
  214. roadmap/adapters/sync/backends/services/github_authentication_service.py +105 -0
  215. roadmap/adapters/sync/backends/services/github_issue_delete_service.py +423 -0
  216. roadmap/adapters/sync/backends/services/github_issue_dependency_service.py +63 -0
  217. roadmap/adapters/sync/backends/services/github_issue_fetch_service.py +158 -0
  218. roadmap/adapters/sync/backends/services/github_label_sync_service.py +126 -0
  219. roadmap/adapters/sync/backends/services/github_local_issue_sync_service.py +229 -0
  220. roadmap/adapters/sync/backends/services/github_milestone_fetch_service.py +204 -0
  221. roadmap/adapters/sync/backends/vanilla_git_sync_backend.py +198 -0
  222. roadmap/adapters/sync/services/__init__.py +11 -0
  223. roadmap/adapters/sync/services/baseline_state_handler.py +83 -0
  224. roadmap/adapters/sync/services/conflict_converter.py +85 -0
  225. roadmap/adapters/sync/services/issue_persistence_service.py +263 -0
  226. roadmap/adapters/sync/services/issue_state_service.py +243 -0
  227. roadmap/adapters/sync/services/local_change_filter.py +129 -0
  228. roadmap/adapters/sync/services/pull_result_processor.py +71 -0
  229. roadmap/adapters/sync/services/remote_issue_creation_service.py +112 -0
  230. roadmap/adapters/sync/services/sync_analysis_service.py +250 -0
  231. roadmap/adapters/sync/services/sync_authentication_service.py +57 -0
  232. roadmap/adapters/sync/services/sync_data_fetch_service.py +212 -0
  233. roadmap/adapters/sync/services/sync_linking_service.py +329 -0
  234. roadmap/adapters/sync/services/sync_report_service.py +62 -0
  235. roadmap/adapters/sync/services/sync_state_update_service.py +51 -0
  236. roadmap/adapters/sync/sync_cache_orchestrator.py +454 -0
  237. roadmap/adapters/sync/sync_merge_engine.py +416 -0
  238. roadmap/adapters/sync/sync_merge_orchestrator.py +1313 -0
  239. roadmap/adapters/sync/sync_retrieval_orchestrator.py +810 -0
  240. roadmap/application/services/__init__.py +1 -0
  241. roadmap/application/services/deduplicate_service.py +517 -0
  242. roadmap/application/use_cases/__init__.py +1 -0
  243. roadmap/common/__init__.py +308 -0
  244. roadmap/common/cache.py +209 -0
  245. roadmap/common/cli_errors.py +147 -0
  246. roadmap/common/configuration/__init__.py +33 -0
  247. roadmap/common/configuration/config_loader.py +264 -0
  248. roadmap/common/configuration/config_manager.py +164 -0
  249. roadmap/common/configuration/config_schema.py +145 -0
  250. roadmap/common/configuration/github/__init__.py +9 -0
  251. roadmap/common/configuration/github/config_manager.py +154 -0
  252. roadmap/common/configuration/github/token_resolver.py +84 -0
  253. roadmap/common/console.py +184 -0
  254. roadmap/common/constants.py +134 -0
  255. roadmap/common/datetime_parser.py +319 -0
  256. roadmap/common/error_formatter.py +84 -0
  257. roadmap/common/errors/__init__.py +143 -0
  258. roadmap/common/errors/error_base.py +73 -0
  259. roadmap/common/errors/error_file.py +82 -0
  260. roadmap/common/errors/error_git.py +67 -0
  261. roadmap/common/errors/error_handler.py +166 -0
  262. roadmap/common/errors/error_network.py +90 -0
  263. roadmap/common/errors/error_security.py +78 -0
  264. roadmap/common/errors/error_standards.py +561 -0
  265. roadmap/common/errors/error_validation.py +111 -0
  266. roadmap/common/errors/exceptions.py +432 -0
  267. roadmap/common/formatters/__init__.py +29 -0
  268. roadmap/common/formatters/base_table_formatter.py +96 -0
  269. roadmap/common/formatters/export/__init__.py +7 -0
  270. roadmap/common/formatters/export/issue_exporter.py +97 -0
  271. roadmap/common/formatters/helpers.py +28 -0
  272. roadmap/common/formatters/kanban/__init__.py +9 -0
  273. roadmap/common/formatters/kanban/layout.py +48 -0
  274. roadmap/common/formatters/kanban/organizer.py +81 -0
  275. roadmap/common/formatters/output/__init__.py +15 -0
  276. roadmap/common/formatters/tables/__init__.py +11 -0
  277. roadmap/common/formatters/tables/column_factory.py +312 -0
  278. roadmap/common/formatters/tables/issue_table.py +276 -0
  279. roadmap/common/formatters/tables/milestone_table.py +247 -0
  280. roadmap/common/formatters/tables/project_table.py +195 -0
  281. roadmap/common/formatters/text/__init__.py +57 -0
  282. roadmap/common/formatters/text/basic.py +217 -0
  283. roadmap/common/formatters/text/display.py +42 -0
  284. roadmap/common/formatters/text/duration.py +36 -0
  285. roadmap/common/formatters/text/operations.py +325 -0
  286. roadmap/common/formatters/text/status_badges.py +57 -0
  287. roadmap/common/initialization/github/__init__.py +11 -0
  288. roadmap/common/initialization/github/setup_service.py +238 -0
  289. roadmap/common/initialization/github/setup_validator.py +78 -0
  290. roadmap/common/logging/__init__.py +113 -0
  291. roadmap/common/logging/audit_logging.py +5 -0
  292. roadmap/common/logging/correlation.py +45 -0
  293. roadmap/common/logging/decorators.py +267 -0
  294. roadmap/common/logging/error_logging.py +217 -0
  295. roadmap/common/logging/formatters.py +124 -0
  296. roadmap/common/logging/loggers.py +68 -0
  297. roadmap/common/logging/performance_tracking.py +267 -0
  298. roadmap/common/logging/utils.py +335 -0
  299. roadmap/common/models/__init__.py +44 -0
  300. roadmap/common/models/cli_models.py +118 -0
  301. roadmap/common/models/config_models.py +199 -0
  302. roadmap/common/models/output_models.py +381 -0
  303. roadmap/common/observability/__init__.py +28 -0
  304. roadmap/common/observability/instrumentation.py +103 -0
  305. roadmap/common/observability/observability.py +76 -0
  306. roadmap/common/observability/otel_init.py +109 -0
  307. roadmap/common/output_formatter.py +393 -0
  308. roadmap/common/progress.py +379 -0
  309. roadmap/common/result.py +396 -0
  310. roadmap/common/security/__init__.py +48 -0
  311. roadmap/common/security/exceptions.py +13 -0
  312. roadmap/common/security/export_cleanup.py +79 -0
  313. roadmap/common/security/file_operations.py +104 -0
  314. roadmap/common/security/filename_sanitization.py +54 -0
  315. roadmap/common/security/logging.py +27 -0
  316. roadmap/common/security/path_validation.py +137 -0
  317. roadmap/common/security/temp_files.py +41 -0
  318. roadmap/common/services/__init__.py +65 -0
  319. roadmap/common/services/decorators.py +183 -0
  320. roadmap/common/services/logging_utils.py +208 -0
  321. roadmap/common/services/metrics.py +161 -0
  322. roadmap/common/services/performance.py +219 -0
  323. roadmap/common/services/profiling.py +288 -0
  324. roadmap/common/services/retry.py +288 -0
  325. roadmap/common/status_style_manager.py +114 -0
  326. roadmap/common/union_find.py +88 -0
  327. roadmap/common/update_constants.py +13 -0
  328. roadmap/common/utils/__init__.py +65 -0
  329. roadmap/common/utils/cli_helpers.py +381 -0
  330. roadmap/common/utils/file_utils.py +440 -0
  331. roadmap/common/utils/path_utils.py +38 -0
  332. roadmap/common/utils/status_utils.py +130 -0
  333. roadmap/common/utils/timezone_utils.py +480 -0
  334. roadmap/common/validation/__init__.py +37 -0
  335. roadmap/common/validation/field_validator.py +104 -0
  336. roadmap/common/validation/result.py +37 -0
  337. roadmap/common/validation/roadmap_validator.py +310 -0
  338. roadmap/common/validation/schema_validator.py +36 -0
  339. roadmap/common/validation/validators.py +50 -0
  340. roadmap/core/__init__.py +1 -0
  341. roadmap/core/domain/__init__.py +30 -0
  342. roadmap/core/domain/comment.py +24 -0
  343. roadmap/core/domain/health.py +15 -0
  344. roadmap/core/domain/issue.py +274 -0
  345. roadmap/core/domain/milestone.py +173 -0
  346. roadmap/core/domain/ports/__init__.py +1 -0
  347. roadmap/core/domain/ports/baseline_repository.py +24 -0
  348. roadmap/core/domain/ports/issue_repository.py +34 -0
  349. roadmap/core/domain/ports/remote_backend_port.py +31 -0
  350. roadmap/core/domain/project.py +130 -0
  351. roadmap/core/interfaces/__init__.py +109 -0
  352. roadmap/core/interfaces/assignee_validator.py +40 -0
  353. roadmap/core/interfaces/backend_factory.py +175 -0
  354. roadmap/core/interfaces/github.py +102 -0
  355. roadmap/core/interfaces/parsers.py +140 -0
  356. roadmap/core/interfaces/persistence.py +45 -0
  357. roadmap/core/interfaces/repositories.py +174 -0
  358. roadmap/core/interfaces/state_managers.py +111 -0
  359. roadmap/core/interfaces/state_storage.py +64 -0
  360. roadmap/core/interfaces/sync_backend.py +275 -0
  361. roadmap/core/interfaces/sync_services.py +119 -0
  362. roadmap/core/interfaces/sync_validators.py +180 -0
  363. roadmap/core/models/__init__.py +31 -0
  364. roadmap/core/models/sync_models.py +162 -0
  365. roadmap/core/models.py +115 -0
  366. roadmap/core/observability/__init__.py +17 -0
  367. roadmap/core/observability/sync_metrics.py +699 -0
  368. roadmap/core/repositories.py +200 -0
  369. roadmap/core/services/__init__.py +313 -0
  370. roadmap/core/services/baseline/__init__.py +1 -0
  371. roadmap/core/services/baseline/baseline_builder_progress.py +274 -0
  372. roadmap/core/services/baseline/baseline_retriever.py +63 -0
  373. roadmap/core/services/baseline/baseline_selector.py +248 -0
  374. roadmap/core/services/baseline/baseline_state_retriever.py +284 -0
  375. roadmap/core/services/baseline/optimized_baseline_builder.py +425 -0
  376. roadmap/core/services/comment/__init__.py +1 -0
  377. roadmap/core/services/comment/comment_service.py +277 -0
  378. roadmap/core/services/git/__init__.py +1 -0
  379. roadmap/core/services/git/git_hook_auto_sync_service.py +403 -0
  380. roadmap/core/services/github/__init__.py +1 -0
  381. roadmap/core/services/github/github_change_detector.py +162 -0
  382. roadmap/core/services/github/github_config_validator.py +148 -0
  383. roadmap/core/services/github/github_conflict_detector.py +179 -0
  384. roadmap/core/services/github/github_entity_classifier.py +51 -0
  385. roadmap/core/services/github/github_integration_service.py +439 -0
  386. roadmap/core/services/github/github_issue_client.py +346 -0
  387. roadmap/core/services/health/__init__.py +1 -0
  388. roadmap/core/services/health/backup_cleanup_service.py +202 -0
  389. roadmap/core/services/health/data_integrity_validator_service.py +90 -0
  390. roadmap/core/services/health/entity_health_scanner.py +460 -0
  391. roadmap/core/services/health/file_repair_service.py +193 -0
  392. roadmap/core/services/health/health_check_service.py +166 -0
  393. roadmap/core/services/health/health_models.py +80 -0
  394. roadmap/core/services/health/infrastructure_validator_service.py +328 -0
  395. roadmap/core/services/health/issue_health_scanner.py +263 -0
  396. roadmap/core/services/helpers/__init__.py +18 -0
  397. roadmap/core/services/helpers/status_change_helpers.py +88 -0
  398. roadmap/core/services/initialization/__init__.py +19 -0
  399. roadmap/core/services/initialization/utils.py +104 -0
  400. roadmap/core/services/initialization/validator.py +78 -0
  401. roadmap/core/services/initialization/workflow.py +182 -0
  402. roadmap/core/services/initialization_service.py +111 -0
  403. roadmap/core/services/issue/__init__.py +1 -0
  404. roadmap/core/services/issue/assignee_validation_service.py +312 -0
  405. roadmap/core/services/issue/issue_creation_service.py +309 -0
  406. roadmap/core/services/issue/issue_filter_service.py +302 -0
  407. roadmap/core/services/issue/issue_matching_service.py +127 -0
  408. roadmap/core/services/issue/issue_service.py +765 -0
  409. roadmap/core/services/issue/issue_update_service.py +144 -0
  410. roadmap/core/services/issue/start_issue_service.py +174 -0
  411. roadmap/core/services/issue_helpers/__init__.py +18 -0
  412. roadmap/core/services/issue_helpers/issue_filters.py +296 -0
  413. roadmap/core/services/milestone_service.py +438 -0
  414. roadmap/core/services/project/__init__.py +1 -0
  415. roadmap/core/services/project/project_service.py +434 -0
  416. roadmap/core/services/project/project_status_service.py +125 -0
  417. roadmap/core/services/project_init/__init__.py +22 -0
  418. roadmap/core/services/project_init/context_detection.py +146 -0
  419. roadmap/core/services/project_init/creation.py +76 -0
  420. roadmap/core/services/project_init/detection.py +51 -0
  421. roadmap/core/services/project_init/template.py +228 -0
  422. roadmap/core/services/status_change_service.py +88 -0
  423. roadmap/core/services/sync/__init__.py +1 -0
  424. roadmap/core/services/sync/batch_processor.py +290 -0
  425. roadmap/core/services/sync/conflict_resolver.py +154 -0
  426. roadmap/core/services/sync/dependency_resolver.py +367 -0
  427. roadmap/core/services/sync/duplicate_detector.py +771 -0
  428. roadmap/core/services/sync/duplicate_resolver.py +315 -0
  429. roadmap/core/services/sync/error_classification.py +470 -0
  430. roadmap/core/services/sync/performance.py +263 -0
  431. roadmap/core/services/sync/sync_change_computer.py +211 -0
  432. roadmap/core/services/sync/sync_checkpoint.py +348 -0
  433. roadmap/core/services/sync/sync_conflict_detector.py +147 -0
  434. roadmap/core/services/sync/sync_conflict_resolver.py +448 -0
  435. roadmap/core/services/sync/sync_errors.py +383 -0
  436. roadmap/core/services/sync/sync_key_normalizer.py +222 -0
  437. roadmap/core/services/sync/sync_metadata_service.py +361 -0
  438. roadmap/core/services/sync/sync_plan.py +171 -0
  439. roadmap/core/services/sync/sync_plan_executor.py +447 -0
  440. roadmap/core/services/sync/sync_report.py +296 -0
  441. roadmap/core/services/sync/sync_state.py +173 -0
  442. roadmap/core/services/sync/sync_state_comparator.py +690 -0
  443. roadmap/core/services/sync/sync_state_manager.py +431 -0
  444. roadmap/core/services/sync/sync_state_normalizer.py +98 -0
  445. roadmap/core/services/sync/sync_three_way.py +78 -0
  446. roadmap/core/services/sync/three_way_merger.py +178 -0
  447. roadmap/core/services/utils/__init__.py +1 -0
  448. roadmap/core/services/utils/configuration_service.py +113 -0
  449. roadmap/core/services/utils/critical_path_calculator.py +418 -0
  450. roadmap/core/services/utils/dependency_analyzer.py +360 -0
  451. roadmap/core/services/utils/field_conflict_detector.py +126 -0
  452. roadmap/core/services/utils/remote_fetcher.py +202 -0
  453. roadmap/core/services/utils/remote_state_normalizer.py +110 -0
  454. roadmap/core/services/utils/retry_policy.py +51 -0
  455. roadmap/core/services/validator_base.py +130 -0
  456. roadmap/core/services/validators/__init__.py +28 -0
  457. roadmap/core/services/validators/_utils.py +20 -0
  458. roadmap/core/services/validators/archivable_issues_validator.py +71 -0
  459. roadmap/core/services/validators/archivable_milestones_validator.py +69 -0
  460. roadmap/core/services/validators/backup_validator.py +89 -0
  461. roadmap/core/services/validators/data_integrity_validator.py +84 -0
  462. roadmap/core/services/validators/duplicate_issues_validator.py +75 -0
  463. roadmap/core/services/validators/duplicate_milestones_validator.py +141 -0
  464. roadmap/core/services/validators/folder_structure_validator.py +165 -0
  465. roadmap/core/services/validators/health_status_utils.py +28 -0
  466. roadmap/core/services/validators/milestone_naming_validator.py +146 -0
  467. roadmap/core/services/validators/missing_headlines_validator.py +97 -0
  468. roadmap/core/services/validators/orphaned_issues_validator.py +142 -0
  469. roadmap/core/services/validators/orphaned_milestones_validator.py +85 -0
  470. roadmap/core/utils/git_remote_parser.py +83 -0
  471. roadmap/core/utils/github_urls.py +66 -0
  472. roadmap/domain/validation.py +30 -0
  473. roadmap/infrastructure/__init__.py +55 -0
  474. roadmap/infrastructure/coordination/__init__.py +8 -0
  475. roadmap/infrastructure/coordination/coordinator_params.py +82 -0
  476. roadmap/infrastructure/coordination/core.py +446 -0
  477. roadmap/infrastructure/coordination/git_coordinator.py +160 -0
  478. roadmap/infrastructure/coordination/initialization.py +348 -0
  479. roadmap/infrastructure/coordination/issue_coordinator.py +154 -0
  480. roadmap/infrastructure/coordination/issue_operations.py +456 -0
  481. roadmap/infrastructure/coordination/milestone_coordinator.py +135 -0
  482. roadmap/infrastructure/coordination/milestone_operations.py +201 -0
  483. roadmap/infrastructure/coordination/project_coordinator.py +113 -0
  484. roadmap/infrastructure/coordination/project_operations.py +144 -0
  485. roadmap/infrastructure/coordination/team_coordinator.py +107 -0
  486. roadmap/infrastructure/coordination/user_operations.py +150 -0
  487. roadmap/infrastructure/coordination/validation_coordinator.py +249 -0
  488. roadmap/infrastructure/coordination_gateway.py +152 -0
  489. roadmap/infrastructure/git/__init__.py +6 -0
  490. roadmap/infrastructure/git/git_integration_ops.py +234 -0
  491. roadmap/infrastructure/git_gateway.py +35 -0
  492. roadmap/infrastructure/github_gateway.py +52 -0
  493. roadmap/infrastructure/maintenance/__init__.py +5 -0
  494. roadmap/infrastructure/maintenance/cleanup.py +483 -0
  495. roadmap/infrastructure/observability/__init__.py +7 -0
  496. roadmap/infrastructure/observability/health.py +196 -0
  497. roadmap/infrastructure/observability/health_formatter.py +73 -0
  498. roadmap/infrastructure/observability/specialized_health_checkers.py +188 -0
  499. roadmap/infrastructure/persistence_gateway.py +164 -0
  500. roadmap/infrastructure/security/__init__.py +1 -0
  501. roadmap/infrastructure/security/credentials.py +489 -0
  502. roadmap/infrastructure/sync_gateway.py +94 -0
  503. roadmap/infrastructure/validation/__init__.py +7 -0
  504. roadmap/infrastructure/validation/file_enumeration.py +219 -0
  505. roadmap/infrastructure/validation/github_assignee_validator.py +47 -0
  506. roadmap/infrastructure/validation/github_validator.py +101 -0
  507. roadmap/infrastructure/validation/milestone_consistency_validator.py +96 -0
  508. roadmap/infrastructure/validation/vanilla_assignee_validator.py +37 -0
  509. roadmap/infrastructure/validation_gateway.py +96 -0
  510. roadmap/presentation/formatters/sync_metrics_formatter.py +355 -0
  511. roadmap/settings.py +345 -0
  512. roadmap/templates/github_workflows/ci-cd-roadmap.yml +241 -0
  513. roadmap/templates/github_workflows/issue-lifecycle.yml +236 -0
  514. roadmap/templates/github_workflows/roadmap-integration.yml +137 -0
  515. roadmap/templates/github_workflows/roadmap-starter.yml +59 -0
  516. roadmap/version.py +381 -0
  517. roadmap_cli-0.1.1.dist-info/METADATA +448 -0
  518. roadmap_cli-0.1.1.dist-info/RECORD +521 -0
  519. roadmap_cli-0.1.1.dist-info/WHEEL +4 -0
  520. roadmap_cli-0.1.1.dist-info/entry_points.txt +2 -0
  521. roadmap_cli-0.1.1.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,374 @@
1
+ """Entity-specific builders for CRUD operations.
2
+
3
+ This module provides builders for each entity type (Issue, Milestone, Project)
4
+ that handle validation and dict building for create/update operations.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from typing import Any
9
+
10
+ from roadmap.common.errors.exceptions import ValidationError
11
+ from roadmap.core.domain import IssueType, Priority
12
+
13
+
14
+ class IssueBuilder:
15
+ """Builder for issue creation and updates."""
16
+
17
+ @staticmethod
18
+ def validate_issue_exists(core: Any, issue_id: str) -> bool:
19
+ """Check if an issue exists.
20
+
21
+ Args:
22
+ core: The core application context
23
+ issue_id: Issue ID to check
24
+
25
+ Returns:
26
+ True if issue exists, False otherwise
27
+ """
28
+ return core.issues.get(issue_id) is not None
29
+
30
+ @staticmethod
31
+ def validate_priority(priority: str) -> Priority:
32
+ """Validate and convert priority string.
33
+
34
+ Args:
35
+ priority: Priority string (critical, high, medium, low)
36
+
37
+ Returns:
38
+ Priority enum value
39
+
40
+ Raises:
41
+ ValidationError: If priority is invalid
42
+ """
43
+ try:
44
+ priority_map = {
45
+ "critical": Priority.CRITICAL,
46
+ "high": Priority.HIGH,
47
+ "medium": Priority.MEDIUM,
48
+ "low": Priority.LOW,
49
+ }
50
+ return priority_map[priority.lower()]
51
+ except KeyError as e:
52
+ raise ValidationError(
53
+ domain_message=f"Invalid priority: {priority}",
54
+ user_message=f"Invalid priority: {priority}. Valid values: critical, high, medium, low",
55
+ ) from e
56
+
57
+ @staticmethod
58
+ def validate_issue_type(issue_type: str) -> IssueType:
59
+ """Validate and convert issue type string.
60
+
61
+ Args:
62
+ issue_type: Issue type string (feature, bug, other)
63
+
64
+ Returns:
65
+ IssueType enum value
66
+
67
+ Raises:
68
+ ValidationError: If type is invalid
69
+ """
70
+ try:
71
+ type_map = {
72
+ "feature": IssueType.FEATURE,
73
+ "bug": IssueType.BUG,
74
+ "other": IssueType.OTHER,
75
+ }
76
+ return type_map[issue_type.lower()]
77
+ except KeyError as e:
78
+ raise ValidationError(
79
+ domain_message=f"Invalid issue type: {issue_type}",
80
+ user_message=f"Invalid issue type: {issue_type}. Valid values: feature, bug, other",
81
+ ) from e
82
+
83
+ @staticmethod
84
+ def build_create_dict(
85
+ title: str,
86
+ priority: str | None = None,
87
+ issue_type: str | None = None,
88
+ milestone: str | None = None,
89
+ assignee: str | None = None,
90
+ labels: list[str] | None = None,
91
+ estimate: float | None = None,
92
+ depends_on: list[str] | None = None,
93
+ blocks: list[str] | None = None,
94
+ description: str | None = None,
95
+ ) -> dict[str, Any]:
96
+ """Build create dictionary for issue.
97
+
98
+ Args:
99
+ title: Issue title (required)
100
+ priority: Priority level
101
+ issue_type: Type of issue
102
+ milestone: Milestone ID to assign
103
+ assignee: Assignee name/email
104
+ labels: List of labels
105
+ estimate: Estimated hours
106
+ depends_on: Issue IDs this depends on
107
+ blocks: Issue IDs this blocks
108
+ description: Markdown content/description
109
+
110
+ Returns:
111
+ Dictionary ready for core.issues.create()
112
+ """
113
+ create_dict: dict[str, Any] = {"title": title, "status": "todo"}
114
+
115
+ if priority:
116
+ create_dict["priority"] = IssueBuilder.validate_priority(priority)
117
+
118
+ if issue_type:
119
+ create_dict["issue_type"] = IssueBuilder.validate_issue_type(issue_type)
120
+
121
+ if milestone:
122
+ create_dict["milestone"] = milestone
123
+
124
+ if assignee:
125
+ create_dict["assignee"] = assignee
126
+
127
+ if labels:
128
+ create_dict["labels"] = labels
129
+
130
+ if estimate is not None:
131
+ create_dict["estimated_hours"] = estimate
132
+
133
+ if depends_on:
134
+ create_dict["depends_on"] = depends_on
135
+
136
+ if blocks:
137
+ create_dict["blocks"] = blocks
138
+
139
+ if description:
140
+ create_dict["content"] = description
141
+
142
+ return create_dict
143
+
144
+ @staticmethod
145
+ def build_update_dict(
146
+ title: str | None = None,
147
+ priority: str | None = None,
148
+ status: str | None = None,
149
+ assignee: str | None = None,
150
+ milestone: str | None = None,
151
+ description: str | None = None,
152
+ estimate: float | None = None,
153
+ ) -> dict[str, Any]:
154
+ """Build update dictionary for issue.
155
+
156
+ Args:
157
+ title: New title
158
+ priority: New priority
159
+ status: New status
160
+ assignee: New assignee
161
+ milestone: New milestone
162
+ description: New description
163
+ estimate: New estimate
164
+
165
+ Returns:
166
+ Dictionary ready for core.issues.update()
167
+ """
168
+ update_dict = {}
169
+
170
+ if title is not None:
171
+ update_dict["title"] = title
172
+
173
+ if priority is not None:
174
+ update_dict["priority"] = IssueBuilder.validate_priority(priority)
175
+
176
+ if status is not None:
177
+ update_dict["status"] = status
178
+
179
+ if assignee is not None:
180
+ update_dict["assignee"] = assignee
181
+
182
+ if milestone is not None:
183
+ update_dict["milestone"] = milestone
184
+
185
+ if description is not None:
186
+ update_dict["content"] = description
187
+
188
+ if estimate is not None:
189
+ update_dict["estimated_hours"] = estimate
190
+
191
+ return update_dict
192
+
193
+
194
+ class MilestoneBuilder:
195
+ """Builder for milestone creation and updates."""
196
+
197
+ @staticmethod
198
+ def validate_milestone_exists(core: Any, milestone_id: str) -> bool:
199
+ """Check if a milestone exists.
200
+
201
+ Args:
202
+ core: The core application context
203
+ milestone_id: Milestone ID to check
204
+
205
+ Returns:
206
+ True if milestone exists, False otherwise
207
+ """
208
+ return core.milestones.get(milestone_id) is not None
209
+
210
+ @staticmethod
211
+ def validate_due_date(due_date: str | None) -> datetime | None:
212
+ """Validate and parse due date.
213
+
214
+ Args:
215
+ due_date: Due date string (YYYY-MM-DD format)
216
+
217
+ Returns:
218
+ Parsed datetime or None
219
+
220
+ Raises:
221
+ ValidationError: If date format is invalid
222
+ """
223
+ if not due_date:
224
+ return None
225
+
226
+ try:
227
+ return datetime.strptime(due_date, "%Y-%m-%d")
228
+ except ValueError as e:
229
+ raise ValidationError(
230
+ domain_message="Invalid due date format: expected YYYY-MM-DD",
231
+ user_message=f"Invalid due date format: {due_date}. Expected format: YYYY-MM-DD (example: 2024-12-31)",
232
+ ) from e
233
+
234
+ @staticmethod
235
+ def build_create_dict(
236
+ name: str,
237
+ description: str | None = None,
238
+ due_date: str | None = None,
239
+ ) -> dict[str, Any]:
240
+ """Build create dictionary for milestone.
241
+
242
+ Args:
243
+ name: Milestone name (required)
244
+ description: Milestone content/description
245
+ due_date: Due date (YYYY-MM-DD format)
246
+
247
+ Returns:
248
+ Dictionary ready for core.milestones.create()
249
+ """
250
+ create_dict: dict[str, Any] = {"name": name, "status": "open"}
251
+
252
+ if description:
253
+ create_dict["headline"] = description
254
+
255
+ if due_date:
256
+ create_dict["due_date"] = MilestoneBuilder.validate_due_date(due_date)
257
+
258
+ return create_dict
259
+
260
+ @staticmethod
261
+ def build_update_dict(
262
+ name: str | None = None,
263
+ description: str | None = None,
264
+ due_date: str | None = None,
265
+ status: str | None = None,
266
+ project_id: str | None = None,
267
+ ) -> dict[str, Any]:
268
+ """Build update dictionary for milestone.
269
+
270
+ Args:
271
+ name: New name
272
+ description: New content/description
273
+ due_date: New due date (YYYY-MM-DD format)
274
+ status: New status
275
+ project_id: Project ID to assign milestone to
276
+
277
+ Returns:
278
+ Dictionary ready for core.milestones.update()
279
+ """
280
+ update_dict = {}
281
+
282
+ if name is not None:
283
+ update_dict["name"] = name
284
+
285
+ if description is not None:
286
+ update_dict["headline"] = description
287
+
288
+ if due_date is not None:
289
+ update_dict["due_date"] = MilestoneBuilder.validate_due_date(due_date)
290
+
291
+ if status is not None:
292
+ update_dict["status"] = status
293
+
294
+ if project_id is not None:
295
+ update_dict["project_id"] = project_id
296
+
297
+ return update_dict
298
+
299
+
300
+ class ProjectBuilder:
301
+ """Builder for project creation and updates."""
302
+
303
+ @staticmethod
304
+ def validate_project_exists(core: Any, project_id: str) -> bool:
305
+ """Check if a project exists.
306
+
307
+ Args:
308
+ core: The core application context
309
+ project_id: Project ID to check
310
+
311
+ Returns:
312
+ True if project exists, False otherwise
313
+ """
314
+ return core.projects.get(project_id) is not None
315
+
316
+ @staticmethod
317
+ def build_create_dict(
318
+ name: str,
319
+ description: str | None = None,
320
+ repository: str | None = None,
321
+ ) -> dict[str, Any]:
322
+ """Build create dictionary for project.
323
+
324
+ Args:
325
+ name: Project name (required)
326
+ description: Project content
327
+ repository: Repository URL
328
+
329
+ Returns:
330
+ Dictionary ready for core.projects.create()
331
+ """
332
+ create_dict = {"name": name, "status": "planning"}
333
+
334
+ if description:
335
+ create_dict["headline"] = description
336
+
337
+ if repository:
338
+ create_dict["repository"] = repository
339
+
340
+ return create_dict
341
+
342
+ @staticmethod
343
+ def build_update_dict(
344
+ name: str | None = None,
345
+ description: str | None = None,
346
+ repository: str | None = None,
347
+ status: str | None = None,
348
+ ) -> dict[str, Any]:
349
+ """Build update dictionary for project.
350
+
351
+ Args:
352
+ name: New name
353
+ description: New description
354
+ repository: New repository URL
355
+ status: New status
356
+
357
+ Returns:
358
+ Dictionary ready for core.projects.update()
359
+ """
360
+ update_dict = {}
361
+
362
+ if name is not None:
363
+ update_dict["name"] = name
364
+
365
+ if description is not None:
366
+ update_dict["headline"] = description
367
+
368
+ if repository is not None:
369
+ update_dict["repository"] = repository
370
+
371
+ if status is not None:
372
+ update_dict["status"] = status
373
+
374
+ return update_dict
@@ -0,0 +1,8 @@
1
+ """Data export and reporting commands.
2
+
3
+ Commands for exporting and managing data.
4
+ """
5
+
6
+ from .commands import data
7
+
8
+ __all__ = ["data"]
@@ -0,0 +1,149 @@
1
+ """Data management commands for export and reporting."""
2
+
3
+ import click
4
+
5
+ from roadmap.common.console import get_console
6
+ from roadmap.common.logging import verbose_output
7
+ from roadmap.core.domain import Issue
8
+
9
+ console = get_console()
10
+
11
+
12
+ def _serialize_issue(issue: Issue) -> dict:
13
+ """Convert an Issue model to a JSON-serializable dict."""
14
+ # Use pydantic's dict but convert datetimes to isoformat strings
15
+ d = issue.model_dump()
16
+ for k, v in d.items():
17
+ if hasattr(v, "isoformat"):
18
+ try:
19
+ d[k] = v.isoformat()
20
+ except Exception:
21
+ d[k] = str(v)
22
+ return d
23
+
24
+
25
+ @click.group()
26
+ def data():
27
+ """Export, import, and analyze roadmap data."""
28
+ pass
29
+
30
+
31
+ @data.command("export")
32
+ @click.option(
33
+ "--format",
34
+ type=click.Choice(["json", "csv", "markdown"]),
35
+ default="json",
36
+ help="Export format",
37
+ )
38
+ @click.option("--output", "-o", help="Output file path")
39
+ @click.option("--filter", help="Filter criteria (simple key=value)")
40
+ @click.pass_context
41
+ @verbose_output
42
+ def export(ctx: click.Context, format: str, output: str, filter: str):
43
+ """Export roadmap issues to JSON, CSV or Markdown.
44
+
45
+ The --filter argument supports a simple key=value filter (e.g. assignee=alice).
46
+ """
47
+ console.print(f"📊 Exporting issues in {format} format...", style="bold blue")
48
+
49
+ # Get core and issues
50
+ core = _get_core(ctx)
51
+ if not core or not core.is_initialized():
52
+ console.print(
53
+ "❌ Roadmap not initialized. Run 'roadmap init' first or run this command inside a roadmap.",
54
+ style="bold red",
55
+ )
56
+ return
57
+
58
+ issues = _load_and_filter_issues(core, filter)
59
+ if not issues:
60
+ console.print("â„šī¸ No issues to export.", style="yellow")
61
+ return
62
+
63
+ # Format and output
64
+ _export_and_write(issues, format, output)
65
+
66
+
67
+ def _get_core(ctx: click.Context):
68
+ """Get RoadmapCore from context or discover existing roadmap."""
69
+ try:
70
+ core = ctx.obj.get("core") if ctx.obj else None
71
+ except Exception:
72
+ core = None
73
+
74
+ if core is None:
75
+ try:
76
+ from roadmap.infrastructure.coordination.core import RoadmapCore
77
+
78
+ core = RoadmapCore.find_existing_roadmap()
79
+ except Exception:
80
+ core = None
81
+
82
+ return core
83
+
84
+
85
+ def _load_and_filter_issues(core, filter_str: str):
86
+ """Load issues and apply filter if provided."""
87
+ try:
88
+ issues = core.issues.list()
89
+ except Exception as e:
90
+ console.print(f"❌ Failed to list issues: {e}", style="bold red")
91
+ return []
92
+
93
+ if filter_str:
94
+ try:
95
+ key, val = filter_str.split("=", 1)
96
+ key = key.strip()
97
+ val = val.strip()
98
+ issues = [
99
+ i for i in issues if str(getattr(i, key, "")).lower() == val.lower()
100
+ ]
101
+ except Exception:
102
+ console.print("âš ī¸ Unable to parse filter, ignoring.", style="yellow")
103
+
104
+ return issues
105
+
106
+
107
+ def _export_and_write(issues, format_type: str, output_path: str):
108
+ """Format issues and write to file or stdout."""
109
+ from roadmap.common.formatters import IssueExporter
110
+
111
+ try:
112
+ if format_type == "json":
113
+ out_text = IssueExporter.to_json(issues, _serialize_issue)
114
+ elif format_type == "csv":
115
+ out_text = IssueExporter.to_csv(issues, _serialize_issue)
116
+ else: # markdown
117
+ out_text = IssueExporter.to_markdown(issues)
118
+
119
+ # Write to file or print
120
+ if output_path:
121
+ with open(output_path, "w", encoding="utf-8") as f:
122
+ f.write(out_text)
123
+ console.print(
124
+ f"✅ Exported {len(issues)} issues to {output_path}", style="bold green"
125
+ )
126
+ else:
127
+ console.print(out_text)
128
+
129
+ except Exception as e:
130
+ console.print(f"❌ Failed to export issues: {e}", style="bold red")
131
+
132
+
133
+ @data.command("generate-report")
134
+ @click.option(
135
+ "--type",
136
+ type=click.Choice(["summary", "detailed", "analytics"]),
137
+ default="summary",
138
+ help="Report type",
139
+ )
140
+ @click.option("--output", "-o", help="Output file path")
141
+ @click.pass_context
142
+ @verbose_output
143
+ def generate_report(ctx: click.Context, type: str, output: str):
144
+ """Generate detailed reports and analytics."""
145
+ console.print(f"📈 Generating {type} report...", style="bold blue")
146
+ # Implementation would go here
147
+ console.print(
148
+ "✅ Report generation functionality will be implemented", style="green"
149
+ )