@ngocsangairvds/vsaf 3.1.26 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/package.json +2 -2
  2. package/src/global.js +70 -10
  3. package/tools/skills/vds-scripts-skill/.openskills.json +6 -0
  4. package/tools/skills/vds-scripts-skill/QUALITY.md +44 -0
  5. package/tools/skills/vds-scripts-skill/SKILL.md +135 -0
  6. package/tools/skills/vds-scripts-skill/references/audit-commands.md +171 -0
  7. package/tools/skills/vds-scripts-skill/references/capability-index.md +34 -0
  8. package/tools/skills/vds-scripts-skill/references/development-commands.md +12 -0
  9. package/tools/skills/vds-scripts-skill/references/google-sheets.md +73 -0
  10. package/tools/skills/vds-scripts-skill/references/integration-commands.md +17 -0
  11. package/tools/skills/vds-scripts-skill/references/platform-bootstrap.md +31 -0
  12. package/tools/skills/vds-scripts-skill/references/specialist-routing.md +14 -0
  13. package/tools/skills/vds-scripts-skill/references/validation-commands.md +15 -0
  14. package/tools/skills/vsaf-build/SKILL.md +32 -2
  15. package/tools/skills/vsaf-push-prd/SKILL.md +43 -40
  16. package/tools/skills/vsaf-push-srs/SKILL.md +44 -41
  17. package/tools/skills/vsaf-ship/SKILL.md +41 -10
  18. package/tools/skills/vsaf-test/SKILL.md +8 -0
  19. package/tools/vds-scripts/.mcp.json +11 -0
  20. package/tools/vds-scripts/.secrets.baseline +133 -0
  21. package/tools/vds-scripts/AGENTS.md +152 -0
  22. package/tools/vds-scripts/CLAUDE.md +101 -0
  23. package/tools/vds-scripts/CLI_COMMAND_OPTIMIZATION.md +156 -0
  24. package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +131 -0
  25. package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +45 -0
  26. package/tools/vds-scripts/README.md +97 -0
  27. package/tools/vds-scripts/bitbucket_manifest_mapping.toml +34 -0
  28. package/tools/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +258 -0
  29. package/tools/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +393 -0
  30. package/tools/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +61 -0
  31. package/tools/vds-scripts/bitbucket_orchestrator/FEATURES.md +908 -0
  32. package/tools/vds-scripts/bitbucket_orchestrator/README.md +687 -0
  33. package/tools/vds-scripts/bitbucket_orchestrator/pyproject.toml +40 -0
  34. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +20 -0
  35. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +657 -0
  36. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +2108 -0
  37. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +2534 -0
  38. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +171 -0
  39. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +67 -0
  40. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +185 -0
  41. package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +244 -0
  42. package/tools/vds-scripts/bitbucket_orchestrator/tests/__init__.py +8 -0
  43. package/tools/vds-scripts/bitbucket_orchestrator/tests/conftest.py +65 -0
  44. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +151 -0
  45. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +546 -0
  46. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +145 -0
  47. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +115 -0
  48. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client.py +157 -0
  49. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +79 -0
  50. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +163 -0
  51. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +32 -0
  52. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +194 -0
  53. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +164 -0
  54. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +179 -0
  55. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +119 -0
  56. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +156 -0
  57. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code.py +98 -0
  58. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +282 -0
  59. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +335 -0
  60. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +147 -0
  61. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_config.py +131 -0
  62. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +352 -0
  63. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +371 -0
  64. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +204 -0
  65. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +261 -0
  66. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +270 -0
  67. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +204 -0
  68. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +334 -0
  69. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +343 -0
  70. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +270 -0
  71. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +189 -0
  72. package/tools/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +233 -0
  73. package/tools/vds-scripts/bitbucket_orchestrator/uv.lock +742 -0
  74. package/tools/vds-scripts/confluence_orchestrator/Dockerfile +19 -0
  75. package/tools/vds-scripts/confluence_orchestrator/README.md +412 -0
  76. package/tools/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +127 -0
  77. package/tools/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +108 -0
  78. package/tools/vds-scripts/confluence_orchestrator/pyproject.toml +48 -0
  79. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +20 -0
  80. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +2532 -0
  81. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +175 -0
  82. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +290 -0
  83. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +94 -0
  84. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +1835 -0
  85. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +80 -0
  86. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +109 -0
  87. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +1114 -0
  88. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +165 -0
  89. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +78 -0
  90. package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +121 -0
  91. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +213 -0
  92. package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +305 -0
  93. package/tools/vds-scripts/confluence_orchestrator/sync_png_attachments.py +305 -0
  94. package/tools/vds-scripts/confluence_orchestrator/tests/__init__.py +0 -0
  95. package/tools/vds-scripts/confluence_orchestrator/tests/conftest.py +8 -0
  96. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +224 -0
  97. package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +188 -0
  98. package/tools/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +247 -0
  99. package/tools/vds-scripts/confluence_orchestrator/tests/test_cli.py +499 -0
  100. package/tools/vds-scripts/confluence_orchestrator/tests/test_config.py +83 -0
  101. package/tools/vds-scripts/confluence_orchestrator/tests/test_content.py +186 -0
  102. package/tools/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +27 -0
  103. package/tools/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +2250 -0
  104. package/tools/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +223 -0
  105. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing.py +71 -0
  106. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +37 -0
  107. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +44 -0
  108. package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +49 -0
  109. package/tools/vds-scripts/confluence_orchestrator/tests/test_export.py +230 -0
  110. package/tools/vds-scripts/confluence_orchestrator/tests/test_history.py +204 -0
  111. package/tools/vds-scripts/confluence_orchestrator/tests/test_http.py +117 -0
  112. package/tools/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +91 -0
  113. package/tools/vds-scripts/confluence_orchestrator/tests/test_reporting.py +24 -0
  114. package/tools/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +34 -0
  115. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_management.py +237 -0
  116. package/tools/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +332 -0
  117. package/tools/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +388 -0
  118. package/tools/vds-scripts/confluence_orchestrator/uv.lock +1023 -0
  119. package/tools/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +119 -0
  120. package/tools/vds-scripts/git_orchestrator/README.md +280 -0
  121. package/tools/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +152 -0
  122. package/tools/vds-scripts/git_orchestrator/pyproject.toml +35 -0
  123. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +7 -0
  124. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +4 -0
  125. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +847 -0
  126. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +63 -0
  127. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +129 -0
  128. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +819 -0
  129. package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +53 -0
  130. package/tools/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
  131. package/tools/vds-scripts/git_orchestrator/tests/test_cli_settings.py +21 -0
  132. package/tools/vds-scripts/git_orchestrator/tests/test_integration.py +74 -0
  133. package/tools/vds-scripts/git_orchestrator/tests/test_manifest.py +79 -0
  134. package/tools/vds-scripts/git_orchestrator/tests/test_orchestrator.py +204 -0
  135. package/tools/vds-scripts/git_orchestrator/tests/test_public_api.py +236 -0
  136. package/tools/vds-scripts/git_orchestrator/tests/test_resilience.py +345 -0
  137. package/tools/vds-scripts/git_orchestrator/uv.lock +271 -0
  138. package/tools/vds-scripts/jira_orchestrator/README.md +770 -0
  139. package/tools/vds-scripts/jira_orchestrator/pyproject.toml +39 -0
  140. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +1 -0
  141. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +1320 -0
  142. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +2271 -0
  143. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +138 -0
  144. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +67 -0
  145. package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +65 -0
  146. package/tools/vds-scripts/jira_orchestrator/tests/__init__.py +1 -0
  147. package/tools/vds-scripts/jira_orchestrator/tests/conftest.py +86 -0
  148. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +54 -0
  149. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +69 -0
  150. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +57 -0
  151. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +45 -0
  152. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +117 -0
  153. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +54 -0
  154. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +42 -0
  155. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +42 -0
  156. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +76 -0
  157. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +91 -0
  158. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +110 -0
  159. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +133 -0
  160. package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +41 -0
  161. package/tools/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +164 -0
  162. package/tools/vds-scripts/jira_orchestrator/tests/test_agile.py +256 -0
  163. package/tools/vds-scripts/jira_orchestrator/tests/test_application_properties.py +193 -0
  164. package/tools/vds-scripts/jira_orchestrator/tests/test_backlog.py +91 -0
  165. package/tools/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +277 -0
  166. package/tools/vds-scripts/jira_orchestrator/tests/test_cli.py +106 -0
  167. package/tools/vds-scripts/jira_orchestrator/tests/test_components.py +106 -0
  168. package/tools/vds-scripts/jira_orchestrator/tests/test_config.py +164 -0
  169. package/tools/vds-scripts/jira_orchestrator/tests/test_dashboard.py +122 -0
  170. package/tools/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +207 -0
  171. package/tools/vds-scripts/jira_orchestrator/tests/test_filter_management.py +333 -0
  172. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +164 -0
  173. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_links.py +257 -0
  174. package/tools/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +171 -0
  175. package/tools/vds-scripts/jira_orchestrator/tests/test_link_types.py +314 -0
  176. package/tools/vds-scripts/jira_orchestrator/tests/test_parse_set.py +37 -0
  177. package/tools/vds-scripts/jira_orchestrator/tests/test_permissions.py +273 -0
  178. package/tools/vds-scripts/jira_orchestrator/tests/test_reindex.py +81 -0
  179. package/tools/vds-scripts/jira_orchestrator/tests/test_remote_links.py +254 -0
  180. package/tools/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +170 -0
  181. package/tools/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +114 -0
  182. package/tools/vds-scripts/jira_orchestrator/tests/test_user_management.py +226 -0
  183. package/tools/vds-scripts/jira_orchestrator/tests/test_version_management.py +339 -0
  184. package/tools/vds-scripts/jira_orchestrator/tests/test_watchers.py +101 -0
  185. package/tools/vds-scripts/jira_orchestrator/tests/test_worklog.py +223 -0
  186. package/tools/vds-scripts/jira_orchestrator/uv.lock +738 -0
  187. package/tools/vds-scripts/mcp_server/Dockerfile +34 -0
  188. package/tools/vds-scripts/mcp_server/README.md +140 -0
  189. package/tools/vds-scripts/mcp_server/pyproject.toml +42 -0
  190. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +4 -0
  191. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/config.py +36 -0
  192. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/server.py +66 -0
  193. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +14 -0
  194. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +47 -0
  195. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +59 -0
  196. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +71 -0
  197. package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +63 -0
  198. package/tools/vds-scripts/mcp_server/tests/__init__.py +2 -0
  199. package/tools/vds-scripts/mcp_server/tests/conftest.py +29 -0
  200. package/tools/vds-scripts/mcp_server/tests/unit/__init__.py +2 -0
  201. package/tools/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +25 -0
  202. package/tools/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +25 -0
  203. package/tools/vds-scripts/mcp_server/tests/unit/test_git_tools.py +32 -0
  204. package/tools/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +32 -0
  205. package/tools/vds-scripts/mcp_server/tests/verification/__init__.py +2 -0
  206. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +40 -0
  207. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +37 -0
  208. package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +47 -0
  209. package/tools/vds-scripts/mcp_server/uv.lock +1032 -0
  210. package/tools/vds-scripts/mypy.ini +5 -0
  211. package/tools/vds-scripts/pyproject.toml +29 -0
  212. package/tools/vds-scripts/repo-manifest.yaml +273 -0
  213. package/tools/vds-scripts/repo-manifest.yaml.example +25 -0
  214. package/tools/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +706 -0
  215. package/tools/vds-scripts/scripts/BRD-Validation-README.md +308 -0
  216. package/tools/vds-scripts/scripts/README.md +162 -0
  217. package/tools/vds-scripts/scripts/bootstrap_uv.sh +30 -0
  218. package/tools/vds-scripts/scripts/brd-validation-environment.json +51 -0
  219. package/tools/vds-scripts/scripts/brd-validation-test-results.json +13023 -0
  220. package/tools/vds-scripts/scripts/brd_coverage_report.json +276 -0
  221. package/tools/vds-scripts/scripts/create_memory_session.py +35 -0
  222. package/tools/vds-scripts/scripts/deployment/load_docker_images_offline.sh +90 -0
  223. package/tools/vds-scripts/scripts/final_completion_report.md +139 -0
  224. package/tools/vds-scripts/scripts/folder_structure_report.json +321 -0
  225. package/tools/vds-scripts/scripts/generate_completion_report.py +125 -0
  226. package/tools/vds-scripts/scripts/generate_intellij_modules.py +150 -0
  227. package/tools/vds-scripts/scripts/link_integrity_report.json +807 -0
  228. package/tools/vds-scripts/scripts/move_audit_artifact_pages.py +255 -0
  229. package/tools/vds-scripts/scripts/move_audit_artifact_pages_rest.py +165 -0
  230. package/tools/vds-scripts/scripts/move_wrong_dept_pages.py +216 -0
  231. package/tools/vds-scripts/scripts/save_intellij_memories.py +120 -0
  232. package/tools/vds-scripts/scripts/save_memories_to_vds_ai.py +83 -0
  233. package/tools/vds-scripts/scripts/save_memories_vds_style.py +129 -0
  234. package/tools/vds-scripts/scripts/search_intellij_memories.py +50 -0
  235. package/tools/vds-scripts/scripts/setup_intellij_workspace.py +65 -0
  236. package/tools/vds-scripts/scripts/target-state-automation/README.md +89 -0
  237. package/tools/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +27 -0
  238. package/tools/vds-scripts/scripts/target-state-automation/coordination.sh +114 -0
  239. package/tools/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +25 -0
  240. package/tools/vds-scripts/scripts/target-state-automation/docs_root.sh +22 -0
  241. package/tools/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +22 -0
  242. package/tools/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +25 -0
  243. package/tools/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +17 -0
  244. package/tools/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +25 -0
  245. package/tools/vds-scripts/scripts/target-state-automation/sync_confluence.sh +30 -0
  246. package/tools/vds-scripts/scripts/target-state-automation/update_dependencies.sh +19 -0
  247. package/tools/vds-scripts/scripts/target-state-automation/validate_links.sh +86 -0
  248. package/tools/vds-scripts/scripts/target-state-automation/validate_markdown.sh +52 -0
  249. package/tools/vds-scripts/scripts/target-state-automation/validate_schemas.sh +26 -0
  250. package/tools/vds-scripts/scripts/target-state-automation/validate_structure.sh +98 -0
  251. package/tools/vds-scripts/scripts/update_modules_xml.py +190 -0
  252. package/tools/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +128 -0
  253. package/tools/vds-scripts/scripts/validate_brd_coverage.py +179 -0
  254. package/tools/vds-scripts/scripts/validate_folder_structure.py +240 -0
  255. package/tools/vds-scripts/scripts/validate_link_integrity.py +272 -0
  256. package/tools/vds-scripts/scripts/vds_sh_helpers.sh +180 -0
  257. package/tools/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +26 -0
  258. package/tools/vds-scripts/scripts/worktree_uv.sh +48 -0
  259. package/tools/vds-scripts/uv.lock +8 -0
  260. package/tools/vds-scripts/vds_cli/README.md +126 -0
  261. package/tools/vds-scripts/vds_cli/VERIFICATION_REPORT.md +41 -0
  262. package/tools/vds-scripts/vds_cli/pyproject.toml +38 -0
  263. package/tools/vds-scripts/vds_cli/src/vds_cli/__init__.py +3 -0
  264. package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +173 -0
  265. package/tools/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +1203 -0
  266. package/tools/vds-scripts/vds_cli/src/vds_cli/env.py +41 -0
  267. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +3 -0
  268. package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +198 -0
  269. package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +93 -0
  270. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_api.py +647 -0
  271. package/tools/vds-scripts/vds_cli/src/vds_cli/sync_service.py +266 -0
  272. package/tools/vds-scripts/vds_cli/tests/__init__.py +2 -0
  273. package/tools/vds-scripts/vds_cli/tests/conftest.py +49 -0
  274. package/tools/vds-scripts/vds_cli/tests/unit/__init__.py +2 -0
  275. package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +143 -0
  276. package/tools/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +422 -0
  277. package/tools/vds-scripts/vds_cli/tests/unit/test_env.py +51 -0
  278. package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +72 -0
  279. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_api.py +357 -0
  280. package/tools/vds-scripts/vds_cli/tests/unit/test_sync_service.py +160 -0
  281. package/tools/vds-scripts/vds_cli/tests/verification/__init__.py +2 -0
  282. package/tools/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +33 -0
  283. package/tools/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +35 -0
  284. package/tools/vds-scripts/vds_cli/tests/verification/test_jira_real.py +41 -0
  285. package/tools/vds-scripts/vds_cli/uv.lock +524 -0
  286. package/tools/vds-scripts/vds_cli_common/README.md +190 -0
  287. package/tools/vds-scripts/vds_cli_common/pyproject.toml +92 -0
  288. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +34 -0
  289. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +139 -0
  290. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +201 -0
  291. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +119 -0
  292. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +318 -0
  293. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +284 -0
  294. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +78 -0
  295. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +213 -0
  296. package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +85 -0
  297. package/tools/vds-scripts/vds_cli_common/tests/__init__.py +1 -0
  298. package/tools/vds-scripts/vds_cli_common/tests/test_completers.py +148 -0
  299. package/tools/vds-scripts/vds_cli_common/tests/test_context.py +192 -0
  300. package/tools/vds-scripts/vds_cli_common/tests/test_env.py +102 -0
  301. package/tools/vds-scripts/vds_cli_common/tests/test_errors.py +186 -0
  302. package/tools/vds-scripts/vds_cli_common/tests/test_output.py +229 -0
  303. package/tools/vds-scripts/vds_cli_common/tests/test_paths.py +61 -0
  304. package/tools/vds-scripts/vds_cli_common/tests/test_testing.py +138 -0
  305. package/tools/vds-scripts/vds_cli_common/tests/test_version.py +64 -0
@@ -0,0 +1,164 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+ from vds_jira_orchestrator.config import JiraSettings, SettingsError, load_settings
7
+
8
+
9
+ @pytest.fixture(autouse=True)
10
+ def _isolate_env(monkeypatch: pytest.MonkeyPatch) -> None:
11
+ for key in ("VDS_USERNAME", "VDS_PASSWORD", "JIRA_TOKEN", "JIRA_BASE_URL"):
12
+ monkeypatch.delenv(key, raising=False)
13
+ monkeypatch.setattr("vds_jira_orchestrator.config.DEFAULT_ENV_PATHS", (), raising=False)
14
+
15
+
16
+ class TestJiraSettings:
17
+ """Test suite for JiraSettings."""
18
+
19
+ def test_default_settings(self) -> None:
20
+ """Test default settings values."""
21
+ settings = JiraSettings()
22
+ assert settings.base_url == "http://jira.digital.vn"
23
+ assert settings.username is None
24
+ assert settings.password is None
25
+ assert settings.token is None
26
+
27
+ def test_settings_from_dict(self) -> None:
28
+ """Test creating settings from dictionary."""
29
+ data = {
30
+ "VDS_USERNAME": "test_user",
31
+ "VDS_PASSWORD": "test_pass",
32
+ "JIRA_TOKEN": "test_token",
33
+ "JIRA_BASE_URL": "https://jira.test.com",
34
+ }
35
+ settings = JiraSettings.model_validate(data)
36
+ assert settings.username == "test_user"
37
+ assert settings.password == "test_pass"
38
+ assert settings.token == "test_token"
39
+ assert settings.base_url == "https://jira.test.com"
40
+
41
+ def test_require_basic_or_token_success_with_token(self) -> None:
42
+ """Test require_basic_or_token with token."""
43
+ settings = JiraSettings(JIRA_TOKEN="test_token")
44
+ settings.require_basic_or_token() # Should not raise
45
+
46
+ def test_require_basic_or_token_success_with_basic(self) -> None:
47
+ """Test require_basic_or_token with username/password."""
48
+ settings = JiraSettings(VDS_USERNAME="test_user", VDS_PASSWORD="test_pass")
49
+ settings.require_basic_or_token() # Should not raise
50
+
51
+ def test_require_basic_or_token_failure(self) -> None:
52
+ """Test require_basic_or_token with no credentials."""
53
+ settings = JiraSettings()
54
+ with pytest.raises(ValueError, match="Missing credentials"):
55
+ settings.require_basic_or_token()
56
+
57
+
58
+ class TestLoadSettings:
59
+ """Test suite for load_settings function."""
60
+
61
+ def test_load_settings_from_env(self, monkeypatch: pytest.MonkeyPatch) -> None:
62
+ """Test loading settings from environment variables."""
63
+ monkeypatch.setenv("VDS_USERNAME", "env_user")
64
+ monkeypatch.setenv("VDS_PASSWORD", "env_pass")
65
+ monkeypatch.setenv("JIRA_TOKEN", "env_token")
66
+
67
+ settings = load_settings()
68
+ assert settings.username == "env_user"
69
+ assert settings.password == "env_pass"
70
+ assert settings.token == "env_token"
71
+
72
+ def test_load_settings_from_file(self, tmp_path: Path) -> None:
73
+ """Test loading settings from .env file."""
74
+ env_content = """
75
+ VDS_USERNAME=file_user
76
+ VDS_PASSWORD=file_pass
77
+ JIRA_TOKEN=file_token
78
+ JIRA_BASE_URL=https://jira.file.com
79
+ """.strip()
80
+ env_path = tmp_path / ".env"
81
+ env_path.write_text(env_content)
82
+
83
+ settings = load_settings(env_path=env_path)
84
+ assert settings.username == "file_user"
85
+ assert settings.password == "file_pass"
86
+ assert settings.token == "file_token"
87
+ assert settings.base_url == "https://jira.file.com"
88
+
89
+ def test_load_settings_with_overrides(self) -> None:
90
+ """Test loading settings with overrides."""
91
+ overrides = {
92
+ "VDS_USERNAME": "override_user",
93
+ "VDS_PASSWORD": "override_pass",
94
+ "JIRA_TOKEN": "override_token",
95
+ }
96
+
97
+ settings = load_settings(overrides=overrides)
98
+ assert settings.username == "override_user"
99
+ assert settings.password == "override_pass"
100
+ assert settings.token == "override_token"
101
+
102
+ def test_load_settings_strict_success(self) -> None:
103
+ """Test loading settings in strict mode with valid credentials."""
104
+ overrides = {"JIRA_TOKEN": "test_token"}
105
+ settings = load_settings(overrides=overrides, strict=True)
106
+ assert settings.token == "test_token"
107
+
108
+ def test_load_settings_strict_failure(self) -> None:
109
+ """Test loading settings in strict mode with invalid credentials."""
110
+ with pytest.raises(SettingsError):
111
+ load_settings(strict=True)
112
+
113
+ def test_load_settings_invalid_data(self) -> None:
114
+ """Test loading settings with invalid data."""
115
+ overrides = {"JIRA_BASE_URL": "invalid_url"} # Invalid URL format
116
+ with pytest.raises(SettingsError):
117
+ load_settings(overrides=overrides)
118
+
119
+ def test_env_file_parsing(self, tmp_path: Path) -> None:
120
+ """Test .env file parsing with various formats."""
121
+ env_content = """
122
+ # Comment line
123
+ VDS_USERNAME = "quoted_user"
124
+ VDS_PASSWORD=unquoted_pass
125
+ JIRA_TOKEN='single_quotes_token'
126
+ EMPTY_VAR=
127
+ # Another comment
128
+ JIRA_BASE_URL=https://jira.test.com
129
+ """.strip()
130
+ env_path = tmp_path / ".env"
131
+ env_path.write_text(env_content)
132
+
133
+ settings = load_settings(env_path=env_path)
134
+ assert settings.username == "quoted_user"
135
+ assert settings.password == "unquoted_pass"
136
+ assert settings.token == "single_quotes_token"
137
+ assert settings.base_url == "https://jira.test.com"
138
+
139
+ def test_load_settings_precedence(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
140
+ """Test settings precedence: overrides > env > file."""
141
+ # Set up file
142
+ env_content = """
143
+ VDS_USERNAME=file_user
144
+ VDS_PASSWORD=file_pass
145
+ JIRA_TOKEN=file_token
146
+ """.strip()
147
+ env_path = tmp_path / ".env"
148
+ env_path.write_text(env_content)
149
+
150
+ # Set up environment
151
+ monkeypatch.setenv("VDS_USERNAME", "env_user")
152
+ monkeypatch.setenv("VDS_PASSWORD", "env_pass")
153
+
154
+ # Set up overrides
155
+ overrides = {"VDS_USERNAME": "override_user"}
156
+
157
+ settings = load_settings(env_path=env_path, overrides=overrides)
158
+
159
+ # Override should win
160
+ assert settings.username == "override_user"
161
+ # Environment should be next
162
+ assert settings.password == "env_pass"
163
+ # File should be last
164
+ assert settings.token == "file_token"
@@ -0,0 +1,122 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import Mock, patch
4
+
5
+ from typer.testing import CliRunner
6
+ from vds_jira_orchestrator.cli import app
7
+ from vds_jira_orchestrator.errors import JiraAdapterError, JiraNotFound
8
+
9
+
10
+ def _runner() -> CliRunner:
11
+ return CliRunner()
12
+
13
+
14
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
15
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
16
+ def test_dashboard_get_requires_id(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
17
+ """Test that dashboard get requires --dashboard-id."""
18
+ runner = _runner()
19
+ result = runner.invoke(app, ["dashboard", "get"])
20
+ assert result.exit_code != 0
21
+ assert "--dashboard-id required" in result.stderr
22
+
23
+
24
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
25
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
26
+ def test_dashboard_get_success_int(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
27
+ """Test successful dashboard get with integer ID."""
28
+ runner = _runner()
29
+ mock_adapter = Mock()
30
+ mock_adapter.get_dashboard.return_value = {"id": "10000", "name": "Test Dashboard"}
31
+ mock_adapter_cls.return_value = mock_adapter
32
+
33
+ result = runner.invoke(app, ["dashboard", "get", "--dashboard-id", "10000"])
34
+ assert result.exit_code == 0
35
+ mock_adapter.get_dashboard.assert_called_once_with(10000)
36
+ assert "Test Dashboard" in result.stdout or "10000" in result.stdout
37
+
38
+
39
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
40
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
41
+ def test_dashboard_get_success_string(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
42
+ """Test successful dashboard get with string ID."""
43
+ runner = _runner()
44
+ mock_adapter = Mock()
45
+ mock_adapter.get_dashboard.return_value = {"id": "abc123", "name": "Test Dashboard"}
46
+ mock_adapter_cls.return_value = mock_adapter
47
+
48
+ result = runner.invoke(app, ["dashboard", "get", "--dashboard-id", "abc123"])
49
+ assert result.exit_code == 0
50
+ mock_adapter.get_dashboard.assert_called_once_with("abc123")
51
+ assert "Test Dashboard" in result.stdout or "abc123" in result.stdout
52
+
53
+
54
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
55
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
56
+ def test_dashboard_list_success(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
57
+ """Test successful dashboard list."""
58
+ runner = _runner()
59
+ mock_adapter = Mock()
60
+ mock_adapter.get_dashboards.return_value = {
61
+ "dashboards": [{"id": "10000", "name": "Dashboard 1"}, {"id": "10001", "name": "Dashboard 2"}]
62
+ }
63
+ mock_adapter_cls.return_value = mock_adapter
64
+
65
+ result = runner.invoke(app, ["dashboard", "list"])
66
+ assert result.exit_code == 0
67
+ mock_adapter.get_dashboards.assert_called_once_with(filter="", start=0, limit=10)
68
+
69
+
70
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
71
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
72
+ def test_dashboard_list_with_filter(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
73
+ """Test dashboard list with filter and pagination."""
74
+ runner = _runner()
75
+ mock_adapter = Mock()
76
+ mock_adapter.get_dashboards.return_value = {"dashboards": []}
77
+ mock_adapter_cls.return_value = mock_adapter
78
+
79
+ result = runner.invoke(
80
+ app, ["dashboard", "list", "--filter", "test", "--start", "10", "--limit", "20"]
81
+ )
82
+ assert result.exit_code == 0
83
+ mock_adapter.get_dashboards.assert_called_once_with(filter="test", start=10, limit=20)
84
+
85
+
86
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
87
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
88
+ def test_dashboard_unknown_action(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
89
+ """Test that unknown action raises error."""
90
+ runner = _runner()
91
+ result = runner.invoke(app, ["dashboard", "unknown"])
92
+ assert result.exit_code != 0
93
+ assert "Unknown action" in result.stderr
94
+
95
+
96
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
97
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
98
+ def test_dashboard_adapter_error(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
99
+ """Test that adapter errors are handled."""
100
+ runner = _runner()
101
+ mock_adapter = Mock()
102
+ mock_adapter.get_dashboard.side_effect = JiraAdapterError("Adapter error")
103
+ mock_adapter_cls.return_value = mock_adapter
104
+
105
+ result = runner.invoke(app, ["dashboard", "get", "--dashboard-id", "10000"])
106
+ assert result.exit_code != 0
107
+ assert "Error" in result.stderr
108
+
109
+
110
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
111
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
112
+ def test_dashboard_not_found(mock_settings: Mock, mock_adapter_cls: Mock) -> None:
113
+ """Test that not found errors are handled."""
114
+ runner = _runner()
115
+ mock_adapter = Mock()
116
+ mock_adapter.get_dashboard.side_effect = JiraNotFound("Dashboard not found: 99999")
117
+ mock_adapter_cls.return_value = mock_adapter
118
+
119
+ result = runner.invoke(app, ["dashboard", "get", "--dashboard-id", "99999"])
120
+ assert result.exit_code != 0
121
+ assert "Error" in result.stderr
122
+
@@ -0,0 +1,207 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from unittest.mock import MagicMock, patch
5
+
6
+ from typer.testing import CliRunner
7
+ from vds_jira_orchestrator import cli
8
+
9
+
10
+ def _mock_settings(mock_settings_cls: MagicMock) -> None:
11
+ settings = mock_settings_cls.return_value
12
+ settings.require_basic_or_token.return_value = None
13
+ settings.username = "user"
14
+ settings.password = "pass"
15
+ settings.token = "token"
16
+ settings.base_url = "https://jira.test"
17
+
18
+
19
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
20
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
21
+ def test_discover_fields_outputs_sorted_fields(
22
+ mock_settings_cls: MagicMock,
23
+ mock_adapter_cls: MagicMock,
24
+ ) -> None:
25
+ _mock_settings(mock_settings_cls)
26
+ mock_adapter = mock_adapter_cls.return_value
27
+ mock_adapter.get_createmeta.return_value = {
28
+ "projects": [
29
+ {
30
+ "key": "TEST",
31
+ "issuetypes": [
32
+ {
33
+ "name": "Task",
34
+ "fields": {
35
+ "summary": {
36
+ "name": "Summary",
37
+ "required": True,
38
+ "schema": {"type": "string"},
39
+ },
40
+ "customfield_10000": {
41
+ "name": "Choice",
42
+ "required": False,
43
+ "schema": {"type": "option"},
44
+ "allowedValues": [{"id": 1, "value": "Option A"}],
45
+ },
46
+ },
47
+ }
48
+ ],
49
+ }
50
+ ]
51
+ }
52
+
53
+ runner = CliRunner()
54
+ result = runner.invoke(
55
+ cli.app,
56
+ ["discover-fields", "--project", "TEST", "--issuetype", "Task", "--include-system"],
57
+ )
58
+
59
+ assert result.exit_code == 0
60
+ payload = json.loads(result.stdout)
61
+ assert payload["count"] == 2
62
+ assert "duration_ms" in payload
63
+ assert payload["fields"][0]["name"] == "Summary"
64
+ assert payload["fields"][0]["required"] is True
65
+ assert payload["fields"][1]["allowedValues"] == [{"id": "1", "value": "Option A"}]
66
+
67
+
68
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
69
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
70
+ def test_discover_fields_excludes_system_by_default(
71
+ mock_settings_cls: MagicMock,
72
+ mock_adapter_cls: MagicMock,
73
+ ) -> None:
74
+ _mock_settings(mock_settings_cls)
75
+ mock_adapter = mock_adapter_cls.return_value
76
+ mock_adapter.get_createmeta.return_value = {
77
+ "projects": [
78
+ {
79
+ "key": "TEST",
80
+ "issuetypes": [
81
+ {
82
+ "name": "Task",
83
+ "fields": {
84
+ "summary": {
85
+ "name": "Summary",
86
+ "required": True,
87
+ "schema": {"type": "string"},
88
+ },
89
+ "customfield_10000": {
90
+ "name": "Choice",
91
+ "required": False,
92
+ "schema": {"type": "option"},
93
+ },
94
+ },
95
+ }
96
+ ],
97
+ }
98
+ ]
99
+ }
100
+
101
+ runner = CliRunner()
102
+ result = runner.invoke(cli.app, ["discover-fields", "--project", "TEST", "--issuetype", "Task"])
103
+
104
+ assert result.exit_code == 0
105
+ payload = json.loads(result.stdout)
106
+ assert payload["count"] == 1
107
+ assert payload["fields"][0]["id"] == "customfield_10000"
108
+
109
+
110
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
111
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
112
+ def test_discover_fields_filters_by_name(
113
+ mock_settings_cls: MagicMock,
114
+ mock_adapter_cls: MagicMock,
115
+ ) -> None:
116
+ _mock_settings(mock_settings_cls)
117
+ mock_adapter = mock_adapter_cls.return_value
118
+ mock_adapter.get_createmeta.return_value = {
119
+ "projects": [
120
+ {
121
+ "key": "TEST",
122
+ "issuetypes": [
123
+ {
124
+ "name": "Task",
125
+ "fields": {
126
+ "customfield_10000": {
127
+ "name": "Choice",
128
+ "required": False,
129
+ "schema": {"type": "option"},
130
+ },
131
+ "customfield_10001": {
132
+ "name": "Owner",
133
+ "required": False,
134
+ "schema": {"type": "user"},
135
+ },
136
+ },
137
+ }
138
+ ],
139
+ }
140
+ ]
141
+ }
142
+
143
+ runner = CliRunner()
144
+ result = runner.invoke(
145
+ cli.app,
146
+ ["discover-fields", "--project", "TEST", "--issuetype", "Task", "--field", "choice"],
147
+ )
148
+
149
+ assert result.exit_code == 0
150
+ payload = json.loads(result.stdout)
151
+ assert payload["count"] == 1
152
+ assert payload["fields"][0]["name"] == "Choice"
153
+
154
+
155
+ @patch("vds_jira_orchestrator.cli.JiraAdapter")
156
+ @patch("vds_jira_orchestrator.cli.JiraSettings")
157
+ def test_discover_fields_merges_allowed_values_from_editmeta(
158
+ mock_settings_cls: MagicMock,
159
+ mock_adapter_cls: MagicMock,
160
+ ) -> None:
161
+ _mock_settings(mock_settings_cls)
162
+ mock_adapter = mock_adapter_cls.return_value
163
+ mock_adapter.get_createmeta.return_value = {
164
+ "projects": [
165
+ {
166
+ "key": "TEST",
167
+ "issuetypes": [
168
+ {
169
+ "name": "Task",
170
+ "fields": {
171
+ "customfield_10000": {
172
+ "name": "Choice",
173
+ "required": False,
174
+ "schema": {"type": "option"},
175
+ },
176
+ },
177
+ }
178
+ ],
179
+ }
180
+ ]
181
+ }
182
+ mock_adapter.get_editmeta.return_value = {
183
+ "fields": {
184
+ "customfield_10000": {
185
+ "allowedValues": [{"id": 10, "value": "Option X"}],
186
+ }
187
+ }
188
+ }
189
+
190
+ runner = CliRunner()
191
+ result = runner.invoke(
192
+ cli.app,
193
+ [
194
+ "discover-fields",
195
+ "--project",
196
+ "TEST",
197
+ "--issuetype",
198
+ "Task",
199
+ "--issue-key",
200
+ "TEST-1",
201
+ ],
202
+ )
203
+
204
+ assert result.exit_code == 0
205
+ payload = json.loads(result.stdout)
206
+ assert payload["count"] == 1
207
+ assert payload["fields"][0]["allowedValues"] == [{"id": "10", "value": "Option X"}]