@ngocsangairvds/vsaf 3.1.27 → 3.2.2

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 +65 -39
  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,117 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ import pytest
6
+ from vds_jira_orchestrator.adapter import JiraAdapter, JiraAuthError, JiraNotFound
7
+
8
+
9
+ @patch("vds_jira_orchestrator.adapter.Jira")
10
+ def test_get_dashboard_calls_client(mock_jira: MagicMock) -> None:
11
+ """Test that get_dashboard calls the SDK client."""
12
+ client = MagicMock()
13
+ client.get_dashboard.return_value = {"id": "10000", "name": "Test Dashboard"}
14
+ mock_jira.return_value = client
15
+
16
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
17
+ result = adapter.get_dashboard("10000")
18
+
19
+ client.get_dashboard.assert_called_once_with("10000")
20
+ assert result == {"id": "10000", "name": "Test Dashboard"}
21
+
22
+
23
+ @patch("vds_jira_orchestrator.adapter.Jira")
24
+ def test_get_dashboard_with_int_id(mock_jira: MagicMock) -> None:
25
+ """Test that get_dashboard works with integer ID."""
26
+ client = MagicMock()
27
+ client.get_dashboard.return_value = {"id": 10000, "name": "Test Dashboard"}
28
+ mock_jira.return_value = client
29
+
30
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
31
+ result = adapter.get_dashboard(10000)
32
+
33
+ client.get_dashboard.assert_called_once_with(10000)
34
+ assert result == {"id": 10000, "name": "Test Dashboard"}
35
+
36
+
37
+ @patch("vds_jira_orchestrator.adapter.Jira")
38
+ def test_get_dashboard_not_found(mock_jira: MagicMock) -> None:
39
+ """Test that get_dashboard raises JiraNotFound when dashboard is not found."""
40
+ client = MagicMock()
41
+ client.get_dashboard.return_value = None
42
+ mock_jira.return_value = client
43
+
44
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
45
+
46
+ with pytest.raises(JiraNotFound, match="Dashboard not found: 99999"):
47
+ adapter.get_dashboard("99999")
48
+
49
+
50
+ @patch("vds_jira_orchestrator.adapter.Jira")
51
+ def test_get_dashboard_maps_error(mock_jira: MagicMock) -> None:
52
+ """Test that get_dashboard maps authentication errors."""
53
+ client = MagicMock()
54
+ client.get_dashboard.side_effect = Exception("401 unauthorized")
55
+ mock_jira.return_value = client
56
+
57
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
58
+
59
+ with pytest.raises(JiraAuthError):
60
+ adapter.get_dashboard("10000")
61
+
62
+
63
+ @patch("vds_jira_orchestrator.adapter.Jira")
64
+ def test_get_dashboards_calls_client(mock_jira: MagicMock) -> None:
65
+ """Test that get_dashboards calls the SDK client."""
66
+ client = MagicMock()
67
+ client.get_dashboards.return_value = {
68
+ "dashboards": [{"id": "10000", "name": "Dashboard 1"}, {"id": "10001", "name": "Dashboard 2"}]
69
+ }
70
+ mock_jira.return_value = client
71
+
72
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
73
+ result = adapter.get_dashboards()
74
+
75
+ client.get_dashboards.assert_called_once_with(filter="", start=0, limit=10)
76
+ assert len(result["dashboards"]) == 2
77
+
78
+
79
+ @patch("vds_jira_orchestrator.adapter.Jira")
80
+ def test_get_dashboards_with_filter(mock_jira: MagicMock) -> None:
81
+ """Test that get_dashboards works with filter and pagination."""
82
+ client = MagicMock()
83
+ client.get_dashboards.return_value = {"dashboards": []}
84
+ mock_jira.return_value = client
85
+
86
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
87
+ result = adapter.get_dashboards(filter="test", start=10, limit=20)
88
+
89
+ client.get_dashboards.assert_called_once_with(filter="test", start=10, limit=20)
90
+ assert result == {"dashboards": []}
91
+
92
+
93
+ @patch("vds_jira_orchestrator.adapter.Jira")
94
+ def test_get_dashboards_returns_empty_dict_when_none(mock_jira: MagicMock) -> None:
95
+ """Test that get_dashboards returns empty dict when client returns None."""
96
+ client = MagicMock()
97
+ client.get_dashboards.return_value = None
98
+ mock_jira.return_value = client
99
+
100
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
101
+ result = adapter.get_dashboards()
102
+
103
+ assert result == {}
104
+
105
+
106
+ @patch("vds_jira_orchestrator.adapter.Jira")
107
+ def test_get_dashboards_maps_error(mock_jira: MagicMock) -> None:
108
+ """Test that get_dashboards maps authentication errors."""
109
+ client = MagicMock()
110
+ client.get_dashboards.side_effect = Exception("401 unauthorized")
111
+ mock_jira.return_value = client
112
+
113
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
114
+
115
+ with pytest.raises(JiraAuthError):
116
+ adapter.get_dashboards()
117
+
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ from vds_jira_orchestrator.adapter import JiraAdapter
6
+
7
+
8
+ @patch("vds_jira_orchestrator.adapter.Jira")
9
+ def test_get_issue_property_keys_calls_sdk(mock_jira: MagicMock) -> None:
10
+ client = MagicMock()
11
+ client.get_issue_property_keys.return_value = {"keys": [{"key": "custom"}]}
12
+ mock_jira.return_value = client
13
+
14
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
15
+ payload = adapter.get_issue_property_keys("NTTC-1")
16
+
17
+ client.get_issue_property_keys.assert_called_once_with("NTTC-1")
18
+ assert payload == {"keys": [{"key": "custom"}]}
19
+
20
+
21
+ @patch("vds_jira_orchestrator.adapter.Jira")
22
+ def test_set_issue_property_calls_sdk(mock_jira: MagicMock) -> None:
23
+ client = MagicMock()
24
+ mock_jira.return_value = client
25
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
26
+
27
+ adapter.set_issue_property("NTTC-2", "custom.key", {"foo": "bar"})
28
+
29
+ client.set_issue_property.assert_called_once_with("NTTC-2", "custom.key", {"foo": "bar"})
30
+
31
+
32
+ @patch("vds_jira_orchestrator.adapter.Jira")
33
+ def test_get_issue_property_calls_sdk(mock_jira: MagicMock) -> None:
34
+ client = MagicMock()
35
+ client.get_issue_property.return_value = {"value": {"foo": "bar"}}
36
+ mock_jira.return_value = client
37
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
38
+
39
+ payload = adapter.get_issue_property("NTTC-3", "custom.key")
40
+
41
+ client.get_issue_property.assert_called_once_with("NTTC-3", "custom.key")
42
+ assert payload == {"value": {"foo": "bar"}}
43
+
44
+
45
+ @patch("vds_jira_orchestrator.adapter.Jira")
46
+ def test_delete_issue_property_calls_sdk(mock_jira: MagicMock) -> None:
47
+ client = MagicMock()
48
+ mock_jira.return_value = client
49
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
50
+
51
+ adapter.delete_issue_property("NTTC-4", "custom.key")
52
+
53
+ client.delete_issue_property.assert_called_once_with("NTTC-4", "custom.key")
54
+
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import Mock, patch
4
+
5
+ import pytest
6
+
7
+ from vds_jira_orchestrator.adapter import JiraAdapter
8
+ from vds_jira_orchestrator.errors import JiraAdapterError
9
+
10
+
11
+ @patch("vds_jira_orchestrator.adapter.Jira")
12
+ def test_get_permissions_uses_official_get_permissions(mock_jira: Mock) -> None:
13
+ class Client:
14
+ def __init__(self) -> None:
15
+ self.get_permissions = Mock(return_value={"permissions": {}})
16
+
17
+ client = Client()
18
+ mock_jira.return_value = client
19
+
20
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
21
+ adapter.get_permissions(permissions=["BROWSE_PROJECTS", "ADMINISTER_PROJECTS"], project_key="NTTC")
22
+
23
+ client.get_permissions.assert_called_once_with(
24
+ permissions="BROWSE_PROJECTS,ADMINISTER_PROJECTS",
25
+ project_id=None,
26
+ project_key="NTTC",
27
+ issue_id=None,
28
+ issue_key=None,
29
+ )
30
+
31
+
32
+ @patch("vds_jira_orchestrator.adapter.Jira")
33
+ def test_get_permissions_raises_when_not_supported(mock_jira: Mock) -> None:
34
+ class Client:
35
+ pass
36
+
37
+ client = Client()
38
+ mock_jira.return_value = client
39
+
40
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
41
+ with pytest.raises(JiraAdapterError):
42
+ adapter.get_permissions(permissions=["BROWSE_PROJECTS"])
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ import pytest
6
+ from vds_jira_orchestrator.adapter import JiraAdapter, JiraAuthError
7
+
8
+
9
+ @patch("vds_jira_orchestrator.adapter.Jira")
10
+ def test_reindex_calls_client(mock_jira: MagicMock) -> None:
11
+ client = MagicMock()
12
+ client.reindex.return_value = {"taskId": 123}
13
+ mock_jira.return_value = client
14
+
15
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
16
+ result = adapter.reindex()
17
+
18
+ client.reindex.assert_called_once_with()
19
+ assert result == {"taskId": 123}
20
+
21
+
22
+ @patch("vds_jira_orchestrator.adapter.Jira")
23
+ def test_reindex_status_maps_error(mock_jira: MagicMock) -> None:
24
+ client = MagicMock()
25
+ client.reindex_status.side_effect = Exception("401 unauthorized")
26
+ mock_jira.return_value = client
27
+
28
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
29
+
30
+ with pytest.raises(JiraAuthError):
31
+ adapter.reindex_status()
32
+
33
+
34
+ @patch("vds_jira_orchestrator.adapter.Jira")
35
+ def test_move_issues_to_backlog(mock_jira: MagicMock) -> None:
36
+ client = MagicMock()
37
+ mock_jira.return_value = client
38
+
39
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
40
+ adapter.move_issues_to_backlog(["NTTC-1", "NTTC-2"])
41
+
42
+ client.move_issues_to_backlog.assert_called_once_with(["NTTC-1", "NTTC-2"])
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ from vds_jira_orchestrator.adapter import JiraAdapter
6
+
7
+
8
+ @patch("vds_jira_orchestrator.adapter.Jira")
9
+ def test_get_issue_remote_links_returns_list(mock_jira: MagicMock) -> None:
10
+ """Ensure get_issue_remote_links proxies to SDK and normalises response."""
11
+ client = MagicMock()
12
+ client.get_issue_remote_links.return_value = [{"id": 1}, {"id": 2}]
13
+ mock_jira.return_value = client
14
+
15
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
16
+ result = adapter.get_issue_remote_links("NTTC-1")
17
+
18
+ client.get_issue_remote_links.assert_called_once_with("NTTC-1")
19
+ assert result == [{"id": 1}, {"id": 2}]
20
+
21
+
22
+ @patch("vds_jira_orchestrator.adapter.Jira")
23
+ def test_create_or_update_issue_remote_link_calls_sdk(mock_jira: MagicMock) -> None:
24
+ """Ensure create_or_update_issue_remote_link delegates to SDK."""
25
+ client = MagicMock()
26
+ client.create_or_update_issue_remote_links.return_value = {"created": True}
27
+ mock_jira.return_value = client
28
+ payload = {"object": {"url": "https://example.com"}}
29
+
30
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
31
+ result = adapter.create_or_update_issue_remote_link("NTTC-2", payload)
32
+
33
+ client.create_or_update_issue_remote_links.assert_called_once_with("NTTC-2", payload)
34
+ assert result == {"created": True}
35
+
36
+
37
+ @patch("vds_jira_orchestrator.adapter.Jira")
38
+ def test_get_issue_remote_link_by_id_calls_sdk(mock_jira: MagicMock) -> None:
39
+ """Ensure get_issue_remote_link_by_id delegates to SDK."""
40
+ client = MagicMock()
41
+ client.get_issue_remote_link_by_id.return_value = {"id": 5}
42
+ mock_jira.return_value = client
43
+
44
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
45
+ result = adapter.get_issue_remote_link_by_id("NTTC-3", 5)
46
+
47
+ client.get_issue_remote_link_by_id.assert_called_once_with("NTTC-3", 5)
48
+ assert result == {"id": 5}
49
+
50
+
51
+ @patch("vds_jira_orchestrator.adapter.Jira")
52
+ def test_update_issue_remote_link_by_id_calls_sdk(mock_jira: MagicMock) -> None:
53
+ """Ensure update_issue_remote_link_by_id delegates to SDK."""
54
+ client = MagicMock()
55
+ client.update_issue_remote_link_by_id.return_value = {"updated": True}
56
+ mock_jira.return_value = client
57
+ payload = {"object": {"url": "https://example.com/updated"}}
58
+
59
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
60
+ result = adapter.update_issue_remote_link_by_id("NTTC-4", "abc", payload)
61
+
62
+ client.update_issue_remote_link_by_id.assert_called_once_with("NTTC-4", "abc", payload)
63
+ assert result == {"updated": True}
64
+
65
+
66
+ @patch("vds_jira_orchestrator.adapter.Jira")
67
+ def test_delete_issue_remote_link_by_id_calls_sdk(mock_jira: MagicMock) -> None:
68
+ """Ensure delete_issue_remote_link_by_id delegates to SDK."""
69
+ client = MagicMock()
70
+ mock_jira.return_value = client
71
+
72
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
73
+ adapter.delete_issue_remote_link_by_id("NTTC-5", 9)
74
+
75
+ client.delete_issue_remote_link_by_id.assert_called_once_with("NTTC-5", 9)
76
+
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import Mock, patch
4
+
5
+ import pytest
6
+
7
+ from vds_jira_orchestrator.adapter import JiraAdapter
8
+ from vds_jira_orchestrator.errors import JiraAdapterError
9
+
10
+
11
+ @patch("vds_jira_orchestrator.adapter.Jira")
12
+ def test_transition_issue_uses_issue_transition(mock_jira: Mock) -> None:
13
+ class Client:
14
+ def __init__(self) -> None:
15
+ self.get_issue_transitions = Mock(return_value=[{"id": 71, "name": "Cancelled"}])
16
+ self.issue_transition = Mock()
17
+
18
+ client = Client()
19
+ mock_jira.return_value = client
20
+
21
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
22
+ adapter.transition_issue("NTTC-1", "Cancelled")
23
+
24
+ client.get_issue_transitions.assert_called_once_with("NTTC-1")
25
+ client.issue_transition.assert_called_once_with("NTTC-1", "Cancelled")
26
+
27
+
28
+ @patch("vds_jira_orchestrator.adapter.Jira")
29
+ def test_transition_issue_falls_back_to_set_issue_status_by_transition_name(mock_jira: Mock) -> None:
30
+ class Client:
31
+ def __init__(self) -> None:
32
+ self.get_issue_transitions = Mock(return_value=[{"id": "11", "name": "Develop"}])
33
+ self.set_issue_status_by_transition_name = Mock()
34
+
35
+ client = Client()
36
+ mock_jira.return_value = client
37
+
38
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
39
+ adapter.transition_issue("NTTC-2", "Develop")
40
+
41
+ client.get_issue_transitions.assert_called_once_with("NTTC-2")
42
+ client.set_issue_status_by_transition_name.assert_called_once_with("NTTC-2", "Develop")
43
+
44
+
45
+ @patch("vds_jira_orchestrator.adapter.Jira")
46
+ def test_transition_issue_falls_back_to_set_issue_status_by_transition_id(mock_jira: Mock) -> None:
47
+ class Client:
48
+ def __init__(self) -> None:
49
+ self.get_issue_transitions = Mock(return_value=[{"id": 81, "name": "Pending"}])
50
+ self.set_issue_status_by_transition_id = Mock()
51
+
52
+ client = Client()
53
+ mock_jira.return_value = client
54
+
55
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
56
+ adapter.transition_issue("NTTC-3", "Pending")
57
+
58
+ client.get_issue_transitions.assert_called_once_with("NTTC-3")
59
+ client.set_issue_status_by_transition_id.assert_called_once_with("NTTC-3", 81)
60
+
61
+
62
+ @patch("vds_jira_orchestrator.adapter.Jira")
63
+ def test_get_issue_transitions_falls_back_to_full_payload(mock_jira: Mock) -> None:
64
+ class Client:
65
+ def __init__(self) -> None:
66
+ self.get_issue_transitions_full = Mock(
67
+ return_value={"transitions": [{"id": "41", "name": "Assign OS", "to": {"name": "Assign OS"}}]}
68
+ )
69
+
70
+ client = Client()
71
+ mock_jira.return_value = client
72
+
73
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
74
+ transitions = adapter.get_issue_transitions("NTTC-4")
75
+
76
+ assert transitions[0]["name"] == "Assign OS"
77
+ client.get_issue_transitions_full.assert_called_once_with("NTTC-4")
78
+
79
+
80
+ @patch("vds_jira_orchestrator.adapter.Jira")
81
+ def test_transition_issue_raises_when_transition_not_found(mock_jira: Mock) -> None:
82
+ class Client:
83
+ def __init__(self) -> None:
84
+ self.get_issue_transitions = Mock(return_value=[{"id": 71, "name": "Cancelled"}])
85
+
86
+ client = Client()
87
+ mock_jira.return_value = client
88
+
89
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
90
+ with pytest.raises(JiraAdapterError):
91
+ adapter.transition_issue("NTTC-5", "Done")
@@ -0,0 +1,110 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ import pytest
6
+ from vds_jira_orchestrator.adapter import JiraAdapter, JiraAdapterError
7
+
8
+
9
+ @patch("vds_jira_orchestrator.adapter.Jira")
10
+ def test_find_users_calls_client(mock_jira: MagicMock) -> None:
11
+ """Test that find_users calls the SDK client."""
12
+ client = MagicMock()
13
+ client.user_find_by_user_string.return_value = [
14
+ {"accountId": "123", "displayName": "Test User", "emailAddress": "test@example.com"}
15
+ ]
16
+ mock_jira.return_value = client
17
+
18
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
19
+ result = adapter.find_users(query="test@example.com")
20
+
21
+ client.user_find_by_user_string.assert_called_once_with(
22
+ query="test@example.com", start=0, limit=50, include_inactive_users=False
23
+ )
24
+ assert len(result) == 1
25
+ assert result[0]["accountId"] == "123"
26
+
27
+
28
+ @patch("vds_jira_orchestrator.adapter.Jira")
29
+ def test_find_users_with_pagination(mock_jira: MagicMock) -> None:
30
+ """Test that find_users passes pagination parameters."""
31
+ client = MagicMock()
32
+ client.user_find_by_user_string.return_value = []
33
+ mock_jira.return_value = client
34
+
35
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
36
+ adapter.find_users(query="test", start=10, limit=20, include_inactive=True)
37
+
38
+ client.user_find_by_user_string.assert_called_once_with(
39
+ query="test", start=10, limit=20, include_inactive_users=True
40
+ )
41
+
42
+
43
+ @patch("vds_jira_orchestrator.adapter.Jira")
44
+ def test_get_user_groups_cloud_mode(mock_jira: MagicMock) -> None:
45
+ """Test that get_user_groups works in Cloud mode."""
46
+ client = MagicMock()
47
+ client.get_user_groups.return_value = [{"name": "jira-users"}, {"name": "jira-administrators"}]
48
+ mock_jira.return_value = client
49
+
50
+ adapter = JiraAdapter(url="https://test.atlassian.net", username="user", password="pass")
51
+ result = adapter.get_user_groups("account-123")
52
+
53
+ client.get_user_groups.assert_called_once_with("account-123")
54
+ assert len(result) == 2
55
+ assert result[0]["name"] == "jira-users"
56
+
57
+
58
+ @patch("vds_jira_orchestrator.adapter.Jira")
59
+ def test_get_user_groups_server_mode_raises_error(mock_jira: MagicMock) -> None:
60
+ """Test that get_user_groups raises error in Server/DC mode."""
61
+ client = MagicMock()
62
+ mock_jira.return_value = client
63
+
64
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
65
+
66
+ with pytest.raises(JiraAdapterError, match="only available in Jira Cloud mode"):
67
+ adapter.get_user_groups("account-123")
68
+
69
+ client.get_user_groups.assert_not_called()
70
+
71
+
72
+ @patch("vds_jira_orchestrator.adapter.Jira")
73
+ def test_get_user_groups_explicit_cloud_mode(mock_jira: MagicMock) -> None:
74
+ """Test that get_user_groups works with explicit cloud=True."""
75
+ client = MagicMock()
76
+ client.get_user_groups.return_value = [{"name": "jira-users"}]
77
+ mock_jira.return_value = client
78
+
79
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass", cloud=True)
80
+ result = adapter.get_user_groups("account-123")
81
+
82
+ client.get_user_groups.assert_called_once_with("account-123")
83
+ assert len(result) == 1
84
+
85
+
86
+ @patch("vds_jira_orchestrator.adapter.Jira")
87
+ def test_deactivate_user_calls_client(mock_jira: MagicMock) -> None:
88
+ """Test that deactivate_user calls the SDK client."""
89
+ client = MagicMock()
90
+ client.user_deactivate.return_value = None
91
+ mock_jira.return_value = client
92
+
93
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
94
+ adapter.deactivate_user("testuser")
95
+
96
+ client.user_deactivate.assert_called_once_with("testuser")
97
+
98
+
99
+ @patch("vds_jira_orchestrator.adapter.Jira")
100
+ def test_deactivate_user_handles_error(mock_jira: MagicMock) -> None:
101
+ """Test that deactivate_user handles errors correctly."""
102
+ client = MagicMock()
103
+ client.user_deactivate.side_effect = Exception("User not found")
104
+ mock_jira.return_value = client
105
+
106
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
107
+
108
+ with pytest.raises(JiraAdapterError):
109
+ adapter.deactivate_user("nonexistent")
110
+
@@ -0,0 +1,133 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import MagicMock, patch
4
+
5
+ import pytest
6
+ from vds_jira_orchestrator.adapter import JiraAdapter, JiraAdapterError
7
+
8
+
9
+ @pytest.fixture
10
+ def mock_adapter() -> JiraAdapter:
11
+ """Fixture for a JiraAdapter."""
12
+ with patch("vds_jira_orchestrator.adapter.Jira") as mock_jira_class:
13
+ mock_client = MagicMock()
14
+ mock_jira_class.return_value = mock_client
15
+ adapter = JiraAdapter(url="https://jira.example.com", username="user", password="pass")
16
+ adapter._client = mock_client
17
+ return adapter
18
+
19
+
20
+ def test_get_project_versions_paginated_calls_client(mock_adapter: JiraAdapter) -> None:
21
+ """Test that get_project_versions_paginated calls the SDK client with correct parameters."""
22
+ mock_adapter._client.get_project_versions_paginated.return_value = {
23
+ "values": [{"id": "10000", "name": "1.0.0"}],
24
+ "startAt": 0,
25
+ "maxResults": 25,
26
+ }
27
+ result = mock_adapter.get_project_versions_paginated(project_key="TEST")
28
+ mock_adapter._client.get_project_versions_paginated.assert_called_once_with(
29
+ "TEST", start=None, limit=None, order_by=None, expand=None, query=None, status=None
30
+ )
31
+ assert "values" in result
32
+ assert len(result["values"]) == 1
33
+
34
+
35
+ def test_get_project_versions_paginated_with_pagination(mock_adapter: JiraAdapter) -> None:
36
+ """Test get_project_versions_paginated with pagination parameters."""
37
+ mock_adapter._client.get_project_versions_paginated.return_value = {
38
+ "values": [{"id": "10001", "name": "1.0.1"}],
39
+ "startAt": 10,
40
+ "maxResults": 20,
41
+ }
42
+ result = mock_adapter.get_project_versions_paginated(project_key="TEST", start=10, limit=20)
43
+ mock_adapter._client.get_project_versions_paginated.assert_called_once_with(
44
+ "TEST", start=10, limit=20, order_by=None, expand=None, query=None, status=None
45
+ )
46
+ assert result["startAt"] == 10
47
+
48
+
49
+ def test_get_project_versions_paginated_with_filtering(mock_adapter: JiraAdapter) -> None:
50
+ """Test get_project_versions_paginated with filtering and sorting."""
51
+ mock_adapter._client.get_project_versions_paginated.return_value = {
52
+ "values": [{"id": "10002", "name": "2.0.0"}],
53
+ "startAt": 0,
54
+ "maxResults": 25,
55
+ }
56
+ result = mock_adapter.get_project_versions_paginated(
57
+ project_key="TEST", order_by="name", query="2.0", status="released"
58
+ )
59
+ mock_adapter._client.get_project_versions_paginated.assert_called_once_with(
60
+ "TEST", start=None, limit=None, order_by="name", expand=None, query="2.0", status="released"
61
+ )
62
+ assert len(result["values"]) == 1
63
+
64
+
65
+ def test_add_version_calls_client(mock_adapter: JiraAdapter) -> None:
66
+ """Test that add_version calls the SDK client."""
67
+ mock_adapter._client.add_version.return_value = {"id": "10000", "name": "1.0.0"}
68
+ result = mock_adapter.add_version(key="TEST", project_id="10000", version="1.0.0")
69
+ mock_adapter._client.add_version.assert_called_once_with("TEST", "10000", "1.0.0", is_archived=False, is_released=False)
70
+ assert result["name"] == "1.0.0"
71
+
72
+
73
+ def test_add_version_with_flags(mock_adapter: JiraAdapter) -> None:
74
+ """Test add_version with archived and released flags."""
75
+ mock_adapter._client.add_version.return_value = {"id": "10001", "name": "1.0.1", "archived": True, "released": True}
76
+ result = mock_adapter.add_version(key="TEST", project_id="10000", version="1.0.1", is_archived=True, is_released=True)
77
+ mock_adapter._client.add_version.assert_called_once_with("TEST", "10000", "1.0.1", is_archived=True, is_released=True)
78
+ assert result["archived"] is True
79
+
80
+
81
+ def test_add_version_handles_error(mock_adapter: JiraAdapter) -> None:
82
+ """Test that add_version handles errors from the SDK client."""
83
+ mock_adapter._client.add_version.side_effect = Exception("API Error")
84
+ with pytest.raises(JiraAdapterError, match="API Error"):
85
+ mock_adapter.add_version(key="TEST", project_id="10000", version="1.0.0")
86
+
87
+
88
+ def test_update_version_calls_client(mock_adapter: JiraAdapter) -> None:
89
+ """Test that update_version calls the SDK client."""
90
+ mock_adapter._client.update_version.return_value = {"id": "10000", "name": "1.0.1"}
91
+ result = mock_adapter.update_version(version="10000", name="1.0.1")
92
+ mock_adapter._client.update_version.assert_called_once_with(
93
+ "10000", name="1.0.1", description=None, is_archived=None, is_released=None, start_date=None, release_date=None
94
+ )
95
+ assert result["name"] == "1.0.1"
96
+
97
+
98
+ def test_update_version_partial_update(mock_adapter: JiraAdapter) -> None:
99
+ """Test update_version with partial updates."""
100
+ mock_adapter._client.update_version.return_value = {
101
+ "id": "10000",
102
+ "name": "1.0.0",
103
+ "description": "Updated description",
104
+ "archived": True,
105
+ }
106
+ result = mock_adapter.update_version(version="10000", description="Updated description", is_archived=True)
107
+ mock_adapter._client.update_version.assert_called_once_with(
108
+ "10000", name=None, description="Updated description", is_archived=True, is_released=None, start_date=None, release_date=None
109
+ )
110
+ assert result["description"] == "Updated description"
111
+
112
+
113
+ def test_update_version_with_dates(mock_adapter: JiraAdapter) -> None:
114
+ """Test update_version with start and release dates."""
115
+ mock_adapter._client.update_version.return_value = {
116
+ "id": "10000",
117
+ "name": "1.0.0",
118
+ "startDate": "2025-01-01",
119
+ "releaseDate": "2025-01-31",
120
+ }
121
+ result = mock_adapter.update_version(version="10000", start_date="2025-01-01", release_date="2025-01-31")
122
+ mock_adapter._client.update_version.assert_called_once_with(
123
+ "10000", name=None, description=None, is_archived=None, is_released=None, start_date="2025-01-01", release_date="2025-01-31"
124
+ )
125
+ assert result["startDate"] == "2025-01-01"
126
+
127
+
128
+ def test_update_version_handles_error(mock_adapter: JiraAdapter) -> None:
129
+ """Test that update_version handles errors from the SDK client."""
130
+ mock_adapter._client.update_version.side_effect = Exception("API Error")
131
+ with pytest.raises(JiraAdapterError, match="API Error"):
132
+ mock_adapter.update_version(version="10000", name="1.0.1")
133
+