-
Notifications
You must be signed in to change notification settings - Fork 2
233 lines (233 loc) · 8.67 KB
/
Copy pathci.yml
File metadata and controls
233 lines (233 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
# Cancel in-flight runs of the same workflow when a new commit is pushed.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0" # CI builds don't benefit from incremental; smaller cache.
CARGO_PROFILE_DEV_DEBUG: "0" # Reduces target/ size, improves cache hit rate.
RUSTFLAGS: -Dwarnings
# Testing strategy grounded in real-world ANN library issues:
# - hnswlib #635: M vs Mcurmax bug in neighbor selection
# - hnswlib #626: Use-after-free in deletion
# - hnswlib #592: Vector not normalized for cosine distance
# - hnswlib #608: Issues after deleting vectors
# - faiss #4295: Integer overflow on large datasets
# - usearch #405: Quantization issues with i8 + inner product
# See docs/TESTING.md for full details
jobs:
# Cheap fan-in gate: fmt + clippy + basic check on ubuntu.
# Failure here aborts every downstream matrix job (saves ~5-10 minutes per
# PR on a fmt typo). Pattern from tokio-rs/tokio.
basics:
name: Basics (fmt + clippy + check)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: Check formatting
run: cargo fmt --check
- name: Clippy (hnsw)
run: cargo clippy --no-default-features --features hnsw --all-targets -- -D warnings
- name: Clippy (all features)
run: cargo clippy --all-features --all-targets -- -D warnings
# Primary test suite (x86) -- nextest for parallel test-binary execution.
test:
name: Test (ubuntu)
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Build
run: cargo build --no-default-features --features hnsw
- name: Test (unit + integration)
run: cargo nextest run --no-default-features --features hnsw
- name: Test (sq4)
run: cargo nextest run --no-default-features --features hnsw,sq4
- name: Test (sq8)
run: cargo nextest run --no-default-features --features hnsw,sq8
- name: Test (lemur)
run: cargo nextest run --no-default-features --features lemur
- name: Test (all features, lib only)
run: cargo nextest run --lib --all-features
env:
RUSTFLAGS: ""
# nextest does not support doctests yet (nextest-rs/nextest#16).
- name: Doc tests
run: cargo test --doc --no-default-features --features hnsw
- name: Property tests
run: cargo nextest run --no-default-features --features hnsw -E 'test(property_)'
# Semver-checks only on PRs.
semver:
name: Semver check
runs-on: ubuntu-latest
needs: basics
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-semver-checks
- run: cargo semver-checks --default-features
# ARM native testing (M1/M2 - tests NEON code paths)
test-arm:
name: Test (macos / ARM)
runs-on: macos-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Build (ARM)
run: cargo build --no-default-features --features hnsw
- name: Test (ARM)
run: cargo nextest run --no-default-features --features hnsw
# MSRV check
msrv:
name: MSRV (1.89)
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@1.89.0
- uses: Swatinem/rust-cache@v2
- name: Check MSRV
run: |
rm -f Cargo.lock # v4 lock requires Cargo 1.83+
cargo check --no-default-features --features hnsw
# Feature-matrix compilation (catches cfg + optional-dep drift)
feature-matrix:
name: Feature matrix
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-hack
- name: Compile each feature (no dev-deps)
run: cargo hack check --each-feature --no-dev-deps --exclude-features persistence
# Cross-compilation check for different targets
cross-compile:
name: Cross-compile (${{ matrix.target }})
runs-on: ubuntu-latest
needs: basics
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- name: Check ${{ matrix.target }}
run: cargo check --target ${{ matrix.target }} --no-default-features --features hnsw
# Recall regression detection -- catches hnswlib #635-class issues.
recall-regression:
name: Recall regression
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build release
run: cargo build --release --no-default-features --features hnsw
- name: Run recall benchmark
run: |
cargo run --release --example 02_measure_recall --no-default-features --features hnsw 2>&1 | tee recall_output.txt
# Fail if recall@10 drops below 80% at ef=100
# This catches issues like hnswlib #635 (wrong M parameter)
awk '/^[[:space:]]*100[[:space:]]/ {
gsub(/%/, "", $2); found=1
if ($2 + 0 < 80.0) { print "FAIL: ef=100 recall " $2 "% < 80%"; exit 1 }
}
END { if (!found) { print "FAIL: ef=100 row missing from output"; exit 1 } }' recall_output.txt
# Regression tests for known bugs
regression:
name: Regression (known bugs)
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Run regression tests
run: cargo nextest run --test regression_known_bugs --no-default-features --features hnsw
# Python bindings: build wheel, lint, type-check, stubtest, pytest.
# Stubtest catches drift between the hand-written `_core.pyi` and the
# compiled module the moment a Rust signature changes (voyager pattern).
python:
name: Python (pyvicinity)
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/setup-python@v6.2.0
with:
python-version: "3.13"
# GH Actions runners don't have a venv, and maturin develop needs
# one. Pin the venv via $VIRTUAL_ENV + $GITHUB_PATH so subsequent
# steps inherit it. maturin develop is preferred over `maturin build
# + pip install` because it drops `_core.so` directly into the source
# tree, which avoids the cwd-shadows-site-packages problem when
# stubtest imports `pyvicinity._core`.
- name: Set up virtualenv
run: |
python -m venv .venv
echo "$GITHUB_WORKSPACE/.venv/bin" >> "$GITHUB_PATH"
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> "$GITHUB_ENV"
- name: Install build + test deps
run: python -m pip install --upgrade pip maturin pytest mypy ruff numpy
- name: Build extension (editable)
run: maturin develop --release --features hnsw,python
- name: Ruff
run: python -m ruff check pyvicinity tests/test_python.py
- name: mypy --strict
run: python -m mypy --strict pyvicinity
- name: Stubtest (.pyi vs compiled module)
run: python -m mypy.stubtest pyvicinity._core
- name: Pytest
run: python -m pytest tests/test_python.py -v
# Documentation build
docs:
name: Docs
runs-on: ubuntu-latest
needs: basics
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build docs
run: cargo doc --no-default-features --features hnsw --no-deps
env:
RUSTDOCFLAGS: -Dwarnings