ci(deps): bump actions/upload-artifact from 4 to 5 #36
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: Tests | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install dependencies | |
| run: | | |
| uv sync --extra dev | |
| - name: Run flake8 | |
| run: | | |
| uv run flake8 ioc/ tests/ | |
| - name: Run mypy (optional) | |
| run: | | |
| uv run mypy ioc/ || true | |
| continue-on-error: true | |
| test-core: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install core dependencies | |
| run: | | |
| uv sync | |
| - name: Run core tests (excluding extras) | |
| run: | | |
| # Run only core tests, excluding extra package tests | |
| uv run python -m unittest discover -s tests -p "test_*.py" -v 2>&1 | grep -v "extra\." | tee test_output.txt | |
| # Check results | |
| if grep -q "FAILED" test_output.txt; then | |
| echo "Core tests failed" | |
| exit 1 | |
| fi | |
| test-with-specific-extras: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.9', '3.11'] | |
| include: | |
| - extras: 'flask' | |
| test_module: 'tests.ioc_test.extra.flask' | |
| - extras: 'jinja2' | |
| test_module: 'tests.ioc_test.extra.jinja' | |
| - extras: 'redis' | |
| test_module: 'tests.ioc_test.extra.redis' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install dependencies with ${{ matrix.extras }} | |
| run: | | |
| uv sync --extra ${{ matrix.extras }} | |
| - name: Check if extras tests exist and dependencies are available | |
| id: check_tests | |
| run: | | |
| # Check if test module exists and can be imported | |
| python -c " | |
| import os | |
| import sys | |
| import importlib.util | |
| test_path = '${{ matrix.test_module }}'.replace('.', '/') | |
| test_exists = os.path.exists(f'{test_path}') | |
| # Check if the extra package is available | |
| extras = '${{ matrix.extras }}'.split(',') | |
| missing = [] | |
| for extra in extras: | |
| try: | |
| if extra == 'flask': | |
| import flask | |
| elif extra == 'jinja2': | |
| import jinja2 | |
| elif extra == 'redis': | |
| import redis | |
| except ImportError: | |
| missing.append(extra) | |
| if test_exists and not missing: | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('should_run=true\\n') | |
| else: | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write('should_run=false\\n') | |
| if missing: | |
| print(f'Missing dependencies: {missing}') | |
| if not test_exists: | |
| print(f'Test module {test_path} does not exist') | |
| " | |
| - name: Run tests for ${{ matrix.extras }} | |
| if: steps.check_tests.outputs.should_run == 'true' | |
| run: | | |
| uv run python -m unittest discover -s $(echo "${{ matrix.test_module }}" | tr '.' '/') -p "test_*.py" -v | |
| continue-on-error: true | |
| test-all-extras: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.9', '3.13'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install all dependencies | |
| run: | | |
| uv sync --extra flask --extra jinja2 --extra redis --extra dev | |
| - name: Create smart test runner | |
| run: | | |
| cat > smart_test_runner.py << 'EOF' | |
| import unittest | |
| import sys | |
| import importlib | |
| # Map test modules to their requirements | |
| OPTIONAL_DEPS = { | |
| 'flask': ['flask'], | |
| 'jinja2': ['jinja2'], | |
| 'redis': ['redis'], | |
| } | |
| def is_module_available(module_name): | |
| try: | |
| importlib.import_module(module_name) | |
| return True | |
| except ImportError: | |
| return False | |
| def main(): | |
| # Check which optional dependencies are available | |
| available_extras = [] | |
| for extra, deps in OPTIONAL_DEPS.items(): | |
| if all(is_module_available(dep) for dep in deps): | |
| available_extras.append(extra) | |
| print(f"Available extras: {', '.join(available_extras) if available_extras else 'None'}") | |
| # Run all tests | |
| loader = unittest.TestLoader() | |
| suite = loader.discover('tests', pattern='test_*.py') | |
| runner = unittest.TextTestRunner(verbosity=2, stream=sys.stdout, buffer=True) | |
| result = runner.run(suite) | |
| # Analyze failures | |
| if not result.wasSuccessful(): | |
| import_errors = 0 | |
| other_errors = 0 | |
| for error in result.errors + result.failures: | |
| error_text = str(error[1]) | |
| if 'ModuleNotFoundError' in error_text or 'ImportError' in error_text: | |
| import_errors += 1 | |
| else: | |
| other_errors += 1 | |
| print(f"\nTest Summary:") | |
| print(f" Import errors (expected): {import_errors}") | |
| print(f" Other errors: {other_errors}") | |
| # Only fail if there are non-import errors | |
| if other_errors > 0: | |
| sys.exit(1) | |
| else: | |
| print("\nAll failures were due to missing optional dependencies - this is expected") | |
| sys.exit(0) | |
| else: | |
| sys.exit(0) | |
| if __name__ == '__main__': | |
| main() | |
| EOF | |
| - name: Run all tests with smart error handling | |
| run: | | |
| uv run python smart_test_runner.py | |
| docs: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install dependencies | |
| run: | | |
| uv sync | |
| uv pip install sphinx | |
| - name: Build documentation | |
| run: | | |
| uv run sphinx-build -nW -b html -d docs/_build/doctrees docs docs/_build/html | |
| - name: Upload documentation artifacts | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: documentation | |
| path: docs/_build/html/ | |
| if: always() | |
| package: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Install build dependencies | |
| run: | | |
| uv sync | |
| uv pip install build twine | |
| - name: Build package | |
| run: | | |
| uv run python -m build | |
| - name: Check package | |
| run: | | |
| uv run twine check dist/* |