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