@ngocsangairvds/vsaf 3.1.27 → 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 (303) 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-ship/SKILL.md +41 -10
  16. package/tools/skills/vsaf-test/SKILL.md +8 -0
  17. package/tools/vds-scripts/.mcp.json +11 -0
  18. package/tools/vds-scripts/.secrets.baseline +133 -0
  19. package/tools/vds-scripts/AGENTS.md +152 -0
  20. package/tools/vds-scripts/CLAUDE.md +101 -0
  21. package/tools/vds-scripts/CLI_COMMAND_OPTIMIZATION.md +156 -0
  22. package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +131 -0
  23. package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +45 -0
  24. package/tools/vds-scripts/README.md +97 -0
  25. package/tools/vds-scripts/bitbucket_manifest_mapping.toml +34 -0
  26. package/tools/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +258 -0
  27. package/tools/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +393 -0
  28. package/tools/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +61 -0
  29. package/tools/vds-scripts/bitbucket_orchestrator/FEATURES.md +908 -0
  30. package/tools/vds-scripts/bitbucket_orchestrator/README.md +687 -0
  31. package/tools/vds-scripts/bitbucket_orchestrator/pyproject.toml +40 -0
  32. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +20 -0
  33. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +657 -0
  34. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +2108 -0
  35. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +2534 -0
  36. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +171 -0
  37. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +67 -0
  38. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +185 -0
  39. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +244 -0
  40. package/tools/vds-scripts/bitbucket_orchestrator/tests/__init__.py +8 -0
  41. package/tools/vds-scripts/bitbucket_orchestrator/tests/conftest.py +65 -0
  42. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +151 -0
  43. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +546 -0
  44. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +145 -0
  45. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +115 -0
  46. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client.py +157 -0
  47. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +79 -0
  48. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +163 -0
  49. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +32 -0
  50. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +194 -0
  51. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +164 -0
  52. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +179 -0
  53. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +119 -0
  54. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +156 -0
  55. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code.py +98 -0
  56. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +282 -0
  57. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +335 -0
  58. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +147 -0
  59. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_config.py +131 -0
  60. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +352 -0
  61. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +371 -0
  62. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +204 -0
  63. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +261 -0
  64. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +270 -0
  65. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +204 -0
  66. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +334 -0
  67. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +343 -0
  68. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +270 -0
  69. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +189 -0
  70. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +233 -0
  71. package/tools/vds-scripts/bitbucket_orchestrator/uv.lock +742 -0
  72. package/tools/vds-scripts/confluence_orchestrator/Dockerfile +19 -0
  73. package/tools/vds-scripts/confluence_orchestrator/README.md +412 -0
  74. package/tools/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +127 -0
  75. package/tools/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +108 -0
  76. package/tools/vds-scripts/confluence_orchestrator/pyproject.toml +48 -0
  77. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +20 -0
  78. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +2532 -0
  79. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +175 -0
  80. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +290 -0
  81. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +94 -0
  82. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +1835 -0
  83. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +80 -0
  84. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +109 -0
  85. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +1114 -0
  86. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +165 -0
  87. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +78 -0
  88. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +121 -0
  89. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +213 -0
  90. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +305 -0
  91. package/tools/vds-scripts/confluence_orchestrator/sync_png_attachments.py +305 -0
  92. package/tools/vds-scripts/confluence_orchestrator/tests/__init__.py +0 -0
  93. package/tools/vds-scripts/confluence_orchestrator/tests/conftest.py +8 -0
  94. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +224 -0
  95. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +188 -0
  96. package/tools/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +247 -0
  97. package/tools/vds-scripts/confluence_orchestrator/tests/test_cli.py +499 -0
  98. package/tools/vds-scripts/confluence_orchestrator/tests/test_config.py +83 -0
  99. package/tools/vds-scripts/confluence_orchestrator/tests/test_content.py +186 -0
  100. package/tools/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +27 -0
  101. package/tools/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +2250 -0
  102. package/tools/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +223 -0
  103. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing.py +71 -0
  104. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +37 -0
  105. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +44 -0
  106. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +49 -0
  107. package/tools/vds-scripts/confluence_orchestrator/tests/test_export.py +230 -0
  108. package/tools/vds-scripts/confluence_orchestrator/tests/test_history.py +204 -0
  109. package/tools/vds-scripts/confluence_orchestrator/tests/test_http.py +117 -0
  110. package/tools/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +91 -0
  111. package/tools/vds-scripts/confluence_orchestrator/tests/test_reporting.py +24 -0
  112. package/tools/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +34 -0
  113. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_management.py +237 -0
  114. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +332 -0
  115. package/tools/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +388 -0
  116. package/tools/vds-scripts/confluence_orchestrator/uv.lock +1023 -0
  117. package/tools/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +119 -0
  118. package/tools/vds-scripts/git_orchestrator/README.md +280 -0
  119. package/tools/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +152 -0
  120. package/tools/vds-scripts/git_orchestrator/pyproject.toml +35 -0
  121. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +7 -0
  122. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +4 -0
  123. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +847 -0
  124. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +63 -0
  125. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +129 -0
  126. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +819 -0
  127. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +53 -0
  128. package/tools/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
  129. package/tools/vds-scripts/git_orchestrator/tests/test_cli_settings.py +21 -0
  130. package/tools/vds-scripts/git_orchestrator/tests/test_integration.py +74 -0
  131. package/tools/vds-scripts/git_orchestrator/tests/test_manifest.py +79 -0
  132. package/tools/vds-scripts/git_orchestrator/tests/test_orchestrator.py +204 -0
  133. package/tools/vds-scripts/git_orchestrator/tests/test_public_api.py +236 -0
  134. package/tools/vds-scripts/git_orchestrator/tests/test_resilience.py +345 -0
  135. package/tools/vds-scripts/git_orchestrator/uv.lock +271 -0
  136. package/tools/vds-scripts/jira_orchestrator/README.md +770 -0
  137. package/tools/vds-scripts/jira_orchestrator/pyproject.toml +39 -0
  138. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +1 -0
  139. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +1320 -0
  140. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +2271 -0
  141. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +138 -0
  142. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +67 -0
  143. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +65 -0
  144. package/tools/vds-scripts/jira_orchestrator/tests/__init__.py +1 -0
  145. package/tools/vds-scripts/jira_orchestrator/tests/conftest.py +86 -0
  146. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +54 -0
  147. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +69 -0
  148. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +57 -0
  149. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +45 -0
  150. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +117 -0
  151. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +54 -0
  152. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +42 -0
  153. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +42 -0
  154. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +76 -0
  155. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +91 -0
  156. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +110 -0
  157. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +133 -0
  158. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +41 -0
  159. package/tools/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +164 -0
  160. package/tools/vds-scripts/jira_orchestrator/tests/test_agile.py +256 -0
  161. package/tools/vds-scripts/jira_orchestrator/tests/test_application_properties.py +193 -0
  162. package/tools/vds-scripts/jira_orchestrator/tests/test_backlog.py +91 -0
  163. package/tools/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +277 -0
  164. package/tools/vds-scripts/jira_orchestrator/tests/test_cli.py +106 -0
  165. package/tools/vds-scripts/jira_orchestrator/tests/test_components.py +106 -0
  166. package/tools/vds-scripts/jira_orchestrator/tests/test_config.py +164 -0
  167. package/tools/vds-scripts/jira_orchestrator/tests/test_dashboard.py +122 -0
  168. package/tools/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +207 -0
  169. package/tools/vds-scripts/jira_orchestrator/tests/test_filter_management.py +333 -0
  170. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +164 -0
  171. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_links.py +257 -0
  172. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +171 -0
  173. package/tools/vds-scripts/jira_orchestrator/tests/test_link_types.py +314 -0
  174. package/tools/vds-scripts/jira_orchestrator/tests/test_parse_set.py +37 -0
  175. package/tools/vds-scripts/jira_orchestrator/tests/test_permissions.py +273 -0
  176. package/tools/vds-scripts/jira_orchestrator/tests/test_reindex.py +81 -0
  177. package/tools/vds-scripts/jira_orchestrator/tests/test_remote_links.py +254 -0
  178. package/tools/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +170 -0
  179. package/tools/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +114 -0
  180. package/tools/vds-scripts/jira_orchestrator/tests/test_user_management.py +226 -0
  181. package/tools/vds-scripts/jira_orchestrator/tests/test_version_management.py +339 -0
  182. package/tools/vds-scripts/jira_orchestrator/tests/test_watchers.py +101 -0
  183. package/tools/vds-scripts/jira_orchestrator/tests/test_worklog.py +223 -0
  184. package/tools/vds-scripts/jira_orchestrator/uv.lock +738 -0
  185. package/tools/vds-scripts/mcp_server/Dockerfile +34 -0
  186. package/tools/vds-scripts/mcp_server/README.md +140 -0
  187. package/tools/vds-scripts/mcp_server/pyproject.toml +42 -0
  188. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +4 -0
  189. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/config.py +36 -0
  190. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/server.py +66 -0
  191. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +14 -0
  192. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +47 -0
  193. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +59 -0
  194. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +71 -0
  195. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +63 -0
  196. package/tools/vds-scripts/mcp_server/tests/__init__.py +2 -0
  197. package/tools/vds-scripts/mcp_server/tests/conftest.py +29 -0
  198. package/tools/vds-scripts/mcp_server/tests/unit/__init__.py +2 -0
  199. package/tools/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +25 -0
  200. package/tools/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +25 -0
  201. package/tools/vds-scripts/mcp_server/tests/unit/test_git_tools.py +32 -0
  202. package/tools/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +32 -0
  203. package/tools/vds-scripts/mcp_server/tests/verification/__init__.py +2 -0
  204. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +40 -0
  205. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +37 -0
  206. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +47 -0
  207. package/tools/vds-scripts/mcp_server/uv.lock +1032 -0
  208. package/tools/vds-scripts/mypy.ini +5 -0
  209. package/tools/vds-scripts/pyproject.toml +29 -0
  210. package/tools/vds-scripts/repo-manifest.yaml +273 -0
  211. package/tools/vds-scripts/repo-manifest.yaml.example +25 -0
  212. package/tools/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +706 -0
  213. package/tools/vds-scripts/scripts/BRD-Validation-README.md +308 -0
  214. package/tools/vds-scripts/scripts/README.md +162 -0
  215. package/tools/vds-scripts/scripts/bootstrap_uv.sh +30 -0
  216. package/tools/vds-scripts/scripts/brd-validation-environment.json +51 -0
  217. package/tools/vds-scripts/scripts/brd-validation-test-results.json +13023 -0
  218. package/tools/vds-scripts/scripts/brd_coverage_report.json +276 -0
  219. package/tools/vds-scripts/scripts/create_memory_session.py +35 -0
  220. package/tools/vds-scripts/scripts/deployment/load_docker_images_offline.sh +90 -0
  221. package/tools/vds-scripts/scripts/final_completion_report.md +139 -0
  222. package/tools/vds-scripts/scripts/folder_structure_report.json +321 -0
  223. package/tools/vds-scripts/scripts/generate_completion_report.py +125 -0
  224. package/tools/vds-scripts/scripts/generate_intellij_modules.py +150 -0
  225. package/tools/vds-scripts/scripts/link_integrity_report.json +807 -0
  226. package/tools/vds-scripts/scripts/move_audit_artifact_pages.py +255 -0
  227. package/tools/vds-scripts/scripts/move_audit_artifact_pages_rest.py +165 -0
  228. package/tools/vds-scripts/scripts/move_wrong_dept_pages.py +216 -0
  229. package/tools/vds-scripts/scripts/save_intellij_memories.py +120 -0
  230. package/tools/vds-scripts/scripts/save_memories_to_vds_ai.py +83 -0
  231. package/tools/vds-scripts/scripts/save_memories_vds_style.py +129 -0
  232. package/tools/vds-scripts/scripts/search_intellij_memories.py +50 -0
  233. package/tools/vds-scripts/scripts/setup_intellij_workspace.py +65 -0
  234. package/tools/vds-scripts/scripts/target-state-automation/README.md +89 -0
  235. package/tools/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +27 -0
  236. package/tools/vds-scripts/scripts/target-state-automation/coordination.sh +114 -0
  237. package/tools/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +25 -0
  238. package/tools/vds-scripts/scripts/target-state-automation/docs_root.sh +22 -0
  239. package/tools/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +22 -0
  240. package/tools/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +25 -0
  241. package/tools/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +17 -0
  242. package/tools/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +25 -0
  243. package/tools/vds-scripts/scripts/target-state-automation/sync_confluence.sh +30 -0
  244. package/tools/vds-scripts/scripts/target-state-automation/update_dependencies.sh +19 -0
  245. package/tools/vds-scripts/scripts/target-state-automation/validate_links.sh +86 -0
  246. package/tools/vds-scripts/scripts/target-state-automation/validate_markdown.sh +52 -0
  247. package/tools/vds-scripts/scripts/target-state-automation/validate_schemas.sh +26 -0
  248. package/tools/vds-scripts/scripts/target-state-automation/validate_structure.sh +98 -0
  249. package/tools/vds-scripts/scripts/update_modules_xml.py +190 -0
  250. package/tools/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +128 -0
  251. package/tools/vds-scripts/scripts/validate_brd_coverage.py +179 -0
  252. package/tools/vds-scripts/scripts/validate_folder_structure.py +240 -0
  253. package/tools/vds-scripts/scripts/validate_link_integrity.py +272 -0
  254. package/tools/vds-scripts/scripts/vds_sh_helpers.sh +180 -0
  255. package/tools/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +26 -0
  256. package/tools/vds-scripts/scripts/worktree_uv.sh +48 -0
  257. package/tools/vds-scripts/uv.lock +8 -0
  258. package/tools/vds-scripts/vds_cli/README.md +126 -0
  259. package/tools/vds-scripts/vds_cli/VERIFICATION_REPORT.md +41 -0
  260. package/tools/vds-scripts/vds_cli/pyproject.toml +38 -0
  261. package/tools/vds-scripts/vds_cli/src/vds_cli/__init__.py +3 -0
  262. package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +173 -0
  263. package/tools/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +1203 -0
  264. package/tools/vds-scripts/vds_cli/src/vds_cli/env.py +41 -0
  265. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +3 -0
  266. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +198 -0
  267. package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +93 -0
  268. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_api.py +647 -0
  269. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_service.py +266 -0
  270. package/tools/vds-scripts/vds_cli/tests/__init__.py +2 -0
  271. package/tools/vds-scripts/vds_cli/tests/conftest.py +49 -0
  272. package/tools/vds-scripts/vds_cli/tests/unit/__init__.py +2 -0
  273. package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +143 -0
  274. package/tools/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +422 -0
  275. package/tools/vds-scripts/vds_cli/tests/unit/test_env.py +51 -0
  276. package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +72 -0
  277. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_api.py +357 -0
  278. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_service.py +160 -0
  279. package/tools/vds-scripts/vds_cli/tests/verification/__init__.py +2 -0
  280. package/tools/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +33 -0
  281. package/tools/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +35 -0
  282. package/tools/vds-scripts/vds_cli/tests/verification/test_jira_real.py +41 -0
  283. package/tools/vds-scripts/vds_cli/uv.lock +524 -0
  284. package/tools/vds-scripts/vds_cli_common/README.md +190 -0
  285. package/tools/vds-scripts/vds_cli_common/pyproject.toml +92 -0
  286. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +34 -0
  287. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +139 -0
  288. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +201 -0
  289. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +119 -0
  290. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +318 -0
  291. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +284 -0
  292. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +78 -0
  293. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +213 -0
  294. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +85 -0
  295. package/tools/vds-scripts/vds_cli_common/tests/__init__.py +1 -0
  296. package/tools/vds-scripts/vds_cli_common/tests/test_completers.py +148 -0
  297. package/tools/vds-scripts/vds_cli_common/tests/test_context.py +192 -0
  298. package/tools/vds-scripts/vds_cli_common/tests/test_env.py +102 -0
  299. package/tools/vds-scripts/vds_cli_common/tests/test_errors.py +186 -0
  300. package/tools/vds-scripts/vds_cli_common/tests/test_output.py +229 -0
  301. package/tools/vds-scripts/vds_cli_common/tests/test_paths.py +61 -0
  302. package/tools/vds-scripts/vds_cli_common/tests/test_testing.py +138 -0
  303. package/tools/vds-scripts/vds_cli_common/tests/test_version.py +64 -0
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import Mock, patch
4
+
5
+ import pytest
6
+ from typer.testing import CliRunner
7
+ from vds_bitbucket_orchestrator.cli import app
8
+
9
+
10
+ @pytest.fixture
11
+ def runner() -> CliRunner:
12
+ return CliRunner()
13
+
14
+
15
+ @pytest.fixture
16
+ def mock_client() -> Mock:
17
+ client = Mock()
18
+ client.list_pull_request_blockers.return_value = [
19
+ {"uuid": "{blocker}", "message": "Fix tests", "reason": "QA"},
20
+ ]
21
+ client.add_pull_request_blocker.return_value = {"uuid": "{blocker}", "message": "Fix tests"}
22
+ return client
23
+
24
+
25
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
26
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
27
+ def test_pr_blocker_list_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
28
+ settings = Mock()
29
+ settings.is_cloud_mode = True
30
+ mock_load.return_value = settings
31
+ mock_build.return_value.__enter__.return_value = mock_client
32
+
33
+ result = runner.invoke(
34
+ app,
35
+ [
36
+ "--no-markdown",
37
+ "pr-blocker",
38
+ "list",
39
+ "--workspace",
40
+ "workspace",
41
+ "--repo-slug",
42
+ "repository",
43
+ "--pull-request-id",
44
+ "1",
45
+ "--search",
46
+ "reason = QA",
47
+ ],
48
+ )
49
+
50
+ assert result.exit_code == 0
51
+ mock_client.list_pull_request_blockers.assert_called_once_with("workspace", "repository", "1", query="reason = QA")
52
+
53
+
54
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
55
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
56
+ def test_pr_blocker_add_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
57
+ settings = Mock()
58
+ settings.is_cloud_mode = True
59
+ mock_load.return_value = settings
60
+ mock_build.return_value.__enter__.return_value = mock_client
61
+
62
+ result = runner.invoke(
63
+ app,
64
+ [
65
+ "--no-markdown",
66
+ "pr-blocker",
67
+ "add",
68
+ "--workspace",
69
+ "workspace",
70
+ "--repo-slug",
71
+ "repository",
72
+ "--pull-request-id",
73
+ "1",
74
+ "--message",
75
+ "Fix tests",
76
+ "--reason",
77
+ "QA",
78
+ ],
79
+ )
80
+
81
+ assert result.exit_code == 0
82
+ mock_client.add_pull_request_blocker.assert_called_once_with(
83
+ "workspace",
84
+ "repository",
85
+ "1",
86
+ "Fix tests",
87
+ reason="QA",
88
+ severity=None,
89
+ )
90
+
91
+
92
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
93
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
94
+ def test_pr_blocker_delete_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
95
+ settings = Mock()
96
+ settings.is_cloud_mode = True
97
+ mock_load.return_value = settings
98
+ mock_build.return_value.__enter__.return_value = mock_client
99
+
100
+ result = runner.invoke(
101
+ app,
102
+ [
103
+ "--no-markdown",
104
+ "pr-blocker",
105
+ "delete",
106
+ "--workspace",
107
+ "workspace",
108
+ "--repo-slug",
109
+ "repository",
110
+ "--pull-request-id",
111
+ "1",
112
+ "--blocker-uuid",
113
+ "{blocker}",
114
+ "--yes",
115
+ ],
116
+ )
117
+
118
+ assert result.exit_code == 0
119
+ mock_client.delete_pull_request_blocker.assert_called_once_with("workspace", "repository", "1", "{blocker}")
120
+
121
+
122
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
123
+ def test_pr_blocker_requires_cloud(mock_load: Mock, runner: CliRunner) -> None:
124
+ settings = Mock()
125
+ settings.is_cloud_mode = False
126
+ mock_load.return_value = settings
127
+
128
+ result = runner.invoke(
129
+ app,
130
+ [
131
+ "pr-blocker",
132
+ "list",
133
+ "--workspace",
134
+ "workspace",
135
+ "--repo-slug",
136
+ "repository",
137
+ "--pull-request-id",
138
+ "1",
139
+ ],
140
+ )
141
+
142
+ assert result.exit_code != 0
143
+ assert "Cloud mode" in result.stdout or "Cloud mode" in result.stderr
144
+
145
+
146
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
147
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
148
+ def test_pr_blocker_add_requires_message(
149
+ mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock
150
+ ) -> None:
151
+ settings = Mock()
152
+ settings.is_cloud_mode = True
153
+ mock_load.return_value = settings
154
+ mock_build.return_value.__enter__.return_value = mock_client
155
+
156
+ result = runner.invoke(
157
+ app,
158
+ [
159
+ "pr-blocker",
160
+ "add",
161
+ "--workspace",
162
+ "workspace",
163
+ "--repo-slug",
164
+ "repository",
165
+ "--pull-request-id",
166
+ "1",
167
+ ],
168
+ )
169
+
170
+ assert result.exit_code != 0
171
+ assert "message" in result.stdout or "message" in result.stderr
172
+ mock_client.add_pull_request_blocker.assert_not_called()
173
+
174
+
175
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
176
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
177
+ def test_pr_blocker_delete_requires_yes(
178
+ mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock
179
+ ) -> None:
180
+ settings = Mock()
181
+ settings.is_cloud_mode = True
182
+ mock_load.return_value = settings
183
+ mock_build.return_value.__enter__.return_value = mock_client
184
+
185
+ result = runner.invoke(
186
+ app,
187
+ [
188
+ "pr-blocker",
189
+ "delete",
190
+ "--workspace",
191
+ "workspace",
192
+ "--repo-slug",
193
+ "repository",
194
+ "--pull-request-id",
195
+ "1",
196
+ "--blocker-uuid",
197
+ "{blocker}",
198
+ ],
199
+ )
200
+
201
+ assert result.exit_code != 0
202
+ assert "Refusing to delete blocker without --yes" in result.stdout or "Refusing to delete blocker without --yes" in result.stderr
203
+ mock_client.delete_pull_request_blocker.assert_not_called()
204
+
@@ -0,0 +1,334 @@
1
+ """Unit tests for Bitbucket protocol interfaces.
2
+
3
+ Tests verify that:
4
+ 1. Protocol classes are properly defined and importable
5
+ 2. BitbucketClient implements all protocols (structural subtyping)
6
+ 3. isinstance() checks work correctly with @runtime_checkable protocols
7
+ 4. Mock implementations can satisfy protocols for testing
8
+
9
+ References:
10
+ - FR-21.2.1: Protocol classes for dependency injection and testability
11
+ - TSK-222: Protocol interfaces for Bitbucket
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any
17
+ from unittest.mock import Mock, patch
18
+
19
+ import pytest
20
+
21
+ from vds_bitbucket_orchestrator import (
22
+ BitbucketBranchClient,
23
+ BitbucketClient,
24
+ BitbucketCodeClient,
25
+ BitbucketFullClient,
26
+ BitbucketRepositoryClient,
27
+ BitbucketSettings,
28
+ )
29
+ from vds_bitbucket_orchestrator.protocols import (
30
+ BitbucketBranchClient as ProtocolBranchClient,
31
+ BitbucketCodeClient as ProtocolCodeClient,
32
+ BitbucketFullClient as ProtocolFullClient,
33
+ BitbucketRepositoryClient as ProtocolRepositoryClient,
34
+ )
35
+
36
+
37
+ # ============================================================================
38
+ # Fixtures
39
+ # ============================================================================
40
+
41
+
42
+ @pytest.fixture
43
+ def mock_settings() -> BitbucketSettings:
44
+ """Create server-mode settings for testing."""
45
+ return BitbucketSettings(
46
+ VDS_USERNAME="test_user",
47
+ VDS_PASSWORD="test_pass",
48
+ BITBUCKET_TOKEN="test_token",
49
+ BITBUCKET_BASE_URL="https://bitbucket.test.com",
50
+ BITBUCKET_MODE="server",
51
+ )
52
+
53
+
54
+ @pytest.fixture
55
+ @patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
56
+ def bitbucket_client(mock_atlassian: Mock, mock_settings: BitbucketSettings) -> BitbucketClient:
57
+ """Create a BitbucketClient instance with mocked SDK."""
58
+ return BitbucketClient(mock_settings)
59
+
60
+
61
+ # ============================================================================
62
+ # Protocol Import Tests
63
+ # ============================================================================
64
+
65
+
66
+ class TestProtocolImports:
67
+ """Test that protocols are properly importable from package root."""
68
+
69
+ def test_import_repository_client_from_package(self) -> None:
70
+ """BitbucketRepositoryClient should be importable from package root."""
71
+ assert BitbucketRepositoryClient is not None
72
+ assert BitbucketRepositoryClient is ProtocolRepositoryClient
73
+
74
+ def test_import_branch_client_from_package(self) -> None:
75
+ """BitbucketBranchClient should be importable from package root."""
76
+ assert BitbucketBranchClient is not None
77
+ assert BitbucketBranchClient is ProtocolBranchClient
78
+
79
+ def test_import_code_client_from_package(self) -> None:
80
+ """BitbucketCodeClient should be importable from package root."""
81
+ assert BitbucketCodeClient is not None
82
+ assert BitbucketCodeClient is ProtocolCodeClient
83
+
84
+ def test_import_full_client_from_package(self) -> None:
85
+ """BitbucketFullClient should be importable from package root."""
86
+ assert BitbucketFullClient is not None
87
+ assert BitbucketFullClient is ProtocolFullClient
88
+
89
+
90
+ # ============================================================================
91
+ # Protocol Compliance Tests (isinstance checks)
92
+ # ============================================================================
93
+
94
+
95
+ class TestBitbucketClientProtocolCompliance:
96
+ """Test that BitbucketClient implements all protocols."""
97
+
98
+ def test_implements_repository_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
99
+ """BitbucketClient should implement BitbucketRepositoryClient protocol."""
100
+ assert isinstance(bitbucket_client, BitbucketRepositoryClient)
101
+
102
+ def test_implements_branch_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
103
+ """BitbucketClient should implement BitbucketBranchClient protocol."""
104
+ assert isinstance(bitbucket_client, BitbucketBranchClient)
105
+
106
+ def test_implements_code_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
107
+ """BitbucketClient should implement BitbucketCodeClient protocol."""
108
+ assert isinstance(bitbucket_client, BitbucketCodeClient)
109
+
110
+ def test_implements_full_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
111
+ """BitbucketClient should implement BitbucketFullClient protocol."""
112
+ assert isinstance(bitbucket_client, BitbucketFullClient)
113
+
114
+
115
+ # ============================================================================
116
+ # Protocol Method Signature Tests
117
+ # ============================================================================
118
+
119
+
120
+ class TestRepositoryClientMethods:
121
+ """Test that BitbucketClient has correct method signatures for BitbucketRepositoryClient."""
122
+
123
+ def test_has_list_projects_method(self, bitbucket_client: BitbucketClient) -> None:
124
+ """BitbucketClient should have list_projects method."""
125
+ assert hasattr(bitbucket_client, "list_projects")
126
+ assert callable(bitbucket_client.list_projects)
127
+
128
+ def test_has_get_project_method(self, bitbucket_client: BitbucketClient) -> None:
129
+ """BitbucketClient should have get_project method."""
130
+ assert hasattr(bitbucket_client, "get_project")
131
+ assert callable(bitbucket_client.get_project)
132
+
133
+ def test_has_list_repositories_method(self, bitbucket_client: BitbucketClient) -> None:
134
+ """BitbucketClient should have list_repositories method."""
135
+ assert hasattr(bitbucket_client, "list_repositories")
136
+ assert callable(bitbucket_client.list_repositories)
137
+
138
+ def test_has_get_repository_method(self, bitbucket_client: BitbucketClient) -> None:
139
+ """BitbucketClient should have get_repository method."""
140
+ assert hasattr(bitbucket_client, "get_repository")
141
+ assert callable(bitbucket_client.get_repository)
142
+
143
+
144
+ class TestBranchClientMethods:
145
+ """Test that BitbucketClient has correct method signatures for BitbucketBranchClient."""
146
+
147
+ def test_has_get_branches_method(self, bitbucket_client: BitbucketClient) -> None:
148
+ """BitbucketClient should have get_branches method."""
149
+ assert hasattr(bitbucket_client, "get_branches")
150
+ assert callable(bitbucket_client.get_branches)
151
+
152
+ def test_has_list_branch_permissions_method(self, bitbucket_client: BitbucketClient) -> None:
153
+ """BitbucketClient should have list_branch_permissions method."""
154
+ assert hasattr(bitbucket_client, "list_branch_permissions")
155
+ assert callable(bitbucket_client.list_branch_permissions)
156
+
157
+
158
+ class TestCodeClientMethods:
159
+ """Test that BitbucketClient has correct method signatures for BitbucketCodeClient."""
160
+
161
+ def test_has_get_content_of_file_method(self, bitbucket_client: BitbucketClient) -> None:
162
+ """BitbucketClient should have get_content_of_file method (not get_file_content)."""
163
+ assert hasattr(bitbucket_client, "get_content_of_file")
164
+ assert callable(bitbucket_client.get_content_of_file)
165
+ # Verify the correct method name is used (not the incorrect one)
166
+ # This validates the code validation note from tasks.md
167
+
168
+ def test_has_get_commits_method(self, bitbucket_client: BitbucketClient) -> None:
169
+ """BitbucketClient should have get_commits method (not list_commits)."""
170
+ assert hasattr(bitbucket_client, "get_commits")
171
+ assert callable(bitbucket_client.get_commits)
172
+ # Verify the correct method name is used (not the incorrect one)
173
+ # This validates the code validation note from tasks.md
174
+
175
+
176
+ # ============================================================================
177
+ # Mock Implementation Tests
178
+ # ============================================================================
179
+
180
+
181
+ class MockRepositoryClient:
182
+ """Mock implementation of BitbucketRepositoryClient for testing."""
183
+
184
+ def list_projects(self, limit: int = 25) -> list[dict[str, Any]]:
185
+ return [{"key": "TEST", "name": "Test Project"}]
186
+
187
+ def get_project(self, project_key: str) -> dict[str, Any]:
188
+ return {"key": project_key, "name": f"Project {project_key}"}
189
+
190
+ def list_repositories(self, project_key: str, limit: int = 25) -> list[dict[str, Any]]:
191
+ return [{"slug": "test-repo", "name": "Test Repository"}]
192
+
193
+ def get_repository(self, project_key: str, repository_slug: str) -> dict[str, Any]:
194
+ return {"slug": repository_slug, "name": f"Repository {repository_slug}"}
195
+
196
+
197
+ class MockBranchClient:
198
+ """Mock implementation of BitbucketBranchClient for testing."""
199
+
200
+ def get_branches(
201
+ self,
202
+ project_key: str,
203
+ repository_slug: str,
204
+ filter: str = "",
205
+ limit: int = 99999,
206
+ details: bool = True,
207
+ ) -> list[dict[str, Any]]:
208
+ return [{"displayId": "main", "isDefault": True}]
209
+
210
+ def list_branch_permissions(
211
+ self,
212
+ project_key: str,
213
+ repository_slug: str | None = None,
214
+ start: int = 0,
215
+ limit: int = 25,
216
+ ) -> list[dict[str, Any]]:
217
+ return [{"type": "no-deletes", "matcher": {"id": "main"}}]
218
+
219
+
220
+ class MockCodeClient:
221
+ """Mock implementation of BitbucketCodeClient for testing."""
222
+
223
+ def get_content_of_file(
224
+ self,
225
+ project_key: str,
226
+ repository_slug: str,
227
+ filename: str,
228
+ at: str | None = None,
229
+ markup: str | None = None,
230
+ ) -> str:
231
+ return f"# Content of {filename}"
232
+
233
+ def get_commits(
234
+ self,
235
+ project_key: str,
236
+ repository_slug: str,
237
+ hash_oldest: str | None = None,
238
+ hash_newest: str | None = None,
239
+ limit: int = 99999,
240
+ ) -> list[dict[str, Any]]:
241
+ return [{"id": "abc123", "message": "Initial commit"}]
242
+
243
+
244
+ class MockFullClient(MockRepositoryClient, MockBranchClient, MockCodeClient):
245
+ """Mock implementation of BitbucketFullClient for testing."""
246
+
247
+ pass
248
+
249
+
250
+ class TestMockImplementations:
251
+ """Test that mock implementations satisfy protocols."""
252
+
253
+ def test_mock_repository_client_satisfies_protocol(self) -> None:
254
+ """MockRepositoryClient should satisfy BitbucketRepositoryClient protocol."""
255
+ mock = MockRepositoryClient()
256
+ assert isinstance(mock, BitbucketRepositoryClient)
257
+
258
+ def test_mock_branch_client_satisfies_protocol(self) -> None:
259
+ """MockBranchClient should satisfy BitbucketBranchClient protocol."""
260
+ mock = MockBranchClient()
261
+ assert isinstance(mock, BitbucketBranchClient)
262
+
263
+ def test_mock_code_client_satisfies_protocol(self) -> None:
264
+ """MockCodeClient should satisfy BitbucketCodeClient protocol."""
265
+ mock = MockCodeClient()
266
+ assert isinstance(mock, BitbucketCodeClient)
267
+
268
+ def test_mock_full_client_satisfies_protocol(self) -> None:
269
+ """MockFullClient should satisfy BitbucketFullClient protocol."""
270
+ mock = MockFullClient()
271
+ assert isinstance(mock, BitbucketFullClient)
272
+
273
+
274
+ # ============================================================================
275
+ # Dependency Injection Tests
276
+ # ============================================================================
277
+
278
+
279
+ def audit_repository_with_protocol(client: BitbucketRepositoryClient, project_key: str) -> dict[str, Any]:
280
+ """Example function using BitbucketRepositoryClient protocol for DI."""
281
+ repos = client.list_repositories(project_key)
282
+ return {"project": project_key, "repository_count": len(repos)}
283
+
284
+
285
+ def get_branch_permissions_with_protocol(
286
+ client: BitbucketBranchClient, project_key: str, repo_slug: str
287
+ ) -> list[dict[str, Any]]:
288
+ """Example function using BitbucketBranchClient protocol for DI."""
289
+ return client.list_branch_permissions(project_key, repo_slug)
290
+
291
+
292
+ def get_file_content_with_protocol(
293
+ client: BitbucketCodeClient, project_key: str, repo_slug: str, filename: str
294
+ ) -> str:
295
+ """Example function using BitbucketCodeClient protocol for DI."""
296
+ return client.get_content_of_file(project_key, repo_slug, filename)
297
+
298
+
299
+ class TestDependencyInjection:
300
+ """Test that protocols enable proper dependency injection."""
301
+
302
+ def test_repository_client_di_with_mock(self) -> None:
303
+ """Functions accepting BitbucketRepositoryClient should work with mock."""
304
+ mock = MockRepositoryClient()
305
+ result = audit_repository_with_protocol(mock, "TEST")
306
+ assert result["project"] == "TEST"
307
+ assert result["repository_count"] == 1
308
+
309
+ def test_branch_client_di_with_mock(self) -> None:
310
+ """Functions accepting BitbucketBranchClient should work with mock."""
311
+ mock = MockBranchClient()
312
+ result = get_branch_permissions_with_protocol(mock, "TEST", "test-repo")
313
+ assert len(result) == 1
314
+ assert result[0]["type"] == "no-deletes"
315
+
316
+ def test_code_client_di_with_mock(self) -> None:
317
+ """Functions accepting BitbucketCodeClient should work with mock."""
318
+ mock = MockCodeClient()
319
+ result = get_file_content_with_protocol(mock, "TEST", "test-repo", "README.md")
320
+ assert "README.md" in result
321
+
322
+ @patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
323
+ def test_repository_client_di_with_real_client(
324
+ self, mock_atlassian: Mock, mock_settings: BitbucketSettings
325
+ ) -> None:
326
+ """Functions accepting BitbucketRepositoryClient should work with real client."""
327
+ client = BitbucketClient(mock_settings)
328
+ mock_atlassian_instance = Mock()
329
+ mock_atlassian_instance.repo_list.return_value = [{"slug": "repo1"}, {"slug": "repo2"}]
330
+ client._client = mock_atlassian_instance
331
+
332
+ result = audit_repository_with_protocol(client, "TEST")
333
+ assert result["project"] == "TEST"
334
+ assert result["repository_count"] == 2