chore: give the workspace root the packages' licence and author metad… #359
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: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| jobs: | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| - uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4 | |
| with: | |
| python-version: "3.11" | |
| # Plain `uv sync`, deliberately, on two counts. | |
| # | |
| # Resolving fresh is wanted on the pull requests where it actually | |
| # happens, which is not all of them. `uv sync` follows the committed lock | |
| # while that lock satisfies pyproject.toml, so an ordinary pull request | |
| # installs the locked versions. When a pull request moves dependency | |
| # metadata without regenerating the lock, uv resolves the new set and | |
| # these jobs exercise it. `--locked` would instead refuse to run and | |
| # report that the lock needs updating, which says nothing about whether | |
| # the new version works. | |
| # | |
| # The two flags tried here also break the release, and for one shared | |
| # reason: the release bumps the version in pyproject.toml and leaves | |
| # uv.lock naming the old one, so uv has to re-resolve. | |
| # | |
| # --locked fails on exactly that mismatch, reporting that the | |
| # lockfile needs to be updated. | |
| # --no-build fails because re-resolving means building this | |
| # workspace's own three packages, which are source rather | |
| # than wheels: "Building source distributions for | |
| # coordinode is disabled". | |
| # | |
| # Verified on the release branch with a cold cache: both fail there, and | |
| # both pass on that same branch once uv.lock carries the new version. So | |
| # restoring either one means first making the release regenerate the | |
| # lock, and even then it gives up the fresh resolution described above. | |
| - run: uv sync | |
| - run: uv run ruff check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/ | |
| - run: uv run ruff format --check coordinode/ langchain-coordinode/ llama-index-coordinode/ tests/ | |
| test: | |
| name: Test (Python ${{ matrix.python-version }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13", "3.14"] | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| submodules: recursive | |
| - uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install dependencies | |
| run: uv sync --all-packages | |
| - name: Generate proto stubs | |
| run: uv run make proto | |
| - name: Unit tests | |
| run: uv run pytest tests/unit/ -v | |
| build-embedded: | |
| name: Build embedded (CI check) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| submodules: recursive | |
| - name: Build (maturin / Linux x86_64) | |
| uses: PyO3/maturin-action@32307a466a178317e8c2ae343b38e73896a047be # v1.47.0 | |
| with: | |
| command: build | |
| args: >- | |
| --manifest-path coordinode-embedded/Cargo.toml | |
| --out dist | |
| manylinux: manylinux_2_28 | |
| before-script-linux: | | |
| dnf install -y protobuf-compiler | |
| - uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4 | |
| with: | |
| python-version: "3.12" | |
| - name: Install wheel + run embedded tests | |
| # The main `test` job skips coordinode_embedded with importorskip | |
| # because that runner doesn't build the wheel. This job has the | |
| # wheel, so install it and run the embedded tests here, then assert | |
| # nothing was skipped (a skip with the wheel installed means a | |
| # broken manylinux glibc / missing numpy / etc., not the expected | |
| # "no wheel" condition). | |
| # maturin-action runs inside a manylinux container; only paths | |
| # under $GITHUB_WORKSPACE are bind-mounted back to the host, so | |
| # the wheel goes to ./dist/ (workspace-relative), not /tmp/. | |
| run: | | |
| set -euo pipefail | |
| WHL=$(ls dist/coordinode_embedded-*.whl | head -1) | |
| test -n "$WHL" | |
| uv venv --python 3.12 /tmp/test-venv | |
| # Pinned to the versions uv.lock already resolves for the workspace, | |
| # so this throwaway venv tests against the same stack as the other | |
| # jobs instead of whatever is newest on PyPI that morning. | |
| uv pip install --python /tmp/test-venv/bin/python "$WHL" \ | |
| numpy==2.4.6 pytest==9.1.1 pytest-timeout==2.4.0 | |
| # Every test file that needs the extension belongs here: the main | |
| # `test` job skips them all for want of a wheel, so a file left out | |
| # of this list runs in no job at all. | |
| OUTPUT=$(/tmp/test-venv/bin/python -m pytest \ | |
| tests/unit/test_hnsw.py tests/unit/test_embedded_values.py \ | |
| -v --strict-markers -ra 2>&1) | |
| echo "$OUTPUT" | |
| # `-ra` prints a "SKIPPED [N]" short summary header when anything was | |
| # skipped; importorskip-based skip also surfaces this way. Use the | |
| # full output instead of the exit code because pytest treats skips | |
| # as success. | |
| if echo "$OUTPUT" | grep -qE '^SKIPPED|=+ .* skipped'; then | |
| echo "::error::Tests were skipped in build-embedded; the wheel is installed so this is a real failure (broken glibc / missing numpy / etc.)" | |
| exit 1 | |
| fi | |
| if ! echo "$OUTPUT" | grep -qE '=+ [0-9]+ passed'; then | |
| echo "::error::No tests passed; the module was likely not collected" | |
| exit 1 | |
| fi | |
| test-integration: | |
| name: Integration tests | |
| runs-on: ubuntu-latest | |
| services: | |
| coordinode: | |
| # Pinned by digest, not by tag: the proto submodule pins a server | |
| # version, and a tag can be re-pushed, so `:0.5.7` alone does not name | |
| # one fixed server. The digest below is 0.5.7; bump both together with | |
| # the submodule. | |
| image: ghcr.io/structured-world/coordinode@sha256:75a6242beb4cea8ab6726c842898fafc03ca9f59c6f7e36e462934a4ca64874c | |
| ports: | |
| - 7080:7080 | |
| - 7084:7084 | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| submodules: recursive | |
| - uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4 | |
| with: | |
| python-version: "3.11" | |
| - name: Wait for coordinode | |
| run: | | |
| echo "Waiting for coordinode to be ready (HTTP :7084 + gRPC :7080)..." | |
| for i in $(seq 1 30); do | |
| if curl -sf http://localhost:7084/health >/dev/null 2>&1 && \ | |
| (echo > /dev/tcp/localhost/7080) 2>/dev/null; then | |
| echo "coordinode is ready (attempt $i)" | |
| exit 0 | |
| fi | |
| echo "Attempt $i/30, not ready yet, sleeping 5s..." | |
| sleep 5 | |
| done | |
| echo "Error: coordinode did not become healthy after 150s" >&2 | |
| exit 1 | |
| - name: Install + generate proto | |
| run: | | |
| uv sync --all-packages | |
| uv run make proto | |
| - name: Integration tests | |
| env: | |
| COORDINODE_ADDR: "localhost:7080" | |
| run: uv run pytest tests/integration/ -v --timeout=30 |