ci: run pydoclint in isolated uvx env (deterministic docstring-parser) #6
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-nlp 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 | |
| env: | |
| # fasttext-wheel 0.9.2 ships no cp313 wheel, so it builds from sdist; its | |
| # src/args.cc uses uint64_t without #include <cstdint>, which fails on the | |
| # runner's GCC (libstdc++ no longer pulls it in transitively). Force-include | |
| # the header for every C++ translation unit so the sdist compiles. | |
| CXXFLAGS: "-include cstdint" | |
| 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 --all-extras | |
| - name: Download spaCy model | |
| run: uv run python -m spacy download en_core_web_sm | |
| - name: Download fastText language-ID model | |
| run: | | |
| mkdir -p ~/.cache/vgi-nlp | |
| curl -L -o ~/.cache/vgi-nlp/lid.176.ftz \ | |
| https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.ftz | |
| - name: Run tests | |
| run: uv run pytest -q | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| # Pin Python 3.13: spacy 3.8 publishes no cp314 wheel, so the default | |
| # newest interpreter (3.14) would fail to resolve the dependency tree. | |
| - name: Set up Python 3.13 | |
| run: uv python install 3.13 | |
| - name: Install dependencies | |
| run: uv sync --all-extras --python 3.13 | |
| - name: Check formatting | |
| run: uv run --python 3.13 ruff format --check . | |
| - name: Check linting | |
| run: uv run --python 3.13 ruff check . | |
| - name: Type check (mypy) | |
| run: uv run --python 3.13 mypy vgi_nlp nlp_worker.py | |
| # Run pydoclint in an isolated env (uvx): the dev venv also contains | |
| # vgi-rpc's `docstring-parser`, which collides with pydoclint's required | |
| # `docstring-parser-fork` in the shared `docstring_parser` import namespace. | |
| - name: Docstring lint (pydoclint) | |
| run: uvx pydoclint --config pyproject.toml vgi_nlp nlp_worker.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 | |
| - name: Download spaCy model | |
| run: uv run python -m spacy download en_core_web_sm | |
| - name: Download fastText language-ID model | |
| run: | | |
| mkdir -p ~/.cache/vgi-nlp | |
| curl -L -o ~/.cache/vgi-nlp/lid.176.ftz \ | |
| https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.ftz | |
| - 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 | |
| # is a repo-root PEP 723 script (no console-script); `uv run` reads its | |
| # inline deps and resolves them from PyPI, so an absolute script path | |
| # spawns correctly regardless of cwd. | |
| UNITTEST="$PWD/$(find hb -name 'haybarn-unittest' -type f | head -1)" | |
| chmod +x "$UNITTEST" | |
| echo "HAYBARN_UNITTEST=$UNITTEST" >> "$GITHUB_ENV" | |
| echo "VGI_NLP_WORKER=uv run --python 3.13 $PWD/nlp_worker.py" >> "$GITHUB_ENV" | |
| - name: Run extension integration suite | |
| run: ci/run-integration.sh |