Skip to content

fix(release): prepare immutable 1.5.8 publication #387

fix(release): prepare immutable 1.5.8 publication

fix(release): prepare immutable 1.5.8 publication #387

Workflow file for this run

name: CI
on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]
env:
CARGO_HOME: ${{ github.workspace }}/../.cargo-home
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
RUST_STABLE_TOOLCHAIN: "1.94.1"
jobs:
# Rust crate: compile, test, lint (parallel with Python jobs)
rust-check:
name: Rust ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
components: clippy
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-v3-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: cargo check
working-directory: type-bridge-core
run: cargo check --all-targets
- name: cargo test
working-directory: type-bridge-core
run: cargo test --all-targets
- name: cargo clippy
working-directory: type-bridge-core
run: cargo clippy --all-targets -- -D warnings
# I6 single-feature offline legs: verify neither single-band feature combination rots.
# These are compile-only checks (no live server, no tests) — cargo check only.
band-feature-check:
name: Band feature check (${{ matrix.band }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- band: band7
features: band7,axum-transport
- band: band8
features: band8,axum-transport
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-band-v3-${{ matrix.band }}-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: cargo check (${{ matrix.band }})
working-directory: type-bridge-core
run: cargo check -p type-bridge-orm -p type-bridge-server --no-default-features --features ${{ matrix.features }}
# Rust code coverage (informational, does not block CI)
rust-coverage:
name: Rust Coverage
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@fd2f5e3d644b484055ebf4268f474c565f148f25 # v2
with:
tool: cargo-llvm-cov
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-nightly-v3-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: Generate LCOV report
run: ./scripts/coverage.sh branch --lcov
- name: Upload Rust coverage to Codecov
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: type-bridge-core/target/llvm-cov/lcov.branch.info
flags: rust
fail_ci_if_error: false
# Build maturin wheels for all platforms (parallel with other jobs)
build-wheels:
name: Build wheel (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
artifact: wheels-linux-x86_64
- target: aarch64-unknown-linux-gnu
runner: ubuntu-latest
artifact: wheels-linux-aarch64
- target: x86_64-apple-darwin
runner: macos-latest
artifact: wheels-macos-x86_64
- target: aarch64-apple-darwin
runner: macos-latest
artifact: wheels-macos-aarch64
- target: x86_64-pc-windows-msvc
runner: windows-latest
artifact: wheels-windows-x86_64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU (Linux aarch64 cross-compilation)
if: matrix.target == 'aarch64-unknown-linux-gnu'
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
with:
platforms: arm64
- name: Set up Python
if: runner.os != 'Linux'
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Build wheel
uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1
env:
# The manylinux aarch64 cross-compiler does not define the ARM ACLE
# macro __ARM_ARCH that ring's pregenerated assembly requires. The
# variable name is target-suffixed, so it only affects the aarch64
# Linux wheel even though it is declared on every matrix leg.
CFLAGS_aarch64_unknown_linux_gnu: ${{ matrix.target == 'aarch64-unknown-linux-gnu' && '-D__ARM_ARCH=8' || '' }}
with:
target: ${{ matrix.target }}
rust-toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
args: --release --out dist -i python3.13
manylinux: auto
working-directory: type-bridge-core
- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: type-bridge-core/dist/*.whl
# Node binding is a required CI gate: the #124 NAPI pillar was previously untested
# in CI, so its native + TypeScript surface and database-free gates run here to keep
# the #110 single-core / thin-bindings invariant from silently regressing.
node-check:
name: Node binding
runs-on: ubuntu-latest
defaults:
run:
working-directory: type-bridge-core/crates/node
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-node-v3-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: type-bridge-core/crates/node/package-lock.json
- name: Install Node dependencies
run: npm ci
- name: Build native module and TypeScript surface
run: npm run build
- name: Verify native module built
run: ls type_bridge_node.*.node
- name: Typecheck
run: npm run typecheck
- name: Unified Query contract typecheck
run: npm run typecheck:query-contract
- name: Unit tests
run: npm run test:unit
- name: DTS baseline parity
run: npm run test:dts
- name: Package smoke
run: npm run smoke:package
- name: Legacy packed-package compatibility
run: npm run smoke:legacy-package
# Exercise both legacy and typed Python APIs from the artifacts users receive.
# The native wheel comes from the existing Linux x86_64 build-wheels leg. The
# legacy runner installs the wheels; the typed runner only extracts the same
# prebuilt artifacts and uses an explicitly prepared interpreter/tool pair.
python-legacy-package-compat:
name: Python ${{ matrix.python-version }} installed/built-wheel compatibility
runs-on: ubuntu-latest
needs: build-wheels
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13.5", "3.14"]
env:
UV_PYTHON: ${{ matrix.python-version }}
UV_PYTHON_PREFERENCE: only-system
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Download Linux x86_64 core wheel
uses: actions/download-artifact@v4
with:
name: wheels-linux-x86_64
path: tmp/legacy-python-wheels/core
- name: Build root Python wheel
run: |
uv build --wheel --package type-bridge \
--out-dir tmp/legacy-python-wheels/root
- name: Prepare typed consumer interpreter and Pyright
run: |
uv venv --python python tmp/typed-python-tools
uv pip install --python tmp/typed-python-tools/bin/python \
'pydantic>=2.12.4' 'isodate==0.7.2' 'jinja2>=3.1.0' \
'typer>=0.15.0' 'pyright>=1.1.407'
- name: Run isolated installed-package compatibility
run: |
mapfile -t core_wheels < <(
find tmp/legacy-python-wheels/core -maxdepth 1 -type f \
-name 'type_bridge_core-*.whl' -print
)
mapfile -t root_wheels < <(
find tmp/legacy-python-wheels/root -maxdepth 1 -type f \
-name 'type_bridge-*.whl' -print
)
if [[ ${#core_wheels[@]} -ne 1 ]]; then
printf 'Expected exactly one Linux x86_64 core wheel, found %s\n' \
"${#core_wheels[@]}" >&2
exit 1
fi
if [[ ${#root_wheels[@]} -ne 1 ]]; then
printf 'Expected exactly one root Python wheel, found %s\n' \
"${#root_wheels[@]}" >&2
exit 1
fi
python scripts/ci/run_legacy_python_compat.py \
--artifact "${core_wheels[0]}" \
--artifact "${root_wheels[0]}"
python scripts/ci/run_typed_python_artifact.py \
--root-wheel "${root_wheels[0]}" \
--core-wheel "${core_wheels[0]}" \
--python "$PWD/tmp/typed-python-tools/bin/python" \
--pyright "$PWD/tmp/typed-python-tools/bin/pyright"
# Code quality: linting and formatting (parallel)
lint:
name: Python ${{ matrix.check }}
runs-on: ubuntu-latest
strategy:
matrix:
check: [ruff-lint, ruff-format]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Run ruff lint check
if: matrix.check == 'ruff-lint'
run: uv run ruff check .
- name: Run ruff format check
if: matrix.check == 'ruff-format'
run: uv run ruff format --check .
# Type checking with pyright (parallel matrix for faster execution)
typecheck:
name: Python Type Check (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
matrix:
target: [type_bridge, examples, tests]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Install pyright
run: uv pip install pyright
- name: Run pyright on ${{ matrix.target }}
run: uv run pyright ${{ matrix.target }}/
- name: Check intentional unified Query typing diagnostics
if: matrix.target == 'tests'
run: uv run python tests/contracts/typed_query/python/check_negative.py
# Unit tests (fast, no external dependencies, parallel execution)
test-unit:
name: Python Unit Tests (${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.12", "3.13.5", "3.14"]
env:
# The repo's .python-version pins 3.13 for local dev; without these,
# uv ignores the matrix interpreter and downloads a managed build
# whose missing shared libpython breaks the typedb native driver.
UV_PYTHON: ${{ matrix.python-version }}
UV_PYTHON_PREFERENCE: only-system
# PyO3 0.23 predates CPython 3.14, but this extension uses abi3-py312.
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: "1"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Install pytest-xdist for parallel execution
run: uv pip install pytest-xdist
- name: Run unit tests with coverage
run: |
uv run pytest tests/unit/ -v --tb=short -n auto \
--cov=type_bridge --cov-branch \
--cov-report=xml:coverage.xml \
--cov-report=term-missing
- name: Upload Python coverage to Codecov
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
flags: python
fail_ci_if_error: false
# Integration tests (require TypeDB server, parallel by test category)
test-integration:
name: Python Integration (${{ matrix.test-group }}, ${{ matrix.typedb-server }})
runs-on: ubuntu-latest
strategy:
matrix:
# Every ordinary integration directory is represented here. Parity and
# proxy retain their dedicated jobs because they require extra runtimes.
test-group:
[crud, queries, schema, expressions, migration, session, generator, validation]
# Fan across all four server lines: band-7 (3.8.3, 3.10.4), band-8
# (3.11.5), and the dual-band 3.12 line. The 3.12 leg prefers the
# embedded band-9 driver after safe discovery, with band-8 retained as
# the compatibility fallback. Keep in sync with compose default and
# version SSOT in crates/core.
typedb-server:
- "typedb/typedb:3.8.3"
- "typedb/typedb:3.10.4"
- "typedb/typedb:3.11.5"
- "typedb/typedb:3.12.0"
include:
# Band-7 legs pair the band-7 installed Python driver — a band-7 user
# has this driver installed, and the gate must not spuriously fire.
- typedb-server: "typedb/typedb:3.8.3"
python-driver: "3.10.0"
- typedb-server: "typedb/typedb:3.10.4"
python-driver: "3.10.0"
- typedb-server: "typedb/typedb:3.11.5"
python-driver: "3.11.5"
# The 3.12 leg pairs the band-9 installed driver a 3.12 user has;
# server 3.12 accepts it natively.
- typedb-server: "typedb/typedb:3.12.0"
python-driver: "3.12.0"
# Start TypeDB as a service container (runs first, before steps)
services:
typedb:
image: ${{ matrix.typedb-server }}
ports:
- 1729:1729
# TypeDB HTTP API; the connect-time version gate probes /v1/version.
- 8000:8000
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Install the band's Python driver
run: uv pip install "typedb-driver==${{ matrix.python-driver }}"
- name: Wait for TypeDB server to be ready
run: |
echo "Waiting for TypeDB server to start..."
echo "Container ID: ${{ job.services.typedb.id }}"
# Show initial logs for debugging
echo "=== Initial TypeDB logs ==="
docker logs ${{ job.services.typedb.id }} 2>&1 || echo "Could not fetch logs"
echo "==========================="
# Wait for server to be ready by checking port connectivity
for i in {1..30}; do
if nc -z localhost 1729 2>/dev/null; then
echo "TypeDB server is ready on port 1729!"
docker logs ${{ job.services.typedb.id }} 2>&1 | tail -20
break
fi
echo "Waiting for port 1729... ($i/30)"
sleep 2
done
# Final check
if ! nc -z localhost 1729 2>/dev/null; then
echo "ERROR: TypeDB server did not start within 60 seconds"
echo "=== Full TypeDB logs ==="
docker logs ${{ job.services.typedb.id }} 2>&1
exit 1
fi
- name: Run integration tests for ${{ matrix.test-group }}
env:
USE_DOCKER: false
TYPEDB_ADDRESS: localhost:1729
run: uv run pytest tests/integration/${{ matrix.test-group }} -m integration -v --tb=short
# Rust ORM live-TypeDB integration. The ordinary rust-check job deliberately
# leaves `integration-tests` disabled so it remains an offline gate. This job
# selects the non-ignored real-provider target explicitly and mirrors the full
# four-version Python/Node server matrix.
rust-integration:
name: Rust integration (${{ matrix.typedb-server }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
typedb-server:
- "typedb/typedb:3.8.3"
- "typedb/typedb:3.10.4"
- "typedb/typedb:3.11.5"
- "typedb/typedb:3.12.0"
services:
typedb:
image: ${{ matrix.typedb-server }}
ports:
- 1729:1729
- 8000:8000
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-rust-integration-v1-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: Wait for TypeDB server to be ready
run: |
for i in {1..30}; do
if nc -z localhost 1729 2>/dev/null; then
echo "TypeDB server is ready on port 1729"
break
fi
echo "Waiting for port 1729... ($i/30)"
sleep 2
done
if ! nc -z localhost 1729 2>/dev/null; then
echo "ERROR: TypeDB server did not start within 60 seconds"
docker logs ${{ job.services.typedb.id }} 2>&1 || true
exit 1
fi
- name: Run Rust ORM integration suite
env:
TYPEDB_ADDRESS: localhost:1729
TYPEDB_HTTP_PORT: "8000"
run: >-
cargo test --manifest-path type-bridge-core/Cargo.toml
-p type-bridge-orm --features integration-tests
--test integration -- --nocapture
# Cross-language parity gate: the #110 single-core / thin-bindings invariant only
# holds if a semantic divergence between the Python and Node sides reds CI. These
# tests shell out to the Node binding, so this job builds the Node prerequisites
# first, then runs them against live TypeDB under TYPE_BRIDGE_PARITY_STRICT so a
# "Node not built" skip fails the job instead of passing it silently (false green).
cross-language-parity:
name: Cross-language parity (${{ matrix.typedb-server }})
runs-on: ubuntu-latest
strategy:
matrix:
# Fan across one representative line per protocol band, per I5:
# band-7 (3.8.3), band-8 (3.11.5), and the dual-band 3.12 line.
# 3.10.4 is redundant for a parity proof.
# Keep in sync with compose + the version SSOT.
typedb-server:
- "typedb/typedb:3.8.3"
- "typedb/typedb:3.11.5"
- "typedb/typedb:3.12.0"
include:
# Band-7 leg pairs the band-7 installed Python driver.
- typedb-server: "typedb/typedb:3.8.3"
python-driver: "3.10.0"
- typedb-server: "typedb/typedb:3.11.5"
python-driver: "3.11.5"
- typedb-server: "typedb/typedb:3.12.0"
python-driver: "3.12.0"
services:
typedb:
image: ${{ matrix.typedb-server }}
ports:
- 1729:1729
# TypeDB HTTP API; the connect-time version gate probes /v1/version.
- 8000:8000
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-parity-v2-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Install the band's Python driver
run: uv pip install "typedb-driver==${{ matrix.python-driver }}"
- name: Build exact Python parity wheels
run: |
uv build --wheel --package type-bridge-core \
--out-dir tmp/typed-query-parity-wheels/core
uv build --wheel --package type-bridge \
--out-dir tmp/typed-query-parity-wheels/root
- name: Export exact Python parity wheel paths
run: |
mapfile -t core_wheels < <(
find tmp/typed-query-parity-wheels/core -maxdepth 1 -type f \
-name 'type_bridge_core-*.whl' -print
)
mapfile -t root_wheels < <(
find tmp/typed-query-parity-wheels/root -maxdepth 1 -type f \
-name 'type_bridge-*.whl' -print
)
if [[ ${#core_wheels[@]} -ne 1 ]]; then
printf 'Expected exactly one parity core wheel, found %s\n' \
"${#core_wheels[@]}" >&2
exit 1
fi
if [[ ${#root_wheels[@]} -ne 1 ]]; then
printf 'Expected exactly one parity root wheel, found %s\n' \
"${#root_wheels[@]}" >&2
exit 1
fi
printf 'TYPE_BRIDGE_PARITY_CORE_WHEEL=%s\n' \
"$(realpath "${core_wheels[0]}")" >> "$GITHUB_ENV"
printf 'TYPE_BRIDGE_PARITY_ROOT_WHEEL=%s\n' \
"$(realpath "${root_wheels[0]}")" >> "$GITHUB_ENV"
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: type-bridge-core/crates/node/package-lock.json
- name: Install Node dependencies
working-directory: type-bridge-core/crates/node
run: npm ci
# build:types is required too: the dynamic parity readers require() the package
# root, which resolves to dist/index.js — build:native only produces the cdylib.
- name: Build Node parity prerequisites
working-directory: type-bridge-core/crates/node
run: |
npm run build:native
npm run build:types
npm run build:typed-integration
npm run build:parity-reader
npm run build:generator-parity
- name: Export native artifact path
working-directory: type-bridge-core/crates/node
run: echo "TYPE_BRIDGE_NODE_NATIVE_PATH=$(ls "$PWD"/type_bridge_node.*.node | head -1)" >> "$GITHUB_ENV"
- name: Wait for TypeDB server to be ready
run: |
for i in {1..30}; do
if nc -z localhost 1729 2>/dev/null; then
echo "TypeDB server is ready on port 1729"
break
fi
echo "Waiting for port 1729... ($i/30)"
sleep 2
done
if ! nc -z localhost 1729 2>/dev/null; then
echo "ERROR: TypeDB server did not start within 60 seconds"
docker logs ${{ job.services.typedb.id }} 2>&1 || true
exit 1
fi
- name: Run cross-language parity (strict — skips for an unbuilt Node binding fail)
env:
USE_DOCKER: false
TYPEDB_ADDRESS: localhost:1729
TYPE_BRIDGE_PARITY_STRICT: "1"
# The `integration or not integration` marker overrides pyproject's default
# `-m 'not integration'` filter so this gate runs BOTH the live-TypeDB parity
# tests and the offline cross-language ones (descriptor snapshots, generator
# parity, fixture contract) — the latter otherwise run in no CI job.
run: |
uv run pytest tests/integration/parity -m "integration or not integration" \
-ra --tb=short --junitxml=parity-results.xml
- name: Assert parity tests actually ran (guard against zero-collected)
if: always()
run: |
uv run python - <<'PY'
import sys
import xml.etree.ElementTree as ET
tree = ET.parse("parity-results.xml")
root = tree.getroot()
suite = root if root.tag == "testsuite" else root.find("testsuite")
tests = int(suite.get("tests", "0"))
skipped = int(suite.get("skipped", "0"))
ran = tests - skipped
print(f"parity: tests={tests} skipped={skipped} ran={ran}")
if ran <= 0:
print("ERROR: no parity test executed — gate would be a no-op")
sys.exit(1)
PY
# Node binding live-TypeDB integration. `node-check` covers the offline Node gates and
# `cross-language-parity` runs the Python parity suite against the binding — but neither
# runs the binding's OWN integration suites. This job mirrors the Python `test-integration`
# job for Node: a TypeDB service container plus the native build, then the binding's
# `test:integration` suite (which itself chains `test:typed-integration`).
node-integration:
name: Node integration (${{ matrix.typedb-server }})
runs-on: ubuntu-latest
defaults:
run:
working-directory: type-bridge-core/crates/node
strategy:
matrix:
# Fan across all four server lines: band-7 (3.8.3, 3.10.4), band-8
# (3.11.5), and the dual-band 3.12 line. No python-driver pairing
# needed — Node reaches TypeDB only through the embedded Rust orm seam.
typedb-server:
- "typedb/typedb:3.8.3"
- "typedb/typedb:3.10.4"
- "typedb/typedb:3.11.5"
- "typedb/typedb:3.12.0"
services:
typedb:
image: ${{ matrix.typedb-server }}
ports:
- 1729:1729
# TypeDB HTTP API; the connect-time version gate probes /v1/version.
- 8000:8000
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-node-v2-${{ hashFiles('type-bridge-core/Cargo.lock') }}
# Node >= 22 is required here (unlike the other Node jobs): run-integration.js
# executes the .test.ts files directly via node --test, relying on Node's
# built-in type stripping, which Node 20 does not have.
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: type-bridge-core/crates/node/package-lock.json
- name: Install Node dependencies
run: npm ci
# Full build (native cdylib + tsc dist/): the integration tests require() the
# package root, which resolves to dist/index.js, so build:native alone is not enough.
- name: Build package
run: npm run build
- name: Export native artifact path
run: echo "TYPE_BRIDGE_NODE_NATIVE_PATH=$(ls "$PWD"/type_bridge_node.*.node | head -1)" >> "$GITHUB_ENV"
- name: Wait for TypeDB server to be ready
run: |
for i in {1..30}; do
if nc -z localhost 1729 2>/dev/null; then
echo "TypeDB server is ready on port 1729"
break
fi
echo "Waiting for port 1729... ($i/30)"
sleep 2
done
if ! nc -z localhost 1729 2>/dev/null; then
echo "ERROR: TypeDB server did not start within 60 seconds"
docker logs ${{ job.services.typedb.id }} 2>&1 || true
exit 1
fi
# The Node suites default TYPEDB_ADDRESS to :1730; the service is on :1729, so set it
# explicitly. test:integration runs the plain integration suite then chains
# test:typed-integration, so one command covers the binding's full live-DB surface.
- name: Run Node integration suite
env:
USE_DOCKER: false
TYPEDB_ADDRESS: localhost:1729
run: npm run test:integration
# Version-gate cells: each cell boots a server and checks either a positive
# connect path or the expected rejection class.
# POS-grpc-fallback-band8: wrong HTTP port still connects through gRPC band 8.
# POS-grpc-fallback-band7: wrong HTTP port tries band 8, then connects through band 7.
# NEG-window: Database.connect() rejects unsupported servers.
# NEG-driver: Database.driver rejects incompatible installed Python drivers.
# NEG-driver-band9: the asymmetric 3.12 pair — a band-9 driver against a
# 3.11 server is rejected, while band-8 against 3.12 is served.
# The band-7 servers (3.8.3, 3.10.4) are now SERVED: normal operation is
# proven green by the test-integration and node-integration legs, while the
# gRPC-only fallback is covered here as an explicit positive cell. Cell
# versions mirror the version SSOT in crates/core and the compatibility table.
version-gate-cells:
name: Version gate (${{ matrix.cell }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- cell: POS-grpc-fallback-band8
typedb-server: "typedb/typedb:3.11.5"
python-driver: "3.11.5"
probe: connect
http-port: 1
expect: ok
- cell: POS-grpc-fallback-band7
typedb-server: "typedb/typedb:3.10.4"
python-driver: "3.10.0"
probe: connect
http-port: 1
expect: ok
- cell: NEG-window
typedb-server: "typedb/typedb:3.7.3"
python-driver: "3.11.5"
probe: connect
http-port: 8000
expect: window
- cell: NEG-driver
typedb-server: "typedb/typedb:3.11.5"
python-driver: "3.10.0"
probe: driver
http-port: 8000
expect: installed
# Asymmetric band acceptance (measured live): a band-9 (3.12) driver
# is refused by a 3.11 server even though the reverse pair —
# band-8 driver against a 3.12 server — is served.
- cell: NEG-driver-band9
typedb-server: "typedb/typedb:3.11.5"
python-driver: "3.12.0"
probe: driver
http-port: 8000
expect: installed
services:
typedb:
image: ${{ matrix.typedb-server }}
ports:
- 1729:1729
# TypeDB HTTP API; the connect-time version gate probes /v1/version.
- 8000:8000
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13.5"
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
toolchain: ${{ env.RUST_STABLE_TOOLCHAIN }}
- name: Cache cargo registry and build
uses: actions/cache@v4
with:
path: |
${{ env.CARGO_HOME }}/registry
${{ env.CARGO_HOME }}/git
type-bridge-core/target
key: ${{ runner.os }}-cargo-gate-v2-${{ hashFiles('type-bridge-core/Cargo.lock') }}
- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Install the cell's Python driver
run: uv pip install "typedb-driver==${{ matrix.python-driver }}"
- name: Wait for TypeDB server to be ready
run: |
for i in {1..30}; do
if nc -z localhost 1729 2>/dev/null; then
echo "TypeDB ready on 1729"
break
fi
sleep 2
done
nc -z localhost 1729
- name: Assert version-gate cell
run: uv run python scripts/ci/assert_gate_rejection.py --address localhost:1729 --probe ${{ matrix.probe }} --http-port ${{ matrix.http-port }} --expect ${{ matrix.expect }}