@ngocsangairvds/vsaf 3.1.27 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/global.js +65 -39
- package/tools/skills/vds-scripts-skill/.openskills.json +6 -0
- package/tools/skills/vds-scripts-skill/QUALITY.md +44 -0
- package/tools/skills/vds-scripts-skill/SKILL.md +135 -0
- package/tools/skills/vds-scripts-skill/references/audit-commands.md +171 -0
- package/tools/skills/vds-scripts-skill/references/capability-index.md +34 -0
- package/tools/skills/vds-scripts-skill/references/development-commands.md +12 -0
- package/tools/skills/vds-scripts-skill/references/google-sheets.md +73 -0
- package/tools/skills/vds-scripts-skill/references/integration-commands.md +17 -0
- package/tools/skills/vds-scripts-skill/references/platform-bootstrap.md +31 -0
- package/tools/skills/vds-scripts-skill/references/specialist-routing.md +14 -0
- package/tools/skills/vds-scripts-skill/references/validation-commands.md +15 -0
- package/tools/skills/vsaf-build/SKILL.md +32 -2
- package/tools/skills/vsaf-ship/SKILL.md +41 -10
- package/tools/skills/vsaf-test/SKILL.md +8 -0
- package/tools/vds-scripts/.mcp.json +11 -0
- package/tools/vds-scripts/.secrets.baseline +133 -0
- package/tools/vds-scripts/AGENTS.md +152 -0
- package/tools/vds-scripts/CLAUDE.md +101 -0
- package/tools/vds-scripts/CLI_COMMAND_OPTIMIZATION.md +156 -0
- package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +131 -0
- package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +45 -0
- package/tools/vds-scripts/README.md +97 -0
- package/tools/vds-scripts/bitbucket_manifest_mapping.toml +34 -0
- package/tools/vds-scripts/bitbucket_orchestrator/ARCHITECTURE_ANALYSIS.md +258 -0
- package/tools/vds-scripts/bitbucket_orchestrator/BITBUCKET_API_PRACTICES.md +393 -0
- package/tools/vds-scripts/bitbucket_orchestrator/EVALUATION_REPORT.md +61 -0
- package/tools/vds-scripts/bitbucket_orchestrator/FEATURES.md +908 -0
- package/tools/vds-scripts/bitbucket_orchestrator/README.md +687 -0
- package/tools/vds-scripts/bitbucket_orchestrator/pyproject.toml +40 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/__init__.py +20 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/async_client.py +657 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/cli.py +2108 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/client.py +2534 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/config.py +171 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/errors.py +67 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/factory.py +185 -0
- package/tools/vds-scripts/bitbucket_orchestrator/src/vds_bitbucket_orchestrator/protocols.py +244 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/__init__.py +8 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/conftest.py +65 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_advanced_search.py +151 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_async_client.py +546 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_branch_permissions.py +145 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_cli.py +115 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client.py +157 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_branch_conditions.py +79 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_advanced.py +163 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_code_file.py +32 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_deployment_environments.py +194 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_issues.py +164 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pipelines_advanced.py +179 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_pr_blockers.py +119 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_client_repository_variables.py +156 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code.py +98 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_advanced.py +282 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_code_insights.py +335 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_conditions.py +147 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_config.py +131 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_deployment_env.py +352 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_factory.py +371 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_fork_operations.py +204 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_issue_cli.py +261 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pipeline_advanced.py +270 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_pr_blocker.py +204 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_protocols.py +334 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_settings.py +343 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_repo_variables.py +270 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_webhooks.py +189 -0
- package/tools/vds-scripts/bitbucket_orchestrator/tests/test_workspace.py +233 -0
- package/tools/vds-scripts/bitbucket_orchestrator/uv.lock +742 -0
- package/tools/vds-scripts/confluence_orchestrator/Dockerfile +19 -0
- package/tools/vds-scripts/confluence_orchestrator/README.md +412 -0
- package/tools/vds-scripts/confluence_orchestrator/SYNC_SCRIPTS.md +127 -0
- package/tools/vds-scripts/confluence_orchestrator/SYNC_STANDARDIZATION.md +108 -0
- package/tools/vds-scripts/confluence_orchestrator/pyproject.toml +48 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/__init__.py +20 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/cli.py +2532 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/config.py +175 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content.py +290 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/content_v2.py +94 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/crawl_tree.py +1835 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/errors.py +80 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/eventing.py +109 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/http.py +1114 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/orchestration.py +165 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/reporting.py +78 -0
- package/tools/vds-scripts/confluence_orchestrator/src/confluence_orchestrator/tree.py +121 -0
- package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_from_markdown.py +213 -0
- package/tools/vds-scripts/confluence_orchestrator/sync_pdfs_to_confluence.py +305 -0
- package/tools/vds-scripts/confluence_orchestrator/sync_png_attachments.py +305 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/conftest.py +8 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_content.py +224 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_advanced_search.py +188 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_cache_management.py +247 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_cli.py +499 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_config.py +83 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_content.py +186 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_content_flags.py +27 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_crawl_tree.py +2250 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_draft_management.py +223 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing.py +71 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_chaos.py +37 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_rate_limit.py +44 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_eventing_timeout.py +49 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_export.py +230 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_history.py +204 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_http.py +117 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_orchestration.py +91 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_reporting.py +24 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_search_cql.py +34 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_space_management.py +237 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_space_permissions.py +332 -0
- package/tools/vds-scripts/confluence_orchestrator/tests/test_user_group_management.py +388 -0
- package/tools/vds-scripts/confluence_orchestrator/uv.lock +1023 -0
- package/tools/vds-scripts/git_orchestrator/ENHANCEMENT_SUMMARY.md +119 -0
- package/tools/vds-scripts/git_orchestrator/README.md +280 -0
- package/tools/vds-scripts/git_orchestrator/VERIFICATION_REPORT.md +152 -0
- package/tools/vds-scripts/git_orchestrator/pyproject.toml +35 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__init__.py +7 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/__main__.py +4 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/cli.py +847 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/logging_config.py +63 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/manifest.py +129 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/orchestrator.py +819 -0
- package/tools/vds-scripts/git_orchestrator/src/vds_git_orchestrator/reporting.py +53 -0
- package/tools/vds-scripts/git_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_cli_settings.py +21 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_integration.py +74 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_manifest.py +79 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_orchestrator.py +204 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_public_api.py +236 -0
- package/tools/vds-scripts/git_orchestrator/tests/test_resilience.py +345 -0
- package/tools/vds-scripts/git_orchestrator/uv.lock +271 -0
- package/tools/vds-scripts/jira_orchestrator/README.md +770 -0
- package/tools/vds-scripts/jira_orchestrator/pyproject.toml +39 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/__init__.py +1 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/adapter.py +1320 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/cli.py +2271 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/config.py +138 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/errors.py +67 -0
- package/tools/vds-scripts/jira_orchestrator/src/vds_jira_orchestrator/reporting.py +65 -0
- package/tools/vds-scripts/jira_orchestrator/tests/__init__.py +1 -0
- package/tools/vds-scripts/jira_orchestrator/tests/conftest.py +86 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_agile_list_payloads.py +54 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_bulk_operations.py +69 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_components.py +57 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_createmeta.py +45 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_dashboard.py +117 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_issue_properties.py +54 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_permissions_compat.py +42 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_reindex.py +42 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_remote_links.py +76 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_transitions.py +91 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_user_management.py +110 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_version_management.py +133 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_adapter_watchers.py +41 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_advanced_search.py +164 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_agile.py +256 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_application_properties.py +193 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_backlog.py +91 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_bulk_operations.py +277 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_cli.py +106 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_components.py +106 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_config.py +164 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_dashboard.py +122 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_discover_fields.py +207 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_filter_management.py +333 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_issue_archiving.py +164 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_issue_links.py +257 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_issue_properties.py +171 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_link_types.py +314 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_parse_set.py +37 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_permissions.py +273 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_reindex.py +81 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_remote_links.py +254 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_security_schemes.py +170 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_transitions_changelog.py +114 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_user_management.py +226 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_version_management.py +339 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_watchers.py +101 -0
- package/tools/vds-scripts/jira_orchestrator/tests/test_worklog.py +223 -0
- package/tools/vds-scripts/jira_orchestrator/uv.lock +738 -0
- package/tools/vds-scripts/mcp_server/Dockerfile +34 -0
- package/tools/vds-scripts/mcp_server/README.md +140 -0
- package/tools/vds-scripts/mcp_server/pyproject.toml +42 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/__init__.py +4 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/config.py +36 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/server.py +66 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/__init__.py +14 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/bitbucket_tools.py +47 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/confluence_tools.py +59 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/git_tools.py +71 -0
- package/tools/vds-scripts/mcp_server/src/vds_mcp_server/tools/jira_tools.py +63 -0
- package/tools/vds-scripts/mcp_server/tests/__init__.py +2 -0
- package/tools/vds-scripts/mcp_server/tests/conftest.py +29 -0
- package/tools/vds-scripts/mcp_server/tests/unit/__init__.py +2 -0
- package/tools/vds-scripts/mcp_server/tests/unit/test_bitbucket_tools.py +25 -0
- package/tools/vds-scripts/mcp_server/tests/unit/test_confluence_tools.py +25 -0
- package/tools/vds-scripts/mcp_server/tests/unit/test_git_tools.py +32 -0
- package/tools/vds-scripts/mcp_server/tests/unit/test_jira_tools.py +32 -0
- package/tools/vds-scripts/mcp_server/tests/verification/__init__.py +2 -0
- package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_confluence_tools.py +40 -0
- package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_jira_tools.py +37 -0
- package/tools/vds-scripts/mcp_server/tests/verification/test_mcp_tool_registration.py +47 -0
- package/tools/vds-scripts/mcp_server/uv.lock +1032 -0
- package/tools/vds-scripts/mypy.ini +5 -0
- package/tools/vds-scripts/pyproject.toml +29 -0
- package/tools/vds-scripts/repo-manifest.yaml +273 -0
- package/tools/vds-scripts/repo-manifest.yaml.example +25 -0
- package/tools/vds-scripts/scripts/BRD-Validation-API.postman_collection.json +706 -0
- package/tools/vds-scripts/scripts/BRD-Validation-README.md +308 -0
- package/tools/vds-scripts/scripts/README.md +162 -0
- package/tools/vds-scripts/scripts/bootstrap_uv.sh +30 -0
- package/tools/vds-scripts/scripts/brd-validation-environment.json +51 -0
- package/tools/vds-scripts/scripts/brd-validation-test-results.json +13023 -0
- package/tools/vds-scripts/scripts/brd_coverage_report.json +276 -0
- package/tools/vds-scripts/scripts/create_memory_session.py +35 -0
- package/tools/vds-scripts/scripts/deployment/load_docker_images_offline.sh +90 -0
- package/tools/vds-scripts/scripts/final_completion_report.md +139 -0
- package/tools/vds-scripts/scripts/folder_structure_report.json +321 -0
- package/tools/vds-scripts/scripts/generate_completion_report.py +125 -0
- package/tools/vds-scripts/scripts/generate_intellij_modules.py +150 -0
- package/tools/vds-scripts/scripts/link_integrity_report.json +807 -0
- package/tools/vds-scripts/scripts/move_audit_artifact_pages.py +255 -0
- package/tools/vds-scripts/scripts/move_audit_artifact_pages_rest.py +165 -0
- package/tools/vds-scripts/scripts/move_wrong_dept_pages.py +216 -0
- package/tools/vds-scripts/scripts/save_intellij_memories.py +120 -0
- package/tools/vds-scripts/scripts/save_memories_to_vds_ai.py +83 -0
- package/tools/vds-scripts/scripts/save_memories_vds_style.py +129 -0
- package/tools/vds-scripts/scripts/search_intellij_memories.py +50 -0
- package/tools/vds-scripts/scripts/setup_intellij_workspace.py +65 -0
- package/tools/vds-scripts/scripts/target-state-automation/README.md +89 -0
- package/tools/vds-scripts/scripts/target-state-automation/confluence_sync_coordinator.sh +27 -0
- package/tools/vds-scripts/scripts/target-state-automation/coordination.sh +114 -0
- package/tools/vds-scripts/scripts/target-state-automation/diagram_coordinator.sh +25 -0
- package/tools/vds-scripts/scripts/target-state-automation/docs_root.sh +22 -0
- package/tools/vds-scripts/scripts/target-state-automation/generate_diagrams.sh +22 -0
- package/tools/vds-scripts/scripts/target-state-automation/markdown_coordinator.sh +25 -0
- package/tools/vds-scripts/scripts/target-state-automation/progress_dashboard.sh +17 -0
- package/tools/vds-scripts/scripts/target-state-automation/schema_coordinator.sh +25 -0
- package/tools/vds-scripts/scripts/target-state-automation/sync_confluence.sh +30 -0
- package/tools/vds-scripts/scripts/target-state-automation/update_dependencies.sh +19 -0
- package/tools/vds-scripts/scripts/target-state-automation/validate_links.sh +86 -0
- package/tools/vds-scripts/scripts/target-state-automation/validate_markdown.sh +52 -0
- package/tools/vds-scripts/scripts/target-state-automation/validate_schemas.sh +26 -0
- package/tools/vds-scripts/scripts/target-state-automation/validate_structure.sh +98 -0
- package/tools/vds-scripts/scripts/update_modules_xml.py +190 -0
- package/tools/vds-scripts/scripts/uv-workspace-alignment-verification-2026-03-25.md +128 -0
- package/tools/vds-scripts/scripts/validate_brd_coverage.py +179 -0
- package/tools/vds-scripts/scripts/validate_folder_structure.py +240 -0
- package/tools/vds-scripts/scripts/validate_link_integrity.py +272 -0
- package/tools/vds-scripts/scripts/vds_sh_helpers.sh +180 -0
- package/tools/vds-scripts/scripts/verification/phase2_portable_paths_ubuntu_docker.sh +26 -0
- package/tools/vds-scripts/scripts/worktree_uv.sh +48 -0
- package/tools/vds-scripts/uv.lock +8 -0
- package/tools/vds-scripts/vds_cli/README.md +126 -0
- package/tools/vds-scripts/vds_cli/VERIFICATION_REPORT.md +41 -0
- package/tools/vds-scripts/vds_cli/pyproject.toml +38 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/__init__.py +3 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +173 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/docs_sync.py +1203 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/env.py +41 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/__init__.py +3 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/google_sheets_orchestrator/google_sheets_orchestrator.py +198 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +93 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/sync_api.py +647 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/sync_service.py +266 -0
- package/tools/vds-scripts/vds_cli/tests/__init__.py +2 -0
- package/tools/vds-scripts/vds_cli/tests/conftest.py +49 -0
- package/tools/vds-scripts/vds_cli/tests/unit/__init__.py +2 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +143 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_docs_sync.py +422 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_env.py +51 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +72 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_sync_api.py +357 -0
- package/tools/vds-scripts/vds_cli/tests/unit/test_sync_service.py +160 -0
- package/tools/vds-scripts/vds_cli/tests/verification/__init__.py +2 -0
- package/tools/vds-scripts/vds_cli/tests/verification/test_bitbucket_real.py +33 -0
- package/tools/vds-scripts/vds_cli/tests/verification/test_confluence_real.py +35 -0
- package/tools/vds-scripts/vds_cli/tests/verification/test_jira_real.py +41 -0
- package/tools/vds-scripts/vds_cli/uv.lock +524 -0
- package/tools/vds-scripts/vds_cli_common/README.md +190 -0
- package/tools/vds-scripts/vds_cli_common/pyproject.toml +92 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/__init__.py +34 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/completers.py +139 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/context.py +201 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/env.py +119 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/errors.py +318 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/output.py +284 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/paths.py +78 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/testing.py +213 -0
- package/tools/vds-scripts/vds_cli_common/src/vds_cli_common/version.py +85 -0
- package/tools/vds-scripts/vds_cli_common/tests/__init__.py +1 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_completers.py +148 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_context.py +192 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_env.py +102 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_errors.py +186 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_output.py +229 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_paths.py +61 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_testing.py +138 -0
- package/tools/vds-scripts/vds_cli_common/tests/test_version.py +64 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from unittest.mock import MagicMock, Mock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from typer.testing import CliRunner
|
|
8
|
+
from vds_bitbucket_orchestrator.cli import app
|
|
9
|
+
from vds_bitbucket_orchestrator.config import BitbucketSettings
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@pytest.fixture
|
|
13
|
+
def runner() -> CliRunner:
|
|
14
|
+
"""Create a CLI runner for testing."""
|
|
15
|
+
return CliRunner()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def mock_settings() -> BitbucketSettings:
|
|
20
|
+
"""Create mock settings for testing."""
|
|
21
|
+
return BitbucketSettings(
|
|
22
|
+
VDS_USERNAME="test_user",
|
|
23
|
+
VDS_PASSWORD="test_pass",
|
|
24
|
+
BITBUCKET_TOKEN="test_token",
|
|
25
|
+
BITBUCKET_BASE_URL="https://bitbucket.test.com",
|
|
26
|
+
BITBUCKET_MODE="server",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestBitbucketCLI:
|
|
31
|
+
"""Regression coverage for top-level Bitbucket CLI commands."""
|
|
32
|
+
|
|
33
|
+
def test_version_option(self, runner: CliRunner) -> None:
|
|
34
|
+
"""`--version` should print the CLI version and exit cleanly."""
|
|
35
|
+
result = runner.invoke(app, ["--version"])
|
|
36
|
+
assert result.exit_code == 0
|
|
37
|
+
assert "vds-bitbucket-orchestrator" in result.stdout
|
|
38
|
+
|
|
39
|
+
@patch("vds_bitbucket_orchestrator.cli.BitbucketClient")
|
|
40
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
41
|
+
def test_projects_command_success(
|
|
42
|
+
self,
|
|
43
|
+
mock_load: Mock,
|
|
44
|
+
mock_client_class: Mock,
|
|
45
|
+
runner: CliRunner,
|
|
46
|
+
mock_settings: BitbucketSettings,
|
|
47
|
+
sample_project_response: dict,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""`projects` should call list_projects and emit JSON when --no-markdown is provided."""
|
|
50
|
+
mock_load.return_value = mock_settings
|
|
51
|
+
|
|
52
|
+
client_manager = MagicMock()
|
|
53
|
+
client_instance = client_manager.__enter__.return_value
|
|
54
|
+
client_instance.list_projects.return_value = [sample_project_response]
|
|
55
|
+
mock_client_class.return_value = client_manager
|
|
56
|
+
|
|
57
|
+
with runner.isolated_filesystem():
|
|
58
|
+
result = runner.invoke(app, ["--report-dir", ".", "projects", "--limit", "5"])
|
|
59
|
+
assert result.exit_code == 0
|
|
60
|
+
assert "Test Project" in result.stdout
|
|
61
|
+
client_instance.list_projects.assert_called_once_with(limit=5)
|
|
62
|
+
assert Path("projects.md").exists()
|
|
63
|
+
|
|
64
|
+
@patch("vds_bitbucket_orchestrator.cli.BitbucketClient")
|
|
65
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
66
|
+
def test_projects_command_handles_error(
|
|
67
|
+
self,
|
|
68
|
+
mock_load: Mock,
|
|
69
|
+
mock_client_class: Mock,
|
|
70
|
+
runner: CliRunner,
|
|
71
|
+
mock_settings: BitbucketSettings,
|
|
72
|
+
) -> None:
|
|
73
|
+
"""`projects` should exit non-zero when the client raises."""
|
|
74
|
+
mock_load.return_value = mock_settings
|
|
75
|
+
|
|
76
|
+
client_manager = MagicMock()
|
|
77
|
+
client_instance = client_manager.__enter__.return_value
|
|
78
|
+
client_instance.list_projects.side_effect = RuntimeError("boom")
|
|
79
|
+
mock_client_class.return_value = client_manager
|
|
80
|
+
|
|
81
|
+
with runner.isolated_filesystem():
|
|
82
|
+
result = runner.invoke(app, ["projects"])
|
|
83
|
+
|
|
84
|
+
assert result.exit_code != 0
|
|
85
|
+
|
|
86
|
+
@patch("vds_bitbucket_orchestrator.cli.BitbucketClient")
|
|
87
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
88
|
+
def test_repositories_command_success(
|
|
89
|
+
self,
|
|
90
|
+
mock_load: Mock,
|
|
91
|
+
mock_client_class: Mock,
|
|
92
|
+
runner: CliRunner,
|
|
93
|
+
mock_settings: BitbucketSettings,
|
|
94
|
+
sample_repository_response: dict,
|
|
95
|
+
) -> None:
|
|
96
|
+
"""`repositories` should call list_repositories with the provided project key."""
|
|
97
|
+
mock_load.return_value = mock_settings
|
|
98
|
+
|
|
99
|
+
client_manager = MagicMock()
|
|
100
|
+
client_instance = client_manager.__enter__.return_value
|
|
101
|
+
client_instance.list_repositories.return_value = [sample_repository_response]
|
|
102
|
+
mock_client_class.return_value = client_manager
|
|
103
|
+
|
|
104
|
+
with runner.isolated_filesystem():
|
|
105
|
+
result = runner.invoke(app, ["--report-dir", ".", "repositories", "TEST", "--limit", "7"])
|
|
106
|
+
assert result.exit_code == 0
|
|
107
|
+
assert "test-repo" in result.stdout
|
|
108
|
+
client_instance.list_repositories.assert_called_once_with("TEST", limit=7)
|
|
109
|
+
assert Path("TEST_repositories.md").exists()
|
|
110
|
+
|
|
111
|
+
def test_repositories_missing_project_argument(self, runner: CliRunner) -> None:
|
|
112
|
+
"""`repositories` without the required project key should exit with usage error."""
|
|
113
|
+
result = runner.invoke(app, ["repositories"])
|
|
114
|
+
assert result.exit_code == 2
|
|
115
|
+
assert "Missing argument 'PROJECT_KEY'" in (result.stdout or result.stderr)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from unittest.mock import Mock, patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from vds_bitbucket_orchestrator.client import BitbucketClient
|
|
8
|
+
from vds_bitbucket_orchestrator.config import BitbucketSettings
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def mock_settings() -> BitbucketSettings:
|
|
13
|
+
"""Create server-mode settings for testing."""
|
|
14
|
+
return BitbucketSettings(
|
|
15
|
+
VDS_USERNAME="test_user",
|
|
16
|
+
VDS_PASSWORD="test_pass",
|
|
17
|
+
BITBUCKET_TOKEN="test_token",
|
|
18
|
+
BITBUCKET_BASE_URL="https://bitbucket.test.com",
|
|
19
|
+
BITBUCKET_MODE="server",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
24
|
+
def test_client_initialization_server_mode(mock_bitbucket_class: Mock, mock_settings: BitbucketSettings) -> None:
|
|
25
|
+
"""Client should initialize correctly in server mode."""
|
|
26
|
+
client = BitbucketClient(mock_settings)
|
|
27
|
+
assert client._settings == mock_settings
|
|
28
|
+
assert client._settings.is_server_mode
|
|
29
|
+
assert not client._settings.is_cloud_mode
|
|
30
|
+
mock_bitbucket_class.assert_called_once()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
34
|
+
def test_client_initialization_cloud_mode(mock_bitbucket_class: Mock) -> None:
|
|
35
|
+
"""Client should initialize correctly in cloud mode."""
|
|
36
|
+
settings = BitbucketSettings(
|
|
37
|
+
BITBUCKET_TOKEN="test_token",
|
|
38
|
+
BITBUCKET_MODE="cloud",
|
|
39
|
+
BITBUCKET_CLOUD_WORKSPACE="test_workspace",
|
|
40
|
+
)
|
|
41
|
+
client = BitbucketClient(settings)
|
|
42
|
+
assert client._settings == settings
|
|
43
|
+
assert client._settings.is_cloud_mode
|
|
44
|
+
assert not client._settings.is_server_mode
|
|
45
|
+
mock_bitbucket_class.assert_called_once()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
49
|
+
def test_list_projects_server_mode(mock_bitbucket_class: Mock, mock_settings: BitbucketSettings) -> None:
|
|
50
|
+
client = BitbucketClient(mock_settings)
|
|
51
|
+
mock_bitbucket = Mock()
|
|
52
|
+
mock_bitbucket.project_list.return_value = [{"key": "TEST", "name": "Test Project"}]
|
|
53
|
+
client._client = mock_bitbucket
|
|
54
|
+
|
|
55
|
+
result = client.list_projects()
|
|
56
|
+
|
|
57
|
+
assert result == [{"key": "TEST", "name": "Test Project"}]
|
|
58
|
+
mock_bitbucket.project_list.assert_called_once_with(limit=25)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
62
|
+
def test_list_repositories_server_mode(mock_bitbucket_class: Mock, mock_settings: BitbucketSettings) -> None:
|
|
63
|
+
client = BitbucketClient(mock_settings)
|
|
64
|
+
mock_bitbucket = Mock()
|
|
65
|
+
mock_bitbucket.repo_list.return_value = [{"slug": "test-repo", "name": "Test Repository"}]
|
|
66
|
+
client._client = mock_bitbucket
|
|
67
|
+
|
|
68
|
+
result = client.list_repositories("TEST")
|
|
69
|
+
|
|
70
|
+
assert result == [{"slug": "test-repo", "name": "Test Repository"}]
|
|
71
|
+
mock_bitbucket.repo_list.assert_called_once_with("TEST", limit=25)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
75
|
+
def test_get_project_server_mode(mock_bitbucket_class: Mock, mock_settings: BitbucketSettings) -> None:
|
|
76
|
+
client = BitbucketClient(mock_settings)
|
|
77
|
+
mock_bitbucket = Mock()
|
|
78
|
+
mock_bitbucket.project.return_value = {"key": "TEST", "name": "Test Project"}
|
|
79
|
+
client._client = mock_bitbucket
|
|
80
|
+
|
|
81
|
+
result = client.get_project("TEST")
|
|
82
|
+
|
|
83
|
+
assert result == {"key": "TEST", "name": "Test Project"}
|
|
84
|
+
mock_bitbucket.project.assert_called_once_with("TEST")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
88
|
+
def test_get_repository_server_mode(mock_bitbucket_class: Mock, mock_settings: BitbucketSettings) -> None:
|
|
89
|
+
client = BitbucketClient(mock_settings)
|
|
90
|
+
mock_bitbucket = Mock()
|
|
91
|
+
mock_bitbucket.get_repo.return_value = {"slug": "test-repo", "name": "Test Repository"}
|
|
92
|
+
client._client = mock_bitbucket
|
|
93
|
+
|
|
94
|
+
result = client.get_repository("TEST", "test-repo")
|
|
95
|
+
|
|
96
|
+
assert result == {"slug": "test-repo", "name": "Test Repository"}
|
|
97
|
+
mock_bitbucket.get_repo.assert_called_once_with("TEST", "test-repo")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_get_url_server_mode(mock_settings: BitbucketSettings) -> None:
|
|
101
|
+
url = mock_settings.get_url()
|
|
102
|
+
assert url == "https://bitbucket.test.com"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_get_url_cloud_mode() -> None:
|
|
106
|
+
settings = BitbucketSettings(
|
|
107
|
+
BITBUCKET_TOKEN="test_token",
|
|
108
|
+
BITBUCKET_MODE="cloud",
|
|
109
|
+
BITBUCKET_CLOUD_WORKSPACE="test_workspace",
|
|
110
|
+
)
|
|
111
|
+
url = settings.get_url()
|
|
112
|
+
assert url == "https://api.bitbucket.org/workspace/test_workspace"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_get_url_cloud_mode_missing_workspace() -> None:
|
|
116
|
+
settings = BitbucketSettings(BITBUCKET_TOKEN="test_token", BITBUCKET_MODE="cloud")
|
|
117
|
+
with pytest.raises(ValueError, match="BITBUCKET_CLOUD_WORKSPACE is required"):
|
|
118
|
+
settings.get_url()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_get_auth_kwargs_with_token() -> None:
|
|
122
|
+
settings = BitbucketSettings(BITBUCKET_TOKEN="test_token")
|
|
123
|
+
auth_kwargs = settings.get_auth_kwargs()
|
|
124
|
+
assert auth_kwargs == {"token": "test_token"}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_get_auth_kwargs_with_username_password() -> None:
|
|
128
|
+
settings = BitbucketSettings(VDS_USERNAME="test_user", VDS_PASSWORD="test_pass")
|
|
129
|
+
auth_kwargs = settings.get_auth_kwargs()
|
|
130
|
+
assert auth_kwargs == {"username": "test_user", "password": "test_pass"}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@patch.dict(os.environ, {}, clear=True)
|
|
134
|
+
def test_get_auth_kwargs_no_credentials() -> None:
|
|
135
|
+
settings = BitbucketSettings(
|
|
136
|
+
VDS_USERNAME=None,
|
|
137
|
+
VDS_PASSWORD=None,
|
|
138
|
+
BITBUCKET_TOKEN=None,
|
|
139
|
+
)
|
|
140
|
+
with pytest.raises(ValueError, match="No valid authentication credentials"):
|
|
141
|
+
settings.get_auth_kwargs()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_require_basic_or_token_success() -> None:
|
|
145
|
+
settings = BitbucketSettings(BITBUCKET_TOKEN="test_token")
|
|
146
|
+
settings.require_basic_or_token()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@patch.dict(os.environ, {}, clear=True)
|
|
150
|
+
def test_require_basic_or_token_failure() -> None:
|
|
151
|
+
settings = BitbucketSettings(
|
|
152
|
+
VDS_USERNAME=None,
|
|
153
|
+
VDS_PASSWORD=None,
|
|
154
|
+
BITBUCKET_TOKEN=None,
|
|
155
|
+
)
|
|
156
|
+
with pytest.raises(ValueError, match="Missing credentials"):
|
|
157
|
+
settings.require_basic_or_token()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import MagicMock, patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from vds_bitbucket_orchestrator.client import BitbucketClient, BitbucketClientError
|
|
7
|
+
from vds_bitbucket_orchestrator.config import BitbucketSettings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
12
|
+
def client(mock_bb: MagicMock) -> BitbucketClient:
|
|
13
|
+
mock_instance = MagicMock()
|
|
14
|
+
mock_bb.return_value = mock_instance
|
|
15
|
+
settings = BitbucketSettings(BITBUCKET_TOKEN="token")
|
|
16
|
+
return BitbucketClient(settings)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
20
|
+
def test_set_branches_permissions_defaults(mock_bb: MagicMock) -> None:
|
|
21
|
+
stub = MagicMock()
|
|
22
|
+
stub.set_branches_permissions.return_value = {"ok": True}
|
|
23
|
+
mock_bb.return_value = stub
|
|
24
|
+
client = BitbucketClient(BitbucketSettings(BITBUCKET_TOKEN="token"))
|
|
25
|
+
|
|
26
|
+
result = client.set_branches_permissions(
|
|
27
|
+
"PRJ",
|
|
28
|
+
matcher_type="BRANCH",
|
|
29
|
+
matcher_value="refs/heads/main",
|
|
30
|
+
permission_type="READ_ONLY",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
assert result == {"ok": True}
|
|
34
|
+
stub.set_branches_permissions.assert_called_once_with(
|
|
35
|
+
"PRJ",
|
|
36
|
+
multiple_permissions=False,
|
|
37
|
+
matcher_type="BRANCH",
|
|
38
|
+
matcher_value="refs/heads/main",
|
|
39
|
+
permission_type="READ_ONLY",
|
|
40
|
+
repository_slug=None,
|
|
41
|
+
except_users=[],
|
|
42
|
+
except_groups=[],
|
|
43
|
+
except_access_keys=[],
|
|
44
|
+
start=0,
|
|
45
|
+
limit=25,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
50
|
+
def test_set_branches_permissions_error(mock_bb: MagicMock) -> None:
|
|
51
|
+
stub = MagicMock()
|
|
52
|
+
stub.set_branches_permissions.side_effect = RuntimeError("boom")
|
|
53
|
+
mock_bb.return_value = stub
|
|
54
|
+
client = BitbucketClient(BitbucketSettings(BITBUCKET_TOKEN="token"))
|
|
55
|
+
|
|
56
|
+
with pytest.raises(BitbucketClientError):
|
|
57
|
+
client.set_branches_permissions("PRJ")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
61
|
+
def test_get_project_conditions_coerces_list(mock_bb: MagicMock) -> None:
|
|
62
|
+
stub = MagicMock()
|
|
63
|
+
stub.get_project_conditions.return_value = {"id": 1}
|
|
64
|
+
mock_bb.return_value = stub
|
|
65
|
+
client = BitbucketClient(BitbucketSettings(BITBUCKET_TOKEN="token"))
|
|
66
|
+
|
|
67
|
+
result = client.get_project_conditions("PRJ")
|
|
68
|
+
assert result == [{"id": 1}]
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
72
|
+
def test_get_project_conditions_handles_none(mock_bb: MagicMock) -> None:
|
|
73
|
+
stub = MagicMock()
|
|
74
|
+
stub.get_project_conditions.return_value = None
|
|
75
|
+
mock_bb.return_value = stub
|
|
76
|
+
client = BitbucketClient(BitbucketSettings(BITBUCKET_TOKEN="token"))
|
|
77
|
+
|
|
78
|
+
result = client.get_project_conditions("PRJ")
|
|
79
|
+
assert result == []
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import Mock, patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from vds_bitbucket_orchestrator.client import BitbucketClient
|
|
7
|
+
from vds_bitbucket_orchestrator.config import BitbucketSettings
|
|
8
|
+
from vds_bitbucket_orchestrator.errors import BitbucketClientError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestBitbucketClientCodeAdvanced:
|
|
12
|
+
"""Test suite for BitbucketClient advanced code operations."""
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def server_settings(self) -> BitbucketSettings:
|
|
16
|
+
"""Create server mode settings for testing."""
|
|
17
|
+
return BitbucketSettings(
|
|
18
|
+
VDS_USERNAME="test_user",
|
|
19
|
+
VDS_PASSWORD="test_pass",
|
|
20
|
+
BITBUCKET_BASE_URL="https://bitbucket.test.com",
|
|
21
|
+
BITBUCKET_MODE="server",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@pytest.fixture
|
|
25
|
+
def cloud_settings(self) -> BitbucketSettings:
|
|
26
|
+
"""Create cloud mode settings for testing."""
|
|
27
|
+
return BitbucketSettings(
|
|
28
|
+
BITBUCKET_TOKEN="test_token",
|
|
29
|
+
BITBUCKET_MODE="cloud",
|
|
30
|
+
BITBUCKET_CLOUD_WORKSPACE="test_workspace",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
34
|
+
def test_get_file_list_success(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
35
|
+
"""Test successful file list retrieval."""
|
|
36
|
+
client = BitbucketClient(server_settings)
|
|
37
|
+
mock_bitbucket = Mock()
|
|
38
|
+
mock_bitbucket.get_file_list.return_value = [{"path": "file1.py"}, {"path": "file2.py"}]
|
|
39
|
+
client._client = mock_bitbucket
|
|
40
|
+
|
|
41
|
+
result = client.get_file_list("PRJ", "repo", sub_folder="src", query="*.py", start=0, limit=100)
|
|
42
|
+
|
|
43
|
+
mock_bitbucket.get_file_list.assert_called_once_with("PRJ", "repo", sub_folder="src", query="*.py", start=0, limit=100)
|
|
44
|
+
assert len(result) == 2
|
|
45
|
+
assert result[0]["path"] == "file1.py"
|
|
46
|
+
|
|
47
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
48
|
+
def test_get_file_list_returns_empty_list(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
49
|
+
"""Test that get_file_list returns empty list when client returns None."""
|
|
50
|
+
client = BitbucketClient(server_settings)
|
|
51
|
+
mock_bitbucket = Mock()
|
|
52
|
+
mock_bitbucket.get_file_list.return_value = None
|
|
53
|
+
client._client = mock_bitbucket
|
|
54
|
+
|
|
55
|
+
result = client.get_file_list("PRJ", "repo")
|
|
56
|
+
|
|
57
|
+
assert result == []
|
|
58
|
+
|
|
59
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
60
|
+
def test_get_file_list_handles_error(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
61
|
+
"""Test that get_file_list handles errors."""
|
|
62
|
+
client = BitbucketClient(server_settings)
|
|
63
|
+
mock_bitbucket = Mock()
|
|
64
|
+
mock_bitbucket.get_file_list.side_effect = Exception("API error")
|
|
65
|
+
client._client = mock_bitbucket
|
|
66
|
+
|
|
67
|
+
with pytest.raises(BitbucketClientError):
|
|
68
|
+
client.get_file_list("PRJ", "repo")
|
|
69
|
+
|
|
70
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
71
|
+
def test_get_commit_info_success(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
72
|
+
"""Test successful commit info retrieval."""
|
|
73
|
+
client = BitbucketClient(server_settings)
|
|
74
|
+
mock_bitbucket = Mock()
|
|
75
|
+
mock_bitbucket.get_commit_info.return_value = {"id": "abc123", "message": "Test commit"}
|
|
76
|
+
client._client = mock_bitbucket
|
|
77
|
+
|
|
78
|
+
result = client.get_commit_info("PRJ", "repo", "abc123", path="file.py")
|
|
79
|
+
|
|
80
|
+
mock_bitbucket.get_commit_info.assert_called_once_with("PRJ", "repo", "abc123", path="file.py")
|
|
81
|
+
assert result["id"] == "abc123"
|
|
82
|
+
|
|
83
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
84
|
+
def test_get_commit_info_handles_error(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
85
|
+
"""Test that get_commit_info handles errors."""
|
|
86
|
+
client = BitbucketClient(server_settings)
|
|
87
|
+
mock_bitbucket = Mock()
|
|
88
|
+
mock_bitbucket.get_commit_info.side_effect = Exception("API error")
|
|
89
|
+
client._client = mock_bitbucket
|
|
90
|
+
|
|
91
|
+
with pytest.raises(BitbucketClientError):
|
|
92
|
+
client.get_commit_info("PRJ", "repo", "abc123")
|
|
93
|
+
|
|
94
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
95
|
+
def test_get_commit_changes_with_commit_id(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
96
|
+
"""Test successful commit changes retrieval with commit_id."""
|
|
97
|
+
client = BitbucketClient(server_settings)
|
|
98
|
+
mock_bitbucket = Mock()
|
|
99
|
+
mock_bitbucket.get_commit_changes.return_value = {"changes": []}
|
|
100
|
+
client._client = mock_bitbucket
|
|
101
|
+
|
|
102
|
+
result = client.get_commit_changes("PRJ", "repo", commit_id="abc123", merges="exclude")
|
|
103
|
+
|
|
104
|
+
mock_bitbucket.get_commit_changes.assert_called_once_with("PRJ", "repo", hash_newest=None, merges="exclude", commit_id="abc123")
|
|
105
|
+
assert result == {"changes": []}
|
|
106
|
+
|
|
107
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
108
|
+
def test_get_commit_changes_with_hash_newest(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
109
|
+
"""Test successful commit changes retrieval with hash_newest."""
|
|
110
|
+
client = BitbucketClient(server_settings)
|
|
111
|
+
mock_bitbucket = Mock()
|
|
112
|
+
mock_bitbucket.get_commit_changes.return_value = {"changes": []}
|
|
113
|
+
client._client = mock_bitbucket
|
|
114
|
+
|
|
115
|
+
result = client.get_commit_changes("PRJ", "repo", hash_newest="def456", merges="include")
|
|
116
|
+
|
|
117
|
+
mock_bitbucket.get_commit_changes.assert_called_once_with("PRJ", "repo", hash_newest="def456", merges="include", commit_id=None)
|
|
118
|
+
assert result == {"changes": []}
|
|
119
|
+
|
|
120
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
121
|
+
def test_get_commit_changes_handles_error(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
122
|
+
"""Test that get_commit_changes handles errors."""
|
|
123
|
+
client = BitbucketClient(server_settings)
|
|
124
|
+
mock_bitbucket = Mock()
|
|
125
|
+
mock_bitbucket.get_commit_changes.side_effect = Exception("API error")
|
|
126
|
+
client._client = mock_bitbucket
|
|
127
|
+
|
|
128
|
+
with pytest.raises(BitbucketClientError):
|
|
129
|
+
client.get_commit_changes("PRJ", "repo", commit_id="abc123")
|
|
130
|
+
|
|
131
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
132
|
+
def test_search_code_requires_cloud_mode(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
133
|
+
"""Test that search_code requires Cloud mode."""
|
|
134
|
+
client = BitbucketClient(server_settings)
|
|
135
|
+
|
|
136
|
+
with pytest.raises(BitbucketClientError, match="Code search is only available in Bitbucket Cloud mode"):
|
|
137
|
+
client.search_code("workspace", "test query")
|
|
138
|
+
|
|
139
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
140
|
+
def test_search_code_success(self, mock_bitbucket_class: Mock, cloud_settings: BitbucketSettings) -> None:
|
|
141
|
+
"""Test successful code search in Cloud mode."""
|
|
142
|
+
client = BitbucketClient(cloud_settings)
|
|
143
|
+
mock_bitbucket = Mock()
|
|
144
|
+
mock_bitbucket.search_code.return_value = {"values": [{"file": {"path": "file.py"}}]}
|
|
145
|
+
client._client = mock_bitbucket
|
|
146
|
+
|
|
147
|
+
result = client.search_code("workspace", "def test", page=1, limit=20)
|
|
148
|
+
|
|
149
|
+
mock_bitbucket.search_code.assert_called_once_with("workspace", "def test", page=1, limit=20)
|
|
150
|
+
assert "values" in result
|
|
151
|
+
assert len(result["values"]) == 1
|
|
152
|
+
|
|
153
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
154
|
+
def test_search_code_handles_error(self, mock_bitbucket_class: Mock, cloud_settings: BitbucketSettings) -> None:
|
|
155
|
+
"""Test that search_code handles errors."""
|
|
156
|
+
client = BitbucketClient(cloud_settings)
|
|
157
|
+
mock_bitbucket = Mock()
|
|
158
|
+
mock_bitbucket.search_code.side_effect = Exception("API error")
|
|
159
|
+
client._client = mock_bitbucket
|
|
160
|
+
|
|
161
|
+
with pytest.raises(BitbucketClientError):
|
|
162
|
+
client.search_code("workspace", "test query")
|
|
163
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import Mock, patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from vds_bitbucket_orchestrator.client import BitbucketClient
|
|
7
|
+
from vds_bitbucket_orchestrator.config import BitbucketSettings
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestBitbucketClientCodeFile:
|
|
11
|
+
"""Tests for file content retrieval."""
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def server_settings(self) -> BitbucketSettings:
|
|
15
|
+
return BitbucketSettings(
|
|
16
|
+
VDS_USERNAME="test_user",
|
|
17
|
+
VDS_PASSWORD="test_pass",
|
|
18
|
+
BITBUCKET_BASE_URL="https://bitbucket.test.com",
|
|
19
|
+
BITBUCKET_MODE="server",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
23
|
+
def test_get_content_of_file_decodes_bytes(self, mock_bitbucket_class: Mock, server_settings: BitbucketSettings) -> None:
|
|
24
|
+
client = BitbucketClient(server_settings)
|
|
25
|
+
mock_bitbucket = Mock()
|
|
26
|
+
mock_bitbucket.get_content_of_file.return_value = b"hello world"
|
|
27
|
+
client._client = mock_bitbucket
|
|
28
|
+
|
|
29
|
+
result = client.get_content_of_file("PRJ", "repo", "README.md")
|
|
30
|
+
|
|
31
|
+
assert result == "hello world"
|
|
32
|
+
|