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,475 @@
1
+ """Git integration and workflow commands."""
2
+
3
+ import sys
4
+ from typing import Literal
5
+
6
+ import click
7
+ import structlog
8
+ from rich.console import Console
9
+
10
+ from roadmap.adapters.cli.cli_command_helpers import require_initialized
11
+ from roadmap.adapters.cli.cli_error_handlers import handle_cli_error
12
+ from roadmap.adapters.cli.git.handlers.git_authentication_handler import (
13
+ GitAuthenticationHandler,
14
+ )
15
+ from roadmap.adapters.cli.git.handlers.git_branch_handler import GitBranchHandler
16
+ from roadmap.adapters.cli.git.handlers.git_connectivity_handler import (
17
+ GitConnectivityHandler,
18
+ )
19
+ from roadmap.adapters.cli.git.handlers.git_hooks_handler import GitHooksHandler
20
+ from roadmap.adapters.cli.git.hooks_config import hooks_config
21
+ from roadmap.common.console import get_console
22
+ from roadmap.core.services.github.github_integration_service import (
23
+ GitHubIntegrationService,
24
+ )
25
+
26
+ from .status_display import GitStatusDisplay
27
+
28
+ console = Console()
29
+ log = structlog.get_logger()
30
+
31
+
32
+ @click.group()
33
+ def git():
34
+ """Git integration and workflow management."""
35
+ pass
36
+
37
+
38
+ # Basic git commands - full implementation would be extracted from main CLI
39
+ @git.command("setup")
40
+ @click.option(
41
+ "--auth",
42
+ is_flag=True,
43
+ help="Set up GitHub authentication for sync operations",
44
+ )
45
+ @click.option(
46
+ "--update-token",
47
+ is_flag=True,
48
+ help="Update stored GitHub token",
49
+ )
50
+ @click.option(
51
+ "--git-auth",
52
+ is_flag=True,
53
+ help="Test and verify Git repository connectivity for self-hosting",
54
+ )
55
+ @click.pass_context
56
+ @require_initialized
57
+ def setup_git(ctx: click.Context, auth: bool, update_token: bool, git_auth: bool):
58
+ """Set up Git integration and authentication.
59
+
60
+ Configure GitHub authentication for sync operations or manage git workflow.
61
+ Supports both GitHub PAT tokens and vanilla Git self-hosting.
62
+ """
63
+ core = ctx.obj["core"]
64
+
65
+ try:
66
+ if auth or update_token:
67
+ _setup_github_auth(core, update_token)
68
+ elif git_auth:
69
+ _test_git_connectivity(core)
70
+ else:
71
+ console.print("โš™๏ธ Git setup", style="green")
72
+ console.print("\nAvailable options:")
73
+ console.print(
74
+ " roadmap git setup --auth Set up GitHub authentication"
75
+ )
76
+ console.print(
77
+ " roadmap git setup --update-token Update stored GitHub token"
78
+ )
79
+ console.print(
80
+ " roadmap git setup --git-auth Test Git repository connectivity"
81
+ )
82
+ console.print(" roadmap git hooks-install Install git hooks")
83
+ except Exception as e:
84
+ log.error("git_setup_failed", error=str(e), error_type=type(e).__name__)
85
+ console.print(f"โŒ Setup failed: {e}", style="bold red")
86
+ ctx.exit(1)
87
+
88
+
89
+ def _setup_github_auth(core, update_token: bool = False):
90
+ """Set up or update GitHub authentication.
91
+
92
+ Args:
93
+ core: RoadmapCore instance
94
+ update_token: If True, force update token; otherwise ask if exists
95
+
96
+ Raises:
97
+ Exception: If authentication setup fails
98
+ """
99
+ handler = GitAuthenticationHandler(console)
100
+ handler.setup_github_auth(update_token)
101
+
102
+
103
+ def _test_git_connectivity(core):
104
+ """Test and verify Git repository connectivity for self-hosting.
105
+
106
+ Args:
107
+ core: RoadmapCore instance
108
+
109
+ Raises:
110
+ Exception: If git connectivity test fails
111
+ """
112
+ handler = GitConnectivityHandler(console)
113
+ handler.test_git_connectivity(core)
114
+
115
+
116
+ @git.command("hooks-install")
117
+ @click.pass_context
118
+ @require_initialized
119
+ def install_hooks(ctx: click.Context):
120
+ """Install Git hooks for roadmap integration.
121
+
122
+ Installs hooks that automatically track commits, branch changes, and integrate
123
+ with your roadmap workflow.
124
+ """
125
+ core = ctx.obj["core"]
126
+
127
+ try:
128
+ handler = GitHooksHandler(console)
129
+ handler.install_hooks(core)
130
+ except Exception:
131
+ ctx.exit(1)
132
+
133
+
134
+ @git.command("hooks-uninstall")
135
+ @click.pass_context
136
+ @require_initialized
137
+ def uninstall_hooks(ctx: click.Context):
138
+ """Remove Git hooks for roadmap integration."""
139
+ core = ctx.obj["core"]
140
+
141
+ try:
142
+ handler = GitHooksHandler(console)
143
+ handler.uninstall_hooks(core)
144
+ except Exception:
145
+ ctx.exit(1)
146
+
147
+
148
+ @git.command("hooks-status")
149
+ @click.pass_context
150
+ @require_initialized
151
+ def hooks_status(ctx: click.Context):
152
+ """Show status of installed Git hooks."""
153
+ core = ctx.obj["core"]
154
+
155
+ try:
156
+ handler = GitHooksHandler(console)
157
+ handler.show_hooks_status(core)
158
+ except Exception:
159
+ ctx.exit(1)
160
+
161
+
162
+ @git.command("sync")
163
+ def _load_github_config(core) -> dict:
164
+ """Load GitHub config and normalise to a plain dict."""
165
+ gh_service = GitHubIntegrationService(core, core.roadmap_dir / "config.yaml")
166
+ config_result = gh_service.get_github_config()
167
+ if isinstance(config_result, tuple):
168
+ token, owner, repo = config_result
169
+ return {"owner": owner, "repo": repo, "token": token}
170
+ return config_result or {}
171
+
172
+
173
+ def _run_sync_apply(
174
+ orchestrator,
175
+ dry_run: bool,
176
+ verbose: bool,
177
+ force_local: bool,
178
+ force_github: bool,
179
+ console_inst,
180
+ ) -> None:
181
+ """Run a dry-run preview then, unless --dry-run, confirm and apply changes."""
182
+ report = orchestrator.sync_all_issues(dry_run=True)
183
+ if report.error:
184
+ console_inst.print(f"โŒ Sync error: {report.error}", style="bold red")
185
+ sys.exit(1)
186
+
187
+ if verbose:
188
+ report.display_verbose()
189
+ else:
190
+ report.display_brief()
191
+ console_inst.print()
192
+
193
+ if dry_run:
194
+ console_inst.print("[dim]Dry-run mode: No changes applied[/dim]")
195
+ return
196
+
197
+ if report.has_conflicts():
198
+ if force_local:
199
+ console_inst.print(
200
+ "[yellow]โš ๏ธ Conflicts detected - using --force-local[/yellow]"
201
+ )
202
+ elif force_github:
203
+ console_inst.print(
204
+ "[yellow]โš ๏ธ Conflicts detected - using --force-github[/yellow]"
205
+ )
206
+ else:
207
+ console_inst.print(
208
+ "[red]โŒ Conflicts detected. Use --force-local or --force-github[/red]"
209
+ )
210
+ sys.exit(1)
211
+
212
+ if report.has_changes() and not click.confirm("Apply these changes?"):
213
+ console_inst.print("โŒ Sync cancelled", style="red")
214
+ return
215
+
216
+ console_inst.print("[cyan]๐Ÿ”„ Applying changes...[/cyan]")
217
+ apply_report = orchestrator.sync_all_issues(
218
+ dry_run=False, force_local=force_local, force_remote=force_github
219
+ )
220
+ if apply_report.error:
221
+ console_inst.print(
222
+ f"โŒ Error applying sync: {apply_report.error}", style="bold red"
223
+ )
224
+ sys.exit(1)
225
+
226
+ console_inst.print()
227
+ console_inst.print("[green]โœ… Sync complete![/green]")
228
+ console_inst.print(f" โ€ข {apply_report.issues_up_to_date} up-to-date")
229
+ console_inst.print(f" โ€ข {apply_report.issues_needs_push} pushed")
230
+ console_inst.print(f" โ€ข {apply_report.issues_needs_pull} pulled")
231
+ if apply_report.conflicts_detected > 0:
232
+ console_inst.print(f" โ€ข {apply_report.conflicts_detected} conflicts resolved")
233
+
234
+
235
+ @git.command("sync")
236
+ @click.option(
237
+ "--dry-run",
238
+ is_flag=True,
239
+ help="Preview changes without applying",
240
+ )
241
+ @click.option("--verbose", is_flag=True, help="Show detailed sync information")
242
+ @click.option(
243
+ "--force-local",
244
+ is_flag=True,
245
+ help="Resolve conflicts by keeping local changes",
246
+ )
247
+ @click.option(
248
+ "--force-github",
249
+ is_flag=True,
250
+ help="Resolve conflicts by keeping GitHub changes",
251
+ )
252
+ @click.option(
253
+ "--backend",
254
+ type=click.Choice(["github", "git"]),
255
+ help="Sync backend to use (github or git)",
256
+ )
257
+ @click.pass_context
258
+ @require_initialized
259
+ def sync_git(
260
+ ctx: click.Context,
261
+ dry_run: bool,
262
+ verbose: bool,
263
+ force_local: bool,
264
+ force_github: bool,
265
+ backend: str | None,
266
+ ) -> None:
267
+ """Sync roadmap with remote repository.
268
+
269
+ Supports multiple backends:
270
+ - github: GitHub issues API (requires GitHub config)
271
+ - git: Vanilla Git push/pull (works with any Git hosting)
272
+
273
+ Two-way sync:
274
+ - Push local changes to remote
275
+ - Pull remote changes to local
276
+ - Detect and resolve conflicts
277
+
278
+ Examples:
279
+ # Preview what will be synced
280
+ roadmap git sync --dry-run
281
+
282
+ # Sync all changes
283
+ roadmap git sync
284
+
285
+ # Sync with specific backend
286
+ roadmap git sync --backend=git
287
+
288
+ # Sync with conflict resolution
289
+ roadmap git sync --force-local
290
+ """
291
+ from roadmap.adapters.cli.services.sync_service import get_sync_backend
292
+ from roadmap.adapters.sync import detect_backend_from_config
293
+
294
+ core = ctx.obj["core"]
295
+ console_inst = get_console()
296
+
297
+ try:
298
+ config = _load_github_config(core)
299
+ backend_type: Literal["github", "git"] = (
300
+ backend if backend else detect_backend_from_config(config) # type: ignore[assignment]
301
+ )
302
+ console_inst.print(
303
+ f"๐Ÿ”„ Syncing with {backend_type.upper()} backend", style="bold cyan"
304
+ )
305
+
306
+ sync_backend = get_sync_backend(backend_type, core, config)
307
+ if not sync_backend:
308
+ console_inst.print(
309
+ f"โŒ Failed to initialize {backend_type} backend", style="bold red"
310
+ )
311
+ hint = (
312
+ " Ensure you're in a Git repository"
313
+ if backend_type == "git"
314
+ else " GitHub config may be missing or incomplete"
315
+ )
316
+ console_inst.print(hint, style="yellow")
317
+ sys.exit(1)
318
+
319
+ from roadmap.adapters.sync import SyncMergeOrchestrator
320
+ from roadmap.core.services.sync.sync_conflict_resolver import (
321
+ SyncConflictResolver,
322
+ )
323
+ from roadmap.core.services.sync.sync_state_comparator import SyncStateComparator
324
+
325
+ orchestrator = SyncMergeOrchestrator(
326
+ core,
327
+ sync_backend,
328
+ state_comparator=SyncStateComparator(),
329
+ conflict_resolver=SyncConflictResolver(),
330
+ )
331
+ _run_sync_apply(
332
+ orchestrator, dry_run, verbose, force_local, force_github, console_inst
333
+ )
334
+ except Exception as e:
335
+ handle_cli_error(
336
+ error=e,
337
+ operation="sync",
338
+ entity_type="git",
339
+ entity_id="repository",
340
+ context={},
341
+ )
342
+
343
+
344
+ @git.command("status")
345
+ @click.pass_context
346
+ @require_initialized
347
+ def git_status(ctx: click.Context):
348
+ """Show Git repository status and roadmap integration info."""
349
+ core = ctx.obj["core"]
350
+
351
+ display = GitStatusDisplay(console)
352
+
353
+ try:
354
+ git_context = core.git.get_context()
355
+
356
+ if not git_context.get("is_git_repo", False):
357
+ display.show_not_git_repo()
358
+ return
359
+
360
+ display.show_header()
361
+ display.show_repository_info(git_context)
362
+ display.show_current_branch(git_context)
363
+
364
+ branch_issues = core.git.get_branch_linked_issues()
365
+ current_branch = git_context.get("current_branch", "")
366
+ display.show_branch_issue_links(branch_issues, current_branch, core)
367
+
368
+ display.show_recent_commits(core)
369
+
370
+ except Exception as e:
371
+ handle_cli_error(
372
+ error=e,
373
+ operation="git_status",
374
+ entity_type="git",
375
+ entity_id="repository",
376
+ context={},
377
+ fatal=False,
378
+ )
379
+ display.show_error(e)
380
+
381
+
382
+ @git.command("branch")
383
+ @click.argument("issue_id")
384
+ @click.option(
385
+ "--checkout/--no-checkout", default=True, help="Checkout the branch after creation"
386
+ )
387
+ @click.pass_context
388
+ def git_branch(ctx: click.Context, issue_id: str, checkout: bool):
389
+ """Create a Git branch for an issue."""
390
+ core = ctx.obj["core"]
391
+
392
+ handler = GitBranchHandler(console)
393
+ handler.create_branch(core, issue_id, checkout=checkout)
394
+
395
+
396
+ def _validate_branch_environment(core) -> bool:
397
+ """Validate roadmap and git environment for branch creation.
398
+
399
+ Args:
400
+ core: RoadmapCore instance
401
+
402
+ Returns:
403
+ True if environment is valid
404
+ """
405
+ handler = GitBranchHandler(console)
406
+ return handler.validate_branch_environment(core)
407
+
408
+
409
+ def _get_and_validate_issue(core, issue_id: str):
410
+ """Get and validate issue exists.
411
+
412
+ Args:
413
+ core: RoadmapCore instance
414
+ issue_id: Issue ID to retrieve
415
+
416
+ Returns:
417
+ Issue object or None if not found
418
+ """
419
+ handler = GitBranchHandler(console)
420
+ return handler.get_and_validate_issue(core, issue_id)
421
+
422
+
423
+ def _safe_create_branch(git, issue, checkout=True) -> bool:
424
+ """Safely create branch with fallback attempts.
425
+
426
+ Args:
427
+ git: Git executor
428
+ issue: Issue object
429
+ checkout: Whether to checkout the new branch
430
+
431
+ Returns:
432
+ True if branch was created
433
+ """
434
+ handler = GitBranchHandler(console)
435
+ return handler._safe_create_branch(git, issue, checkout=checkout)
436
+
437
+
438
+ def _display_branch_success(branch_name: str, issue, checkout: bool) -> None:
439
+ """Display success messages for branch creation.
440
+
441
+ Args:
442
+ branch_name: Name of created branch
443
+ issue: Issue object
444
+ checkout: Whether branch was checked out
445
+ """
446
+ handler = GitBranchHandler(console)
447
+ handler._display_branch_success(branch_name, issue, checkout)
448
+
449
+
450
+ def _update_issue_status_if_needed(core, issue, issue_id: str) -> None:
451
+ """Update issue status to in-progress if it's todo.
452
+
453
+ Args:
454
+ core: RoadmapCore instance
455
+ issue: Issue object
456
+ issue_id: Issue ID
457
+ """
458
+ handler = GitBranchHandler(console)
459
+ handler._update_issue_status_if_needed(core, issue, issue_id)
460
+
461
+
462
+ @git.command("link")
463
+ @click.argument("issue_id")
464
+ @click.pass_context
465
+ @require_initialized
466
+ def git_link(ctx: click.Context, issue_id: str):
467
+ """Link an issue to the current Git branch."""
468
+ core = ctx.obj["core"]
469
+
470
+ handler = GitBranchHandler(console)
471
+ handler.link_issue_to_branch(core, issue_id)
472
+
473
+
474
+ # Register hooks-config command
475
+ git.add_command(hooks_config, name="hooks-config")
@@ -0,0 +1 @@
1
+ """Git command handlers for CLI operations."""
@@ -0,0 +1,124 @@
1
+ """Handler for GitHub authentication setup in CLI."""
2
+
3
+ import click
4
+ import structlog
5
+ from rich.console import Console
6
+
7
+ from roadmap.adapters.github.github import GitHubClient
8
+ from roadmap.infrastructure.security.credentials import CredentialManager
9
+
10
+ logger = structlog.get_logger()
11
+
12
+
13
+ class GitAuthenticationHandler:
14
+ """Handles GitHub authentication setup and management."""
15
+
16
+ def __init__(self, console: Console):
17
+ """Initialize handler with console for output.
18
+
19
+ Args:
20
+ console: Rich Console instance
21
+ """
22
+ self.console = console
23
+ self.cred_manager = CredentialManager()
24
+
25
+ def setup_github_auth(self, update_token: bool = False):
26
+ """Set up or update GitHub authentication.
27
+
28
+ Args:
29
+ update_token: If True, force update token; otherwise ask if exists
30
+
31
+ Raises:
32
+ Exception: If authentication setup fails
33
+ """
34
+ existing_token = None
35
+
36
+ if not update_token:
37
+ try:
38
+ existing_token = self.cred_manager.get_token()
39
+ if existing_token:
40
+ self.console.print("๐Ÿ” Found existing GitHub credentials")
41
+ if click.confirm("Use existing GitHub token?"):
42
+ logger.info("github_auth_using_existing")
43
+ self.console.print("โœ… GitHub authentication configured")
44
+ return
45
+ elif not click.confirm("Update GitHub token?"):
46
+ self.console.print("Skipped GitHub authentication setup")
47
+ return
48
+ except Exception as e:
49
+ logger.debug(
50
+ "existing_token_check_failed",
51
+ error=str(e),
52
+ action="check_existing_token",
53
+ )
54
+
55
+ # Get new token from user
56
+ self.console.print("๐Ÿ”‘ GitHub Authentication Setup", style="bold cyan")
57
+ self.console.print()
58
+ self.console.print(
59
+ "You'll need a Personal Access Token with 'repo' scope to sync with GitHub."
60
+ )
61
+ self.console.print("Create one here: https://github.com/settings/tokens/new")
62
+ self.console.print()
63
+ self.console.print(
64
+ "Required scopes: repo (full control of private repositories)",
65
+ style="dim",
66
+ )
67
+ self.console.print()
68
+
69
+ token = click.prompt("Enter your GitHub Personal Access Token", hide_input=True)
70
+
71
+ if not token or len(token.strip()) == 0:
72
+ self.console.print("โŒ Token cannot be empty", style="bold red")
73
+ logger.warning("github_auth_empty_token", severity="operational")
74
+ return
75
+
76
+ # Validate token
77
+ self.console.print("๐Ÿงช Validating GitHub token...", style="cyan")
78
+ logger.debug("github_token_validating")
79
+
80
+ try:
81
+ client = GitHubClient(token)
82
+ # Test connection and authentication
83
+ user_data = client.test_authentication()
84
+ username = user_data.get("login", "user")
85
+ self.console.print(
86
+ f"โœ… Token valid (authenticated as @{username})", style="green"
87
+ )
88
+ logger.info("github_token_valid", username=username)
89
+ except Exception as e:
90
+ self.console.print(f"โŒ Token validation failed: {e}", style="bold red")
91
+ logger.error(
92
+ "github_token_validation_error",
93
+ error=str(e),
94
+ error_type=type(e).__name__,
95
+ severity="infrastructure",
96
+ )
97
+ return
98
+
99
+ # Store token
100
+ try:
101
+ if self.cred_manager.store_token(token):
102
+ self.console.print("โœ… GitHub authentication configured", style="green")
103
+ self.console.print(
104
+ "Token stored securely in system keychain",
105
+ style="dim",
106
+ )
107
+ logger.info("github_token_stored")
108
+ else:
109
+ self.console.print(
110
+ "โš ๏ธ Token validation succeeded but storage failed",
111
+ style="yellow",
112
+ )
113
+ logger.warning("github_token_storage_failed", severity="operational")
114
+ except Exception as e:
115
+ self.console.print(
116
+ f"โš ๏ธ Token validation succeeded but could not store: {e}",
117
+ style="yellow",
118
+ )
119
+ logger.warning(
120
+ "github_token_storage_error",
121
+ error=str(e),
122
+ error_type=type(e).__name__,
123
+ severity="system_error",
124
+ )