Spaces:
Sleeping
Sleeping
| name: CI Pipeline | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| PYTHON_VERSION: "3.11" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # =========================================================================== | |
| # Linting - Fast feedback on code style | |
| # =========================================================================== | |
| lint: | |
| name: Lint & Format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run ruff linter | |
| run: uv run ruff check . --output-format=github | |
| - name: Check ruff formatting | |
| run: uv run ruff format --check . | |
| # =========================================================================== | |
| # Type Checking - Static analysis with mypy | |
| # =========================================================================== | |
| typecheck: | |
| name: Type Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run mypy | |
| run: uv run mypy src/ --ignore-missing-imports | |
| # =========================================================================== | |
| # Unit Tests - Fast, isolated tests | |
| # =========================================================================== | |
| test-unit: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run unit tests | |
| run: | | |
| uv run pytest tests/unit/ -v \ | |
| --cov=src \ | |
| --cov-report=xml \ | |
| --cov-report=term-missing \ | |
| --tb=short | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| files: coverage.xml | |
| fail_ci_if_error: false | |
| verbose: true | |
| # =========================================================================== | |
| # Integration Tests - Tests with mocked external services | |
| # =========================================================================== | |
| test-integration: | |
| name: Integration Tests | |
| runs-on: ubuntu-latest | |
| needs: [lint, typecheck] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run integration tests | |
| run: | | |
| uv run pytest tests/integration/ -v \ | |
| --tb=short \ | |
| -m "not slow" | |
| # =========================================================================== | |
| # E2E Tests - Full browser-based tests with Playwright | |
| # =========================================================================== | |
| test-e2e: | |
| name: E2E Tests | |
| runs-on: ubuntu-latest | |
| needs: [test-integration] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Install Playwright browsers | |
| run: uv run playwright install chromium --with-deps | |
| - name: Start Gradio app in background | |
| run: | | |
| uv run python app.py & | |
| sleep 15 # Wait for server to start | |
| env: | |
| GRADIO_SERVER_PORT: 7860 | |
| - name: Run E2E tests | |
| run: | | |
| uv run pytest tests/e2e/ -v \ | |
| --tb=short \ | |
| -m "not slow" | |
| # =========================================================================== | |
| # Security Scanning | |
| # =========================================================================== | |
| security: | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run pip-audit (vulnerability scan) | |
| run: uv run pip-audit --strict | |
| continue-on-error: true | |
| - name: Run bandit (security linter) | |
| run: uv run bandit -r src/ -c pyproject.toml | |
| # =========================================================================== | |
| # Docker Build Test | |
| # =========================================================================== | |
| docker: | |
| name: Docker Build | |
| runs-on: ubuntu-latest | |
| needs: [test-unit] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Build Docker image | |
| run: | | |
| docker build \ | |
| --tag medium-mcp:test \ | |
| --cache-from type=gha \ | |
| --cache-to type=gha,mode=max \ | |
| . | |
| - name: Test Docker image | |
| run: | | |
| docker run --rm medium-mcp:test \ | |
| python -c "from src.service import ScraperService; print('Import OK')" | |
| # =========================================================================== | |
| # All Tests Passed Gate | |
| # =========================================================================== | |
| all-tests-pass: | |
| name: All Tests Pass | |
| runs-on: ubuntu-latest | |
| needs: [lint, typecheck, test-unit, test-integration, security] | |
| if: always() | |
| steps: | |
| - name: Check all jobs passed | |
| run: | | |
| if [ "${{ needs.lint.result }}" != "success" ] || \ | |
| [ "${{ needs.typecheck.result }}" != "success" ] || \ | |
| [ "${{ needs.test-unit.result }}" != "success" ] || \ | |
| [ "${{ needs.test-integration.result }}" != "success" ]; then | |
| echo "One or more required jobs failed" | |
| exit 1 | |
| fi | |
| echo "All required jobs passed!" | |