@ngocsangairvds/vsaf 3.1.27 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/global.js +70 -10
- 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,204 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import Mock, patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from typer.testing import CliRunner
|
|
7
|
+
from vds_bitbucket_orchestrator.cli import app
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture
|
|
11
|
+
def runner() -> CliRunner:
|
|
12
|
+
return CliRunner()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def mock_client() -> Mock:
|
|
17
|
+
client = Mock()
|
|
18
|
+
client.list_pull_request_blockers.return_value = [
|
|
19
|
+
{"uuid": "{blocker}", "message": "Fix tests", "reason": "QA"},
|
|
20
|
+
]
|
|
21
|
+
client.add_pull_request_blocker.return_value = {"uuid": "{blocker}", "message": "Fix tests"}
|
|
22
|
+
return client
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@patch("vds_bitbucket_orchestrator.cli._build_client")
|
|
26
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
27
|
+
def test_pr_blocker_list_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
|
|
28
|
+
settings = Mock()
|
|
29
|
+
settings.is_cloud_mode = True
|
|
30
|
+
mock_load.return_value = settings
|
|
31
|
+
mock_build.return_value.__enter__.return_value = mock_client
|
|
32
|
+
|
|
33
|
+
result = runner.invoke(
|
|
34
|
+
app,
|
|
35
|
+
[
|
|
36
|
+
"--no-markdown",
|
|
37
|
+
"pr-blocker",
|
|
38
|
+
"list",
|
|
39
|
+
"--workspace",
|
|
40
|
+
"workspace",
|
|
41
|
+
"--repo-slug",
|
|
42
|
+
"repository",
|
|
43
|
+
"--pull-request-id",
|
|
44
|
+
"1",
|
|
45
|
+
"--search",
|
|
46
|
+
"reason = QA",
|
|
47
|
+
],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
assert result.exit_code == 0
|
|
51
|
+
mock_client.list_pull_request_blockers.assert_called_once_with("workspace", "repository", "1", query="reason = QA")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@patch("vds_bitbucket_orchestrator.cli._build_client")
|
|
55
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
56
|
+
def test_pr_blocker_add_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
|
|
57
|
+
settings = Mock()
|
|
58
|
+
settings.is_cloud_mode = True
|
|
59
|
+
mock_load.return_value = settings
|
|
60
|
+
mock_build.return_value.__enter__.return_value = mock_client
|
|
61
|
+
|
|
62
|
+
result = runner.invoke(
|
|
63
|
+
app,
|
|
64
|
+
[
|
|
65
|
+
"--no-markdown",
|
|
66
|
+
"pr-blocker",
|
|
67
|
+
"add",
|
|
68
|
+
"--workspace",
|
|
69
|
+
"workspace",
|
|
70
|
+
"--repo-slug",
|
|
71
|
+
"repository",
|
|
72
|
+
"--pull-request-id",
|
|
73
|
+
"1",
|
|
74
|
+
"--message",
|
|
75
|
+
"Fix tests",
|
|
76
|
+
"--reason",
|
|
77
|
+
"QA",
|
|
78
|
+
],
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
assert result.exit_code == 0
|
|
82
|
+
mock_client.add_pull_request_blocker.assert_called_once_with(
|
|
83
|
+
"workspace",
|
|
84
|
+
"repository",
|
|
85
|
+
"1",
|
|
86
|
+
"Fix tests",
|
|
87
|
+
reason="QA",
|
|
88
|
+
severity=None,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@patch("vds_bitbucket_orchestrator.cli._build_client")
|
|
93
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
94
|
+
def test_pr_blocker_delete_success(mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock) -> None:
|
|
95
|
+
settings = Mock()
|
|
96
|
+
settings.is_cloud_mode = True
|
|
97
|
+
mock_load.return_value = settings
|
|
98
|
+
mock_build.return_value.__enter__.return_value = mock_client
|
|
99
|
+
|
|
100
|
+
result = runner.invoke(
|
|
101
|
+
app,
|
|
102
|
+
[
|
|
103
|
+
"--no-markdown",
|
|
104
|
+
"pr-blocker",
|
|
105
|
+
"delete",
|
|
106
|
+
"--workspace",
|
|
107
|
+
"workspace",
|
|
108
|
+
"--repo-slug",
|
|
109
|
+
"repository",
|
|
110
|
+
"--pull-request-id",
|
|
111
|
+
"1",
|
|
112
|
+
"--blocker-uuid",
|
|
113
|
+
"{blocker}",
|
|
114
|
+
"--yes",
|
|
115
|
+
],
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
assert result.exit_code == 0
|
|
119
|
+
mock_client.delete_pull_request_blocker.assert_called_once_with("workspace", "repository", "1", "{blocker}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
123
|
+
def test_pr_blocker_requires_cloud(mock_load: Mock, runner: CliRunner) -> None:
|
|
124
|
+
settings = Mock()
|
|
125
|
+
settings.is_cloud_mode = False
|
|
126
|
+
mock_load.return_value = settings
|
|
127
|
+
|
|
128
|
+
result = runner.invoke(
|
|
129
|
+
app,
|
|
130
|
+
[
|
|
131
|
+
"pr-blocker",
|
|
132
|
+
"list",
|
|
133
|
+
"--workspace",
|
|
134
|
+
"workspace",
|
|
135
|
+
"--repo-slug",
|
|
136
|
+
"repository",
|
|
137
|
+
"--pull-request-id",
|
|
138
|
+
"1",
|
|
139
|
+
],
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
assert result.exit_code != 0
|
|
143
|
+
assert "Cloud mode" in result.stdout or "Cloud mode" in result.stderr
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@patch("vds_bitbucket_orchestrator.cli._build_client")
|
|
147
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
148
|
+
def test_pr_blocker_add_requires_message(
|
|
149
|
+
mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock
|
|
150
|
+
) -> None:
|
|
151
|
+
settings = Mock()
|
|
152
|
+
settings.is_cloud_mode = True
|
|
153
|
+
mock_load.return_value = settings
|
|
154
|
+
mock_build.return_value.__enter__.return_value = mock_client
|
|
155
|
+
|
|
156
|
+
result = runner.invoke(
|
|
157
|
+
app,
|
|
158
|
+
[
|
|
159
|
+
"pr-blocker",
|
|
160
|
+
"add",
|
|
161
|
+
"--workspace",
|
|
162
|
+
"workspace",
|
|
163
|
+
"--repo-slug",
|
|
164
|
+
"repository",
|
|
165
|
+
"--pull-request-id",
|
|
166
|
+
"1",
|
|
167
|
+
],
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
assert result.exit_code != 0
|
|
171
|
+
assert "message" in result.stdout or "message" in result.stderr
|
|
172
|
+
mock_client.add_pull_request_blocker.assert_not_called()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@patch("vds_bitbucket_orchestrator.cli._build_client")
|
|
176
|
+
@patch("vds_bitbucket_orchestrator.cli.load_settings")
|
|
177
|
+
def test_pr_blocker_delete_requires_yes(
|
|
178
|
+
mock_load: Mock, mock_build: Mock, runner: CliRunner, mock_client: Mock
|
|
179
|
+
) -> None:
|
|
180
|
+
settings = Mock()
|
|
181
|
+
settings.is_cloud_mode = True
|
|
182
|
+
mock_load.return_value = settings
|
|
183
|
+
mock_build.return_value.__enter__.return_value = mock_client
|
|
184
|
+
|
|
185
|
+
result = runner.invoke(
|
|
186
|
+
app,
|
|
187
|
+
[
|
|
188
|
+
"pr-blocker",
|
|
189
|
+
"delete",
|
|
190
|
+
"--workspace",
|
|
191
|
+
"workspace",
|
|
192
|
+
"--repo-slug",
|
|
193
|
+
"repository",
|
|
194
|
+
"--pull-request-id",
|
|
195
|
+
"1",
|
|
196
|
+
"--blocker-uuid",
|
|
197
|
+
"{blocker}",
|
|
198
|
+
],
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
assert result.exit_code != 0
|
|
202
|
+
assert "Refusing to delete blocker without --yes" in result.stdout or "Refusing to delete blocker without --yes" in result.stderr
|
|
203
|
+
mock_client.delete_pull_request_blocker.assert_not_called()
|
|
204
|
+
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"""Unit tests for Bitbucket protocol interfaces.
|
|
2
|
+
|
|
3
|
+
Tests verify that:
|
|
4
|
+
1. Protocol classes are properly defined and importable
|
|
5
|
+
2. BitbucketClient implements all protocols (structural subtyping)
|
|
6
|
+
3. isinstance() checks work correctly with @runtime_checkable protocols
|
|
7
|
+
4. Mock implementations can satisfy protocols for testing
|
|
8
|
+
|
|
9
|
+
References:
|
|
10
|
+
- FR-21.2.1: Protocol classes for dependency injection and testability
|
|
11
|
+
- TSK-222: Protocol interfaces for Bitbucket
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Any
|
|
17
|
+
from unittest.mock import Mock, patch
|
|
18
|
+
|
|
19
|
+
import pytest
|
|
20
|
+
|
|
21
|
+
from vds_bitbucket_orchestrator import (
|
|
22
|
+
BitbucketBranchClient,
|
|
23
|
+
BitbucketClient,
|
|
24
|
+
BitbucketCodeClient,
|
|
25
|
+
BitbucketFullClient,
|
|
26
|
+
BitbucketRepositoryClient,
|
|
27
|
+
BitbucketSettings,
|
|
28
|
+
)
|
|
29
|
+
from vds_bitbucket_orchestrator.protocols import (
|
|
30
|
+
BitbucketBranchClient as ProtocolBranchClient,
|
|
31
|
+
BitbucketCodeClient as ProtocolCodeClient,
|
|
32
|
+
BitbucketFullClient as ProtocolFullClient,
|
|
33
|
+
BitbucketRepositoryClient as ProtocolRepositoryClient,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Fixtures
|
|
39
|
+
# ============================================================================
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.fixture
|
|
43
|
+
def mock_settings() -> BitbucketSettings:
|
|
44
|
+
"""Create server-mode settings for testing."""
|
|
45
|
+
return BitbucketSettings(
|
|
46
|
+
VDS_USERNAME="test_user",
|
|
47
|
+
VDS_PASSWORD="test_pass",
|
|
48
|
+
BITBUCKET_TOKEN="test_token",
|
|
49
|
+
BITBUCKET_BASE_URL="https://bitbucket.test.com",
|
|
50
|
+
BITBUCKET_MODE="server",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@pytest.fixture
|
|
55
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
56
|
+
def bitbucket_client(mock_atlassian: Mock, mock_settings: BitbucketSettings) -> BitbucketClient:
|
|
57
|
+
"""Create a BitbucketClient instance with mocked SDK."""
|
|
58
|
+
return BitbucketClient(mock_settings)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ============================================================================
|
|
62
|
+
# Protocol Import Tests
|
|
63
|
+
# ============================================================================
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TestProtocolImports:
|
|
67
|
+
"""Test that protocols are properly importable from package root."""
|
|
68
|
+
|
|
69
|
+
def test_import_repository_client_from_package(self) -> None:
|
|
70
|
+
"""BitbucketRepositoryClient should be importable from package root."""
|
|
71
|
+
assert BitbucketRepositoryClient is not None
|
|
72
|
+
assert BitbucketRepositoryClient is ProtocolRepositoryClient
|
|
73
|
+
|
|
74
|
+
def test_import_branch_client_from_package(self) -> None:
|
|
75
|
+
"""BitbucketBranchClient should be importable from package root."""
|
|
76
|
+
assert BitbucketBranchClient is not None
|
|
77
|
+
assert BitbucketBranchClient is ProtocolBranchClient
|
|
78
|
+
|
|
79
|
+
def test_import_code_client_from_package(self) -> None:
|
|
80
|
+
"""BitbucketCodeClient should be importable from package root."""
|
|
81
|
+
assert BitbucketCodeClient is not None
|
|
82
|
+
assert BitbucketCodeClient is ProtocolCodeClient
|
|
83
|
+
|
|
84
|
+
def test_import_full_client_from_package(self) -> None:
|
|
85
|
+
"""BitbucketFullClient should be importable from package root."""
|
|
86
|
+
assert BitbucketFullClient is not None
|
|
87
|
+
assert BitbucketFullClient is ProtocolFullClient
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# ============================================================================
|
|
91
|
+
# Protocol Compliance Tests (isinstance checks)
|
|
92
|
+
# ============================================================================
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class TestBitbucketClientProtocolCompliance:
|
|
96
|
+
"""Test that BitbucketClient implements all protocols."""
|
|
97
|
+
|
|
98
|
+
def test_implements_repository_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
|
|
99
|
+
"""BitbucketClient should implement BitbucketRepositoryClient protocol."""
|
|
100
|
+
assert isinstance(bitbucket_client, BitbucketRepositoryClient)
|
|
101
|
+
|
|
102
|
+
def test_implements_branch_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
|
|
103
|
+
"""BitbucketClient should implement BitbucketBranchClient protocol."""
|
|
104
|
+
assert isinstance(bitbucket_client, BitbucketBranchClient)
|
|
105
|
+
|
|
106
|
+
def test_implements_code_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
|
|
107
|
+
"""BitbucketClient should implement BitbucketCodeClient protocol."""
|
|
108
|
+
assert isinstance(bitbucket_client, BitbucketCodeClient)
|
|
109
|
+
|
|
110
|
+
def test_implements_full_client_protocol(self, bitbucket_client: BitbucketClient) -> None:
|
|
111
|
+
"""BitbucketClient should implement BitbucketFullClient protocol."""
|
|
112
|
+
assert isinstance(bitbucket_client, BitbucketFullClient)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ============================================================================
|
|
116
|
+
# Protocol Method Signature Tests
|
|
117
|
+
# ============================================================================
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class TestRepositoryClientMethods:
|
|
121
|
+
"""Test that BitbucketClient has correct method signatures for BitbucketRepositoryClient."""
|
|
122
|
+
|
|
123
|
+
def test_has_list_projects_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
124
|
+
"""BitbucketClient should have list_projects method."""
|
|
125
|
+
assert hasattr(bitbucket_client, "list_projects")
|
|
126
|
+
assert callable(bitbucket_client.list_projects)
|
|
127
|
+
|
|
128
|
+
def test_has_get_project_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
129
|
+
"""BitbucketClient should have get_project method."""
|
|
130
|
+
assert hasattr(bitbucket_client, "get_project")
|
|
131
|
+
assert callable(bitbucket_client.get_project)
|
|
132
|
+
|
|
133
|
+
def test_has_list_repositories_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
134
|
+
"""BitbucketClient should have list_repositories method."""
|
|
135
|
+
assert hasattr(bitbucket_client, "list_repositories")
|
|
136
|
+
assert callable(bitbucket_client.list_repositories)
|
|
137
|
+
|
|
138
|
+
def test_has_get_repository_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
139
|
+
"""BitbucketClient should have get_repository method."""
|
|
140
|
+
assert hasattr(bitbucket_client, "get_repository")
|
|
141
|
+
assert callable(bitbucket_client.get_repository)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TestBranchClientMethods:
|
|
145
|
+
"""Test that BitbucketClient has correct method signatures for BitbucketBranchClient."""
|
|
146
|
+
|
|
147
|
+
def test_has_get_branches_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
148
|
+
"""BitbucketClient should have get_branches method."""
|
|
149
|
+
assert hasattr(bitbucket_client, "get_branches")
|
|
150
|
+
assert callable(bitbucket_client.get_branches)
|
|
151
|
+
|
|
152
|
+
def test_has_list_branch_permissions_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
153
|
+
"""BitbucketClient should have list_branch_permissions method."""
|
|
154
|
+
assert hasattr(bitbucket_client, "list_branch_permissions")
|
|
155
|
+
assert callable(bitbucket_client.list_branch_permissions)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class TestCodeClientMethods:
|
|
159
|
+
"""Test that BitbucketClient has correct method signatures for BitbucketCodeClient."""
|
|
160
|
+
|
|
161
|
+
def test_has_get_content_of_file_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
162
|
+
"""BitbucketClient should have get_content_of_file method (not get_file_content)."""
|
|
163
|
+
assert hasattr(bitbucket_client, "get_content_of_file")
|
|
164
|
+
assert callable(bitbucket_client.get_content_of_file)
|
|
165
|
+
# Verify the correct method name is used (not the incorrect one)
|
|
166
|
+
# This validates the code validation note from tasks.md
|
|
167
|
+
|
|
168
|
+
def test_has_get_commits_method(self, bitbucket_client: BitbucketClient) -> None:
|
|
169
|
+
"""BitbucketClient should have get_commits method (not list_commits)."""
|
|
170
|
+
assert hasattr(bitbucket_client, "get_commits")
|
|
171
|
+
assert callable(bitbucket_client.get_commits)
|
|
172
|
+
# Verify the correct method name is used (not the incorrect one)
|
|
173
|
+
# This validates the code validation note from tasks.md
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ============================================================================
|
|
177
|
+
# Mock Implementation Tests
|
|
178
|
+
# ============================================================================
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class MockRepositoryClient:
|
|
182
|
+
"""Mock implementation of BitbucketRepositoryClient for testing."""
|
|
183
|
+
|
|
184
|
+
def list_projects(self, limit: int = 25) -> list[dict[str, Any]]:
|
|
185
|
+
return [{"key": "TEST", "name": "Test Project"}]
|
|
186
|
+
|
|
187
|
+
def get_project(self, project_key: str) -> dict[str, Any]:
|
|
188
|
+
return {"key": project_key, "name": f"Project {project_key}"}
|
|
189
|
+
|
|
190
|
+
def list_repositories(self, project_key: str, limit: int = 25) -> list[dict[str, Any]]:
|
|
191
|
+
return [{"slug": "test-repo", "name": "Test Repository"}]
|
|
192
|
+
|
|
193
|
+
def get_repository(self, project_key: str, repository_slug: str) -> dict[str, Any]:
|
|
194
|
+
return {"slug": repository_slug, "name": f"Repository {repository_slug}"}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class MockBranchClient:
|
|
198
|
+
"""Mock implementation of BitbucketBranchClient for testing."""
|
|
199
|
+
|
|
200
|
+
def get_branches(
|
|
201
|
+
self,
|
|
202
|
+
project_key: str,
|
|
203
|
+
repository_slug: str,
|
|
204
|
+
filter: str = "",
|
|
205
|
+
limit: int = 99999,
|
|
206
|
+
details: bool = True,
|
|
207
|
+
) -> list[dict[str, Any]]:
|
|
208
|
+
return [{"displayId": "main", "isDefault": True}]
|
|
209
|
+
|
|
210
|
+
def list_branch_permissions(
|
|
211
|
+
self,
|
|
212
|
+
project_key: str,
|
|
213
|
+
repository_slug: str | None = None,
|
|
214
|
+
start: int = 0,
|
|
215
|
+
limit: int = 25,
|
|
216
|
+
) -> list[dict[str, Any]]:
|
|
217
|
+
return [{"type": "no-deletes", "matcher": {"id": "main"}}]
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class MockCodeClient:
|
|
221
|
+
"""Mock implementation of BitbucketCodeClient for testing."""
|
|
222
|
+
|
|
223
|
+
def get_content_of_file(
|
|
224
|
+
self,
|
|
225
|
+
project_key: str,
|
|
226
|
+
repository_slug: str,
|
|
227
|
+
filename: str,
|
|
228
|
+
at: str | None = None,
|
|
229
|
+
markup: str | None = None,
|
|
230
|
+
) -> str:
|
|
231
|
+
return f"# Content of {filename}"
|
|
232
|
+
|
|
233
|
+
def get_commits(
|
|
234
|
+
self,
|
|
235
|
+
project_key: str,
|
|
236
|
+
repository_slug: str,
|
|
237
|
+
hash_oldest: str | None = None,
|
|
238
|
+
hash_newest: str | None = None,
|
|
239
|
+
limit: int = 99999,
|
|
240
|
+
) -> list[dict[str, Any]]:
|
|
241
|
+
return [{"id": "abc123", "message": "Initial commit"}]
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class MockFullClient(MockRepositoryClient, MockBranchClient, MockCodeClient):
|
|
245
|
+
"""Mock implementation of BitbucketFullClient for testing."""
|
|
246
|
+
|
|
247
|
+
pass
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class TestMockImplementations:
|
|
251
|
+
"""Test that mock implementations satisfy protocols."""
|
|
252
|
+
|
|
253
|
+
def test_mock_repository_client_satisfies_protocol(self) -> None:
|
|
254
|
+
"""MockRepositoryClient should satisfy BitbucketRepositoryClient protocol."""
|
|
255
|
+
mock = MockRepositoryClient()
|
|
256
|
+
assert isinstance(mock, BitbucketRepositoryClient)
|
|
257
|
+
|
|
258
|
+
def test_mock_branch_client_satisfies_protocol(self) -> None:
|
|
259
|
+
"""MockBranchClient should satisfy BitbucketBranchClient protocol."""
|
|
260
|
+
mock = MockBranchClient()
|
|
261
|
+
assert isinstance(mock, BitbucketBranchClient)
|
|
262
|
+
|
|
263
|
+
def test_mock_code_client_satisfies_protocol(self) -> None:
|
|
264
|
+
"""MockCodeClient should satisfy BitbucketCodeClient protocol."""
|
|
265
|
+
mock = MockCodeClient()
|
|
266
|
+
assert isinstance(mock, BitbucketCodeClient)
|
|
267
|
+
|
|
268
|
+
def test_mock_full_client_satisfies_protocol(self) -> None:
|
|
269
|
+
"""MockFullClient should satisfy BitbucketFullClient protocol."""
|
|
270
|
+
mock = MockFullClient()
|
|
271
|
+
assert isinstance(mock, BitbucketFullClient)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# ============================================================================
|
|
275
|
+
# Dependency Injection Tests
|
|
276
|
+
# ============================================================================
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def audit_repository_with_protocol(client: BitbucketRepositoryClient, project_key: str) -> dict[str, Any]:
|
|
280
|
+
"""Example function using BitbucketRepositoryClient protocol for DI."""
|
|
281
|
+
repos = client.list_repositories(project_key)
|
|
282
|
+
return {"project": project_key, "repository_count": len(repos)}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def get_branch_permissions_with_protocol(
|
|
286
|
+
client: BitbucketBranchClient, project_key: str, repo_slug: str
|
|
287
|
+
) -> list[dict[str, Any]]:
|
|
288
|
+
"""Example function using BitbucketBranchClient protocol for DI."""
|
|
289
|
+
return client.list_branch_permissions(project_key, repo_slug)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_file_content_with_protocol(
|
|
293
|
+
client: BitbucketCodeClient, project_key: str, repo_slug: str, filename: str
|
|
294
|
+
) -> str:
|
|
295
|
+
"""Example function using BitbucketCodeClient protocol for DI."""
|
|
296
|
+
return client.get_content_of_file(project_key, repo_slug, filename)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class TestDependencyInjection:
|
|
300
|
+
"""Test that protocols enable proper dependency injection."""
|
|
301
|
+
|
|
302
|
+
def test_repository_client_di_with_mock(self) -> None:
|
|
303
|
+
"""Functions accepting BitbucketRepositoryClient should work with mock."""
|
|
304
|
+
mock = MockRepositoryClient()
|
|
305
|
+
result = audit_repository_with_protocol(mock, "TEST")
|
|
306
|
+
assert result["project"] == "TEST"
|
|
307
|
+
assert result["repository_count"] == 1
|
|
308
|
+
|
|
309
|
+
def test_branch_client_di_with_mock(self) -> None:
|
|
310
|
+
"""Functions accepting BitbucketBranchClient should work with mock."""
|
|
311
|
+
mock = MockBranchClient()
|
|
312
|
+
result = get_branch_permissions_with_protocol(mock, "TEST", "test-repo")
|
|
313
|
+
assert len(result) == 1
|
|
314
|
+
assert result[0]["type"] == "no-deletes"
|
|
315
|
+
|
|
316
|
+
def test_code_client_di_with_mock(self) -> None:
|
|
317
|
+
"""Functions accepting BitbucketCodeClient should work with mock."""
|
|
318
|
+
mock = MockCodeClient()
|
|
319
|
+
result = get_file_content_with_protocol(mock, "TEST", "test-repo", "README.md")
|
|
320
|
+
assert "README.md" in result
|
|
321
|
+
|
|
322
|
+
@patch("vds_bitbucket_orchestrator.client.AtlassianBitbucket")
|
|
323
|
+
def test_repository_client_di_with_real_client(
|
|
324
|
+
self, mock_atlassian: Mock, mock_settings: BitbucketSettings
|
|
325
|
+
) -> None:
|
|
326
|
+
"""Functions accepting BitbucketRepositoryClient should work with real client."""
|
|
327
|
+
client = BitbucketClient(mock_settings)
|
|
328
|
+
mock_atlassian_instance = Mock()
|
|
329
|
+
mock_atlassian_instance.repo_list.return_value = [{"slug": "repo1"}, {"slug": "repo2"}]
|
|
330
|
+
client._client = mock_atlassian_instance
|
|
331
|
+
|
|
332
|
+
result = audit_repository_with_protocol(client, "TEST")
|
|
333
|
+
assert result["project"] == "TEST"
|
|
334
|
+
assert result["repository_count"] == 2
|