Skip to content

feat(mcp): #30 add every_tool and does_not_accept for catalog-wide to… #81

feat(mcp): #30 add every_tool and does_not_accept for catalog-wide to…

feat(mcp): #30 add every_tool and does_not_accept for catalog-wide to… #81

Workflow file for this run

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."