ci: run pydoclint isolated via uvx to avoid docstring-parser namespac… #4
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
| # Copyright 2026 Query Farm LLC - https://query.farm | |
| # | |
| # Unit tests (pytest), lint, and the sqllogictest extension suite | |
| # (test/sql/*.test) run against the vgi-rerank worker through the real signed | |
| # `vgi` DuckDB community extension via a prebuilt standalone `haybarn-unittest`. | |
| # See ci/README.md for the design. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| paths-ignore: ['README.md'] | |
| pull_request: | |
| branches: [main] | |
| paths-ignore: ['README.md'] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| test: | |
| name: Python ${{ matrix.python-version }} on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| python-version: ["3.13"] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| run: uv python install ${{ matrix.python-version }} | |
| - name: Install dependencies | |
| run: uv sync --frozen --all-extras | |
| # Pre-warm the fastembed cache so the model download happens once, here, | |
| # rather than inline during the first test (and so the model-gated tests run). | |
| - name: Warm the reranker model cache | |
| run: uv run --no-sync python -c "from vgi_rerank import models; models.warm_up()" | |
| - name: Run tests | |
| run: uv run --no-sync pytest | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| - name: Install dependencies | |
| run: uv sync --frozen --all-extras | |
| - name: Check formatting | |
| run: uv run --no-sync ruff format --check . | |
| - name: Check linting | |
| run: uv run --no-sync ruff check . | |
| - name: Type check (mypy) | |
| run: uv run --no-sync mypy vgi_rerank rerank_worker.py serve.py | |
| - name: Docstring lint (pydoclint) | |
| # Run isolated: pydoclint needs `docstring-parser-fork`, which shares the | |
| # `docstring_parser` import namespace with the plain `docstring-parser` | |
| # that vgi-rpc pulls in transitively. Co-installed, whichever lands last | |
| # wins — a non-deterministic ImportError. uvx gives pydoclint its own env. | |
| run: uvx --from "pydoclint>=0.5" pydoclint vgi_rerank rerank_worker.py serve.py | |
| # Resolve the latest published haybarn release once, so the whole matrix tests | |
| # the same version (and we never hardcode/pin it). | |
| resolve-haybarn: | |
| name: Resolve haybarn release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release: ${{ steps.r.outputs.release }} | |
| steps: | |
| - id: r | |
| run: | | |
| REL=$(gh release view --repo Query-farm-haybarn/haybarn --json tagName --jq .tagName) | |
| echo "release=$REL" >> "$GITHUB_OUTPUT" | |
| echo "Latest haybarn release: $REL" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| integration: | |
| name: End-to-end SQL on ${{ matrix.os }} | |
| needs: resolve-haybarn | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: ubuntu-latest, asset: haybarn_unittest-linux-amd64.zip } | |
| - { os: macos-latest, asset: haybarn_unittest-osx-arm64.zip } | |
| runs-on: ${{ matrix.os }} | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| - name: Set up Python 3.13 | |
| run: uv python install 3.13 | |
| - name: Install the worker (from the lockfile) | |
| run: uv sync --frozen --python 3.13 | |
| # Pre-warm the fastembed/ONNX model cache so the first ATTACH+score isn't | |
| # paying the ~80 MB download inline. | |
| - name: Warm the reranker model cache | |
| run: uv run --no-sync python -c "from vgi_rerank import models; models.warm_up()" | |
| - name: Download haybarn-unittest | |
| run: | | |
| gh release download "$HAYBARN_RELEASE" \ | |
| --repo Query-farm-haybarn/haybarn \ | |
| --pattern '${{ matrix.asset }}' \ | |
| --output haybarn-unittest.zip --clobber | |
| mkdir -p hb && unzip -o -q haybarn-unittest.zip -d hb | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| HAYBARN_RELEASE: ${{ needs.resolve-haybarn.outputs.release }} | |
| - name: Resolve runner + worker paths | |
| run: | | |
| # Absolute paths: run-integration.sh cd's into a staging dir before | |
| # invoking the runner, so relative paths would not resolve. The worker | |
| # runs from the synced .venv (deps resolved from PyPI via the lockfile); | |
| # plain `.venv/bin/python` ignores the PEP 723 header and reuses the | |
| # already-warmed model cache. | |
| UNITTEST="$PWD/$(find hb -name 'haybarn-unittest' -type f | head -1)" | |
| chmod +x "$UNITTEST" | |
| echo "HAYBARN_UNITTEST=$UNITTEST" >> "$GITHUB_ENV" | |
| echo "VGI_RERANK_WORKER=$PWD/.venv/bin/python $PWD/rerank_worker.py" >> "$GITHUB_ENV" | |
| - name: Run extension integration suite | |
| run: ci/run-integration.sh |