Skip to content

Commit cd4cb54

Browse files
chore: configure crates.io publishing, CI, and Codecov (#15)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9cebcb4 commit cd4cb54

12 files changed

Lines changed: 542 additions & 4 deletions

File tree

.github/dependabot.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
version: 2
2+
3+
updates:
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
schedule:
7+
interval: "monthly"
8+
ignore:
9+
- dependency-name: "*"
10+
update-types: ["version-update:semver-patch"]
11+
# MSRV is intentionally pinned to a specific Rust version (1.89).
12+
# Ignore updates so Dependabot doesn't try to bump it every month.
13+
- dependency-name: "dtolnay/rust-toolchain"
14+
groups:
15+
github-actions-dependencies:
16+
patterns:
17+
- "*"
18+
19+
- package-ecosystem: "cargo"
20+
directory: "/"
21+
schedule:
22+
interval: "monthly"
23+
ignore:
24+
- dependency-name: "*"
25+
update-types: ["version-update:semver-patch"]
26+
groups:
27+
cargo-dependencies:
28+
patterns:
29+
- "*"

.github/workflows/ci.yml

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
RUST_BACKTRACE: 1
12+
13+
permissions:
14+
contents: read
15+
16+
jobs:
17+
test:
18+
name: Test (${{ matrix.name }})
19+
runs-on: ${{ matrix.os }}
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
include:
24+
- name: "default features"
25+
os: ubuntu-latest
26+
features: ""
27+
- name: "openblas"
28+
os: ubuntu-latest
29+
features: "--features openblas"
30+
- name: "accelerate"
31+
os: macos-latest
32+
features: "--features accelerate"
33+
steps:
34+
- uses: actions/checkout@v7
35+
36+
- name: Install OpenBLAS
37+
if: matrix.name == 'openblas'
38+
run: sudo apt-get update && sudo apt-get install -y libopenblas-dev pkg-config
39+
40+
- name: Install Rust toolchain
41+
uses: dtolnay/rust-toolchain@stable
42+
43+
- name: Cache cargo registry and build
44+
uses: actions/cache@v6
45+
with:
46+
path: |
47+
~/.cargo/registry
48+
~/.cargo/git
49+
target
50+
key: ${{ runner.os }}-cargo-${{ matrix.name }}-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}
51+
restore-keys: |
52+
${{ runner.os }}-cargo-${{ matrix.name }}-
53+
54+
- name: Run tests (${{ matrix.name }})
55+
run: cargo test ${{ matrix.features }} --verbose
56+
57+
clippy:
58+
name: Clippy
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@v7
62+
63+
- name: Install Rust toolchain
64+
uses: dtolnay/rust-toolchain@stable
65+
with:
66+
components: clippy
67+
68+
- name: Cache cargo registry and build
69+
uses: actions/cache@v6
70+
with:
71+
path: |
72+
~/.cargo/registry
73+
~/.cargo/git
74+
target
75+
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}
76+
restore-keys: |
77+
${{ runner.os }}-cargo-clippy-
78+
79+
- name: Run Clippy (default features)
80+
run: cargo clippy -- -D warnings
81+
82+
- name: Run Clippy (openblas backend)
83+
run: cargo clippy --features openblas -- -D warnings
84+
85+
fmt:
86+
name: Format
87+
runs-on: ubuntu-latest
88+
steps:
89+
- uses: actions/checkout@v7
90+
91+
- name: Install Rust toolchain
92+
uses: dtolnay/rust-toolchain@stable
93+
with:
94+
components: rustfmt
95+
96+
- name: Check formatting
97+
run: cargo fmt --all -- --check
98+
99+
docs:
100+
name: Documentation
101+
runs-on: ubuntu-latest
102+
steps:
103+
- uses: actions/checkout@v7
104+
105+
- name: Install Rust toolchain
106+
uses: dtolnay/rust-toolchain@stable
107+
108+
- name: Cache cargo registry and build
109+
uses: actions/cache@v6
110+
with:
111+
path: |
112+
~/.cargo/registry
113+
~/.cargo/git
114+
target
115+
key: ${{ runner.os }}-cargo-docs-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}
116+
restore-keys: |
117+
${{ runner.os }}-cargo-docs-
118+
119+
- name: Check documentation
120+
env:
121+
RUSTDOCFLAGS: -D warnings
122+
run: cargo doc --no-deps
123+
124+
msrv:
125+
name: Minimum Supported Rust Version
126+
runs-on: ubuntu-latest
127+
steps:
128+
- uses: actions/checkout@v7
129+
130+
- name: Install Rust toolchain (MSRV)
131+
uses: dtolnay/rust-toolchain@1.89
132+
133+
- name: Cache cargo registry and build
134+
uses: actions/cache@v6
135+
with:
136+
path: |
137+
~/.cargo/registry
138+
~/.cargo/git
139+
target
140+
key: ${{ runner.os }}-cargo-msrv-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}
141+
restore-keys: |
142+
${{ runner.os }}-cargo-msrv-
143+
144+
- name: Check MSRV compatibility
145+
run: cargo check
146+
147+
coverage:
148+
name: Code Coverage
149+
runs-on: ubuntu-latest
150+
steps:
151+
- uses: actions/checkout@v7
152+
153+
- name: Install Rust toolchain
154+
uses: dtolnay/rust-toolchain@stable
155+
with:
156+
components: llvm-tools-preview
157+
158+
- name: Install cargo-llvm-cov
159+
uses: taiki-e/install-action@cargo-llvm-cov
160+
161+
- name: Cache cargo registry and build
162+
uses: actions/cache@v6
163+
with:
164+
path: |
165+
~/.cargo/registry
166+
~/.cargo/git
167+
target
168+
key: ${{ runner.os }}-cargo-cov-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}
169+
restore-keys: |
170+
${{ runner.os }}-cargo-cov-
171+
172+
- name: Generate coverage report
173+
run: cargo llvm-cov --lcov --output-path lcov.info
174+
175+
- name: Upload coverage to Codecov
176+
uses: codecov/codecov-action@v7
177+
with:
178+
files: lcov.info
179+
fail_ci_if_error: true
180+
token: ${{ secrets.CODECOV_TOKEN }}
181+
slug: paradedb/superkmeans-rs
182+
183+
- name: Generate coverage summary
184+
run: |
185+
# Run coverage and capture the human-readable table.
186+
COVERAGE_OUTPUT=$(cargo llvm-cov 2>&1)
187+
188+
# The TOTAL row lists percentages as: Regions Functions Lines (Branches).
189+
TOTAL_LINE=$(echo "$COVERAGE_OUTPUT" | grep "^TOTAL")
190+
REGION_COV=$(echo "$TOTAL_LINE" | grep -oE '[0-9]+\.[0-9]+%' | head -1)
191+
FUNC_COV=$(echo "$TOTAL_LINE" | grep -oE '[0-9]+\.[0-9]+%' | head -2 | tail -1)
192+
LINE_COV=$(echo "$TOTAL_LINE" | grep -oE '[0-9]+\.[0-9]+%' | head -3 | tail -1)
193+
194+
echo "## 📊 Code Coverage Summary" >> $GITHUB_STEP_SUMMARY
195+
echo "" >> $GITHUB_STEP_SUMMARY
196+
echo "| Metric | Coverage |" >> $GITHUB_STEP_SUMMARY
197+
echo "|--------|----------|" >> $GITHUB_STEP_SUMMARY
198+
echo "| **Lines** | $LINE_COV |" >> $GITHUB_STEP_SUMMARY
199+
echo "| **Functions** | $FUNC_COV |" >> $GITHUB_STEP_SUMMARY
200+
echo "| **Regions** | $REGION_COV |" >> $GITHUB_STEP_SUMMARY

.github/workflows/release.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
env:
9+
CARGO_TERM_COLOR: always
10+
11+
permissions:
12+
contents: write
13+
14+
jobs:
15+
validate:
16+
name: Validate Release
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v7
20+
21+
- name: Install Rust toolchain
22+
uses: dtolnay/rust-toolchain@stable
23+
with:
24+
components: clippy
25+
26+
- name: Verify version matches tag
27+
run: |
28+
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
29+
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
30+
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
31+
echo "Error: Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)"
32+
exit 1
33+
fi
34+
echo "Version validated: $TAG_VERSION"
35+
36+
- name: Run tests
37+
run: cargo test --verbose
38+
39+
- name: Run clippy
40+
run: cargo clippy -- -D warnings
41+
42+
publish:
43+
name: Publish to crates.io
44+
needs: validate
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v7
48+
49+
- name: Install Rust toolchain
50+
uses: dtolnay/rust-toolchain@stable
51+
52+
- name: Publish to crates.io
53+
env:
54+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
55+
run: cargo publish
56+
57+
github-release:
58+
name: Create GitHub Release
59+
needs: publish
60+
runs-on: ubuntu-latest
61+
steps:
62+
- uses: actions/checkout@v7
63+
64+
- name: Create GitHub Release
65+
uses: softprops/action-gh-release@v3
66+
with:
67+
generate_release_notes: true
68+
draft: false
69+
prerelease: ${{ contains(github.ref, '-') }}

CONTRIBUTING.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Contributing to superkmeans-rs
2+
3+
Thanks for your interest in contributing to superkmeans-rs!
4+
5+
## Prerequisites
6+
7+
- **Rust 1.89+** (the minimum supported Rust version)
8+
- Optional, for the BLAS backends:
9+
- `openblas` — a system OpenBLAS (`libopenblas-dev` on Debian/Ubuntu, `brew install openblas` on macOS)
10+
- `accelerate` — macOS only; uses the system Accelerate framework (no extra install)
11+
12+
## Development
13+
14+
```bash
15+
cargo build # Default build (pure-Rust matrixmultiply backend)
16+
cargo build --features openblas # Route SGEMM through a system OpenBLAS
17+
cargo build --features accelerate # Route SGEMM through Apple Accelerate (macOS)
18+
cargo test # Run tests
19+
cargo run --example simple_clustering
20+
```
21+
22+
The `blas` feature is an internal marker — enable a concrete backend
23+
(`openblas` or `accelerate`) rather than `blas` directly. Do not enable
24+
`accelerate` and `openblas` at the same time.
25+
26+
Before submitting a PR, make sure CI checks pass locally:
27+
28+
```bash
29+
cargo fmt --all -- --check
30+
cargo clippy -- -D warnings
31+
cargo test
32+
```
33+
34+
## Submitting Changes
35+
36+
1. Fork the repository and create a branch from `main`.
37+
2. Add tests for any new functionality or bug fixes.
38+
3. Run the checks above.
39+
4. Open a pull request against `main`.
40+
41+
## Reporting Issues
42+
43+
Open an issue on [GitHub](https://github.com/paradedb/superkmeans-rs/issues) with a clear description of the problem or feature request.
44+
45+
## License
46+
47+
By contributing, you agree that your contributions will be licensed under the [MIT License](LICENSE).

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22
name = "superkmeans-rs"
33
version = "0.1.0"
44
edition = "2024"
5+
rust-version = "1.89"
6+
authors = ["ParadeDB <support@paradedb.com>"]
57
description = "A Rust port of SuperKMeans: fast k-means clustering for high-dimensional vector embeddings"
68
license = "MIT"
9+
readme = "README.md"
10+
repository = "https://github.com/paradedb/superkmeans-rs"
11+
homepage = "https://github.com/paradedb/superkmeans-rs"
12+
categories = ["algorithms", "science", "mathematics"]
13+
keywords = ["kmeans", "clustering", "embeddings", "vector", "simd"]
714

815
[lib]
916
name = "superkmeans"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 ParadeDB
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

0 commit comments

Comments
 (0)