@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,335 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from tempfile import NamedTemporaryFile
5
+ from unittest.mock import Mock, patch
6
+
7
+ from typer.testing import CliRunner
8
+ from vds_bitbucket_orchestrator.cli import app
9
+ from vds_bitbucket_orchestrator.errors import BitbucketClientError
10
+
11
+
12
+ def _runner() -> CliRunner:
13
+ return CliRunner()
14
+
15
+
16
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
17
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
18
+ def test_code_insights_requires_cloud_mode(mock_load: Mock, mock_build: Mock) -> None:
19
+ """Test that Code Insights requires Cloud mode."""
20
+ runner = _runner()
21
+ settings = Mock()
22
+ settings.is_cloud_mode = False
23
+ mock_load.return_value = settings
24
+
25
+ result = runner.invoke(app, ["code-insights", "get", "PRJ", "repo", "abc123", "--report-key", "test-report"])
26
+ assert result.exit_code != 0
27
+ # Exit code 1 indicates Cloud mode requirement failed
28
+ mock_build.assert_not_called()
29
+
30
+
31
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
32
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
33
+ def test_code_insights_get_requires_report_key(mock_load: Mock, mock_build: Mock) -> None:
34
+ """Test that get requires --report-key."""
35
+ runner = _runner()
36
+ settings = Mock(is_cloud_mode=True)
37
+ mock_load.return_value = settings
38
+
39
+ result = runner.invoke(app, ["code-insights", "get", "PRJ", "repo", "abc123"])
40
+ assert result.exit_code != 0
41
+ assert "--report-key required" in result.stderr
42
+
43
+
44
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
45
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
46
+ def test_code_insights_get_success(mock_load: Mock, mock_build: Mock) -> None:
47
+ """Test successful Code Insights get."""
48
+ runner = _runner()
49
+ settings = Mock(is_cloud_mode=True)
50
+ mock_load.return_value = settings
51
+
52
+ client = Mock()
53
+ client.get_code_insights_report.return_value = {"title": "Test Report", "result": "PASSED"}
54
+ mock_build.return_value.__enter__.return_value = client
55
+
56
+ result = runner.invoke(app, ["code-insights", "get", "PRJ", "repo", "abc123", "--report-key", "test-report"])
57
+ assert result.exit_code == 0
58
+ client.get_code_insights_report.assert_called_once_with("PRJ", "repo", "abc123", "test-report")
59
+
60
+
61
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
62
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
63
+ def test_code_insights_create_requires_yes(mock_load: Mock, mock_build: Mock) -> None:
64
+ """Test that create requires --yes."""
65
+ runner = _runner()
66
+ settings = Mock(is_cloud_mode=True)
67
+ mock_load.return_value = settings
68
+
69
+ result = runner.invoke(
70
+ app,
71
+ [
72
+ "code-insights",
73
+ "create",
74
+ "PRJ",
75
+ "repo",
76
+ "abc123",
77
+ "--report-key",
78
+ "test-report",
79
+ "--title",
80
+ "Test",
81
+ "--reporter",
82
+ "test",
83
+ "--result",
84
+ "PASSED",
85
+ ],
86
+ )
87
+ assert result.exit_code != 0
88
+ assert "Refusing to create report without --yes" in result.stderr
89
+
90
+
91
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
92
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
93
+ def test_code_insights_create_requires_title(mock_load: Mock, mock_build: Mock) -> None:
94
+ """Test that create requires --title."""
95
+ runner = _runner()
96
+ settings = Mock(is_cloud_mode=True)
97
+ mock_load.return_value = settings
98
+
99
+ result = runner.invoke(
100
+ app,
101
+ [
102
+ "code-insights",
103
+ "create",
104
+ "PRJ",
105
+ "repo",
106
+ "abc123",
107
+ "--report-key",
108
+ "test-report",
109
+ "--reporter",
110
+ "test",
111
+ "--result",
112
+ "PASSED",
113
+ "--yes",
114
+ ],
115
+ )
116
+ assert result.exit_code != 0
117
+ assert "--title required" in result.stderr
118
+
119
+
120
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
121
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
122
+ def test_code_insights_create_success(mock_load: Mock, mock_build: Mock) -> None:
123
+ """Test successful Code Insights create."""
124
+ runner = _runner()
125
+ settings = Mock(is_cloud_mode=True)
126
+ mock_load.return_value = settings
127
+
128
+ client = Mock()
129
+ client.create_code_insights_report.return_value = {"title": "Test Report", "result": "PASSED"}
130
+ mock_build.return_value.__enter__.return_value = client
131
+
132
+ result = runner.invoke(
133
+ app,
134
+ [
135
+ "code-insights",
136
+ "create",
137
+ "PRJ",
138
+ "repo",
139
+ "abc123",
140
+ "--report-key",
141
+ "test-report",
142
+ "--title",
143
+ "Test Report",
144
+ "--reporter",
145
+ "test-reporter",
146
+ "--result",
147
+ "PASSED",
148
+ "--yes",
149
+ ],
150
+ )
151
+ assert result.exit_code == 0
152
+ client.create_code_insights_report.assert_called_once()
153
+ call_kwargs = client.create_code_insights_report.call_args[1]
154
+ assert call_kwargs["project_key"] == "PRJ"
155
+ assert call_kwargs["repository_slug"] == "repo"
156
+ assert call_kwargs["commit_id"] == "abc123"
157
+ assert call_kwargs["report_key"] == "test-report"
158
+ assert call_kwargs["report_title"] == "Test Report"
159
+ assert call_kwargs["reporter"] == "test-reporter"
160
+ assert call_kwargs["result"] == "PASSED"
161
+
162
+
163
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
164
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
165
+ def test_code_insights_create_with_data_file(mock_load: Mock, mock_build: Mock) -> None:
166
+ """Test create with data file."""
167
+ runner = _runner()
168
+ settings = Mock(is_cloud_mode=True)
169
+ mock_load.return_value = settings
170
+
171
+ client = Mock()
172
+ client.create_code_insights_report.return_value = {"title": "Test Report"}
173
+ mock_build.return_value.__enter__.return_value = client
174
+
175
+ with NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
176
+ f.write('[{"title": "Coverage", "type": "NUMBER", "value": 85}]')
177
+ data_file = Path(f.name)
178
+
179
+ try:
180
+ result = runner.invoke(
181
+ app,
182
+ [
183
+ "code-insights",
184
+ "create",
185
+ "PRJ",
186
+ "repo",
187
+ "abc123",
188
+ "--report-key",
189
+ "test-report",
190
+ "--title",
191
+ "Test Report",
192
+ "--reporter",
193
+ "test",
194
+ "--result",
195
+ "PASSED",
196
+ "--data-file",
197
+ str(data_file),
198
+ "--yes",
199
+ ],
200
+ )
201
+ assert result.exit_code == 0
202
+ call_kwargs = client.create_code_insights_report.call_args[1]
203
+ assert call_kwargs["data"] == [{"title": "Coverage", "type": "NUMBER", "value": 85}]
204
+ finally:
205
+ data_file.unlink()
206
+
207
+
208
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
209
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
210
+ def test_code_insights_annotate_requires_yes(mock_load: Mock, mock_build: Mock) -> None:
211
+ """Test that annotate requires --yes."""
212
+ runner = _runner()
213
+ settings = Mock(is_cloud_mode=True)
214
+ mock_load.return_value = settings
215
+
216
+ result = runner.invoke(app, ["code-insights", "annotate", "PRJ", "repo", "abc123", "--report-key", "test-report"])
217
+ assert result.exit_code != 0
218
+ assert "Refusing to add annotations without --yes" in result.stderr
219
+
220
+
221
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
222
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
223
+ def test_code_insights_annotate_requires_file(mock_load: Mock, mock_build: Mock) -> None:
224
+ """Test that annotate requires --annotations-file."""
225
+ runner = _runner()
226
+ settings = Mock(is_cloud_mode=True)
227
+ mock_load.return_value = settings
228
+
229
+ result = runner.invoke(
230
+ app, ["code-insights", "annotate", "PRJ", "repo", "abc123", "--report-key", "test-report", "--yes"]
231
+ )
232
+ assert result.exit_code != 0
233
+ assert "--annotations-file required" in result.stderr
234
+
235
+
236
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
237
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
238
+ def test_code_insights_annotate_success(mock_load: Mock, mock_build: Mock) -> None:
239
+ """Test successful Code Insights annotate."""
240
+ runner = _runner()
241
+ settings = Mock(is_cloud_mode=True)
242
+ mock_load.return_value = settings
243
+
244
+ client = Mock()
245
+ client.add_code_insights_annotations_to_report.return_value = {"annotations": []}
246
+ mock_build.return_value.__enter__.return_value = client
247
+
248
+ with NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
249
+ f.write('[{"path": "file.py", "line": 10, "severity": "HIGH"}]')
250
+ annotations_file = Path(f.name)
251
+
252
+ try:
253
+ result = runner.invoke(
254
+ app,
255
+ [
256
+ "code-insights",
257
+ "annotate",
258
+ "PRJ",
259
+ "repo",
260
+ "abc123",
261
+ "--report-key",
262
+ "test-report",
263
+ "--annotations-file",
264
+ str(annotations_file),
265
+ "--yes",
266
+ ],
267
+ )
268
+ assert result.exit_code == 0
269
+ client.add_code_insights_annotations_to_report.assert_called_once_with(
270
+ "PRJ", "repo", "abc123", "test-report", [{"path": "file.py", "line": 10, "severity": "HIGH"}]
271
+ )
272
+ finally:
273
+ annotations_file.unlink()
274
+
275
+
276
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
277
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
278
+ def test_code_insights_delete_requires_yes(mock_load: Mock, mock_build: Mock) -> None:
279
+ """Test that delete requires --yes."""
280
+ runner = _runner()
281
+ settings = Mock(is_cloud_mode=True)
282
+ mock_load.return_value = settings
283
+
284
+ result = runner.invoke(app, ["code-insights", "delete", "PRJ", "repo", "abc123", "--report-key", "test-report"])
285
+ assert result.exit_code != 0
286
+ assert "Refusing to delete report without --yes" in result.stderr
287
+
288
+
289
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
290
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
291
+ def test_code_insights_delete_success(mock_load: Mock, mock_build: Mock) -> None:
292
+ """Test successful Code Insights delete."""
293
+ runner = _runner()
294
+ settings = Mock(is_cloud_mode=True)
295
+ mock_load.return_value = settings
296
+
297
+ client = Mock()
298
+ mock_build.return_value.__enter__.return_value = client
299
+
300
+ result = runner.invoke(
301
+ app, ["code-insights", "delete", "PRJ", "repo", "abc123", "--report-key", "test-report", "--yes"]
302
+ )
303
+ assert result.exit_code == 0
304
+ client.delete_code_insights_report.assert_called_once_with("PRJ", "repo", "abc123", "test-report")
305
+
306
+
307
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
308
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
309
+ def test_code_insights_unknown_action(mock_load: Mock, mock_build: Mock) -> None:
310
+ """Test that unknown action raises error."""
311
+ runner = _runner()
312
+ settings = Mock(is_cloud_mode=True)
313
+ mock_load.return_value = settings
314
+
315
+ result = runner.invoke(app, ["code-insights", "unknown", "PRJ", "repo", "abc123", "--report-key", "test-report"])
316
+ assert result.exit_code != 0
317
+ assert "Unknown action" in result.stderr
318
+
319
+
320
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
321
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
322
+ def test_code_insights_client_error(mock_load: Mock, mock_build: Mock) -> None:
323
+ """Test that client errors are handled."""
324
+ runner = _runner()
325
+ settings = Mock(is_cloud_mode=True)
326
+ mock_load.return_value = settings
327
+
328
+ client = Mock()
329
+ client.get_code_insights_report.side_effect = BitbucketClientError("Client error", context={})
330
+ mock_build.return_value.__enter__.return_value = client
331
+
332
+ result = runner.invoke(app, ["code-insights", "get", "PRJ", "repo", "abc123", "--report-key", "test-report"])
333
+ assert result.exit_code != 0
334
+ assert "Error" in result.stderr
335
+
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from unittest.mock import Mock, patch
6
+
7
+ from typer.testing import CliRunner
8
+ from vds_bitbucket_orchestrator.cli import app
9
+ from vds_bitbucket_orchestrator.errors import BitbucketClientError
10
+
11
+
12
+ def _runner() -> CliRunner:
13
+ return CliRunner()
14
+
15
+
16
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
17
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
18
+ def test_conditions_list_project(mock_load: Mock, mock_build: Mock) -> None:
19
+ runner = _runner()
20
+ client = Mock()
21
+ client.get_project_conditions.return_value = []
22
+ mock_build.return_value.__enter__.return_value = client
23
+
24
+ result = runner.invoke(app, ["conditions", "list", "PRJ"])
25
+ assert result.exit_code == 0
26
+ client.get_project_conditions.assert_called_once_with("PRJ")
27
+
28
+
29
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
30
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
31
+ def test_conditions_list_repo(mock_load: Mock, mock_build: Mock) -> None:
32
+ runner = _runner()
33
+ client = Mock()
34
+ client.get_repo_conditions.return_value = []
35
+ mock_build.return_value.__enter__.return_value = client
36
+
37
+ result = runner.invoke(app, ["conditions", "list", "PRJ", "--repo", "repo"])
38
+ assert result.exit_code == 0
39
+ client.get_repo_conditions.assert_called_once_with("PRJ", "repo")
40
+
41
+
42
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
43
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
44
+ def test_conditions_get_repo(mock_load: Mock, mock_build: Mock) -> None:
45
+ runner = _runner()
46
+ client = Mock()
47
+ client.get_repo_condition.return_value = {"id": 5}
48
+ mock_build.return_value.__enter__.return_value = client
49
+
50
+ result = runner.invoke(app, ["conditions", "get", "PRJ", "--repo", "repo", "--condition-id", "5"])
51
+ assert result.exit_code == 0
52
+ client.get_repo_condition.assert_called_once_with("PRJ", "repo", 5)
53
+
54
+
55
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
56
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
57
+ def test_conditions_create_project(mock_load: Mock, mock_build: Mock, tmp_path: Path) -> None:
58
+ runner = _runner()
59
+ client = Mock()
60
+ mock_build.return_value.__enter__.return_value = client
61
+
62
+ payload = {"sourceMatcher": {"id": "any"}}
63
+ condition_file = tmp_path / "condition.json"
64
+ condition_file.write_text(json.dumps(payload))
65
+
66
+ result = runner.invoke(
67
+ app,
68
+ ["conditions", "create", "PRJ", "--condition-file", str(condition_file), "--yes"],
69
+ )
70
+ assert result.exit_code == 0
71
+ client.create_project_condition.assert_called_once_with("PRJ", payload)
72
+
73
+
74
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
75
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
76
+ def test_conditions_create_requires_file(mock_load: Mock, mock_build: Mock) -> None:
77
+ runner = _runner()
78
+
79
+ result = runner.invoke(
80
+ app,
81
+ ["conditions", "create", "PRJ", "--yes"],
82
+ )
83
+ assert result.exit_code != 0
84
+ assert "--condition-file required for create" in result.stdout
85
+
86
+
87
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
88
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
89
+ def test_conditions_create_project_error(mock_load: Mock, mock_build: Mock, tmp_path: Path) -> None:
90
+ runner = _runner()
91
+ client = Mock()
92
+ client.create_project_condition.side_effect = BitbucketClientError("fail")
93
+ mock_build.return_value.__enter__.return_value = client
94
+
95
+ payload = {"sourceMatcher": {"id": "any"}}
96
+ condition_file = tmp_path / "condition.json"
97
+ condition_file.write_text(json.dumps(payload))
98
+
99
+ result = runner.invoke(
100
+ app,
101
+ ["conditions", "create", "PRJ", "--condition-file", str(condition_file), "--yes"],
102
+ )
103
+ assert result.exit_code != 0
104
+ assert "bitbucket_error" in result.stdout
105
+
106
+
107
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
108
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
109
+ def test_conditions_update_repo(mock_load: Mock, mock_build: Mock, tmp_path: Path) -> None:
110
+ runner = _runner()
111
+ client = Mock()
112
+ mock_build.return_value.__enter__.return_value = client
113
+
114
+ payload = {"targetMatcher": {"id": "refs/heads/main"}}
115
+ condition_file = tmp_path / "condition.json"
116
+ condition_file.write_text(json.dumps(payload))
117
+
118
+ result = runner.invoke(
119
+ app,
120
+ [
121
+ "conditions",
122
+ "update",
123
+ "PRJ",
124
+ "--repo",
125
+ "repo",
126
+ "--condition-id",
127
+ "11",
128
+ "--condition-file",
129
+ str(condition_file),
130
+ "--yes",
131
+ ],
132
+ )
133
+ assert result.exit_code == 0
134
+ client.update_repo_condition.assert_called_once_with("PRJ", "repo", payload, 11)
135
+
136
+
137
+ @patch("vds_bitbucket_orchestrator.cli._build_client")
138
+ @patch("vds_bitbucket_orchestrator.cli.load_settings")
139
+ def test_conditions_delete_requires_id(mock_load: Mock, mock_build: Mock) -> None:
140
+ runner = _runner()
141
+
142
+ result = runner.invoke(
143
+ app,
144
+ ["conditions", "delete", "PRJ", "--yes"],
145
+ )
146
+ assert result.exit_code != 0
147
+ assert "--condition-id required for delete" in result.stdout
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+ from vds_bitbucket_orchestrator.config import load_settings
7
+
8
+
9
+ def write_env(tmp_path: Path, content: str) -> Path:
10
+ """Write a temporary .env file for testing."""
11
+ env_path = tmp_path / ".env"
12
+ env_path.write_text(content)
13
+ return env_path
14
+
15
+
16
+ def clear_runtime_env(monkeypatch: pytest.MonkeyPatch) -> None:
17
+ """Clear runtime environment variables for testing."""
18
+ for key in (
19
+ "VDS_USERNAME",
20
+ "VDS_PASSWORD",
21
+ "BITBUCKET_TOKEN",
22
+ "BITBUCKET_BASE_URL",
23
+ "BITBUCKET_CLOUD_WORKSPACE",
24
+ "BITBUCKET_MODE",
25
+ ):
26
+ monkeypatch.delenv(key, raising=False)
27
+
28
+
29
+ def test_load_settings_prefers_env_over_file(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
30
+ """Test that environment variables take precedence over file settings."""
31
+ clear_runtime_env(monkeypatch)
32
+ env_path = write_env(
33
+ tmp_path,
34
+ """
35
+ VDS_USERNAME=file_user
36
+ VDS_PASSWORD=file_pass
37
+ BITBUCKET_TOKEN=file_token
38
+ BITBUCKET_MODE=server
39
+ """.strip(),
40
+ )
41
+
42
+ monkeypatch.setenv("VDS_USERNAME", "env_user")
43
+ settings = load_settings(env_path=env_path)
44
+
45
+ assert settings.username == "env_user"
46
+ assert settings.password == "file_pass"
47
+ assert settings.token == "file_token"
48
+ assert settings.mode == "server"
49
+
50
+
51
+ def test_load_settings_strict_requires_credentials(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
52
+ """Test that strict mode requires either basic auth or token."""
53
+ clear_runtime_env(monkeypatch)
54
+ env_path = write_env(
55
+ tmp_path,
56
+ """
57
+ VDS_USERNAME=file_user
58
+ VDS_PASSWORD=file_pass
59
+ """.strip(),
60
+ )
61
+
62
+ # Should work with basic auth
63
+ settings = load_settings(env_path=env_path, strict=True)
64
+ assert settings.username == "file_user"
65
+ assert settings.password == "file_pass"
66
+
67
+ # Should fail with no credentials
68
+ clear_runtime_env(monkeypatch)
69
+ empty_env_path = write_env(tmp_path, "")
70
+ with pytest.raises(ValueError, match="Missing credentials"):
71
+ load_settings(env_path=empty_env_path, strict=True)
72
+
73
+
74
+ def test_cloud_mode_configuration(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
75
+ """Test cloud mode configuration validation."""
76
+ clear_runtime_env(monkeypatch)
77
+ env_path = write_env(
78
+ tmp_path,
79
+ """
80
+ BITBUCKET_MODE=cloud
81
+ BITBUCKET_CLOUD_WORKSPACE=testworkspace
82
+ BITBUCKET_TOKEN=cloud_token
83
+ """.strip(),
84
+ )
85
+
86
+ settings = load_settings(env_path=env_path, strict=True)
87
+ assert settings.is_cloud_mode
88
+ assert settings.cloud_workspace == "testworkspace"
89
+ assert settings.token == "cloud_token"
90
+
91
+ # Test URL generation for cloud mode
92
+ url = settings.get_url()
93
+ assert "testworkspace" in url
94
+ assert "api.bitbucket.org" in url
95
+
96
+
97
+ def test_server_mode_configuration(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
98
+ """Test server mode configuration validation."""
99
+ clear_runtime_env(monkeypatch)
100
+ env_path = write_env(
101
+ tmp_path,
102
+ """
103
+ BITBUCKET_MODE=server
104
+ BITBUCKET_BASE_URL=https://bitbucket.company.com
105
+ VDS_USERNAME=server_user
106
+ VDS_PASSWORD=server_pass
107
+ """.strip(),
108
+ )
109
+
110
+ settings = load_settings(env_path=env_path, strict=True)
111
+ assert settings.is_server_mode
112
+ assert str(settings.base_url) == "https://bitbucket.company.com"
113
+ assert settings.username == "server_user"
114
+ assert settings.password == "server_pass"
115
+
116
+
117
+ def test_auth_kwargs_generation(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
118
+ """Test authentication kwargs generation for different auth methods."""
119
+ clear_runtime_env(monkeypatch)
120
+
121
+ # Test token auth
122
+ token_env_path = write_env(tmp_path, "BITBUCKET_TOKEN=test_token\n")
123
+ settings = load_settings(env_path=token_env_path)
124
+ auth_kwargs = settings.get_auth_kwargs()
125
+ assert auth_kwargs == {"token": "test_token"}
126
+
127
+ # Test basic auth
128
+ basic_env_path = write_env(tmp_path, "VDS_USERNAME=test_user\nVDS_PASSWORD=test_pass\n")
129
+ settings = load_settings(env_path=basic_env_path)
130
+ auth_kwargs = settings.get_auth_kwargs()
131
+ assert auth_kwargs == {"username": "test_user", "password": "test_pass"}