Issue #110: Pin black - unbounded ">=" made CI fail with no code change #13
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: Fast CI | ||
| on: | ||
| pull_request: | ||
| branches: [main, master, develop] | ||
| paths: | ||
| - 'clustrix/**' | ||
| - 'tests/**' | ||
| - 'setup.py' | ||
| - 'pyproject.toml' | ||
| - 'requirements*.txt' | ||
| push: | ||
| branches: [develop] # Only run on develop pushes to avoid duplication with main Tests workflow | ||
| paths: | ||
| - 'clustrix/**' | ||
| - 'tests/**' | ||
| - 'setup.py' | ||
| - 'pyproject.toml' | ||
| - 'requirements*.txt' | ||
| jobs: | ||
| quick-checks: | ||
| name: Quick Checks | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v4 | ||
| with: | ||
| python-version: '3.10' | ||
| - name: Cache dependencies | ||
| uses: actions/cache@v3 | ||
| with: | ||
| path: ~/.cache/pip | ||
| key: ${{ runner.os }}-pip-quick-${{ hashFiles('**/requirements.txt') }} | ||
| - name: Install dependencies | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install black flake8 mypy pytest | ||
| pip install -e . | ||
| - name: Format check with Black | ||
| run: black --check clustrix/ tests/ | ||
| - name: Lint with Flake8 | ||
| run: flake8 clustrix/ --count --select=E9,F63,F7,F82 --show-source --statistics | ||
| - name: Type check with MyPy | ||
| run: mypy clustrix/ --ignore-missing-imports | ||
| continue-on-error: true # Don't fail on type errors yet | ||
| - name: Run quick unit tests | ||
| run: | | ||
| pytest tests/unit/ -v \ | ||
| -m "not real_world and not slow" \ | ||
| --timeout=60 \ | ||
| -x \ | ||
| --tb=short \ | ||
| --maxfail=3 | ||
| timeout-minutes: 5 | ||
| local-integration: | ||
| name: Local Integration Test | ||
| runs-on: ubuntu-latest | ||
| needs: quick-checks | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v4 | ||
| with: | ||
| python-version: '3.10' | ||
| - name: Install dependencies | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install -e ".[dev]" | ||
| - name: Run local executor test | ||
| run: | | ||
| python -c " | ||
| from clustrix import cluster, configure | ||
| # Configure for local execution | ||
| configure(cluster_type='local') | ||
| @cluster(cores=2, memory='2GB') | ||
| def test_function(x, y): | ||
| import numpy as np | ||
| return np.array([x, y]).sum() | ||
| result = test_function(10, 20) | ||
| assert result == 30, f'Expected 30, got {result}' | ||
| print('✅ Local execution test passed') | ||
| " | ||
| - name: Run serialization test | ||
| run: | | ||
| python -c " | ||
| from clustrix import cluster | ||
| import pickle | ||
| import cloudpickle | ||
| @cluster(cores=1) | ||
| def test_serialization(): | ||
| return {'status': 'success', 'value': 42} | ||
| # Test function can be serialized | ||
| serialized = cloudpickle.dumps(test_serialization) | ||
| assert len(serialized) > 0 | ||
| print('✅ Serialization test passed') | ||
| # Test execution | ||
| result = test_serialization() | ||
| assert result['status'] == 'success' | ||
| assert result['value'] == 42 | ||
| print('✅ Execution test passed') | ||
| " | ||
| docker-test: | ||
| name: Docker Container Test | ||
| runs-on: ubuntu-latest | ||
| needs: quick-checks | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Build test container | ||
| run: | | ||
| cat << 'EOF' > Dockerfile.test | ||
| FROM python:3.10-slim | ||
| WORKDIR /app | ||
| COPY . . | ||
| RUN pip install -e . | ||
| RUN pip install pytest numpy pandas | ||
| CMD ["python", "-c", "from clustrix import cluster; print('✅ Import successful')"] | ||
| EOF | ||
| docker build -f Dockerfile.test -t clustrix-test . | ||
| - name: Run container test | ||
| run: | | ||
| docker run --rm clustrix-test | ||
| # Test with actual computation | ||
| docker run --rm clustrix-test python -c " | ||
| from clustrix import cluster, configure | ||
| import numpy as np | ||
| configure(cluster_type='local') | ||
| @cluster(cores=1, memory='1GB') | ||
| def compute(): | ||
| data = np.random.randn(1000, 1000) | ||
| return {'mean': float(np.mean(data)), 'std': float(np.std(data))} | ||
| result = compute() | ||
| print(f'Result: {result}') | ||
| assert abs(result['mean']) < 0.1 | ||
| assert abs(result['std'] - 1.0) < 0.1 | ||
| print('✅ Container test passed') | ||
| " | ||
| security-scan: | ||
| name: Security Scan | ||
| runs-on: ubuntu-latest | ||
| needs: quick-checks | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Run Trivy security scan | ||
| uses: aquasecurity/trivy-action@master | ||
| with: | ||
| scan-type: 'fs' | ||
| scan-ref: '.' | ||
| format: 'sarif' | ||
| output: 'trivy-results.sarif' | ||
| - name: Upload Trivy results | ||
| uses: github/codeql-action/upload-sarif@v2 | ||
| with: | ||
| sarif_file: 'trivy-results.sarif' | ||
| - name: Check for secrets | ||
| run: | | ||
| # Check for potential secrets/credentials | ||
| ! grep -r "password\|secret\|key\|token" clustrix/ --include="*.py" | grep -v "def\|class\|#\|test" | ||
| status-check: | ||
| name: CI Status | ||
| runs-on: ubuntu-latest | ||
| needs: [quick-checks, local-integration, docker-test, security-scan] | ||
| if: always() | ||
| steps: | ||
| - name: Check status | ||
| run: | | ||
| if [ "${{ needs.quick-checks.result }}" != "success" ] || \ | ||
| [ "${{ needs.local-integration.result }}" != "success" ] || \ | ||
| [ "${{ needs.docker-test.result }}" != "success" ]; then | ||
| echo "❌ CI checks failed" | ||
| exit 1 | ||
| else | ||
| echo "✅ All CI checks passed" | ||
| fi | ||