@ngocsangairvds/vsaf 3.1.26 → 3.2.1

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 (305) hide show
  1. package/package.json +2 -2
  2. package/src/global.js +70 -10
  3. package/tools/skills/vds-scripts-skill/.openskills.json +6 -0
  4. package/tools/skills/vds-scripts-skill/QUALITY.md +44 -0
  5. package/tools/skills/vds-scripts-skill/SKILL.md +135 -0
  6. package/tools/skills/vds-scripts-skill/references/audit-commands.md +171 -0
  7. package/tools/skills/vds-scripts-skill/references/capability-index.md +34 -0
  8. package/tools/skills/vds-scripts-skill/references/development-commands.md +12 -0
  9. package/tools/skills/vds-scripts-skill/references/google-sheets.md +73 -0
  10. package/tools/skills/vds-scripts-skill/references/integration-commands.md +17 -0
  11. package/tools/skills/vds-scripts-skill/references/platform-bootstrap.md +31 -0
  12. package/tools/skills/vds-scripts-skill/references/specialist-routing.md +14 -0
  13. package/tools/skills/vds-scripts-skill/references/validation-commands.md +15 -0
  14. package/tools/skills/vsaf-build/SKILL.md +32 -2
  15. package/tools/skills/vsaf-push-prd/SKILL.md +43 -40
  16. package/tools/skills/vsaf-push-srs/SKILL.md +44 -41
  17. package/tools/skills/vsaf-ship/SKILL.md +41 -10
  18. package/tools/skills/vsaf-test/SKILL.md +8 -0
  19. package/tools/vds-scripts/.mcp.json +11 -0
  20. package/tools/vds-scripts/.secrets.baseline +133 -0
  21. package/tools/vds-scripts/AGENTS.md +152 -0
  22. package/tools/vds-scripts/CLAUDE.md +101 -0
  23. package/tools/vds-scripts/CLI_COMMAND_OPTIMIZATION.md +156 -0
  24. package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +131 -0
  25. package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +45 -0
  26. package/tools/vds-scripts/README.md +97 -0
  27. package/tools/vds-scripts/bitbucket_manifest_mapping.toml +34 -0
  28. package/tools/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +258 -0
  29. package/tools/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +393 -0
  30. package/tools/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +61 -0
  31. package/tools/vds-scripts/bitbucket_orchestrator/FEATURES.md +908 -0
  32. package/tools/vds-scripts/bitbucket_orchestrator/README.md +687 -0
  33. package/tools/vds-scripts/bitbucket_orchestrator/pyproject.toml +40 -0
  34. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +20 -0
  35. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +657 -0
  36. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +2108 -0
  37. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +2534 -0
  38. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +171 -0
  39. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +67 -0
  40. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +185 -0
  41. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +244 -0
  42. package/tools/vds-scripts/bitbucket_orchestrator/tests/__init__.py +8 -0
  43. package/tools/vds-scripts/bitbucket_orchestrator/tests/conftest.py +65 -0
  44. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +151 -0
  45. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +546 -0
  46. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +145 -0
  47. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +115 -0
  48. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client.py +157 -0
  49. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +79 -0
  50. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +163 -0
  51. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +32 -0
  52. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +194 -0
  53. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +164 -0
  54. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +179 -0
  55. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +119 -0
  56. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +156 -0
  57. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code.py +98 -0
  58. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +282 -0
  59. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +335 -0
  60. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +147 -0
  61. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_config.py +131 -0
  62. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +352 -0
  63. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +371 -0
  64. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +204 -0
  65. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +261 -0
  66. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +270 -0
  67. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +204 -0
  68. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +334 -0
  69. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +343 -0
  70. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +270 -0
  71. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +189 -0
  72. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +233 -0
  73. package/tools/vds-scripts/bitbucket_orchestrator/uv.lock +742 -0
  74. package/tools/vds-scripts/confluence_orchestrator/Dockerfile +19 -0
  75. package/tools/vds-scripts/confluence_orchestrator/README.md +412 -0
  76. package/tools/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +127 -0
  77. package/tools/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +108 -0
  78. package/tools/vds-scripts/confluence_orchestrator/pyproject.toml +48 -0
  79. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +20 -0
  80. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +2532 -0
  81. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +175 -0
  82. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +290 -0
  83. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +94 -0
  84. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +1835 -0
  85. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +80 -0
  86. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +109 -0
  87. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +1114 -0
  88. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +165 -0
  89. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +78 -0
  90. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +121 -0
  91. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +213 -0
  92. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +305 -0
  93. package/tools/vds-scripts/confluence_orchestrator/sync_png_attachments.py +305 -0
  94. package/tools/vds-scripts/confluence_orchestrator/tests/__init__.py +0 -0
  95. package/tools/vds-scripts/confluence_orchestrator/tests/conftest.py +8 -0
  96. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +224 -0
  97. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +188 -0
  98. package/tools/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +247 -0
  99. package/tools/vds-scripts/confluence_orchestrator/tests/test_cli.py +499 -0
  100. package/tools/vds-scripts/confluence_orchestrator/tests/test_config.py +83 -0
  101. package/tools/vds-scripts/confluence_orchestrator/tests/test_content.py +186 -0
  102. package/tools/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +27 -0
  103. package/tools/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +2250 -0
  104. package/tools/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +223 -0
  105. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing.py +71 -0
  106. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +37 -0
  107. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +44 -0
  108. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +49 -0
  109. package/tools/vds-scripts/confluence_orchestrator/tests/test_export.py +230 -0
  110. package/tools/vds-scripts/confluence_orchestrator/tests/test_history.py +204 -0
  111. package/tools/vds-scripts/confluence_orchestrator/tests/test_http.py +117 -0
  112. package/tools/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +91 -0
  113. package/tools/vds-scripts/confluence_orchestrator/tests/test_reporting.py +24 -0
  114. package/tools/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +34 -0
  115. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_management.py +237 -0
  116. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +332 -0
  117. package/tools/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +388 -0
  118. package/tools/vds-scripts/confluence_orchestrator/uv.lock +1023 -0
  119. package/tools/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +119 -0
  120. package/tools/vds-scripts/git_orchestrator/README.md +280 -0
  121. package/tools/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +152 -0
  122. package/tools/vds-scripts/git_orchestrator/pyproject.toml +35 -0
  123. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +7 -0
  124. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +4 -0
  125. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +847 -0
  126. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +63 -0
  127. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +129 -0
  128. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +819 -0
  129. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +53 -0
  130. package/tools/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
  131. package/tools/vds-scripts/git_orchestrator/tests/test_cli_settings.py +21 -0
  132. package/tools/vds-scripts/git_orchestrator/tests/test_integration.py +74 -0
  133. package/tools/vds-scripts/git_orchestrator/tests/test_manifest.py +79 -0
  134. package/tools/vds-scripts/git_orchestrator/tests/test_orchestrator.py +204 -0
  135. package/tools/vds-scripts/git_orchestrator/tests/test_public_api.py +236 -0
  136. package/tools/vds-scripts/git_orchestrator/tests/test_resilience.py +345 -0
  137. package/tools/vds-scripts/git_orchestrator/uv.lock +271 -0
  138. package/tools/vds-scripts/jira_orchestrator/README.md +770 -0
  139. package/tools/vds-scripts/jira_orchestrator/pyproject.toml +39 -0
  140. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +1 -0
  141. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +1320 -0
  142. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +2271 -0
  143. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +138 -0
  144. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +67 -0
  145. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +65 -0
  146. package/tools/vds-scripts/jira_orchestrator/tests/__init__.py +1 -0
  147. package/tools/vds-scripts/jira_orchestrator/tests/conftest.py +86 -0
  148. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +54 -0
  149. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +69 -0
  150. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +57 -0
  151. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +45 -0
  152. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +117 -0
  153. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +54 -0
  154. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +42 -0
  155. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +42 -0
  156. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +76 -0
  157. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +91 -0
  158. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +110 -0
  159. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +133 -0
  160. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +41 -0
  161. package/tools/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +164 -0
  162. package/tools/vds-scripts/jira_orchestrator/tests/test_agile.py +256 -0
  163. package/tools/vds-scripts/jira_orchestrator/tests/test_application_properties.py +193 -0
  164. package/tools/vds-scripts/jira_orchestrator/tests/test_backlog.py +91 -0
  165. package/tools/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +277 -0
  166. package/tools/vds-scripts/jira_orchestrator/tests/test_cli.py +106 -0
  167. package/tools/vds-scripts/jira_orchestrator/tests/test_components.py +106 -0
  168. package/tools/vds-scripts/jira_orchestrator/tests/test_config.py +164 -0
  169. package/tools/vds-scripts/jira_orchestrator/tests/test_dashboard.py +122 -0
  170. package/tools/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +207 -0
  171. package/tools/vds-scripts/jira_orchestrator/tests/test_filter_management.py +333 -0
  172. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +164 -0
  173. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_links.py +257 -0
  174. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +171 -0
  175. package/tools/vds-scripts/jira_orchestrator/tests/test_link_types.py +314 -0
  176. package/tools/vds-scripts/jira_orchestrator/tests/test_parse_set.py +37 -0
  177. package/tools/vds-scripts/jira_orchestrator/tests/test_permissions.py +273 -0
  178. package/tools/vds-scripts/jira_orchestrator/tests/test_reindex.py +81 -0
  179. package/tools/vds-scripts/jira_orchestrator/tests/test_remote_links.py +254 -0
  180. package/tools/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +170 -0
  181. package/tools/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +114 -0
  182. package/tools/vds-scripts/jira_orchestrator/tests/test_user_management.py +226 -0
  183. package/tools/vds-scripts/jira_orchestrator/tests/test_version_management.py +339 -0
  184. package/tools/vds-scripts/jira_orchestrator/tests/test_watchers.py +101 -0
  185. package/tools/vds-scripts/jira_orchestrator/tests/test_worklog.py +223 -0
  186. package/tools/vds-scripts/jira_orchestrator/uv.lock +738 -0
  187. package/tools/vds-scripts/mcp_server/Dockerfile +34 -0
  188. package/tools/vds-scripts/mcp_server/README.md +140 -0
  189. package/tools/vds-scripts/mcp_server/pyproject.toml +42 -0
  190. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +4 -0
  191. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/config.py +36 -0
  192. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/server.py +66 -0
  193. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +14 -0
  194. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +47 -0
  195. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +59 -0
  196. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +71 -0
  197. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +63 -0
  198. package/tools/vds-scripts/mcp_server/tests/__init__.py +2 -0
  199. package/tools/vds-scripts/mcp_server/tests/conftest.py +29 -0
  200. package/tools/vds-scripts/mcp_server/tests/unit/__init__.py +2 -0
  201. package/tools/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +25 -0
  202. package/tools/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +25 -0
  203. package/tools/vds-scripts/mcp_server/tests/unit/test_git_tools.py +32 -0
  204. package/tools/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +32 -0
  205. package/tools/vds-scripts/mcp_server/tests/verification/__init__.py +2 -0
  206. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +40 -0
  207. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +37 -0
  208. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +47 -0
  209. package/tools/vds-scripts/mcp_server/uv.lock +1032 -0
  210. package/tools/vds-scripts/mypy.ini +5 -0
  211. package/tools/vds-scripts/pyproject.toml +29 -0
  212. package/tools/vds-scripts/repo-manifest.yaml +273 -0
  213. package/tools/vds-scripts/repo-manifest.yaml.example +25 -0
  214. package/tools/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +706 -0
  215. package/tools/vds-scripts/scripts/BRD-Validation-README.md +308 -0
  216. package/tools/vds-scripts/scripts/README.md +162 -0
  217. package/tools/vds-scripts/scripts/bootstrap_uv.sh +30 -0
  218. package/tools/vds-scripts/scripts/brd-validation-environment.json +51 -0
  219. package/tools/vds-scripts/scripts/brd-validation-test-results.json +13023 -0
  220. package/tools/vds-scripts/scripts/brd_coverage_report.json +276 -0
  221. package/tools/vds-scripts/scripts/create_memory_session.py +35 -0
  222. package/tools/vds-scripts/scripts/deployment/load_docker_images_offline.sh +90 -0
  223. package/tools/vds-scripts/scripts/final_completion_report.md +139 -0
  224. package/tools/vds-scripts/scripts/folder_structure_report.json +321 -0
  225. package/tools/vds-scripts/scripts/generate_completion_report.py +125 -0
  226. package/tools/vds-scripts/scripts/generate_intellij_modules.py +150 -0
  227. package/tools/vds-scripts/scripts/link_integrity_report.json +807 -0
  228. package/tools/vds-scripts/scripts/move_audit_artifact_pages.py +255 -0
  229. package/tools/vds-scripts/scripts/move_audit_artifact_pages_rest.py +165 -0
  230. package/tools/vds-scripts/scripts/move_wrong_dept_pages.py +216 -0
  231. package/tools/vds-scripts/scripts/save_intellij_memories.py +120 -0
  232. package/tools/vds-scripts/scripts/save_memories_to_vds_ai.py +83 -0
  233. package/tools/vds-scripts/scripts/save_memories_vds_style.py +129 -0
  234. package/tools/vds-scripts/scripts/search_intellij_memories.py +50 -0
  235. package/tools/vds-scripts/scripts/setup_intellij_workspace.py +65 -0
  236. package/tools/vds-scripts/scripts/target-state-automation/README.md +89 -0
  237. package/tools/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +27 -0
  238. package/tools/vds-scripts/scripts/target-state-automation/coordination.sh +114 -0
  239. package/tools/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +25 -0
  240. package/tools/vds-scripts/scripts/target-state-automation/docs_root.sh +22 -0
  241. package/tools/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +22 -0
  242. package/tools/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +25 -0
  243. package/tools/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +17 -0
  244. package/tools/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +25 -0
  245. package/tools/vds-scripts/scripts/target-state-automation/sync_confluence.sh +30 -0
  246. package/tools/vds-scripts/scripts/target-state-automation/update_dependencies.sh +19 -0
  247. package/tools/vds-scripts/scripts/target-state-automation/validate_links.sh +86 -0
  248. package/tools/vds-scripts/scripts/target-state-automation/validate_markdown.sh +52 -0
  249. package/tools/vds-scripts/scripts/target-state-automation/validate_schemas.sh +26 -0
  250. package/tools/vds-scripts/scripts/target-state-automation/validate_structure.sh +98 -0
  251. package/tools/vds-scripts/scripts/update_modules_xml.py +190 -0
  252. package/tools/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +128 -0
  253. package/tools/vds-scripts/scripts/validate_brd_coverage.py +179 -0
  254. package/tools/vds-scripts/scripts/validate_folder_structure.py +240 -0
  255. package/tools/vds-scripts/scripts/validate_link_integrity.py +272 -0
  256. package/tools/vds-scripts/scripts/vds_sh_helpers.sh +180 -0
  257. package/tools/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +26 -0
  258. package/tools/vds-scripts/scripts/worktree_uv.sh +48 -0
  259. package/tools/vds-scripts/uv.lock +8 -0
  260. package/tools/vds-scripts/vds_cli/README.md +126 -0
  261. package/tools/vds-scripts/vds_cli/VERIFICATION_REPORT.md +41 -0
  262. package/tools/vds-scripts/vds_cli/pyproject.toml +38 -0
  263. package/tools/vds-scripts/vds_cli/src/vds_cli/__init__.py +3 -0
  264. package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +173 -0
  265. package/tools/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +1203 -0
  266. package/tools/vds-scripts/vds_cli/src/vds_cli/env.py +41 -0
  267. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +3 -0
  268. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +198 -0
  269. package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +93 -0
  270. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_api.py +647 -0
  271. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_service.py +266 -0
  272. package/tools/vds-scripts/vds_cli/tests/__init__.py +2 -0
  273. package/tools/vds-scripts/vds_cli/tests/conftest.py +49 -0
  274. package/tools/vds-scripts/vds_cli/tests/unit/__init__.py +2 -0
  275. package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +143 -0
  276. package/tools/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +422 -0
  277. package/tools/vds-scripts/vds_cli/tests/unit/test_env.py +51 -0
  278. package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +72 -0
  279. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_api.py +357 -0
  280. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_service.py +160 -0
  281. package/tools/vds-scripts/vds_cli/tests/verification/__init__.py +2 -0
  282. package/tools/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +33 -0
  283. package/tools/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +35 -0
  284. package/tools/vds-scripts/vds_cli/tests/verification/test_jira_real.py +41 -0
  285. package/tools/vds-scripts/vds_cli/uv.lock +524 -0
  286. package/tools/vds-scripts/vds_cli_common/README.md +190 -0
  287. package/tools/vds-scripts/vds_cli_common/pyproject.toml +92 -0
  288. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +34 -0
  289. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +139 -0
  290. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +201 -0
  291. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +119 -0
  292. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +318 -0
  293. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +284 -0
  294. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +78 -0
  295. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +213 -0
  296. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +85 -0
  297. package/tools/vds-scripts/vds_cli_common/tests/__init__.py +1 -0
  298. package/tools/vds-scripts/vds_cli_common/tests/test_completers.py +148 -0
  299. package/tools/vds-scripts/vds_cli_common/tests/test_context.py +192 -0
  300. package/tools/vds-scripts/vds_cli_common/tests/test_env.py +102 -0
  301. package/tools/vds-scripts/vds_cli_common/tests/test_errors.py +186 -0
  302. package/tools/vds-scripts/vds_cli_common/tests/test_output.py +229 -0
  303. package/tools/vds-scripts/vds_cli_common/tests/test_paths.py +61 -0
  304. package/tools/vds-scripts/vds_cli_common/tests/test_testing.py +138 -0
  305. package/tools/vds-scripts/vds_cli_common/tests/test_version.py +64 -0
@@ -0,0 +1,371 @@
1
+ """Unit tests for factory functions (TSK-223).
2
+
3
+ Tests for create_client() and create_async_client() factory functions
4
+ that auto-load credentials from ~/.vds/.env.
5
+
6
+ References:
7
+ - FR-21.2.2: Factory functions that load credentials from `~/.vds/.env` automatically
8
+ - TSK-223: Factory functions for Bitbucket
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from pathlib import Path
14
+ from unittest.mock import MagicMock, patch
15
+
16
+ import pytest
17
+ from vds_cli_common.paths import get_shared_env_path
18
+
19
+ from vds_bitbucket_orchestrator.factory import (
20
+ DEFAULT_VDS_ENV_PATH,
21
+ create_async_client,
22
+ create_client,
23
+ )
24
+
25
+
26
+ def write_env(tmp_path: Path, content: str) -> Path:
27
+ """Write a temporary .env file for testing."""
28
+ env_path = tmp_path / ".env"
29
+ env_path.write_text(content)
30
+ return env_path
31
+
32
+
33
+ def clear_runtime_env(monkeypatch: pytest.MonkeyPatch) -> None:
34
+ """Clear runtime environment variables for testing."""
35
+ for key in (
36
+ "VDS_USERNAME",
37
+ "VDS_PASSWORD",
38
+ "BITBUCKET_TOKEN",
39
+ "VDS_BITBUCKET_URL",
40
+ "BITBUCKET_BASE_URL",
41
+ "VDS_BITBUCKET_HTTP_BASE",
42
+ "BITBUCKET_CLOUD_WORKSPACE",
43
+ "BITBUCKET_MODE",
44
+ ):
45
+ monkeypatch.delenv(key, raising=False)
46
+
47
+
48
+ class TestDefaultEnvPath:
49
+ """Test default environment path configuration."""
50
+
51
+ def test_default_env_path_is_shared_env(self) -> None:
52
+ """Test that default env path uses the shared VDS env helper."""
53
+ expected = get_shared_env_path()
54
+ assert DEFAULT_VDS_ENV_PATH == expected
55
+
56
+
57
+ class TestCreateClient:
58
+ """Tests for create_client() factory function."""
59
+
60
+ def test_create_client_with_valid_credentials(
61
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
62
+ ) -> None:
63
+ """Test creating client with valid credentials from env file."""
64
+ clear_runtime_env(monkeypatch)
65
+ env_path = write_env(
66
+ tmp_path,
67
+ """
68
+ VDS_USERNAME=test_user
69
+ VDS_PASSWORD=test_pass
70
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
71
+ BITBUCKET_MODE=server
72
+ """.strip(),
73
+ )
74
+
75
+ # Mock the BitbucketClient to avoid actual API calls
76
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
77
+ mock_instance = MagicMock()
78
+ mock_client.return_value = mock_instance
79
+
80
+ client = create_client(env_path=env_path)
81
+
82
+ # Verify client was created
83
+ assert client is mock_instance
84
+ mock_client.assert_called_once()
85
+
86
+ # Verify settings were passed correctly
87
+ call_args = mock_client.call_args
88
+ settings = call_args[0][0] # First positional arg
89
+ assert settings.username == "test_user"
90
+ assert settings.password == "test_pass"
91
+ assert str(settings.base_url) == "https://bitbucket.test.com"
92
+ assert settings.mode == "server"
93
+
94
+ def test_create_client_with_token_auth(
95
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
96
+ ) -> None:
97
+ """Test creating client with token authentication."""
98
+ clear_runtime_env(monkeypatch)
99
+ env_path = write_env(
100
+ tmp_path,
101
+ """
102
+ BITBUCKET_TOKEN=test_token_12345
103
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
104
+ """.strip(),
105
+ )
106
+
107
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
108
+ mock_instance = MagicMock()
109
+ mock_client.return_value = mock_instance
110
+
111
+ client = create_client(env_path=env_path)
112
+
113
+ assert client is mock_instance
114
+ call_args = mock_client.call_args
115
+ settings = call_args[0][0]
116
+ assert settings.token == "test_token_12345"
117
+
118
+ def test_create_client_mode_override(
119
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
120
+ ) -> None:
121
+ """Test that mode parameter overrides env file setting."""
122
+ clear_runtime_env(monkeypatch)
123
+ env_path = write_env(
124
+ tmp_path,
125
+ """
126
+ VDS_USERNAME=test_user
127
+ VDS_PASSWORD=test_pass
128
+ BITBUCKET_MODE=server
129
+ BITBUCKET_CLOUD_WORKSPACE=testworkspace
130
+ """.strip(),
131
+ )
132
+
133
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
134
+ mock_instance = MagicMock()
135
+ mock_client.return_value = mock_instance
136
+
137
+ # Override mode to cloud
138
+ client = create_client(env_path=env_path, mode="cloud")
139
+
140
+ assert client is mock_instance
141
+ call_args = mock_client.call_args
142
+ settings = call_args[0][0]
143
+ assert settings.mode == "cloud"
144
+
145
+ def test_create_client_server_mode_default(
146
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
147
+ ) -> None:
148
+ """Test that server mode is the default when not specified."""
149
+ clear_runtime_env(monkeypatch)
150
+ env_path = write_env(
151
+ tmp_path,
152
+ """
153
+ VDS_USERNAME=test_user
154
+ VDS_PASSWORD=test_pass
155
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
156
+ """.strip(),
157
+ )
158
+
159
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
160
+ mock_instance = MagicMock()
161
+ mock_client.return_value = mock_instance
162
+
163
+ client = create_client(env_path=env_path)
164
+
165
+ call_args = mock_client.call_args
166
+ settings = call_args[0][0]
167
+ assert settings.mode == "server"
168
+
169
+ def test_create_client_custom_timeout(
170
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
171
+ ) -> None:
172
+ """Test creating client with custom timeout."""
173
+ clear_runtime_env(monkeypatch)
174
+ env_path = write_env(
175
+ tmp_path,
176
+ """
177
+ VDS_USERNAME=test_user
178
+ VDS_PASSWORD=test_pass
179
+ """.strip(),
180
+ )
181
+
182
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
183
+ mock_instance = MagicMock()
184
+ mock_client.return_value = mock_instance
185
+
186
+ create_client(env_path=env_path, timeout=60)
187
+
188
+ call_args = mock_client.call_args
189
+ assert call_args.kwargs.get("timeout") == 60
190
+
191
+ def test_create_client_strict_mode_fails_without_credentials(
192
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
193
+ ) -> None:
194
+ """Test that strict mode raises error when credentials are missing."""
195
+ clear_runtime_env(monkeypatch)
196
+ env_path = write_env(tmp_path, "")
197
+
198
+ with pytest.raises(ValueError, match="Missing credentials"):
199
+ create_client(env_path=env_path, strict=True)
200
+
201
+ def test_create_client_non_strict_mode_allows_missing_credentials(
202
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
203
+ ) -> None:
204
+ """Test that non-strict mode allows missing credentials."""
205
+ clear_runtime_env(monkeypatch)
206
+ env_path = write_env(
207
+ tmp_path,
208
+ """
209
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
210
+ """.strip(),
211
+ )
212
+
213
+ # Non-strict mode should not raise during settings load
214
+ # But BitbucketClient will still validate credentials
215
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
216
+ mock_instance = MagicMock()
217
+ mock_client.return_value = mock_instance
218
+
219
+ # This should not raise during load_settings
220
+ client = create_client(env_path=env_path, strict=False)
221
+ assert client is mock_instance
222
+
223
+ def test_create_client_cloud_mode(
224
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
225
+ ) -> None:
226
+ """Test creating client in cloud mode."""
227
+ clear_runtime_env(monkeypatch)
228
+ env_path = write_env(
229
+ tmp_path,
230
+ """
231
+ BITBUCKET_TOKEN=cloud_token
232
+ BITBUCKET_CLOUD_WORKSPACE=myworkspace
233
+ """.strip(),
234
+ )
235
+
236
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
237
+ mock_instance = MagicMock()
238
+ mock_client.return_value = mock_instance
239
+
240
+ client = create_client(env_path=env_path, mode="cloud")
241
+
242
+ call_args = mock_client.call_args
243
+ settings = call_args[0][0]
244
+ assert settings.mode == "cloud"
245
+ assert settings.cloud_workspace == "myworkspace"
246
+ assert settings.is_cloud_mode
247
+
248
+
249
+ class TestCreateAsyncClient:
250
+ """Tests for create_async_client() factory function."""
251
+
252
+ def test_create_async_client_returns_async_client(
253
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
254
+ ) -> None:
255
+ """Test that create_async_client returns AsyncBitbucketClient (TSK-225 implemented)."""
256
+ clear_runtime_env(monkeypatch)
257
+ env_path = write_env(
258
+ tmp_path,
259
+ """
260
+ VDS_USERNAME=test_user
261
+ VDS_PASSWORD=test_pass
262
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
263
+ """.strip(),
264
+ )
265
+
266
+ with patch("vds_bitbucket_orchestrator.factory.AsyncBitbucketClient") as mock_async:
267
+ with patch("vds_bitbucket_orchestrator.async_client.BitbucketClient"):
268
+ mock_instance = MagicMock()
269
+ mock_async.return_value = mock_instance
270
+
271
+ client = create_async_client(env_path=env_path)
272
+
273
+ # Verify AsyncBitbucketClient was created (not NotImplementedError)
274
+ assert client is mock_instance
275
+ mock_async.assert_called_once()
276
+
277
+ def test_create_async_client_passes_settings_and_timeout(
278
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
279
+ ) -> None:
280
+ """Test that create_async_client passes settings and timeout correctly."""
281
+ clear_runtime_env(monkeypatch)
282
+ env_path = write_env(
283
+ tmp_path,
284
+ """
285
+ VDS_USERNAME=test_user
286
+ VDS_PASSWORD=test_pass
287
+ VDS_BITBUCKET_URL=https://bitbucket.test.com
288
+ """.strip(),
289
+ )
290
+
291
+ with patch("vds_bitbucket_orchestrator.factory.AsyncBitbucketClient") as mock_async:
292
+ with patch("vds_bitbucket_orchestrator.async_client.BitbucketClient"):
293
+ mock_instance = MagicMock()
294
+ mock_async.return_value = mock_instance
295
+
296
+ create_async_client(env_path=env_path, timeout=60)
297
+
298
+ call_args = mock_async.call_args
299
+ settings = call_args[0][0]
300
+ assert settings.username == "test_user"
301
+ assert call_args.kwargs.get("timeout") == 60
302
+
303
+
304
+ class TestFactoryImports:
305
+ """Test that factory functions are properly exported from package."""
306
+
307
+ def test_factory_functions_importable_from_package(self) -> None:
308
+ """Test that factory functions can be imported from package root."""
309
+ from vds_bitbucket_orchestrator import create_async_client, create_client
310
+
311
+ assert callable(create_client)
312
+ assert callable(create_async_client)
313
+
314
+ def test_default_env_path_importable(self) -> None:
315
+ """Test that DEFAULT_VDS_ENV_PATH is accessible."""
316
+ from vds_bitbucket_orchestrator.factory import DEFAULT_VDS_ENV_PATH
317
+
318
+ assert isinstance(DEFAULT_VDS_ENV_PATH, Path)
319
+
320
+
321
+ class TestFactoryWithEnvVarPriority:
322
+ """Test factory functions respect env var priority (FR-21.1.1)."""
323
+
324
+ def test_factory_uses_primary_env_var(
325
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
326
+ ) -> None:
327
+ """Test that factory uses VDS_BITBUCKET_URL as primary."""
328
+ clear_runtime_env(monkeypatch)
329
+ env_path = write_env(
330
+ tmp_path,
331
+ """
332
+ VDS_USERNAME=test_user
333
+ VDS_PASSWORD=test_pass
334
+ VDS_BITBUCKET_URL=https://primary.bitbucket.com
335
+ BITBUCKET_BASE_URL=https://legacy.bitbucket.com
336
+ """.strip(),
337
+ )
338
+
339
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
340
+ mock_instance = MagicMock()
341
+ mock_client.return_value = mock_instance
342
+
343
+ create_client(env_path=env_path)
344
+
345
+ call_args = mock_client.call_args
346
+ settings = call_args[0][0]
347
+ assert str(settings.base_url) == "https://primary.bitbucket.com"
348
+
349
+ def test_factory_falls_back_to_legacy_env_var(
350
+ self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
351
+ ) -> None:
352
+ """Test that factory falls back to BITBUCKET_BASE_URL."""
353
+ clear_runtime_env(monkeypatch)
354
+ env_path = write_env(
355
+ tmp_path,
356
+ """
357
+ VDS_USERNAME=test_user
358
+ VDS_PASSWORD=test_pass
359
+ BITBUCKET_BASE_URL=https://legacy.bitbucket.com
360
+ """.strip(),
361
+ )
362
+
363
+ with patch("vds_bitbucket_orchestrator.factory.BitbucketClient") as mock_client:
364
+ mock_instance = MagicMock()
365
+ mock_client.return_value = mock_instance
366
+
367
+ create_client(env_path=env_path)
368
+
369
+ call_args = mock_client.call_args
370
+ settings = call_args[0][0]
371
+ assert str(settings.base_url) == "https://legacy.bitbucket.com"
@@ -0,0 +1,204 @@
1
+ """Tests for Bitbucket fork operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import MagicMock, Mock, patch
6
+
7
+ import pytest
8
+ from typer.testing import CliRunner
9
+ from vds_bitbucket_orchestrator.cli import app
10
+ from vds_bitbucket_orchestrator.client import BitbucketClient
11
+ from vds_bitbucket_orchestrator.config import BitbucketSettings
12
+ from vds_bitbucket_orchestrator.errors import BitbucketClientError
13
+
14
+ runner = CliRunner()
15
+
16
+
17
+ @pytest.fixture
18
+ def mock_settings() -> BitbucketSettings:
19
+ """Create server-mode settings for testing."""
20
+ return BitbucketSettings(
21
+ VDS_USERNAME="test_user",
22
+ VDS_PASSWORD="test_pass",
23
+ BITBUCKET_TOKEN="test_token",
24
+ BITBUCKET_BASE_URL="https://bitbucket.test.com",
25
+ BITBUCKET_MODE="server",
26
+ )
27
+
28
+
29
+ @pytest.fixture
30
+ def mock_sdk_client() -> MagicMock:
31
+ """Mock SDK client."""
32
+ client = MagicMock()
33
+ client.fork_repository.return_value = {"slug": "repo-fork", "name": "Repository Fork"}
34
+ client.fork_repository_new_project.return_value = {"slug": "new-repo", "name": "New Repository"}
35
+ client.repo_list.return_value = [
36
+ {"slug": "repo-fork", "name": "Repository Fork"},
37
+ {"slug": "repo-fork-2", "name": "Repository Fork 2"},
38
+ ]
39
+ return client
40
+
41
+
42
+ @pytest.fixture
43
+ def mock_client(mock_settings: BitbucketSettings, mock_sdk_client: MagicMock) -> BitbucketClient:
44
+ """Create a BitbucketClient with mocked SDK."""
45
+ with patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket", return_value=mock_sdk_client):
46
+ client = BitbucketClient(mock_settings)
47
+ client._client = mock_sdk_client
48
+ return client
49
+
50
+
51
+ class TestForkRepository:
52
+ """Tests for fork_repository method."""
53
+
54
+ def test_fork_repository_same_project(self, mock_client: BitbucketClient, mock_sdk_client: MagicMock) -> None:
55
+ """Test forking repository within same project."""
56
+ result = mock_client.fork_repository("PROJ", "repo", new_repository_slug="repo-fork")
57
+
58
+ assert result == {"slug": "repo-fork", "name": "Repository Fork"}
59
+ mock_sdk_client.fork_repository.assert_called_once_with("PROJ", "repo", "repo-fork")
60
+
61
+ def test_fork_repository_same_project_default_name(
62
+ self, mock_client: BitbucketClient, mock_sdk_client: MagicMock
63
+ ) -> None:
64
+ """Test forking repository within same project with default name."""
65
+ result = mock_client.fork_repository("PROJ", "repo")
66
+
67
+ assert result == {"slug": "repo-fork", "name": "Repository Fork"}
68
+ mock_sdk_client.fork_repository.assert_called_once_with("PROJ", "repo", "repo-fork")
69
+
70
+ def test_fork_repository_new_project(self, mock_client: BitbucketClient, mock_sdk_client: MagicMock) -> None:
71
+ """Test forking repository to new project."""
72
+ result = mock_client.fork_repository("PROJ", "repo", new_project_key="NEWPROJ", new_repository_slug="new-repo")
73
+
74
+ assert result == {"slug": "new-repo", "name": "New Repository"}
75
+ mock_sdk_client.fork_repository_new_project.assert_called_once_with("PROJ", "repo", "NEWPROJ", "new-repo")
76
+
77
+ def test_fork_repository_new_project_default_name(
78
+ self, mock_client: BitbucketClient, mock_sdk_client: MagicMock
79
+ ) -> None:
80
+ """Test forking repository to new project with default name."""
81
+ result = mock_client.fork_repository("PROJ", "repo", new_project_key="NEWPROJ")
82
+
83
+ assert result == {"slug": "new-repo", "name": "New Repository"}
84
+ mock_sdk_client.fork_repository_new_project.assert_called_once_with("PROJ", "repo", "NEWPROJ", "repo")
85
+
86
+ def test_fork_repository_handles_error(self, mock_client: BitbucketClient, mock_sdk_client: MagicMock) -> None:
87
+ """Test fork_repository error handling."""
88
+ mock_sdk_client.fork_repository.side_effect = Exception("Repository already exists")
89
+
90
+ with pytest.raises(BitbucketClientError, match="fork_repository"):
91
+ mock_client.fork_repository("PROJ", "repo", new_repository_slug="repo-fork")
92
+
93
+
94
+ class TestGetForkedRepositories:
95
+ """Tests for get_forked_repositories method."""
96
+
97
+ def test_get_forked_repositories_success(self, mock_client: BitbucketClient, mock_sdk_client: MagicMock) -> None:
98
+ """Test getting forked repositories."""
99
+ result = mock_client.get_forked_repositories("PROJ", "repo")
100
+
101
+ assert len(result) == 2
102
+ assert result[0]["slug"] == "repo-fork"
103
+ mock_sdk_client.repo_list.assert_called_once()
104
+
105
+ def test_get_forked_repositories_empty(self, mock_client: BitbucketClient, mock_sdk_client: MagicMock) -> None:
106
+ """Test getting forked repositories when none exist."""
107
+ mock_sdk_client.repo_list.return_value = []
108
+
109
+ result = mock_client.get_forked_repositories("PROJ", "repo")
110
+
111
+ assert result == []
112
+
113
+ def test_get_forked_repositories_handles_error(
114
+ self, mock_client: BitbucketClient, mock_sdk_client: MagicMock
115
+ ) -> None:
116
+ """Test get_forked_repositories error handling."""
117
+ mock_sdk_client.repo_list.side_effect = Exception("Project not found")
118
+
119
+ with pytest.raises(BitbucketClientError, match="get_forked_repositories"):
120
+ mock_client.get_forked_repositories("PROJ", "repo")
121
+
122
+
123
+ class TestForkCLI:
124
+ """Tests for fork CLI commands."""
125
+
126
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
127
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
128
+ def test_fork_create_success(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
129
+ """Test fork create command success."""
130
+ mock_client = MagicMock()
131
+ mock_client.fork_repository.return_value = {"slug": "repo-fork", "name": "Repository Fork"}
132
+ mock_build_client.return_value.__enter__.return_value = mock_client
133
+
134
+ result = runner.invoke(app, ["fork", "create", "PROJ", "repo", "--new-repo", "repo-fork", "--yes"])
135
+
136
+ assert result.exit_code == 0
137
+ assert "success" in result.stdout
138
+ mock_client.fork_repository.assert_called_once_with("PROJ", "repo", None, "repo-fork")
139
+
140
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
141
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
142
+ def test_fork_create_new_project(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
143
+ """Test fork create command with new project."""
144
+ mock_client = MagicMock()
145
+ mock_client.fork_repository.return_value = {"slug": "new-repo", "name": "New Repository"}
146
+ mock_build_client.return_value.__enter__.return_value = mock_client
147
+
148
+ result = runner.invoke(
149
+ app, ["fork", "create", "PROJ", "repo", "--new-project", "NEWPROJ", "--new-repo", "new-repo", "--yes"]
150
+ )
151
+
152
+ assert result.exit_code == 0
153
+ assert "success" in result.stdout
154
+ mock_client.fork_repository.assert_called_once_with("PROJ", "repo", "NEWPROJ", "new-repo")
155
+
156
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
157
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
158
+ def test_fork_create_requires_yes(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
159
+ """Test fork create requires --yes flag."""
160
+ result = runner.invoke(app, ["fork", "create", "PROJ", "repo", "--new-repo", "repo-fork"])
161
+
162
+ assert result.exit_code != 0
163
+ assert "--yes" in result.stdout or "without --yes" in result.stdout or "Refusing" in result.stdout
164
+
165
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
166
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
167
+ def test_fork_list_success(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
168
+ """Test fork list command success."""
169
+ mock_client = MagicMock()
170
+ mock_client.get_forked_repositories.return_value = [
171
+ {"slug": "repo-fork", "name": "Repository Fork"},
172
+ {"slug": "repo-fork-2", "name": "Repository Fork 2"},
173
+ ]
174
+ mock_build_client.return_value.__enter__.return_value = mock_client
175
+
176
+ result = runner.invoke(app, ["fork", "list", "PROJ", "repo"])
177
+
178
+ assert result.exit_code == 0
179
+ assert "forks" in result.stdout
180
+ assert "count" in result.stdout
181
+ mock_client.get_forked_repositories.assert_called_once_with("PROJ", "repo")
182
+
183
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
184
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
185
+ def test_fork_invalid_action(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
186
+ """Test fork command with invalid action."""
187
+ result = runner.invoke(app, ["fork", "invalid", "PROJ", "repo"])
188
+
189
+ assert result.exit_code != 0
190
+ assert "Unknown action" in result.stdout or "Unknown action" in result.stderr
191
+
192
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
193
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
194
+ def test_fork_create_handles_error(self, mock_build_client: Mock, mock_load_settings: Mock) -> None:
195
+ """Test fork create command error handling."""
196
+ mock_client = MagicMock()
197
+ mock_client.fork_repository.side_effect = BitbucketClientError("Repository already exists")
198
+ mock_build_client.return_value.__enter__.return_value = mock_client
199
+
200
+ result = runner.invoke(app, ["fork", "create", "PROJ", "repo", "--new-repo", "repo-fork", "--yes"])
201
+
202
+ assert result.exit_code != 0
203
+ assert "Error" in result.stdout or "Error" in result.stderr
204
+