feat(mcp): #30 add every_tool and does_not_accept for catalog-wide to… #81
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: Test | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| branches: [master] | |
| types: [opened, synchronize, reopened] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: uv sync --all-extras | |
| - name: Check formatting | |
| run: uv run ruff format --check src/ tests/ | |
| - name: Check linting | |
| run: uv run ruff check src/ tests/ | |
| typecheck: | |
| name: Type Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: uv sync --all-extras | |
| - name: Run mypy | |
| run: uv run mypy src/pyssertive | |
| test-core: | |
| name: Test core (py${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install core dependencies (no Django) | |
| run: uv sync --no-default-groups --group test-core | |
| - name: Verify no adapter framework is installed | |
| # The core job must run against a venv with zero adapter frameworks. | |
| # Append new packages to `forbidden` as adapters are added (flask, ...). | |
| # --no-sync prevents uv from auto-resyncing to the project's default | |
| # groups (which would pull adapter test deps and their frameworks). | |
| run: | | |
| forbidden=(django httpx) | |
| for pkg in "${forbidden[@]}"; do | |
| if uv run --no-sync python -c "import $pkg" 2>/dev/null; then | |
| echo "ERROR: $pkg should not be installed for the core job" | |
| exit 1 | |
| fi | |
| done | |
| echo "OK: no adapter framework installed — core runs against pyssertive[core] only" | |
| - name: Run core tests | |
| env: | |
| COVERAGE_FILE: .coverage.core-py${{ matrix.python-version }} | |
| run: | | |
| uv run --no-sync pytest tests/formats/ tests/arch/ tests/protocols/ \ | |
| --cov-fail-under=0 --cov-report= | |
| - name: Upload coverage data | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-core-py${{ matrix.python-version }} | |
| path: .coverage.core-py${{ matrix.python-version }} | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| test-django: | |
| name: Test Django adapter (py${{ matrix.python-version }}, dj${{ matrix.django-version }}) | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Django 4.2 (Python 3.10–3.12) | |
| - python-version: "3.10" | |
| django-version: "4.2" | |
| - python-version: "3.11" | |
| django-version: "4.2" | |
| - python-version: "3.12" | |
| django-version: "4.2" | |
| # Django 5.2 (Python 3.10–3.14) | |
| - python-version: "3.10" | |
| django-version: "5.2" | |
| - python-version: "3.11" | |
| django-version: "5.2" | |
| - python-version: "3.12" | |
| django-version: "5.2" | |
| - python-version: "3.13" | |
| django-version: "5.2" | |
| - python-version: "3.14" | |
| django-version: "5.2" | |
| # Django 6.0 (Python 3.12–3.14) | |
| - python-version: "3.12" | |
| django-version: "6.0" | |
| - python-version: "3.13" | |
| django-version: "6.0" | |
| - python-version: "3.14" | |
| django-version: "6.0" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install Django adapter dependencies | |
| run: | | |
| uv sync --extra django --group test-django | |
| uv pip install "Django~=${{ matrix.django-version }}.0" | |
| - name: Run Django adapter tests | |
| env: | |
| COVERAGE_FILE: .coverage.django-py${{ matrix.python-version }}-dj${{ matrix.django-version }} | |
| run: | | |
| uv run pytest tests/adapters/django/ \ | |
| --cov-fail-under=0 --cov-report= | |
| - name: Upload coverage data | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-django-py${{ matrix.python-version }}-dj${{ matrix.django-version }} | |
| path: .coverage.django-py${{ matrix.python-version }}-dj${{ matrix.django-version }} | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| test-httpx: | |
| name: Test httpx adapter (py${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install httpx adapter dependencies | |
| run: uv sync --no-default-groups --extra httpx --group test-httpx | |
| - name: Verify Django is not installed | |
| run: | | |
| if uv run --no-sync python -c "import django" 2>/dev/null; then | |
| echo "ERROR: django should not be installed for the httpx job" | |
| exit 1 | |
| fi | |
| echo "OK: only httpx adapter framework installed" | |
| - name: Run httpx adapter tests | |
| env: | |
| COVERAGE_FILE: .coverage.httpx-py${{ matrix.python-version }} | |
| run: | | |
| uv run --no-sync pytest tests/adapters/httpx/ \ | |
| --cov-fail-under=0 --cov-report= | |
| - name: Upload coverage data | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-httpx-py${{ matrix.python-version }} | |
| path: .coverage.httpx-py${{ matrix.python-version }} | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| test-cross-adapter: | |
| name: Test cross-adapter (py${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| needs: [lint] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install both adapters | |
| run: uv sync --all-extras | |
| - name: Run cross-adapter tests | |
| env: | |
| COVERAGE_FILE: .coverage.cross-py${{ matrix.python-version }} | |
| run: | | |
| uv run --no-sync pytest tests/adapters/test_*.py \ | |
| --cov-fail-under=0 --cov-report= | |
| - name: Upload coverage data | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-cross-py${{ matrix.python-version }} | |
| path: .coverage.cross-py${{ matrix.python-version }} | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| coverage: | |
| name: Coverage (merge + 100% gate) | |
| runs-on: ubuntu-latest | |
| needs: [test-core, test-django, test-httpx, test-cross-adapter] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: uv sync --all-extras | |
| - name: Download all coverage data | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: coverage-* | |
| merge-multiple: true | |
| - name: Combine coverage and enforce 100% gate | |
| run: | | |
| uv run coverage combine | |
| uv run coverage report --fail-under=100 | |
| uv run coverage xml -o coverage.xml | |
| - name: Upload merged coverage report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: coverage.xml | |
| sonarcloud: | |
| name: SonarCloud Analysis | |
| runs-on: ubuntu-latest | |
| needs: [coverage] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Download merged coverage | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: coverage-report | |
| - name: SonarCloud Scan | |
| uses: SonarSource/sonarqube-scan-action@v8 | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| ci-success: | |
| name: CI Success | |
| runs-on: ubuntu-latest | |
| needs: [lint, typecheck, test-core, test-django, test-httpx, test-cross-adapter, coverage, sonarcloud] | |
| if: always() | |
| steps: | |
| - name: Check all jobs | |
| run: | | |
| echo "===== Job Results =====" | |
| echo "Lint: ${{ needs.lint.result }}" | |
| echo "Typecheck: ${{ needs.typecheck.result }}" | |
| echo "Test (core): ${{ needs.test-core.result }}" | |
| echo "Test (django): ${{ needs.test-django.result }}" | |
| echo "Test (httpx): ${{ needs.test-httpx.result }}" | |
| echo "Test (cross-adapter): ${{ needs.test-cross-adapter.result }}" | |
| echo "Coverage: ${{ needs.coverage.result }}" | |
| echo "SonarCloud: ${{ needs.sonarcloud.result }}" | |
| echo "=======================" | |
| fail=0 | |
| if [ "${{ needs.lint.result }}" != "success" ]; then | |
| echo "❌ Lint failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.typecheck.result }}" != "success" ]; then | |
| echo "❌ Typecheck failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.test-core.result }}" != "success" ]; then | |
| echo "❌ Tests (core) failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.test-django.result }}" != "success" ]; then | |
| echo "❌ Tests (Django) failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.test-httpx.result }}" != "success" ]; then | |
| echo "❌ Tests (httpx) failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.test-cross-adapter.result }}" != "success" ]; then | |
| echo "❌ Tests (cross-adapter) failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.coverage.result }}" != "success" ]; then | |
| echo "❌ Coverage gate failed" | |
| fail=1 | |
| fi | |
| if [ "${{ needs.sonarcloud.result }}" != "success" ]; then | |
| echo "❌ SonarCloud failed" | |
| fail=1 | |
| fi | |
| if [ "$fail" -ne 0 ]; then | |
| echo "🛑 Release blocked — fix the failures above." | |
| exit 1 | |
| fi | |
| echo "✅ All required checks passed — release-ready." |