chore(providers): onboarding prep — unblock Azure/GCP/OCI merges #1202
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Package Testing Strategy | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'src/**' | |
| - 'pyproject.toml' | |
| - '.github/workflows/package-testing.yml' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'src/**' | |
| - 'pyproject.toml' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Per-ref concurrency: prevents a rapid series of pushes to main from queuing | |
| # redundant package-testing runs. Each ref can only have one run active at a | |
| # time; a newer push cancels the older in-progress run. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Shared configuration: provides python-versions, default-python-version, and | |
| # package-extras (via the discover step in shared-config) so this workflow has | |
| # a single source of truth instead of duplicating hardcoded version strings. | |
| config: | |
| name: Get Configuration | |
| uses: ./.github/workflows/shared-config.yml | |
| package-variants: | |
| name: Test Package Variants | |
| runs-on: ubuntu-latest | |
| needs: [config] | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Dynamic: fromJSON pulls the discovered extras list from shared-config. | |
| # The 'minimal' base install (no extras) is always tested first via a | |
| # separate include entry so the matrix only needs extra names here. | |
| # Static fallback ['cli','api','monitoring'] preserves historical coverage. | |
| extra: ${{ fromJSON(needs.config.outputs.package-extras || '["cli","api","monitoring"]') }} | |
| # Python version axis driven from .project.yml via shared-config. | |
| # Static fallback keeps act/offline CI valid; update it when python.versions changes. | |
| python-version: ${{ fromJSON(needs.config.outputs.python-versions || '["3.10", "3.11", "3.12", "3.13", "3.14"]') }} | |
| include: | |
| # Always test the minimal (no extras) variant on the oldest + newest supported versions. | |
| - extra: "minimal" | |
| python-version: "3.10" | |
| - extra: "minimal" | |
| python-version: "3.14" | |
| # Always test the .[all] meta-extra (all feature layers together). | |
| - extra: "all" | |
| python-version: "3.10" | |
| - extra: "all" | |
| python-version: "3.14" | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install package variant | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build wheel | |
| python -m build | |
| # Install the built wheel (not editable source) for true variant isolation. | |
| # 'minimal' maps to the base package with no extras; 'all' is the | |
| # meta-extra that pulls in all feature layers; everything else is | |
| # installed as .[<extra>]. | |
| EXTRA="${{ matrix.extra }}" | |
| WHEEL=$(find dist -name '*.whl' | head -1) | |
| if [ "$EXTRA" = "minimal" ]; then | |
| pip install "${WHEEL}" | |
| else | |
| pip install "${WHEEL}[${EXTRA}]" | |
| fi | |
| - name: Test core imports | |
| run: | | |
| python -c " | |
| import sys | |
| extra = '${{ matrix.extra }}' | |
| print(f'Testing extra: {extra}') | |
| print(f'Python version: {sys.version}') | |
| # Core package must import regardless of which extra is installed. | |
| try: | |
| import orb.run | |
| from orb.bootstrap import Application | |
| from orb.domain.base.exceptions import DomainException | |
| from orb.infrastructure.logging.logger import get_logger | |
| print('PASS: Core imports successful') | |
| except ImportError as e: | |
| print(f'FAIL: Core import failed: {e}') | |
| sys.exit(1) | |
| " | |
| - name: Test CLI functionality | |
| run: | | |
| # Test basic CLI works | |
| python -m orb --help | |
| python -m orb --version | |
| # Test commands that should work in all variants | |
| python -m orb templates list --help || echo "Templates command help failed (expected in some cases)" | |
| # Data-driven per-extra assertion: replaces the old boolean-flag steps | |
| # (test_cli_rich / test_api / test_monitoring). Each extra gets one step | |
| # that probes the specific import it provides. Unknown extras only run | |
| # the core-import step above. | |
| - name: Test CLI extra (rich formatting) | |
| if: matrix.extra == 'cli' || matrix.extra == 'all' | |
| run: | | |
| python -c " | |
| try: | |
| from orb.cli.formatters import format_generic_table | |
| from orb.cli.console import get_console | |
| test_data = [{'id': '1', 'name': 'test'}] | |
| format_generic_table(test_data, 'Test Items') | |
| console = get_console() | |
| console.print('[green]Rich console test[/green]') | |
| print('PASS: Rich CLI formatting successful') | |
| except ImportError as e: | |
| print(f'FAIL: Rich CLI functionality failed: {e}') | |
| import sys; sys.exit(1) | |
| " | |
| - name: Test minimal variant (no rich, CLI fallbacks only) | |
| if: matrix.extra == 'minimal' | |
| run: | | |
| python -c " | |
| try: | |
| import rich | |
| print('WARNING: Rich is available but should not be in minimal variant') | |
| except ImportError: | |
| print('PASS: Rich correctly not available in minimal variant') | |
| from orb.cli.formatters import format_generic_table | |
| from orb.cli.console import get_console | |
| test_data = [{'id': '1', 'name': 'test'}] | |
| format_generic_table(test_data, 'Test Items') | |
| console = get_console() | |
| console.print('Plain console test') | |
| print('PASS: CLI fallback formatting works in minimal variant') | |
| " | |
| - name: Test API extra (FastAPI available) | |
| if: matrix.extra == 'api' || matrix.extra == 'all' | |
| run: | | |
| python -c " | |
| try: | |
| from orb.api.server import create_fastapi_app | |
| print('PASS: FastAPI imports successful') | |
| except ImportError as e: | |
| print(f'FAIL: API functionality failed: {e}') | |
| import sys; sys.exit(1) | |
| " | |
| - name: Test API graceful failure (non-API extras) | |
| if: matrix.extra != 'api' && matrix.extra != 'all' | |
| run: | | |
| python -c " | |
| extra = '${{ matrix.extra }}' | |
| try: | |
| import fastapi | |
| print(f'INFO: FastAPI present for extra={extra} (may be transitive dep)') | |
| except ImportError: | |
| print(f'PASS: FastAPI correctly absent for extra={extra}') | |
| try: | |
| from orb.api.server import create_fastapi_app | |
| try: | |
| create_fastapi_app(None) | |
| # FastAPI may be present via a transitive dep in some extras (e.g. monitoring). | |
| print(f'INFO: API callable for extra={extra} (fastapi present as transitive dep)') | |
| except ImportError as e: | |
| if 'FastAPI not installed' in str(e): | |
| print('PASS: API gracefully fails without FastAPI') | |
| else: | |
| print(f'FAIL: Unexpected API error: {e}') | |
| import sys; sys.exit(1) | |
| except ImportError: | |
| print(f'PASS: API server module handles missing FastAPI for extra={extra}') | |
| " | |
| - name: Test monitoring extra (OpenTelemetry available) | |
| if: matrix.extra == 'monitoring' || matrix.extra == 'all' | |
| run: | | |
| python -c " | |
| try: | |
| from orb.monitoring.health import HealthCheck | |
| print('PASS: Monitoring imports successful') | |
| except ImportError as e: | |
| print(f'FAIL: Monitoring functionality failed: {e}') | |
| import sys; sys.exit(1) | |
| " | |
| - name: Test monitoring module imports gracefully (non-monitoring extras) | |
| if: matrix.extra != 'monitoring' && matrix.extra != 'all' | |
| run: | | |
| python -c " | |
| extra = '${{ matrix.extra }}' | |
| optional_monitoring = ['prometheus_client', 'opentelemetry', 'psutil'] | |
| for dep in optional_monitoring: | |
| try: | |
| __import__(dep) | |
| print(f'INFO: {dep} present for extra={extra} (may be transitive dep)') | |
| except ImportError: | |
| print(f'PASS: {dep} absent for extra={extra}') | |
| try: | |
| from orb.monitoring.health import HealthCheck | |
| print('PASS: Monitoring module imports with limited functionality') | |
| except ImportError as e: | |
| print(f'FAIL: Monitoring module should import even without optional deps: {e}') | |
| import sys; sys.exit(1) | |
| " | |
| import-guard-validation: | |
| name: Import Guard Validation | |
| runs-on: ubuntu-latest | |
| needs: [config] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Set up Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: ${{ needs.config.outputs.default-python-version }} | |
| - name: Install minimal dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build pytest pytest-mock | |
| python -m build | |
| pip install "$(find dist -name '*.whl' | head -1)" | |
| - name: Test import guards | |
| run: | | |
| python -c " | |
| import sys | |
| from unittest.mock import patch | |
| print('Testing import guards...') | |
| # Test CLI without Rich | |
| with patch.dict(sys.modules, {'rich': None, 'rich.console': None, 'rich.table': None}): | |
| try: | |
| from orb.cli.console import get_console, print_success | |
| console = get_console() | |
| print('PASS: CLI console works without Rich') | |
| except Exception as e: | |
| print(f'FAIL: CLI console failed without Rich: {e}') | |
| sys.exit(1) | |
| # Test API without FastAPI | |
| with patch.dict(sys.modules, {'fastapi': None}): | |
| try: | |
| from orb.api.server import create_fastapi_app | |
| try: | |
| create_fastapi_app(None) | |
| print('FAIL: API should fail without FastAPI') | |
| sys.exit(1) | |
| except ImportError as e: | |
| if 'FastAPI not installed' in str(e): | |
| print('PASS: API correctly fails without FastAPI') | |
| else: | |
| print(f'FAIL: Unexpected API error: {e}') | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f'FAIL: API import guard test failed: {e}') | |
| sys.exit(1) | |
| print('All import guard tests passed!') | |
| " | |
| dependency-isolation: | |
| name: Dependency Isolation Test | |
| runs-on: ubuntu-latest | |
| needs: [config] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Set up Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: ${{ needs.config.outputs.default-python-version }} | |
| - name: Test clean environment | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build | |
| python -m build | |
| pip install "$(find dist -name '*.whl' | head -1)" | |
| # Verify no optional dependencies are installed | |
| python -c " | |
| import sys | |
| # psutil is a base dependency (system health check), so it is | |
| # intentionally present in every install and not listed here. | |
| optional_deps = ['rich', 'fastapi', 'uvicorn', 'opentelemetry', 'prometheus_client'] | |
| leaked = [] | |
| for dep in optional_deps: | |
| try: | |
| __import__(dep) | |
| print(f'FAIL: {dep} leaked into minimal install') | |
| leaked.append(dep) | |
| except ImportError: | |
| print(f'PASS: {dep} correctly not available') | |
| if leaked: | |
| print(f'ERROR: {len(leaked)} optional dep(s) leaked: {leaked}') | |
| sys.exit(1) | |
| # Test that core functionality still works | |
| import orb.run | |
| from orb.bootstrap import Application | |
| from orb.domain.base.exceptions import DomainException | |
| print('PASS: Core functionality works without optional deps') | |
| # Test CLI with fallbacks | |
| from orb.cli.console import get_console | |
| console = get_console() | |
| console.print('Test message') | |
| print('PASS: CLI works with fallbacks') | |
| " | |
| error-message-quality: | |
| name: Error Message Quality Test | |
| runs-on: ubuntu-latest | |
| needs: [config] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Set up Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: ${{ needs.config.outputs.default-python-version }} | |
| - name: Install minimal package | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build | |
| python -m build | |
| pip install "$(find dist -name '*.whl' | head -1)" | |
| - name: Test error messages are helpful | |
| run: | | |
| python -c " | |
| import sys | |
| # Test API error message | |
| try: | |
| from orb.api.server import create_fastapi_app | |
| try: | |
| create_fastapi_app(None) | |
| print('FAIL: API should have failed') | |
| sys.exit(1) | |
| except ImportError as e: | |
| error_msg = str(e) | |
| if 'pip install orb-py[api]' in error_msg: | |
| print('PASS: API error message is helpful') | |
| else: | |
| print(f'FAIL: API error message not helpful: {error_msg}') | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f'FAIL: Error message test failed: {e}') | |
| sys.exit(1) | |
| print('Error message quality tests passed!') | |
| " | |
| integration-test: | |
| name: Integration Test | |
| runs-on: ubuntu-latest | |
| needs: [config, package-variants, import-guard-validation, dependency-isolation] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Set up Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 | |
| with: | |
| python-version: ${{ needs.config.outputs.default-python-version }} | |
| - name: Test full installation | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build | |
| python -m build | |
| pip install "$(find dist -name '*.whl' | head -1)[all]" | |
| - name: Run comprehensive test | |
| run: | | |
| # Test all functionality works together | |
| python -c " | |
| # Test all imports work | |
| from orb.cli.formatters import format_generic_table | |
| from orb.cli.console import get_console | |
| from orb.api.server import create_fastapi_app | |
| from orb.monitoring.health import HealthCheck | |
| print('PASS: All modules import successfully') | |
| # Test Rich formatting | |
| test_data = [{'id': '1', 'name': 'test', 'status': 'active'}] | |
| table_output = format_generic_table(test_data, 'Test Data') | |
| print('PASS: Rich table formatting works') | |
| # Test console | |
| console = get_console() | |
| console.print('Integration test successful') | |
| print('PASS: Rich console works') | |
| print('Integration test completed successfully!') | |
| " | |
| - name: Test CLI commands | |
| run: | | |
| python -m orb --help | |
| python -m orb --version | |
| echo "PASS: CLI commands work" | |
| summary: | |
| name: Package Testing Summary | |
| runs-on: ubuntu-latest | |
| needs: [package-variants, import-guard-validation, dependency-isolation, error-message-quality, integration-test] | |
| if: always() | |
| steps: | |
| - name: Display summary | |
| run: | | |
| { | |
| echo "## Package Testing Strategy Results" | |
| echo "" | |
| echo "### Test Results:" | |
| echo "- Package Variants: ${{ needs.package-variants.result }}" | |
| echo "- Import Guard Validation: ${{ needs.import-guard-validation.result }}" | |
| echo "- Dependency Isolation: ${{ needs.dependency-isolation.result }}" | |
| echo "- Error Message Quality: ${{ needs.error-message-quality.result }}" | |
| echo "- Integration Test: ${{ needs.integration-test.result }}" | |
| echo "" | |
| if [[ "${{ needs.package-variants.result }}" == "success" && | |
| "${{ needs.import-guard-validation.result }}" == "success" && | |
| "${{ needs.dependency-isolation.result }}" == "success" && | |
| "${{ needs.error-message-quality.result }}" == "success" && | |
| "${{ needs.integration-test.result }}" == "success" ]]; then | |
| echo "PASS: All package testing strategy tests passed!" | |
| else | |
| echo "FAIL: Some package testing strategy tests failed!" | |
| exit 1 | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" |