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,310 @@
1
+ """Main roadmap entity validators."""
2
+
3
+ import re
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from structlog import get_logger
9
+
10
+ from roadmap.common.constants import IssueType, MilestoneStatus, Priority, Status
11
+
12
+ from .field_validator import FieldValidator
13
+ from .result import ValidationResult
14
+ from .schema_validator import SchemaValidator
15
+
16
+ logger = get_logger()
17
+
18
+
19
+ class RoadmapValidator:
20
+ """Main validation class with predefined validators for roadmap entities."""
21
+
22
+ def __init__(self):
23
+ """Initialize RoadmapValidator."""
24
+ self._setup_predefined_validators()
25
+
26
+ def _setup_predefined_validators(self):
27
+ """Set up predefined validators for common roadmap entities."""
28
+ # Issue validation schema
29
+ self.issue_schema = SchemaValidator("issue")
30
+ self.issue_schema.add_field(
31
+ FieldValidator("id", required=True, pattern=r"^[a-f0-9]{8}$")
32
+ ).add_field(
33
+ FieldValidator("title", required=True, min_length=1, max_length=200)
34
+ ).add_field(
35
+ FieldValidator(
36
+ "priority", required=True, enum_values=[p.value for p in Priority]
37
+ )
38
+ ).add_field(
39
+ FieldValidator(
40
+ "status", required=True, enum_values=[s.value for s in Status]
41
+ )
42
+ ).add_field(
43
+ FieldValidator("issue_type", enum_values=[t.value for t in IssueType])
44
+ ).add_field(
45
+ FieldValidator(
46
+ "assignee", max_length=100, custom_validator=self._validate_assignee
47
+ )
48
+ ).add_field(FieldValidator("milestone", max_length=100)).add_field(
49
+ FieldValidator(
50
+ "estimated_hours", custom_validator=self._validate_positive_number
51
+ )
52
+ ).add_field(
53
+ FieldValidator(
54
+ "progress_percentage", custom_validator=self._validate_percentage
55
+ )
56
+ )
57
+
58
+ # Milestone validation schema
59
+ self.milestone_schema = SchemaValidator("milestone")
60
+ self.milestone_schema.add_field(
61
+ FieldValidator("name", required=True, min_length=1, max_length=100)
62
+ ).add_field(
63
+ FieldValidator(
64
+ "status", required=True, enum_values=[s.value for s in MilestoneStatus]
65
+ )
66
+ ).add_field(FieldValidator("description", max_length=1000)).add_field(
67
+ FieldValidator("due_date", custom_validator=self._validate_datetime)
68
+ )
69
+
70
+ # Project validation schema
71
+ self.project_schema = SchemaValidator("project")
72
+ self.project_schema.add_field(
73
+ FieldValidator("id", required=True, pattern=r"^[a-f0-9-]+$")
74
+ ).add_field(
75
+ FieldValidator("name", required=True, min_length=1, max_length=200)
76
+ ).add_field(FieldValidator("description", max_length=2000)).add_field(
77
+ FieldValidator("owner", max_length=100)
78
+ ).add_field(
79
+ FieldValidator(
80
+ "estimated_hours", custom_validator=self._validate_positive_number
81
+ )
82
+ )
83
+
84
+ def _validate_assignee(self, value: Any) -> tuple[bool, str]:
85
+ """Validate assignee format."""
86
+ if value is None:
87
+ return True, ""
88
+
89
+ str_value = str(value)
90
+ if not str_value:
91
+ return True, ""
92
+
93
+ # Basic username format validation
94
+ if not re.match(r"^[a-zA-Z0-9_-]+$", str_value):
95
+ return (
96
+ False,
97
+ "must contain only alphanumeric characters, hyphens, and underscores",
98
+ )
99
+
100
+ if len(str_value) > 39: # GitHub username limit
101
+ return False, "must be 39 characters or less"
102
+
103
+ return True, ""
104
+
105
+ def _validate_positive_number(self, value: Any) -> tuple[bool, str]:
106
+ """Validate that a number is positive."""
107
+ if value is None:
108
+ return True, ""
109
+
110
+ try:
111
+ num_value = float(value)
112
+ if num_value < 0:
113
+ return False, "must be a positive number"
114
+ return True, ""
115
+ except (ValueError, TypeError) as e:
116
+ logger.debug("number_validation_failed", value=value, error=str(e))
117
+ return False, "must be a valid number"
118
+
119
+ def _validate_percentage(self, value: Any) -> tuple[bool, str]:
120
+ """Validate percentage value (0-100)."""
121
+ if value is None:
122
+ return True, ""
123
+
124
+ try:
125
+ num_value = float(value)
126
+ if not 0 <= num_value <= 100:
127
+ return False, "must be between 0 and 100"
128
+ return True, ""
129
+ except (ValueError, TypeError) as e:
130
+ logger.debug("percentage_validation_failed", value=value, error=str(e))
131
+ return False, "must be a valid number"
132
+
133
+ def _validate_datetime(self, value: Any) -> tuple[bool, str]:
134
+ """Validate datetime format."""
135
+ if value is None:
136
+ return True, ""
137
+
138
+ if isinstance(value, datetime):
139
+ return True, ""
140
+
141
+ # Try to parse string as datetime
142
+ if isinstance(value, str):
143
+ try:
144
+ from roadmap.common.datetime_parser import parse_datetime
145
+
146
+ parse_datetime(value, "flexible")
147
+ return True, ""
148
+ except Exception as e:
149
+ logger.debug("datetime_parsing_failed", value=value, error=str(e))
150
+ return False, "must be a valid datetime format"
151
+
152
+ return False, "must be a datetime or valid datetime string"
153
+
154
+ def validate_issue(self, issue_data: dict[str, Any]) -> ValidationResult:
155
+ """Validate issue data."""
156
+ return self.issue_schema.validate(issue_data)
157
+
158
+ def validate_milestone(self, milestone_data: dict[str, Any]) -> ValidationResult:
159
+ """Validate milestone data."""
160
+ return self.milestone_schema.validate(milestone_data)
161
+
162
+ def validate_project(self, project_data: dict[str, Any]) -> ValidationResult:
163
+ """Validate project data."""
164
+ return self.project_schema.validate(project_data)
165
+
166
+ def validate_required_fields(
167
+ self, data: dict[str, Any], required_fields: list[str]
168
+ ) -> ValidationResult:
169
+ """Validate that required fields are present."""
170
+ result = ValidationResult()
171
+ missing_fields = []
172
+
173
+ for field in required_fields:
174
+ if field not in data or data[field] is None or data[field] == "":
175
+ missing_fields.append(field)
176
+
177
+ if missing_fields:
178
+ result.add_error(f"Missing required fields: {', '.join(missing_fields)}")
179
+
180
+ return result
181
+
182
+ def validate_enum_field(
183
+ self, value: Any, field_name: str, enum_class: Any
184
+ ) -> ValidationResult:
185
+ """Validate an enum field."""
186
+ result = ValidationResult(field=field_name)
187
+
188
+ if value is None:
189
+ return result
190
+
191
+ valid_values = [e.value for e in enum_class]
192
+ check_value = value.value if hasattr(value, "value") else value
193
+
194
+ if check_value not in valid_values:
195
+ result.add_error(
196
+ f"Invalid {field_name}: {check_value}. Valid values: {', '.join(valid_values)}"
197
+ )
198
+
199
+ return result
200
+
201
+ def validate_string_length(
202
+ self,
203
+ value: str,
204
+ field_name: str,
205
+ min_length: int = 0,
206
+ max_length: int | None = None,
207
+ ) -> ValidationResult:
208
+ """Validate string length constraints."""
209
+ result = ValidationResult(field=field_name)
210
+
211
+ if value is None:
212
+ return result
213
+
214
+ if len(value) < min_length:
215
+ result.add_error(f"{field_name} must be at least {min_length} characters")
216
+
217
+ if max_length and len(value) > max_length:
218
+ result.add_error(
219
+ f"{field_name} must be no more than {max_length} characters"
220
+ )
221
+
222
+ return result
223
+
224
+ def validate_id_format(
225
+ self, id_value: str, field_name: str = "id"
226
+ ) -> ValidationResult:
227
+ """Validate ID format (8-character hex for issues, UUID-like for projects)."""
228
+ result = ValidationResult(field=field_name)
229
+
230
+ if not id_value:
231
+ result.add_error(f"{field_name} is required")
232
+ return result
233
+
234
+ # For issue IDs (8-character hex)
235
+ if len(id_value) == 8 and re.match(r"^[a-f0-9]{8}$", id_value):
236
+ return result
237
+
238
+ # For project IDs (UUID-like format)
239
+ if re.match(r"^[a-f0-9-]+$", id_value):
240
+ return result
241
+
242
+ result.add_error(f"{field_name} must be a valid ID format")
243
+ return result
244
+
245
+ def validate_path(
246
+ self, path_value: str | Path, field_name: str = "path"
247
+ ) -> ValidationResult:
248
+ """Validate file path."""
249
+ result = ValidationResult(field=field_name)
250
+
251
+ if path_value is None:
252
+ return result
253
+
254
+ try:
255
+ path = Path(path_value)
256
+
257
+ # Check for path traversal attempts
258
+ if ".." in str(path):
259
+ result.add_error(f"{field_name} cannot contain '..' (path traversal)")
260
+
261
+ # Check for absolute paths when relative expected
262
+ if path.is_absolute() and field_name in ["filename", "relative_path"]:
263
+ result.add_error(f"{field_name} should be a relative path")
264
+
265
+ except Exception as e:
266
+ logger.error("path_validation_failed", path=str(path_value), error=str(e))
267
+ result.add_error(f"Invalid {field_name}: {str(e)}")
268
+
269
+ return result
270
+
271
+ def validate_github_issue_number(
272
+ self, issue_number: Any, field_name: str = "github_issue"
273
+ ) -> ValidationResult:
274
+ """Validate GitHub issue number."""
275
+ result = ValidationResult(field=field_name)
276
+
277
+ if issue_number is None:
278
+ return result
279
+
280
+ try:
281
+ num = int(issue_number)
282
+ if num <= 0:
283
+ result.add_error(f"{field_name} must be a positive integer")
284
+ except (ValueError, TypeError):
285
+ result.add_error(f"{field_name} must be a valid integer")
286
+
287
+ return result
288
+
289
+ def validate_labels(
290
+ self, labels: Any, field_name: str = "labels"
291
+ ) -> ValidationResult:
292
+ """Validate labels list."""
293
+ result = ValidationResult(field=field_name)
294
+
295
+ if labels is None:
296
+ return result
297
+
298
+ if not isinstance(labels, list):
299
+ result.add_error(f"{field_name} must be a list")
300
+ return result
301
+
302
+ for i, label in enumerate(labels):
303
+ if not isinstance(label, str):
304
+ result.add_error(f"{field_name}[{i}] must be a string")
305
+ elif len(label) > 50:
306
+ result.add_error(f"{field_name}[{i}] must be 50 characters or less")
307
+ elif not label.strip():
308
+ result.add_error(f"{field_name}[{i}] cannot be empty")
309
+
310
+ return result
@@ -0,0 +1,36 @@
1
+ """Schema-based validator for complex data structures."""
2
+
3
+ from typing import Any
4
+
5
+ from .field_validator import FieldValidator
6
+ from .result import ValidationResult
7
+
8
+
9
+ class SchemaValidator:
10
+ """Schema-based validator for complex data structures."""
11
+
12
+ def __init__(self, schema_name: str):
13
+ """Initialize SchemaValidator.
14
+
15
+ Args:
16
+ schema_name: Name of the schema being validated.
17
+ """
18
+ self.schema_name = schema_name
19
+ self.validators: dict[str, FieldValidator] = {}
20
+
21
+ def add_field(self, validator: FieldValidator) -> "SchemaValidator":
22
+ """Add a field validator to the schema."""
23
+ self.validators[validator.field_name] = validator
24
+ return self
25
+
26
+ def validate(self, data: dict[str, Any]) -> ValidationResult:
27
+ """Validate data against the schema."""
28
+ result = ValidationResult()
29
+
30
+ # Validate each field
31
+ for field_name, validator in self.validators.items():
32
+ value = data.get(field_name)
33
+ field_result = validator.validate(value)
34
+ result.merge(field_result)
35
+
36
+ return result
@@ -0,0 +1,50 @@
1
+ """Validation utility functions and helpers."""
2
+
3
+ from enum import Enum
4
+ from typing import Any
5
+
6
+ from roadmap.common.errors.exceptions import ValidationError
7
+
8
+ from .result import ValidationResult
9
+
10
+
11
+ class ValidationType(Enum):
12
+ """Types of validation checks."""
13
+
14
+ REQUIRED = "required"
15
+ FORMAT = "format"
16
+ RANGE = "range"
17
+ ENUM = "enum"
18
+ LENGTH = "length"
19
+ PATTERN = "pattern"
20
+ CUSTOM = "custom"
21
+
22
+
23
+ def validate_and_raise(validation_result: ValidationResult, context: str | None = None):
24
+ """Validate result and raise ValidationError if invalid."""
25
+ if not validation_result.is_valid:
26
+ error_message = "; ".join(validation_result.errors)
27
+ if context:
28
+ error_message = f"{context}: {error_message}"
29
+
30
+ raise ValidationError(domain_message=error_message, user_message=error_message)
31
+
32
+
33
+ def validate_frontmatter_structure(
34
+ frontmatter: dict[str, Any], expected_type: str
35
+ ) -> tuple[bool, list[str]]:
36
+ """Validate frontmatter structure for backward compatibility."""
37
+ from .roadmap_validator import RoadmapValidator
38
+
39
+ validator = RoadmapValidator()
40
+
41
+ if expected_type == "issue":
42
+ result = validator.validate_issue(frontmatter)
43
+ elif expected_type == "milestone":
44
+ result = validator.validate_milestone(frontmatter)
45
+ elif expected_type == "project":
46
+ result = validator.validate_project(frontmatter)
47
+ else:
48
+ return False, [f"Unknown type: {expected_type}"]
49
+
50
+ return result.is_valid, result.errors
@@ -0,0 +1 @@
1
+ """Core domain models and services for roadmap management."""
@@ -0,0 +1,30 @@
1
+ """Domain Layer - Pure Business Logic & Models.
2
+
3
+ This layer contains the core business models and domain logic that are
4
+ independent of any framework or external system. Models here should:
5
+
6
+ - Have no dependencies on infrastructure or presentation layers
7
+ - Contain only business rules and validation
8
+ - Be fully testable in isolation
9
+ - Represent core concepts of the problem domain
10
+
11
+ Models: Issue, Milestone, Project, Comment
12
+ """
13
+
14
+ from .comment import Comment
15
+ from .issue import Issue, IssueType, Priority, Status
16
+ from .milestone import Milestone, MilestoneStatus, RiskLevel
17
+ from .project import Project, ProjectStatus
18
+
19
+ __all__ = [
20
+ "Issue",
21
+ "IssueType",
22
+ "Priority",
23
+ "Status",
24
+ "Milestone",
25
+ "MilestoneStatus",
26
+ "RiskLevel",
27
+ "Project",
28
+ "ProjectStatus",
29
+ "Comment",
30
+ ]
@@ -0,0 +1,24 @@
1
+ """Comment model for issue discussions."""
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+
6
+
7
+ @dataclass
8
+ class Comment:
9
+ """Comment data model for issues."""
10
+
11
+ id: int # GitHub comment ID
12
+ issue_id: str # Local issue ID or GitHub issue number
13
+ author: str # GitHub username
14
+ body: str # Comment content (markdown)
15
+ created_at: datetime
16
+ updated_at: datetime
17
+ github_url: str | None = None # GitHub comment URL
18
+ in_reply_to: int | None = None # Comment ID this is a reply to (for threading)
19
+
20
+ def __str__(self) -> str:
21
+ """Return string representation."""
22
+ return (
23
+ f"Comment by {self.author} on {self.created_at.strftime('%Y-%m-%d %H:%M')}"
24
+ )
@@ -0,0 +1,15 @@
1
+ """Health status domain models.
2
+
3
+ This module defines health status enumerations used across the application
4
+ for reporting system and component health states.
5
+ """
6
+
7
+ from enum import Enum
8
+
9
+
10
+ class HealthStatus(Enum):
11
+ """Health status levels for system components."""
12
+
13
+ HEALTHY = "healthy"
14
+ DEGRADED = "degraded"
15
+ UNHEALTHY = "unhealthy"