@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,314 @@
1
+ """Tests for JIRA issue link type CLI commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from unittest.mock import Mock, patch
7
+
8
+ import pytest
9
+ from typer.testing import CliRunner
10
+ from vds_jira_orchestrator.cli import app
11
+ from vds_jira_orchestrator.errors import JiraNotFound
12
+
13
+
14
+ @pytest.fixture
15
+ def runner() -> CliRunner:
16
+ """Create a CLI runner for testing."""
17
+ return CliRunner()
18
+
19
+
20
+ @pytest.fixture
21
+ def mock_adapter() -> Mock:
22
+ """Create a mock adapter."""
23
+ adapter = Mock()
24
+ adapter.get_issue_link_types.return_value = [
25
+ {"id": "10000", "name": "Blocks", "inward": "is blocked by", "outward": "blocks"},
26
+ {"id": "10001", "name": "Relates", "inward": "relates to", "outward": "relates to"},
27
+ ]
28
+ adapter.get_issue_link_type.return_value = {"id": "10000", "name": "Blocks", "inward": "is blocked by", "outward": "blocks"}
29
+ adapter.create_issue_link_type.return_value = {"id": "10002", "name": "Tests", "inward": "is tested by", "outward": "tests"}
30
+ adapter.update_issue_link_type.return_value = {"id": "10000", "name": "Blocks Updated", "inward": "is blocked by", "outward": "blocks"}
31
+ return adapter
32
+
33
+
34
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
35
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
36
+ def test_link_type_list_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
37
+ """Test link-type list command success."""
38
+ mock_settings = Mock()
39
+ mock_settings.base_url = "https://jira.example.com"
40
+ mock_settings.username = "test"
41
+ mock_settings.password = "test"
42
+ mock_settings.token = None
43
+ mock_settings.require_basic_or_token = Mock()
44
+ mock_settings_class.return_value = mock_settings
45
+ mock_adapter_class.return_value = mock_adapter
46
+
47
+ result = runner.invoke(app, ["link-type", "list"])
48
+
49
+ assert result.exit_code == 0
50
+ assert "link_types" in result.stdout
51
+ assert "Blocks" in result.stdout
52
+ mock_adapter.get_issue_link_types.assert_called_once()
53
+
54
+
55
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
56
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
57
+ def test_link_type_get_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
58
+ """Test link-type get command success."""
59
+ mock_settings = Mock()
60
+ mock_settings.base_url = "https://jira.example.com"
61
+ mock_settings.username = "test"
62
+ mock_settings.password = "test"
63
+ mock_settings.token = None
64
+ mock_settings.require_basic_or_token = Mock()
65
+ mock_settings_class.return_value = mock_settings
66
+ mock_adapter_class.return_value = mock_adapter
67
+
68
+ result = runner.invoke(app, ["link-type", "get", "--link-type-id", "10000"])
69
+
70
+ assert result.exit_code == 0
71
+ assert "Blocks" in result.stdout
72
+ mock_adapter.get_issue_link_type.assert_called_once_with("10000")
73
+
74
+
75
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
76
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
77
+ def test_link_type_get_missing_id(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
78
+ """Test link-type get command with missing link-type-id."""
79
+ mock_settings = Mock()
80
+ mock_settings.base_url = "https://jira.example.com"
81
+ mock_settings.username = "test"
82
+ mock_settings.password = "test"
83
+ mock_settings.token = None
84
+ mock_settings.require_basic_or_token = Mock()
85
+ mock_settings_class.return_value = mock_settings
86
+
87
+ result = runner.invoke(app, ["link-type", "get"])
88
+
89
+ assert result.exit_code != 0
90
+ assert "link-type-id required" in result.stdout or "link-type-id required" in result.stderr
91
+
92
+
93
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
94
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
95
+ def test_link_type_create_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
96
+ """Test link-type create command success."""
97
+ mock_settings = Mock()
98
+ mock_settings.base_url = "https://jira.example.com"
99
+ mock_settings.username = "test"
100
+ mock_settings.password = "test"
101
+ mock_settings.token = None
102
+ mock_settings.require_basic_or_token = Mock()
103
+ mock_settings_class.return_value = mock_settings
104
+ mock_adapter_class.return_value = mock_adapter
105
+
106
+ result = runner.invoke(
107
+ app,
108
+ [
109
+ "link-type",
110
+ "create",
111
+ "--name",
112
+ "Tests",
113
+ "--inward",
114
+ "is tested by",
115
+ "--outward",
116
+ "tests",
117
+ "--yes",
118
+ ],
119
+ )
120
+
121
+ assert result.exit_code == 0
122
+ assert "Tests" in result.stdout
123
+ mock_adapter.create_issue_link_type.assert_called_once_with({"name": "Tests", "inward": "is tested by", "outward": "tests"})
124
+
125
+
126
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
127
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
128
+ def test_link_type_create_with_data_file(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock, tmp_path: Path) -> None:
129
+ """Test link-type create command with data file."""
130
+ mock_settings = Mock()
131
+ mock_settings.base_url = "https://jira.example.com"
132
+ mock_settings.username = "test"
133
+ mock_settings.password = "test"
134
+ mock_settings.token = None
135
+ mock_settings.require_basic_or_token = Mock()
136
+ mock_settings_class.return_value = mock_settings
137
+ mock_adapter_class.return_value = mock_adapter
138
+
139
+ data_file = tmp_path / "link_type.json"
140
+ data_file.write_text('{"name": "Tests", "inward": "is tested by", "outward": "tests"}')
141
+
142
+ result = runner.invoke(app, ["link-type", "create", "--data-file", str(data_file), "--yes"])
143
+
144
+ assert result.exit_code == 0
145
+ assert "Tests" in result.stdout
146
+ mock_adapter.create_issue_link_type.assert_called_once_with({"name": "Tests", "inward": "is tested by", "outward": "tests"})
147
+
148
+
149
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
150
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
151
+ def test_link_type_create_requires_yes(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
152
+ """Test link-type create command requires --yes flag."""
153
+ mock_settings = Mock()
154
+ mock_settings.base_url = "https://jira.example.com"
155
+ mock_settings.username = "test"
156
+ mock_settings.password = "test"
157
+ mock_settings.token = None
158
+ mock_settings.require_basic_or_token = Mock()
159
+ mock_settings_class.return_value = mock_settings
160
+
161
+ result = runner.invoke(app, ["link-type", "create", "--name", "Tests", "--inward", "is tested by", "--outward", "tests"])
162
+
163
+ assert result.exit_code != 0
164
+ assert "without --yes" in result.stdout or "without --yes" in result.stderr
165
+
166
+
167
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
168
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
169
+ def test_link_type_create_missing_params(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
170
+ """Test link-type create command with missing parameters."""
171
+ mock_settings = Mock()
172
+ mock_settings.base_url = "https://jira.example.com"
173
+ mock_settings.username = "test"
174
+ mock_settings.password = "test"
175
+ mock_settings.token = None
176
+ mock_settings.require_basic_or_token = Mock()
177
+ mock_settings_class.return_value = mock_settings
178
+
179
+ result = runner.invoke(app, ["link-type", "create", "--name", "Tests", "--yes"])
180
+
181
+ assert result.exit_code != 0
182
+ assert "required" in result.stdout or "required" in result.stderr
183
+
184
+
185
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
186
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
187
+ def test_link_type_update_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
188
+ """Test link-type update command success."""
189
+ mock_settings = Mock()
190
+ mock_settings.base_url = "https://jira.example.com"
191
+ mock_settings.username = "test"
192
+ mock_settings.password = "test"
193
+ mock_settings.token = None
194
+ mock_settings.require_basic_or_token = Mock()
195
+ mock_settings_class.return_value = mock_settings
196
+ mock_adapter_class.return_value = mock_adapter
197
+
198
+ result = runner.invoke(
199
+ app,
200
+ [
201
+ "link-type",
202
+ "update",
203
+ "--link-type-id",
204
+ "10000",
205
+ "--name",
206
+ "Blocks Updated",
207
+ "--inward",
208
+ "is blocked by",
209
+ "--outward",
210
+ "blocks",
211
+ "--yes",
212
+ ],
213
+ )
214
+
215
+ assert result.exit_code == 0
216
+ assert "Blocks Updated" in result.stdout
217
+ mock_adapter.update_issue_link_type.assert_called_once_with("10000", {"name": "Blocks Updated", "inward": "is blocked by", "outward": "blocks"})
218
+
219
+
220
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
221
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
222
+ def test_link_type_update_requires_yes(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
223
+ """Test link-type update command requires --yes flag."""
224
+ mock_settings = Mock()
225
+ mock_settings.base_url = "https://jira.example.com"
226
+ mock_settings.username = "test"
227
+ mock_settings.password = "test"
228
+ mock_settings.token = None
229
+ mock_settings.require_basic_or_token = Mock()
230
+ mock_settings_class.return_value = mock_settings
231
+
232
+ result = runner.invoke(
233
+ app, ["link-type", "update", "--link-type-id", "10000", "--name", "Blocks Updated", "--inward", "is blocked by", "--outward", "blocks"]
234
+ )
235
+
236
+ assert result.exit_code != 0
237
+ assert "without --yes" in result.stdout or "without --yes" in result.stderr
238
+
239
+
240
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
241
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
242
+ def test_link_type_delete_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
243
+ """Test link-type delete command success."""
244
+ mock_settings = Mock()
245
+ mock_settings.base_url = "https://jira.example.com"
246
+ mock_settings.username = "test"
247
+ mock_settings.password = "test"
248
+ mock_settings.token = None
249
+ mock_settings.require_basic_or_token = Mock()
250
+ mock_settings_class.return_value = mock_settings
251
+ mock_adapter_class.return_value = mock_adapter
252
+
253
+ result = runner.invoke(app, ["link-type", "delete", "--link-type-id", "10000", "--yes"])
254
+
255
+ assert result.exit_code == 0
256
+ assert "deleted" in result.stdout
257
+ mock_adapter.delete_issue_link_type.assert_called_once_with("10000")
258
+
259
+
260
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
261
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
262
+ def test_link_type_delete_requires_yes(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
263
+ """Test link-type delete command requires --yes flag."""
264
+ mock_settings = Mock()
265
+ mock_settings.base_url = "https://jira.example.com"
266
+ mock_settings.username = "test"
267
+ mock_settings.password = "test"
268
+ mock_settings.token = None
269
+ mock_settings.require_basic_or_token = Mock()
270
+ mock_settings_class.return_value = mock_settings
271
+
272
+ result = runner.invoke(app, ["link-type", "delete", "--link-type-id", "10000"])
273
+
274
+ assert result.exit_code != 0
275
+ assert "without --yes" in result.stdout or "without --yes" in result.stderr
276
+
277
+
278
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
279
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
280
+ def test_link_type_unknown_action(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
281
+ """Test link-type command with unknown action."""
282
+ mock_settings = Mock()
283
+ mock_settings.base_url = "https://jira.example.com"
284
+ mock_settings.username = "test"
285
+ mock_settings.password = "test"
286
+ mock_settings.token = None
287
+ mock_settings.require_basic_or_token = Mock()
288
+ mock_settings_class.return_value = mock_settings
289
+
290
+ result = runner.invoke(app, ["link-type", "unknown"])
291
+
292
+ assert result.exit_code != 0
293
+ assert "Unknown action" in result.stdout or "Unknown action" in result.stderr
294
+
295
+
296
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
297
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
298
+ def test_link_type_error_handling(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
299
+ """Test link-type command error handling."""
300
+ mock_settings = Mock()
301
+ mock_settings.base_url = "https://jira.example.com"
302
+ mock_settings.username = "test"
303
+ mock_settings.password = "test"
304
+ mock_settings.token = None
305
+ mock_settings.require_basic_or_token = Mock()
306
+ mock_settings_class.return_value = mock_settings
307
+ mock_adapter_class.return_value = mock_adapter
308
+ mock_adapter.get_issue_link_type.side_effect = JiraNotFound("Link type not found")
309
+
310
+ result = runner.invoke(app, ["link-type", "get", "--link-type-id", "99999"])
311
+
312
+ assert result.exit_code != 0
313
+ assert "Error" in result.stdout or "Error" in result.stderr
314
+
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+ import typer
5
+ from vds_jira_orchestrator.cli import _parse_set
6
+
7
+
8
+ def test_parse_set_parses_objects_and_arrays() -> None:
9
+ result = _parse_set(
10
+ [
11
+ 'customfield_1={"value": "Option"}',
12
+ 'labels=["alpha", "beta"]',
13
+ ]
14
+ )
15
+
16
+ assert result["customfield_1"] == {"value": "Option"}
17
+ assert result["labels"] == ["alpha", "beta"]
18
+
19
+
20
+ def test_parse_set_keeps_scalars_as_strings_by_default() -> None:
21
+ result = _parse_set(["flag=true", "count=1"])
22
+
23
+ assert result["flag"] == "true"
24
+ assert result["count"] == "1"
25
+
26
+
27
+ def test_parse_set_allows_scalar_json_when_enabled() -> None:
28
+ result = _parse_set(["flag=true", "count=1"], allow_scalar_json=True)
29
+
30
+ assert result["flag"] is True
31
+ assert result["count"] == 1
32
+
33
+
34
+ @pytest.mark.parametrize("value", ["missing", "=value"])
35
+ def test_parse_set_rejects_invalid_items(value: str) -> None:
36
+ with pytest.raises(typer.BadParameter):
37
+ _parse_set([value])
@@ -0,0 +1,273 @@
1
+ """Tests for JIRA permission CLI commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from unittest.mock import Mock, patch
6
+
7
+ import pytest
8
+ from typer.testing import CliRunner
9
+ from vds_jira_orchestrator.cli import app
10
+ from vds_jira_orchestrator.errors import JiraAdapterError
11
+
12
+
13
+ @pytest.fixture
14
+ def runner() -> CliRunner:
15
+ """Create a CLI runner for testing."""
16
+ return CliRunner()
17
+
18
+
19
+ @pytest.fixture
20
+ def mock_adapter() -> Mock:
21
+ """Create a mock adapter."""
22
+ adapter = Mock()
23
+ adapter.get_all_permissions.return_value = [
24
+ {"id": "ADMINISTER_PROJECTS", "name": "Administer Projects"},
25
+ {"id": "BROWSE_PROJECTS", "name": "Browse Projects"},
26
+ ]
27
+ adapter.get_permissions.return_value = {
28
+ "permissions": {
29
+ "ADMINISTER_PROJECTS": {"havePermission": True},
30
+ "BROWSE_PROJECTS": {"havePermission": True},
31
+ }
32
+ }
33
+ adapter.get_project_permission_scheme.return_value = {
34
+ "id": "10000",
35
+ "name": "Default Permission Scheme",
36
+ "permissions": [],
37
+ }
38
+ adapter.get_project_issue_security_scheme.return_value = {
39
+ "id": "10000",
40
+ "name": "Default Security Scheme",
41
+ "levels": [],
42
+ }
43
+ return adapter
44
+
45
+
46
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
47
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
48
+ def test_permissions_all_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
49
+ """Test permissions all command success."""
50
+ mock_settings = Mock()
51
+ mock_settings.base_url = "https://jira.example.com"
52
+ mock_settings.username = "test"
53
+ mock_settings.password = "test"
54
+ mock_settings.token = None
55
+ mock_settings.require_basic_or_token = Mock()
56
+ mock_settings_class.return_value = mock_settings
57
+ mock_adapter_class.return_value = mock_adapter
58
+
59
+ result = runner.invoke(app, ["permissions", "all"])
60
+
61
+ assert result.exit_code == 0
62
+ assert "permissions" in result.stdout
63
+ assert "ADMINISTER_PROJECTS" in result.stdout
64
+ mock_adapter.get_all_permissions.assert_called_once()
65
+
66
+
67
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
68
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
69
+ def test_permissions_check_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
70
+ """Test permissions check command success."""
71
+ mock_settings = Mock()
72
+ mock_settings.base_url = "https://jira.example.com"
73
+ mock_settings.username = "test"
74
+ mock_settings.password = "test"
75
+ mock_settings.token = None
76
+ mock_settings.require_basic_or_token = Mock()
77
+ mock_settings_class.return_value = mock_settings
78
+ mock_adapter_class.return_value = mock_adapter
79
+
80
+ result = runner.invoke(app, ["permissions", "check", "--permissions", "ADMINISTER_PROJECTS,BROWSE_PROJECTS"])
81
+
82
+ assert result.exit_code == 0
83
+ assert "permissions" in result.stdout
84
+ mock_adapter.get_permissions.assert_called_once_with(
85
+ permissions=["ADMINISTER_PROJECTS", "BROWSE_PROJECTS"],
86
+ project_key=None,
87
+ issue_key=None,
88
+ )
89
+
90
+
91
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
92
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
93
+ def test_permissions_check_with_project(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
94
+ """Test permissions check command with project key."""
95
+ mock_settings = Mock()
96
+ mock_settings.base_url = "https://jira.example.com"
97
+ mock_settings.username = "test"
98
+ mock_settings.password = "test"
99
+ mock_settings.token = None
100
+ mock_settings.require_basic_or_token = Mock()
101
+ mock_settings_class.return_value = mock_settings
102
+ mock_adapter_class.return_value = mock_adapter
103
+
104
+ result = runner.invoke(
105
+ app, ["permissions", "check", "--permissions", "ADMINISTER_PROJECTS", "--project-key", "NTTC"]
106
+ )
107
+
108
+ assert result.exit_code == 0
109
+ mock_adapter.get_permissions.assert_called_once_with(
110
+ permissions=["ADMINISTER_PROJECTS"],
111
+ project_key="NTTC",
112
+ issue_key=None,
113
+ )
114
+
115
+
116
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
117
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
118
+ def test_permissions_check_with_issue(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
119
+ """Test permissions check command with issue key."""
120
+ mock_settings = Mock()
121
+ mock_settings.base_url = "https://jira.example.com"
122
+ mock_settings.username = "test"
123
+ mock_settings.password = "test"
124
+ mock_settings.token = None
125
+ mock_settings.require_basic_or_token = Mock()
126
+ mock_settings_class.return_value = mock_settings
127
+ mock_adapter_class.return_value = mock_adapter
128
+
129
+ result = runner.invoke(
130
+ app, ["permissions", "check", "--permissions", "BROWSE_PROJECTS", "--issue-key", "NTTC-123"]
131
+ )
132
+
133
+ assert result.exit_code == 0
134
+ mock_adapter.get_permissions.assert_called_once_with(
135
+ permissions=["BROWSE_PROJECTS"],
136
+ project_key=None,
137
+ issue_key="NTTC-123",
138
+ )
139
+
140
+
141
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
142
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
143
+ def test_permissions_check_missing_permissions(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
144
+ """Test permissions check command with missing permissions."""
145
+ mock_settings = Mock()
146
+ mock_settings.base_url = "https://jira.example.com"
147
+ mock_settings.username = "test"
148
+ mock_settings.password = "test"
149
+ mock_settings.token = None
150
+ mock_settings.require_basic_or_token = Mock()
151
+ mock_settings_class.return_value = mock_settings
152
+
153
+ result = runner.invoke(app, ["permissions", "check"])
154
+
155
+ assert result.exit_code != 0
156
+ assert "permissions required" in result.stdout or "permissions required" in result.stderr
157
+
158
+
159
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
160
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
161
+ def test_permissions_unknown_action(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner) -> None:
162
+ """Test permissions command with unknown action."""
163
+ mock_settings = Mock()
164
+ mock_settings.base_url = "https://jira.example.com"
165
+ mock_settings.username = "test"
166
+ mock_settings.password = "test"
167
+ mock_settings.token = None
168
+ mock_settings.require_basic_or_token = Mock()
169
+ mock_settings_class.return_value = mock_settings
170
+
171
+ result = runner.invoke(app, ["permissions", "unknown"])
172
+
173
+ assert result.exit_code != 0
174
+ assert "Unknown action" in result.stdout or "Unknown action" in result.stderr
175
+
176
+
177
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
178
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
179
+ def test_permission_scheme_get_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
180
+ """Test permission-scheme get command success."""
181
+ mock_settings = Mock()
182
+ mock_settings.base_url = "https://jira.example.com"
183
+ mock_settings.username = "test"
184
+ mock_settings.password = "test"
185
+ mock_settings.token = None
186
+ mock_settings.require_basic_or_token = Mock()
187
+ mock_settings_class.return_value = mock_settings
188
+ mock_adapter_class.return_value = mock_adapter
189
+
190
+ result = runner.invoke(app, ["permission-scheme", "NTTC"])
191
+
192
+ assert result.exit_code == 0
193
+ assert "Default Permission Scheme" in result.stdout
194
+ mock_adapter.get_project_permission_scheme.assert_called_once_with("NTTC", expand=None)
195
+
196
+
197
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
198
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
199
+ def test_permission_scheme_get_with_expand(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
200
+ """Test permission-scheme get command with expand."""
201
+ mock_settings = Mock()
202
+ mock_settings.base_url = "https://jira.example.com"
203
+ mock_settings.username = "test"
204
+ mock_settings.password = "test"
205
+ mock_settings.token = None
206
+ mock_settings.require_basic_or_token = Mock()
207
+ mock_settings_class.return_value = mock_settings
208
+ mock_adapter_class.return_value = mock_adapter
209
+
210
+ result = runner.invoke(app, ["permission-scheme", "NTTC", "--expand", "permissions,user"])
211
+
212
+ assert result.exit_code == 0
213
+ mock_adapter.get_project_permission_scheme.assert_called_once_with("NTTC", expand="permissions,user")
214
+
215
+
216
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
217
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
218
+ def test_issue_security_scheme_get_success(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
219
+ """Test issue-security-scheme get command success."""
220
+ mock_settings = Mock()
221
+ mock_settings.base_url = "https://jira.example.com"
222
+ mock_settings.username = "test"
223
+ mock_settings.password = "test"
224
+ mock_settings.token = None
225
+ mock_settings.require_basic_or_token = Mock()
226
+ mock_settings_class.return_value = mock_settings
227
+ mock_adapter_class.return_value = mock_adapter
228
+
229
+ result = runner.invoke(app, ["issue-security-scheme", "NTTC"])
230
+
231
+ assert result.exit_code == 0
232
+ assert "Default Security Scheme" in result.stdout
233
+ mock_adapter.get_project_issue_security_scheme.assert_called_once_with("NTTC", only_levels=False)
234
+
235
+
236
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
237
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
238
+ def test_issue_security_scheme_get_with_only_levels(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
239
+ """Test issue-security-scheme get command with --only-levels."""
240
+ mock_settings = Mock()
241
+ mock_settings.base_url = "https://jira.example.com"
242
+ mock_settings.username = "test"
243
+ mock_settings.password = "test"
244
+ mock_settings.token = None
245
+ mock_settings.require_basic_or_token = Mock()
246
+ mock_settings_class.return_value = mock_settings
247
+ mock_adapter_class.return_value = mock_adapter
248
+
249
+ result = runner.invoke(app, ["issue-security-scheme", "NTTC", "--only-levels"])
250
+
251
+ assert result.exit_code == 0
252
+ mock_adapter.get_project_issue_security_scheme.assert_called_once_with("NTTC", only_levels=True)
253
+
254
+
255
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
256
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
257
+ def test_permissions_error_handling(mock_settings_class: Mock, mock_adapter_class: Mock, runner: CliRunner, mock_adapter: Mock) -> None:
258
+ """Test permissions command error handling."""
259
+ mock_settings = Mock()
260
+ mock_settings.base_url = "https://jira.example.com"
261
+ mock_settings.username = "test"
262
+ mock_settings.password = "test"
263
+ mock_settings.token = None
264
+ mock_settings.require_basic_or_token = Mock()
265
+ mock_settings_class.return_value = mock_settings
266
+ mock_adapter_class.return_value = mock_adapter
267
+ mock_adapter.get_all_permissions.side_effect = JiraAdapterError("Adapter error")
268
+
269
+ result = runner.invoke(app, ["permissions", "all"])
270
+
271
+ assert result.exit_code != 0
272
+ assert "Error" in result.stdout or "Error" in result.stderr
273
+