@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,171 @@
|
|
|
1
|
+
"""Strongly-typed Bitbucket settings using pydantic-settings (consistent with VDS orchestrators)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from collections.abc import Iterable, Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from pydantic import Field
|
|
11
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
12
|
+
|
|
13
|
+
_PROJECT_ROOT = Path(__file__).resolve().parents[3]
|
|
14
|
+
_SCRIPTS_DIR = _PROJECT_ROOT.parent
|
|
15
|
+
|
|
16
|
+
DEFAULT_ENV_PATHS = (
|
|
17
|
+
Path.home() / ".vds" / ".env",
|
|
18
|
+
_SCRIPTS_DIR / ".env",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
_REQUIRED_KEYS: tuple[str, ...] = (
|
|
22
|
+
"VDS_USERNAME",
|
|
23
|
+
"VDS_PASSWORD",
|
|
24
|
+
"BITBUCKET_TOKEN",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
_OPTIONAL_KEYS: tuple[str, ...] = (
|
|
28
|
+
"BITBUCKET_BASE_URL",
|
|
29
|
+
"BITBUCKET_CLOUD_WORKSPACE",
|
|
30
|
+
"BITBUCKET_MODE",
|
|
31
|
+
"BITBUCKET_MAX_RETRIES",
|
|
32
|
+
"BITBUCKET_RETRY_BACKOFF",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SettingsError(RuntimeError):
|
|
37
|
+
"""Raised when the environment configuration cannot be loaded."""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class BitbucketSettings(BaseSettings):
|
|
41
|
+
model_config = SettingsConfigDict(env_file=None, env_prefix="", case_sensitive=True, populate_by_name=True)
|
|
42
|
+
|
|
43
|
+
username: str | None = Field(default=None, alias="VDS_USERNAME")
|
|
44
|
+
password: str | None = Field(default=None, alias="VDS_PASSWORD")
|
|
45
|
+
|
|
46
|
+
# Bitbucket Server/DC URL (for on-premise installations)
|
|
47
|
+
base_url: str = Field(default="http://bitbucket.digital.vn", alias="BITBUCKET_BASE_URL")
|
|
48
|
+
|
|
49
|
+
# Bitbucket Cloud workspace (for cloud.bitbucket.com)
|
|
50
|
+
cloud_workspace: str | None = Field(default=None, alias="BITBUCKET_CLOUD_WORKSPACE")
|
|
51
|
+
|
|
52
|
+
# Optional: Personal Access Token for Bitbucket Cloud or Server
|
|
53
|
+
token: str | None = Field(default=None, alias="BITBUCKET_TOKEN")
|
|
54
|
+
|
|
55
|
+
# Default mode: 'cloud' or 'server'
|
|
56
|
+
mode: str = Field(default="server", alias="BITBUCKET_MODE")
|
|
57
|
+
|
|
58
|
+
# Retry configuration
|
|
59
|
+
max_retries: int = Field(default=3, alias="BITBUCKET_MAX_RETRIES")
|
|
60
|
+
retry_backoff_factor: float = Field(default=1.0, alias="BITBUCKET_RETRY_BACKOFF")
|
|
61
|
+
|
|
62
|
+
def require_basic_or_token(self) -> None:
|
|
63
|
+
if not ((self.username and self.password) or self.token):
|
|
64
|
+
raise ValueError("Missing credentials: set VDS_USERNAME/VDS_PASSWORD or BITBUCKET_TOKEN")
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def is_cloud_mode(self) -> bool:
|
|
68
|
+
return self.mode.lower() == "cloud"
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def is_server_mode(self) -> bool:
|
|
72
|
+
return self.mode.lower() == "server"
|
|
73
|
+
|
|
74
|
+
def get_url(self) -> str:
|
|
75
|
+
"""Get appropriate URL based on mode."""
|
|
76
|
+
if self.is_cloud_mode:
|
|
77
|
+
if not self.cloud_workspace:
|
|
78
|
+
raise ValueError("BITBUCKET_CLOUD_WORKSPACE is required for cloud mode")
|
|
79
|
+
return f"https://api.bitbucket.org/workspace/{self.cloud_workspace}"
|
|
80
|
+
return str(self.base_url)
|
|
81
|
+
|
|
82
|
+
def get_auth_kwargs(self) -> dict[str, str]:
|
|
83
|
+
"""Get authentication kwargs for atlassian-python-api."""
|
|
84
|
+
if self.token:
|
|
85
|
+
return {"token": self.token}
|
|
86
|
+
elif self.username and self.password:
|
|
87
|
+
return {"username": self.username, "password": self.password}
|
|
88
|
+
else:
|
|
89
|
+
raise ValueError("No valid authentication credentials available")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass(frozen=True)
|
|
93
|
+
class EnvSnapshot:
|
|
94
|
+
"""A snapshot of relevant environment variables."""
|
|
95
|
+
|
|
96
|
+
values: Mapping[str, str]
|
|
97
|
+
source: Path | str | None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _parse_env_file(env_path: Path) -> dict[str, str]:
|
|
101
|
+
if not env_path.exists():
|
|
102
|
+
return {}
|
|
103
|
+
|
|
104
|
+
result: dict[str, str] = {}
|
|
105
|
+
for raw_line in env_path.read_text().splitlines():
|
|
106
|
+
line = raw_line.strip()
|
|
107
|
+
if not line or line.startswith("#"):
|
|
108
|
+
continue
|
|
109
|
+
if "=" not in line:
|
|
110
|
+
continue
|
|
111
|
+
key, raw_value = line.split("=", 1)
|
|
112
|
+
key = key.strip()
|
|
113
|
+
value = raw_value.strip().strip('"').strip("'")
|
|
114
|
+
if key:
|
|
115
|
+
result[key] = value
|
|
116
|
+
return result
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _merge_env_sources(*snapshots: EnvSnapshot) -> dict[str, str]:
|
|
120
|
+
merged: dict[str, str] = {}
|
|
121
|
+
for snapshot in snapshots:
|
|
122
|
+
merged.update(snapshot.values)
|
|
123
|
+
return merged
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _filter_keys(source: Mapping[str, str]) -> dict[str, str]:
|
|
127
|
+
relevant_keys = set(_REQUIRED_KEYS + _OPTIONAL_KEYS)
|
|
128
|
+
return {key: value for key, value in source.items() if key in relevant_keys}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _resolve_env_paths(env_path: Path | None) -> Iterable[Path]:
|
|
132
|
+
if env_path is not None:
|
|
133
|
+
return (env_path,)
|
|
134
|
+
return DEFAULT_ENV_PATHS
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def load_settings(
|
|
138
|
+
*,
|
|
139
|
+
env_path: Path | None = None,
|
|
140
|
+
overrides: Mapping[str, str] | None = None,
|
|
141
|
+
strict: bool = False,
|
|
142
|
+
) -> BitbucketSettings:
|
|
143
|
+
"""Load orchestrator settings from the environment and optional .env file."""
|
|
144
|
+
|
|
145
|
+
snapshots = []
|
|
146
|
+
for candidate in _resolve_env_paths(env_path):
|
|
147
|
+
snapshots.append(
|
|
148
|
+
EnvSnapshot(
|
|
149
|
+
values=_filter_keys(_parse_env_file(candidate)), source=candidate if candidate.exists() else None
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
snapshots.append(EnvSnapshot(values=_filter_keys(os.environ), source="os.environ"))
|
|
154
|
+
|
|
155
|
+
if overrides:
|
|
156
|
+
snapshots.append(EnvSnapshot(values=_filter_keys(overrides), source="overrides"))
|
|
157
|
+
|
|
158
|
+
merged = _merge_env_sources(*snapshots)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
settings = BitbucketSettings.model_validate(merged)
|
|
162
|
+
except Exception as exc:
|
|
163
|
+
raise SettingsError(str(exc)) from exc
|
|
164
|
+
|
|
165
|
+
if strict:
|
|
166
|
+
settings.require_basic_or_token()
|
|
167
|
+
|
|
168
|
+
return settings
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
__all__ = ["BitbucketSettings", "SettingsError", "load_settings", "DEFAULT_ENV_PATHS"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Bitbucket-specific error types (consistent with VDS orchestrators)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BitbucketClientError(RuntimeError):
|
|
9
|
+
"""Base class for Bitbucket client errors."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, message: str, *, context: dict[str, Any] | None = None) -> None:
|
|
12
|
+
super().__init__(message)
|
|
13
|
+
self.context = context or {}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BitbucketAuthError(BitbucketClientError):
|
|
17
|
+
"""Raised when authentication fails (401/403)."""
|
|
18
|
+
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BitbucketRateLimitedError(BitbucketClientError):
|
|
23
|
+
"""Raised when rate limited by Bitbucket (429)."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self, message: str, *, retry_after: float | None = None, context: dict[str, Any] | None = None
|
|
27
|
+
) -> None:
|
|
28
|
+
super().__init__(message, context=context)
|
|
29
|
+
self.retry_after = retry_after
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class BitbucketNotFoundError(BitbucketClientError):
|
|
33
|
+
"""Raised when a resource is not found (404)."""
|
|
34
|
+
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BitbucketConflictError(BitbucketClientError):
|
|
39
|
+
"""Raised when there's a conflict (409)."""
|
|
40
|
+
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class BitbucketResponseError(BitbucketClientError):
|
|
45
|
+
"""Raised for other HTTP errors (4xx/5xx)."""
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self, message: str, *, status_code: int | None = None, context: dict[str, Any] | None = None
|
|
49
|
+
) -> None:
|
|
50
|
+
super().__init__(message, context=context)
|
|
51
|
+
self.status_code = status_code
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class BitbucketTransportError(BitbucketClientError):
|
|
55
|
+
"""Raised for network/transport issues."""
|
|
56
|
+
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BitbucketRetryError(BitbucketClientError):
|
|
61
|
+
"""Raised when retry attempts are exhausted."""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self, message: str, *, attempts: int | None = None, context: dict[str, Any] | None = None
|
|
65
|
+
) -> None:
|
|
66
|
+
super().__init__(message, context=context)
|
|
67
|
+
self.attempts = attempts
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Factory functions for creating Bitbucket clients with automatic credential loading.
|
|
2
|
+
|
|
3
|
+
This module provides convenient factory functions that automatically load credentials
|
|
4
|
+
from the shared VDS environment loader (`vds_cli_common.env`), simplifying client instantiation.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from vds_bitbucket_orchestrator import create_client, create_async_client
|
|
8
|
+
|
|
9
|
+
# Create a sync client with auto-loaded credentials
|
|
10
|
+
client = create_client()
|
|
11
|
+
|
|
12
|
+
# Create a sync client with explicit mode
|
|
13
|
+
client = create_client(mode="cloud")
|
|
14
|
+
|
|
15
|
+
# Create an async client for non-blocking operations
|
|
16
|
+
async_client = create_async_client()
|
|
17
|
+
|
|
18
|
+
References:
|
|
19
|
+
- FR-21.2.2: Factory functions that load credentials from the shared VDS env file automatically
|
|
20
|
+
- FR-21.2.3: AsyncBitbucketClient using asyncio.to_thread()
|
|
21
|
+
- TSK-223: Factory functions for Bitbucket
|
|
22
|
+
- TSK-225: Async Bitbucket wrapper
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Literal
|
|
29
|
+
|
|
30
|
+
from vds_cli_common.paths import get_shared_env_path
|
|
31
|
+
|
|
32
|
+
from .async_client import AsyncBitbucketClient
|
|
33
|
+
from .client import BitbucketClient
|
|
34
|
+
from .config import load_settings
|
|
35
|
+
|
|
36
|
+
# Default path for the shared VDS environment file
|
|
37
|
+
DEFAULT_VDS_ENV_PATH = get_shared_env_path()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_client(
|
|
41
|
+
*,
|
|
42
|
+
mode: Literal["server", "cloud"] | None = None,
|
|
43
|
+
env_path: Path | None = None,
|
|
44
|
+
timeout: int | None = 30,
|
|
45
|
+
strict: bool = True,
|
|
46
|
+
) -> BitbucketClient:
|
|
47
|
+
"""Create a Bitbucket client with auto-loaded credentials from the shared VDS env file.
|
|
48
|
+
|
|
49
|
+
This factory function simplifies client creation by automatically loading
|
|
50
|
+
credentials from the standard VDS environment file location.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
mode: Bitbucket mode - 'server' (default) for Bitbucket Server/DC,
|
|
54
|
+
'cloud' for Bitbucket Cloud. If None, uses value from env file
|
|
55
|
+
or defaults to 'server'.
|
|
56
|
+
env_path: Optional custom path to .env file. Defaults to the shared VDS env path.
|
|
57
|
+
timeout: HTTP timeout in seconds (default: 30).
|
|
58
|
+
strict: If True (default), validates that credentials are present.
|
|
59
|
+
Set to False to allow creating client without validation.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
BitbucketClient: Configured Bitbucket client instance.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ValueError: If strict=True and credentials are missing.
|
|
66
|
+
SettingsError: If environment configuration cannot be loaded.
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
# Simple usage with defaults (server mode, shared VDS env path)
|
|
70
|
+
client = create_client()
|
|
71
|
+
|
|
72
|
+
# Cloud mode
|
|
73
|
+
client = create_client(mode="cloud")
|
|
74
|
+
|
|
75
|
+
# Custom env file
|
|
76
|
+
client = create_client(env_path=Path("/custom/path/.env"))
|
|
77
|
+
|
|
78
|
+
# Non-strict mode (for testing)
|
|
79
|
+
client = create_client(strict=False)
|
|
80
|
+
|
|
81
|
+
Note:
|
|
82
|
+
The client implements BitbucketFullClient protocol, enabling type-safe
|
|
83
|
+
dependency injection:
|
|
84
|
+
|
|
85
|
+
def audit_repo(client: BitbucketFullClient, project: str, repo: str):
|
|
86
|
+
return client.get_repository(project, repo)
|
|
87
|
+
|
|
88
|
+
client = create_client()
|
|
89
|
+
result = audit_repo(client, "INS", "insurance-core")
|
|
90
|
+
"""
|
|
91
|
+
# Build overrides dict for mode if specified
|
|
92
|
+
overrides: dict[str, str] | None = None
|
|
93
|
+
if mode is not None:
|
|
94
|
+
overrides = {"BITBUCKET_MODE": mode}
|
|
95
|
+
|
|
96
|
+
# Load settings from env file with optional overrides
|
|
97
|
+
settings = load_settings(
|
|
98
|
+
env_path=env_path or DEFAULT_VDS_ENV_PATH,
|
|
99
|
+
overrides=overrides,
|
|
100
|
+
strict=strict,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Create and return the client
|
|
104
|
+
return BitbucketClient(settings, timeout=timeout)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def create_async_client(
|
|
108
|
+
*,
|
|
109
|
+
mode: Literal["server", "cloud"] | None = None,
|
|
110
|
+
env_path: Path | None = None,
|
|
111
|
+
timeout: int | None = 30,
|
|
112
|
+
strict: bool = True,
|
|
113
|
+
) -> AsyncBitbucketClient:
|
|
114
|
+
"""Create an async Bitbucket client with auto-loaded credentials from the shared VDS env file.
|
|
115
|
+
|
|
116
|
+
This factory function creates an AsyncBitbucketClient that wraps the synchronous
|
|
117
|
+
BitbucketClient methods using asyncio.to_thread() for non-blocking execution.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
mode: Bitbucket mode - 'server' (default) for Bitbucket Server/DC,
|
|
121
|
+
'cloud' for Bitbucket Cloud. If None, uses value from env file
|
|
122
|
+
or defaults to 'server'.
|
|
123
|
+
env_path: Optional custom path to .env file. Defaults to the shared VDS env path.
|
|
124
|
+
timeout: HTTP timeout in seconds (default: 30).
|
|
125
|
+
strict: If True (default), validates that credentials are present.
|
|
126
|
+
Set to False to allow creating client without validation.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
AsyncBitbucketClient: Async Bitbucket client instance.
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
ValueError: If strict=True and credentials are missing.
|
|
133
|
+
SettingsError: If environment configuration cannot be loaded.
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
import asyncio
|
|
137
|
+
from vds_bitbucket_orchestrator import create_async_client
|
|
138
|
+
|
|
139
|
+
async def audit_repos():
|
|
140
|
+
client = create_async_client()
|
|
141
|
+
|
|
142
|
+
# Non-blocking API calls
|
|
143
|
+
repos = await client.list_repositories("INS")
|
|
144
|
+
|
|
145
|
+
# Concurrent API calls
|
|
146
|
+
repo_info, branches = await asyncio.gather(
|
|
147
|
+
client.get_repository("INS", "insurance-core"),
|
|
148
|
+
client.get_branches("INS", "insurance-core"),
|
|
149
|
+
)
|
|
150
|
+
return repos, repo_info, branches
|
|
151
|
+
|
|
152
|
+
# Run the async function
|
|
153
|
+
result = asyncio.run(audit_repos())
|
|
154
|
+
|
|
155
|
+
Note:
|
|
156
|
+
The AsyncBitbucketClient implements the same protocols as BitbucketClient:
|
|
157
|
+
- BitbucketRepositoryClient
|
|
158
|
+
- BitbucketBranchClient
|
|
159
|
+
- BitbucketCodeClient
|
|
160
|
+
- BitbucketFullClient
|
|
161
|
+
|
|
162
|
+
The underlying HTTP calls are synchronous but run in a thread pool,
|
|
163
|
+
preventing them from blocking the async event loop.
|
|
164
|
+
"""
|
|
165
|
+
# Build overrides dict for mode if specified
|
|
166
|
+
overrides: dict[str, str] | None = None
|
|
167
|
+
if mode is not None:
|
|
168
|
+
overrides = {"BITBUCKET_MODE": mode}
|
|
169
|
+
|
|
170
|
+
# Load settings from env file with optional overrides
|
|
171
|
+
settings = load_settings(
|
|
172
|
+
env_path=env_path or DEFAULT_VDS_ENV_PATH,
|
|
173
|
+
overrides=overrides,
|
|
174
|
+
strict=strict,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Create and return the async client
|
|
178
|
+
return AsyncBitbucketClient(settings, timeout=timeout)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
__all__ = [
|
|
182
|
+
"create_client",
|
|
183
|
+
"create_async_client",
|
|
184
|
+
"DEFAULT_VDS_ENV_PATH",
|
|
185
|
+
]
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""Protocol interfaces for Bitbucket client dependency injection and testability.
|
|
2
|
+
|
|
3
|
+
This module defines Protocol classes that enable:
|
|
4
|
+
- Dependency injection for testing with mock implementations
|
|
5
|
+
- Type-safe interfaces for different Bitbucket API capabilities
|
|
6
|
+
- Separation of concerns between repository, branch, and code operations
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from vds_bitbucket_orchestrator.protocols import (
|
|
10
|
+
BitbucketRepositoryClient,
|
|
11
|
+
BitbucketBranchClient,
|
|
12
|
+
BitbucketCodeClient,
|
|
13
|
+
BitbucketFullClient,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def audit_repository(client: BitbucketRepositoryClient, project_key: str) -> dict:
|
|
17
|
+
repos = client.list_repositories(project_key)
|
|
18
|
+
return {"repositories": repos}
|
|
19
|
+
|
|
20
|
+
References:
|
|
21
|
+
- FR-21.2.1: Protocol classes for dependency injection and testability
|
|
22
|
+
- TSK-222: Protocol interfaces for Bitbucket
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import Any, Protocol, runtime_checkable
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@runtime_checkable
|
|
31
|
+
class BitbucketRepositoryClient(Protocol):
|
|
32
|
+
"""Protocol for Bitbucket repository operations.
|
|
33
|
+
|
|
34
|
+
This protocol defines the interface for repository-related operations
|
|
35
|
+
including listing, getting, creating, and managing repositories.
|
|
36
|
+
|
|
37
|
+
Implementations:
|
|
38
|
+
- BitbucketClient: Full implementation using atlassian-python-api
|
|
39
|
+
- Mock implementations for testing
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def list_projects(self, limit: int = 25) -> list[dict[str, Any]]:
|
|
43
|
+
"""List all projects.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
limit: Maximum number of projects to return (default: 25)
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of project dictionaries with keys like 'key', 'name', 'description'
|
|
50
|
+
"""
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
def get_project(self, project_key: str) -> dict[str, Any]:
|
|
54
|
+
"""Get project information.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
project_key: The project key (e.g., 'INS', 'LEP')
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Project dictionary with metadata
|
|
61
|
+
"""
|
|
62
|
+
...
|
|
63
|
+
|
|
64
|
+
def list_repositories(self, project_key: str, limit: int = 25) -> list[dict[str, Any]]:
|
|
65
|
+
"""List repositories in a project.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
project_key: The project key
|
|
69
|
+
limit: Maximum number of repositories to return (default: 25)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
List of repository dictionaries with keys like 'slug', 'name', 'description'
|
|
73
|
+
"""
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
def get_repository(self, project_key: str, repository_slug: str) -> dict[str, Any]:
|
|
77
|
+
"""Get repository information.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
project_key: The project key
|
|
81
|
+
repository_slug: The repository slug
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Repository dictionary with metadata
|
|
85
|
+
"""
|
|
86
|
+
...
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@runtime_checkable
|
|
90
|
+
class BitbucketBranchClient(Protocol):
|
|
91
|
+
"""Protocol for Bitbucket branch and permission operations.
|
|
92
|
+
|
|
93
|
+
This protocol defines the interface for branch-related operations
|
|
94
|
+
including listing branches, managing permissions, and branch restrictions.
|
|
95
|
+
|
|
96
|
+
Implementations:
|
|
97
|
+
- BitbucketClient: Full implementation using atlassian-python-api
|
|
98
|
+
- Mock implementations for testing
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def get_branches(
|
|
102
|
+
self,
|
|
103
|
+
project_key: str,
|
|
104
|
+
repository_slug: str,
|
|
105
|
+
filter: str = "",
|
|
106
|
+
limit: int = 99999,
|
|
107
|
+
details: bool = True,
|
|
108
|
+
) -> list[dict[str, Any]]:
|
|
109
|
+
"""Get branches from a repository.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
project_key: The project key
|
|
113
|
+
repository_slug: The repository slug
|
|
114
|
+
filter: Optional filter string for branch names
|
|
115
|
+
limit: Maximum number of branches to return (default: 99999)
|
|
116
|
+
details: Whether to include branch details (default: True)
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
List of branch dictionaries with metadata
|
|
120
|
+
"""
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
def list_branch_permissions(
|
|
124
|
+
self,
|
|
125
|
+
project_key: str,
|
|
126
|
+
repository_slug: str | None = None,
|
|
127
|
+
start: int = 0,
|
|
128
|
+
limit: int = 25,
|
|
129
|
+
) -> list[dict[str, Any]]:
|
|
130
|
+
"""List branch permissions (server and cloud).
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
project_key: The project key
|
|
134
|
+
repository_slug: Optional repository slug (required for cloud mode)
|
|
135
|
+
start: Start index for pagination (default: 0)
|
|
136
|
+
limit: Maximum number of permissions to return (default: 25)
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Normalized list of branch restriction objects
|
|
140
|
+
"""
|
|
141
|
+
...
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@runtime_checkable
|
|
145
|
+
class BitbucketCodeClient(Protocol):
|
|
146
|
+
"""Protocol for Bitbucket code and commit operations.
|
|
147
|
+
|
|
148
|
+
This protocol defines the interface for code-related operations
|
|
149
|
+
including file content retrieval and commit history.
|
|
150
|
+
|
|
151
|
+
Implementations:
|
|
152
|
+
- BitbucketClient: Full implementation using atlassian-python-api
|
|
153
|
+
- Mock implementations for testing
|
|
154
|
+
|
|
155
|
+
Note:
|
|
156
|
+
Method names match the atlassian-python-api SDK:
|
|
157
|
+
- get_content_of_file() (not get_file_content)
|
|
158
|
+
- get_commits() (not list_commits)
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def get_content_of_file(
|
|
162
|
+
self,
|
|
163
|
+
project_key: str,
|
|
164
|
+
repository_slug: str,
|
|
165
|
+
filename: str,
|
|
166
|
+
at: str | None = None,
|
|
167
|
+
markup: str | None = None,
|
|
168
|
+
) -> str:
|
|
169
|
+
"""Get raw content of a file from repository.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
project_key: The project key
|
|
173
|
+
repository_slug: The repository slug
|
|
174
|
+
filename: Path to the file in the repository
|
|
175
|
+
at: Optional commit hash, branch, or tag to retrieve file at
|
|
176
|
+
markup: Optional markup format for rendering
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
File content as string
|
|
180
|
+
"""
|
|
181
|
+
...
|
|
182
|
+
|
|
183
|
+
def get_commits(
|
|
184
|
+
self,
|
|
185
|
+
project_key: str,
|
|
186
|
+
repository_slug: str,
|
|
187
|
+
hash_oldest: str | None = None,
|
|
188
|
+
hash_newest: str | None = None,
|
|
189
|
+
limit: int = 99999,
|
|
190
|
+
) -> list[dict[str, Any]]:
|
|
191
|
+
"""Get commit list from repository.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
project_key: The project key
|
|
195
|
+
repository_slug: The repository slug
|
|
196
|
+
hash_oldest: Optional oldest commit hash to start from
|
|
197
|
+
hash_newest: Optional newest commit hash to end at
|
|
198
|
+
limit: Maximum number of commits to return (default: 99999)
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of commit dictionaries with metadata
|
|
202
|
+
"""
|
|
203
|
+
...
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@runtime_checkable
|
|
207
|
+
class BitbucketFullClient(BitbucketRepositoryClient, BitbucketBranchClient, BitbucketCodeClient, Protocol):
|
|
208
|
+
"""Combined protocol for full Bitbucket client capabilities.
|
|
209
|
+
|
|
210
|
+
This protocol is a union of all Bitbucket client protocols:
|
|
211
|
+
- BitbucketRepositoryClient: Repository operations
|
|
212
|
+
- BitbucketBranchClient: Branch and permission operations
|
|
213
|
+
- BitbucketCodeClient: Code and commit operations
|
|
214
|
+
|
|
215
|
+
Use this protocol when you need access to all Bitbucket capabilities.
|
|
216
|
+
For more focused interfaces, use the individual protocols.
|
|
217
|
+
|
|
218
|
+
Implementations:
|
|
219
|
+
- BitbucketClient: Full implementation using atlassian-python-api
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
def full_audit(client: BitbucketFullClient, project_key: str, repo_slug: str):
|
|
223
|
+
# Repository operations
|
|
224
|
+
repo = client.get_repository(project_key, repo_slug)
|
|
225
|
+
|
|
226
|
+
# Branch operations
|
|
227
|
+
permissions = client.list_branch_permissions(project_key, repo_slug)
|
|
228
|
+
|
|
229
|
+
# Code operations
|
|
230
|
+
readme = client.get_content_of_file(project_key, repo_slug, "README.md")
|
|
231
|
+
commits = client.get_commits(project_key, repo_slug, limit=10)
|
|
232
|
+
|
|
233
|
+
return {"repo": repo, "permissions": permissions, "readme": readme, "commits": commits}
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
__all__ = [
|
|
240
|
+
"BitbucketRepositoryClient",
|
|
241
|
+
"BitbucketBranchClient",
|
|
242
|
+
"BitbucketCodeClient",
|
|
243
|
+
"BitbucketFullClient",
|
|
244
|
+
]
|