Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1 @@
# Graph performance baseline

View File

@@ -0,0 +1,284 @@
# RuVector Release Pipeline Flow Diagram
```
┌─────────────────────────────────────────────────────────────────┐
│ TRIGGER RELEASE PIPELINE │
│ │
│ Method 1: git tag v0.1.3 && git push origin v0.1.3 │
│ Method 2: Manual workflow_dispatch with version input │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STAGE 1: VALIDATION │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ • cargo fmt --check │ │
│ │ • cargo clippy (all warnings as errors) │ │
│ │ • cargo test --workspace │ │
│ │ • npm run test:unit │ │
│ └────────────────────────────────────────────────────────────┘ │
│ Runner: ubuntu-22.04 │
│ Time: 3-12 minutes │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────┴─────────────────┐
│ │
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐
│ STAGE 2: BUILD CRATES │ │ STAGE 3: BUILD WASM │
│ ┌─────────────────────┐ │ │ ┌─────────────────────┐ │
│ │ • Build 26 crates │ │ │ │ • ruvector-wasm │ │
│ │ • Dependency order │ │ │ │ • ruvector-gnn-wasm │ │
│ │ • Release mode │ │ │ │ • ruvector-graph- │ │
│ │ • Run tests │ │ │ │ wasm │ │
│ └─────────────────────┘ │ │ │ • tiny-dancer-wasm │ │
│ ubuntu-22.04 │ │ └─────────────────────┘ │
│ 5-20 minutes │ │ ubuntu-22.04 │
└───────────────────────────┘ │ 4-15 minutes │
│ └───────────────────────────┘
│ │
└──────────┬────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ STAGE 4: BUILD NATIVE (Parallel Matrix) │
│ ┌──────────────────────────────────────────────────────────────┐│
│ │ Platform 1 Platform 2 Platform 3 ││
│ │ linux-x64-gnu linux-arm64-gnu darwin-x64 ││
│ │ ubuntu-22.04 ubuntu-22.04 macos-13 ││
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││
│ │ │ napi-rs │ │ napi-rs │ │ napi-rs │ ││
│ │ │ build │ │ + cross │ │ build │ ││
│ │ │ │ │ compile │ │ │ ││
│ │ └──────────┘ └──────────┘ └──────────┘ ││
│ │ ││
│ │ Platform 4 Platform 5 ││
│ │ darwin-arm64 win32-x64-msvc ││
│ │ macos-14 windows-2022 ││
│ │ ┌──────────┐ ┌──────────┐ ││
│ │ │ napi-rs │ │ napi-rs │ ││
│ │ │ build │ │ build │ ││
│ │ │ │ │ │ ││
│ │ └──────────┘ └──────────┘ ││
│ └──────────────────────────────────────────────────────────────┘│
│ Time: 3-12 minutes per platform (runs in parallel) │
└──────────────────────────────────────────────────────────────────┘
┌────────────────────┴────────────────────┐
│ │
▼ ▼
┌────────────────────────┐ ┌────────────────────────┐
│ STAGE 5: PUBLISH │ │ STAGE 6: PUBLISH │
│ RUST CRATES │ │ npm PACKAGES │
│ │ │ │
│ Publishing Order: │ │ Publishing Order: │
│ 1. ruvector-core │ │ 1. Platform packages │
│ 2. ruvector-metrics │ │ (@ruvector/core-*) │
│ 3. ruvector-filter │ │ 2. @ruvector/wasm │
│ 4. ruvector-snapshot │ │ 3. @ruvector/cli │
│ 5. ruvector- │ │ 4. @ruvector/ │
│ collections │ │ extensions │
│ ... (26 total) │ │ 5. @ruvector/core │
│ │ │ │
│ Target: crates.io │ │ Target: npmjs.com │
│ Auth: CARGO_REGISTRY_ │ │ Auth: NPM_TOKEN │
│ TOKEN │ │ │
│ Time: 5-10 minutes │ │ Time: 2-5 minutes │
└────────────────────────┘ └────────────────────────┘
│ │
└────────────────────┬────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STAGE 7: CREATE GITHUB RELEASE │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ 1. Download all artifacts (native + WASM) │ │
│ │ 2. Package as .tar.gz files: │ │
│ │ - ruvector-native-linux-x64-gnu.tar.gz │ │
│ │ - ruvector-native-linux-arm64-gnu.tar.gz │ │
│ │ - ruvector-native-darwin-x64.tar.gz │ │
│ │ - ruvector-native-darwin-arm64.tar.gz │ │
│ │ - ruvector-native-win32-x64-msvc.tar.gz │ │
│ │ - ruvector-wasm.tar.gz │ │
│ │ 3. Generate comprehensive release notes │ │
│ │ 4. Create GitHub release with artifacts │ │
│ └────────────────────────────────────────────────────────────┘ │
│ Time: 2-3 minutes │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STAGE 8: RELEASE SUMMARY │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Generate final summary with: │ │
│ │ • Status of all jobs (success/failure) │ │
│ │ • Links to published packages │ │
│ │ • Verification steps │ │
│ │ • Next steps for maintainers │ │
│ └────────────────────────────────────────────────────────────┘ │
│ Always runs (even on failure) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ RELEASE COMPLETE! 🎉 │
│ │
│ Published to: │
│ ✅ crates.io: https://crates.io/crates/ruvector-core │
│ ✅ npmjs.com: https://www.npmjs.com/package/@ruvector/core │
│ ✅ GitHub: https://github.com/ruvnet/ruvector/releases │
│ │
│ Total Time: 15-30 minutes (with caching) │
└─────────────────────────────────────────────────────────────────┘
```
## Key Features
### 🚀 Parallel Execution
- Stages 2, 3, and 4 run simultaneously
- 5 native platform builds run in parallel
- Total time: ~60% faster than sequential
### 💾 Smart Caching
- Rust dependencies cached via `Swatinem/rust-cache`
- npm dependencies cached via `actions/setup-node`
- wasm-pack binary cached
- Cache hit rate: 70-95%
### 🔒 Security
- Secrets never exposed in logs
- Environment protection for production
- Optional reviewer approval gates
- Conditional publishing (tag or manual only)
### 🛡️ Error Handling
- Continue on already-published packages
- Graceful failure handling
- Rate limiting protection (10s between publishes)
- Comprehensive error logging
### 📊 Monitoring
- Job summaries at each stage
- Final comprehensive summary
- Artifact upload/download tracking
- GitHub release with all binaries
## Workflow Dependencies
```
┌──────────┐
│ validate │──┐
└──────────┘ │
├──> build-crates ──┐
│ │
├──> build-wasm ─────┤
│ ├──> publish-crates ──┐
└──> build-native ───┤ │
├──> publish-npm ─────┤
│ │
└─────────────────────┴──> create-release
└──> release-summary
```
## Critical Paths
### Path 1: Rust Publishing
```
validate → build-crates → publish-crates → create-release
```
**Time**: 15-25 minutes
### Path 2: npm Publishing
```
validate → build-native → publish-npm → create-release
→ build-wasm ─┘
```
**Time**: 12-20 minutes
### Path 3: Release Creation
```
All paths → create-release → release-summary
```
**Time**: 2-3 minutes
## Artifact Flow
```
┌──────────────┐
│ build-native │──> bindings-linux-x64-gnu.artifact
│ │──> bindings-linux-arm64-gnu.artifact
│ │──> bindings-darwin-x64.artifact
│ │──> bindings-darwin-arm64.artifact
│ │──> bindings-win32-x64-msvc.artifact
└──────────────┘
├──> publish-npm (downloads & publishes)
└──> create-release (downloads & packages)
┌──────────────┐
│ build-wasm │──> wasm-packages.artifact
└──────────────┘
├──> publish-npm (downloads & publishes)
└──> create-release (downloads & packages)
```
## Environment Variables
| Variable | Scope | Purpose |
|----------|-------|---------|
| `CARGO_TERM_COLOR` | Global | Colored Cargo output |
| `RUST_BACKTRACE` | Global | Detailed error traces |
| `CARGO_REGISTRY_TOKEN` | publish-crates | crates.io auth |
| `NODE_AUTH_TOKEN` | publish-npm | npmjs.com auth |
| `GITHUB_TOKEN` | create-release | GitHub API auth |
## Job Conditions
| Job | Runs When |
|-----|-----------|
| `validate` | Always (unless skip_tests=true) |
| `build-crates` | After validation passes |
| `build-wasm` | After validation passes |
| `build-native` | After validation passes |
| `publish-crates` | Tag push OR manual + not dry_run |
| `publish-npm` | Tag push OR manual + not dry_run |
| `create-release` | All builds succeed + tag OR manual |
| `release-summary` | Always (even on failure) |
## Quick Start Commands
```bash
# Test the workflow locally (dry run)
gh workflow run release.yml \
-f version=0.1.3-test \
-f dry_run=true
# Trigger production release
git tag v0.1.3
git push origin v0.1.3
# Emergency release (skip tests)
gh workflow run release.yml \
-f version=0.1.3 \
-f skip_tests=true
# View workflow status
gh run list --workflow=release.yml
```
## Support Matrix
| Component | Platforms | Total |
|-----------|-----------|-------|
| Native Binaries | linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64 | 5 |
| WASM Packages | Universal (wasm32-unknown-unknown) | 4 |
| Rust Crates | Platform-independent source | 26 |
| npm Packages | 5 platform + 4 core | 9 |
**Total Release Artifacts**: 44 packages across 3 registries

View File

@@ -0,0 +1,567 @@
# RuVector Release Pipeline Documentation
## Overview
The RuVector release pipeline is a comprehensive CI/CD workflow that automates the building, testing, and publishing of Rust crates and npm packages across multiple platforms.
## Workflow Files
- **`release.yml`**: Main release pipeline workflow
- **`build-native.yml`**: Reusable workflow for building native Node.js modules
- **`validate-lockfile.yml`**: Validates package-lock.json integrity
## Trigger Methods
### 1. Tag-Based Release (Recommended)
```bash
# Create and push a version tag
git tag v0.1.3
git push origin v0.1.3
```
This automatically triggers the full release pipeline.
### 2. Manual Workflow Dispatch
Navigate to: **Actions → Release Pipeline → Run workflow**
Options:
- **Version**: Version to release (e.g., `0.1.3`)
- **Skip Tests**: Skip validation tests (not recommended)
- **Dry Run**: Build everything but don't publish
## Pipeline Stages
### Stage 1: Validation (`validate`)
**Runs on**: `ubuntu-22.04`
**Tasks**:
- ✅ Check code formatting with `cargo fmt`
- ✅ Run Clippy lints with all warnings as errors
- ✅ Run Rust test suite across all crates
- ✅ Run npm unit tests
- ✅ Generate validation summary
**Skip condition**: Set `skip_tests: true` in manual workflow dispatch
### Stage 2: Build Rust Crates (`build-crates`)
**Runs on**: `ubuntu-22.04`
**Tasks**:
- Build all workspace crates in release mode
- Run crate-specific tests
- Generate build summary with all crate versions
**Crates built** (26 total):
- Core: `ruvector-core`, `ruvector-metrics`, `ruvector-filter`
- Graph: `ruvector-graph`, `ruvector-gnn`
- Distributed: `ruvector-cluster`, `ruvector-raft`, `ruvector-replication`
- Bindings: `ruvector-node`, `ruvector-wasm`
- And 16 more specialized crates
### Stage 3: Build WASM Packages (`build-wasm`)
**Runs on**: `ubuntu-22.04`
**Tasks**:
- Install `wasm-pack` build tool
- Build WASM packages for:
- `ruvector-wasm` (core WASM)
- `ruvector-gnn-wasm` (graph neural networks)
- `ruvector-graph-wasm` (graph database)
- `ruvector-tiny-dancer-wasm` (tiny dancer)
- Upload WASM artifacts for later stages
**Caching**:
- Rust dependencies via `Swatinem/rust-cache`
- wasm-pack binary
### Stage 4: Build Native Modules (`build-native`)
**Runs on**: Multi-platform matrix
**Reuses**: `./.github/workflows/build-native.yml` as callable workflow
**Platforms built**:
- Linux x64 (GNU) - `ubuntu-22.04`
- Linux ARM64 (GNU) - `ubuntu-22.04` with cross-compilation
- macOS x64 (Intel) - `macos-13`
- macOS ARM64 (Apple Silicon) - `macos-14`
- Windows x64 (MSVC) - `windows-2022`
**Build matrix details**:
```yaml
- host: ubuntu-22.04, target: x86_64-unknown-linux-gnu
- host: ubuntu-22.04, target: aarch64-unknown-linux-gnu
- host: macos-13, target: x86_64-apple-darwin
- host: macos-14, target: aarch64-apple-darwin
- host: windows-2022, target: x86_64-pc-windows-msvc
```
**Output**: Binary artifacts for each platform uploaded to GitHub Actions
### Stage 5: Publish Rust Crates (`publish-crates`)
**Runs on**: `ubuntu-22.04`
**Requires**:
- ✅ Validation passed
- ✅ Build crates succeeded
- 🔑 `CARGO_REGISTRY_TOKEN` secret configured
- Tag starts with `v*` OR manual workflow dispatch
- NOT in dry-run mode
**Publishing order** (respects dependencies):
```
1. ruvector-core (foundation)
2. ruvector-metrics, ruvector-filter, ruvector-snapshot
3. ruvector-collections, ruvector-router-core
4. ruvector-raft, ruvector-cluster, ruvector-replication
5. ruvector-gnn, ruvector-graph
6. ruvector-server, ruvector-tiny-dancer-core
7. ruvector-router-cli, ruvector-router-ffi, ruvector-router-wasm
8. ruvector-cli, ruvector-bench
9. ruvector-wasm, ruvector-node
10. ruvector-gnn-wasm, ruvector-gnn-node
11. ruvector-graph-wasm, ruvector-graph-node
12. ruvector-tiny-dancer-wasm, ruvector-tiny-dancer-node
```
**Rate limiting**: 10 second delay between publishes to avoid crates.io rate limits
**Error handling**: Continues if a crate already exists (409 error)
### Stage 6: Publish npm Packages (`publish-npm`)
**Runs on**: `ubuntu-22.04`
**Requires**:
- ✅ Validation passed
- ✅ Build native succeeded
- ✅ Build WASM succeeded
- 🔑 `NPM_TOKEN` secret configured
- Tag starts with `v*` OR manual workflow dispatch
- NOT in dry-run mode
**Publishing order**:
```
1. Platform-specific packages (@ruvector/core-*)
- @ruvector/core-linux-x64-gnu
- @ruvector/core-linux-arm64-gnu
- @ruvector/core-darwin-x64
- @ruvector/core-darwin-arm64
- @ruvector/core-win32-x64-msvc
2. @ruvector/wasm (WebAssembly bindings)
3. @ruvector/cli (Command-line interface)
4. @ruvector/extensions (Extensions)
5. @ruvector/core (Main package - depends on platform packages)
```
**Artifact handling**:
- Downloads native binaries from `build-native` job
- Downloads WASM packages from `build-wasm` job
- Copies to appropriate package directories
- Runs `npm ci` and `npm run build`
- Publishes with `--access public`
### Stage 7: Create GitHub Release (`create-release`)
**Runs on**: `ubuntu-22.04`
**Requires**:
- ✅ All build jobs succeeded
- Tag starts with `v*` OR manual workflow dispatch
**Tasks**:
1. **Download all artifacts**
- Native binaries for all platforms
- WASM packages
2. **Package artifacts**
- `ruvector-native-linux-x64-gnu.tar.gz`
- `ruvector-native-linux-arm64-gnu.tar.gz`
- `ruvector-native-darwin-x64.tar.gz`
- `ruvector-native-darwin-arm64.tar.gz`
- `ruvector-native-win32-x64-msvc.tar.gz`
- `ruvector-wasm.tar.gz`
3. **Generate release notes**
- What's new section
- Package lists (Rust crates and npm)
- Platform support matrix
- Installation instructions
- Links to registries
- Build metrics
4. **Create GitHub release**
- Uses `softprops/action-gh-release@v1`
- Attaches packaged artifacts
- Marks as prerelease if version contains `alpha` or `beta`
### Stage 8: Release Summary (`release-summary`)
**Runs on**: `ubuntu-22.04`
**Always runs**: Even if previous jobs fail
**Tasks**:
- Generate comprehensive status table
- Show success/failure for each job
- Provide next steps and verification links
## Required Secrets
### CARGO_REGISTRY_TOKEN
**Purpose**: Publish Rust crates to crates.io
**Setup**:
1. Go to https://crates.io/settings/tokens
2. Create new token with `publish-new` and `publish-update` scopes
3. Add to GitHub: **Settings → Secrets → Actions → New secret**
- Name: `CARGO_REGISTRY_TOKEN`
- Value: Your crates.io token
### NPM_TOKEN
**Purpose**: Publish npm packages to npmjs.com
**Setup**:
1. Login to npmjs.com
2. Go to **Access Tokens → Generate New Token**
3. Select **Automation** type
4. Add to GitHub: **Settings → Secrets → Actions → New secret**
- Name: `NPM_TOKEN`
- Value: Your npm token
## Environments
The workflow uses GitHub Environments for additional security:
### `crates-io` Environment
- Used for `publish-crates` job
- Can add required reviewers
- Can add environment-specific secrets
### `npm` Environment
- Used for `publish-npm` job
- Can add required reviewers
- Can add environment-specific secrets
**Setup environments**:
1. Go to **Settings → Environments**
2. Create `crates-io` and `npm` environments
3. (Optional) Add required reviewers for production releases
## Caching Strategy
### Rust Cache
```yaml
uses: Swatinem/rust-cache@v2
with:
prefix-key: 'v1-rust'
shared-key: 'validate|build-crates|wasm'
```
**Caches**:
- `~/.cargo/registry`
- `~/.cargo/git`
- `target/` directory
**Benefits**: 2-5x faster builds
### Node.js Cache
```yaml
uses: actions/setup-node@v4
with:
cache: 'npm'
cache-dependency-path: npm/package-lock.json
```
**Caches**: `~/.npm` directory
## Build Matrix
The native build job uses a strategic matrix to cover all platforms:
| Platform | Host Runner | Rust Target | NAPI Platform | Cross-Compile |
|----------|-------------|-------------|---------------|---------------|
| Linux x64 | ubuntu-22.04 | x86_64-unknown-linux-gnu | linux-x64-gnu | No |
| Linux ARM64 | ubuntu-22.04 | aarch64-unknown-linux-gnu | linux-arm64-gnu | Yes (gcc-aarch64) |
| macOS Intel | macos-13 | x86_64-apple-darwin | darwin-x64 | No |
| macOS ARM | macos-14 | aarch64-apple-darwin | darwin-arm64 | No |
| Windows | windows-2022 | x86_64-pc-windows-msvc | win32-x64-msvc | No |
## Artifact Retention
- **Native binaries**: 7 days
- **WASM packages**: 7 days
- **Release packages**: Permanent (attached to GitHub release)
## Common Scenarios
### Regular Release
```bash
# 1. Update versions in Cargo.toml files
# 2. Update npm package.json files
# 3. Commit changes
git add .
git commit -m "chore: Bump version to 0.1.3"
# 4. Create and push tag
git tag v0.1.3
git push origin main
git push origin v0.1.3
# 5. Monitor workflow at:
# https://github.com/ruvnet/ruvector/actions/workflows/release.yml
```
### Dry Run (Test Release)
1. Go to **Actions → Release Pipeline**
2. Click **Run workflow**
3. Set:
- Version: `0.1.3-test`
- Dry run: `true`
4. Click **Run workflow**
This builds everything but skips publishing.
### Emergency Hotfix
```bash
# 1. Create hotfix branch
git checkout -b hotfix/critical-fix
# 2. Make fixes
# 3. Bump patch version
# 4. Commit and tag
git commit -m "fix: Critical security patch"
git tag v0.1.3-hotfix.1
git push origin hotfix/critical-fix
git push origin v0.1.3-hotfix.1
# 5. Manually trigger release workflow if needed
```
### Republish Failed Package
If a single npm package fails to publish:
```bash
# 1. Check error in workflow logs
# 2. Fix issue locally
# 3. Manually publish that package:
cd npm/packages/wasm
npm publish --access public
# Or trigger just the npm publishing:
# Manually run workflow_dispatch with skip_tests: true
```
## Troubleshooting
### Build Failures
**Symptom**: `build-crates` job fails
**Solutions**:
1. Check Rust version compatibility
2. Verify all dependencies are available
3. Look for compilation errors in logs
4. Test locally: `cargo build --workspace --release`
### Publishing Failures
**Symptom**: `publish-crates` or `publish-npm` fails
**Solutions**:
1. **Rate limiting**:
- Wait and re-run workflow
- Increase delay between publishes
2. **Already published**:
- Bump version number
- Or skip that package (it's already live)
3. **Authentication**:
- Verify secrets are set correctly
- Check token hasn't expired
- Verify token has correct permissions
4. **Dependency issues**:
- Check publishing order
- Ensure dependencies are published first
### Cross-Compilation Issues
**Symptom**: Linux ARM64 build fails
**Solutions**:
1. Verify cross-compilation tools installed
2. Check linker configuration
3. Test with: `cargo build --target aarch64-unknown-linux-gnu`
### WASM Build Issues
**Symptom**: `build-wasm` job fails
**Solutions**:
1. Verify `wasm-pack` installation
2. Check for incompatible dependencies
3. Ensure `wasm32-unknown-unknown` target installed
4. Test locally: `wasm-pack build --target nodejs`
## Performance Optimization
### Parallel Builds
The workflow runs these jobs in parallel:
- `build-crates`
- `build-wasm`
- `build-native` (5 platform builds in parallel)
Total time: ~15-25 minutes (vs. 60+ minutes sequential)
### Cache Hit Rates
With proper caching:
- Rust builds: 70-90% cache hit rate
- npm installs: 90-95% cache hit rate
### Build Time Breakdown
| Job | Uncached | Cached |
|-----|----------|--------|
| Validate | 8-12 min | 3-5 min |
| Build Crates | 15-20 min | 5-8 min |
| Build WASM | 10-15 min | 4-6 min |
| Build Native (per platform) | 8-12 min | 3-5 min |
| Publish Crates | 5-10 min | 5-10 min |
| Publish npm | 3-5 min | 2-3 min |
| Create Release | 2-3 min | 2-3 min |
**Total (worst case)**: ~25-30 minutes with cache
**Total (cold start)**: ~45-60 minutes without cache
## Best Practices
1. **Always test locally first**
```bash
cargo test --workspace
cargo build --workspace --release
cd npm && npm run build
```
2. **Use semantic versioning**
- MAJOR.MINOR.PATCH (e.g., 0.1.3)
- Breaking changes: bump MAJOR
- New features: bump MINOR
- Bug fixes: bump PATCH
3. **Write clear commit messages**
```bash
feat: Add new vector search capability
fix: Resolve memory leak in HNSW index
chore: Bump dependencies
```
4. **Review workflow logs**
- Check for warnings
- Verify all tests passed
- Confirm all packages published
5. **Update CHANGELOG.md**
- Document breaking changes
- List new features
- Mention bug fixes
## Monitoring and Alerts
### GitHub Actions Notifications
1. Go to **Settings → Notifications**
2. Enable: "Actions - Only notify for failed workflows"
### Slack/Discord Integration
Add webhook to workflow:
```yaml
- name: Notify Slack
if: failure()
uses: slackapi/slack-github-action@v1
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "Release failed: ${{ github.ref }}"
}
```
## Version Management
### Cargo.toml Versions
All crates use workspace version:
```toml
[workspace.package]
version = "0.1.2"
```
Update once in root `Cargo.toml`, applies to all crates.
### package.json Versions
Update independently:
- `npm/packages/core/package.json`
- `npm/packages/wasm/package.json`
- `npm/packages/cli/package.json`
Or use `npm version`:
```bash
cd npm/packages/core
npm version patch # 0.1.2 -> 0.1.3
```
## Security Considerations
1. **Secrets**: Never log or expose `CARGO_REGISTRY_TOKEN` or `NPM_TOKEN`
2. **Branch protection**: Require reviews for version tags
3. **Environment protection**: Add reviewers for production environments
4. **Dependency scanning**: Enabled via GitHub security features
5. **Code signing**: Consider GPG signing for releases
## Future Enhancements
- [ ] Add code signing for native binaries
- [ ] Implement changelog generation from commits
- [ ] Add performance benchmarks to release notes
- [ ] Create Docker images as release artifacts
- [ ] Add automatic version bumping
- [ ] Implement release candidate (RC) workflow
- [ ] Add rollback capabilities
- [ ] Create platform-specific installers
- [ ] Add integration tests for published packages
- [ ] Implement canary releases
## Support
- **Issues**: https://github.com/ruvnet/ruvector/issues
- **Discussions**: https://github.com/ruvnet/ruvector/discussions
- **Documentation**: https://github.com/ruvnet/ruvector
## License
This workflow is part of the RuVector project and follows the same MIT license.

View File

@@ -0,0 +1,354 @@
name: Agentic-Synth CI/CD
on:
push:
branches:
- main
- develop
- 'claude/**'
paths:
- 'packages/agentic-synth/**'
- '.github/workflows/agentic-synth-ci.yml'
pull_request:
branches:
- main
- develop
paths:
- 'packages/agentic-synth/**'
workflow_dispatch:
inputs:
run_tests:
description: 'Run tests'
required: false
default: 'true'
run_benchmarks:
description: 'Run benchmarks'
required: false
default: 'false'
env:
NODE_VERSION: '18.x'
PACKAGE_PATH: packages/agentic-synth
jobs:
# Job 1: Code Quality Checks
quality:
name: Code Quality & Linting
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: npm install
- name: Run TypeScript type checking
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run typecheck
- name: Run ESLint
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run lint || echo "Linting warnings found"
- name: Check package.json validity
working-directory: ${{ env.PACKAGE_PATH }}
run: |
node -e "const pkg = require('./package.json'); console.log('Package:', pkg.name, pkg.version)"
npm pack --dry-run
# Job 2: Build & Test (Matrix)
build-test:
name: Build & Test (Node ${{ matrix.node-version }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: quality
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: ['18.x', '20.x', '22.x']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: npm install
- name: Build package (ESM + CJS)
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run build:all
- name: Verify build artifacts
working-directory: ${{ env.PACKAGE_PATH }}
run: |
ls -lah dist/
test -f dist/index.js || (echo "ESM build missing" && exit 1)
test -f dist/index.cjs || (echo "CJS build missing" && exit 1)
test -f dist/generators/index.js || (echo "Generators ESM missing" && exit 1)
test -f dist/cache/index.js || (echo "Cache ESM missing" && exit 1)
- name: Test CLI executable
working-directory: ${{ env.PACKAGE_PATH }}
run: |
chmod +x bin/cli.js
./bin/cli.js --help
./bin/cli.js config show || echo "Config command ran"
- name: Run unit tests
if: github.event.inputs.run_tests != 'false'
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run test:unit
- name: Run integration tests
if: github.event.inputs.run_tests != 'false'
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run test:integration || echo "Integration tests require API keys"
- name: Run CLI tests
if: github.event.inputs.run_tests != 'false'
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run test:cli || echo "CLI tests have known issues with JSON output format"
- name: Upload build artifacts
if: matrix.os == 'ubuntu-latest' && matrix.node-version == '20.x'
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
${{ env.PACKAGE_PATH }}/dist/
${{ env.PACKAGE_PATH }}/package.json
retention-days: 7
# Job 3: Test Coverage
coverage:
name: Test Coverage Report
runs-on: ubuntu-latest
needs: quality
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: npm install
- name: Run tests with coverage
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run test:coverage || echo "Coverage generation completed with warnings"
- name: Upload coverage reports
uses: codecov/codecov-action@v4
with:
files: ${{ env.PACKAGE_PATH }}/coverage/coverage-final.json
flags: agentic-synth
name: agentic-synth-coverage
fail_ci_if_error: false
- name: Coverage summary
working-directory: ${{ env.PACKAGE_PATH }}
run: |
if [ -d "coverage" ]; then
echo "## Test Coverage Summary" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
cat coverage/coverage-summary.txt || echo "Coverage summary not available"
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
# Job 4: Performance Benchmarks
benchmarks:
name: Performance Benchmarks
runs-on: ubuntu-latest
needs: build-test
if: github.event.inputs.run_benchmarks == 'true' || github.ref == 'refs/heads/main'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: npm install
- name: Build package
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run build:all
- name: Run benchmarks
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run benchmark || echo "Benchmarks completed"
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: ${{ env.PACKAGE_PATH }}/benchmarks/results/
retention-days: 30
# Job 5: Security Audit
security:
name: Security Audit
runs-on: ubuntu-latest
needs: quality
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Run npm audit
working-directory: ${{ env.PACKAGE_PATH }}
run: npm audit --audit-level=moderate || echo "Security audit found issues"
- name: Check for vulnerable dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: |
npm audit --json > audit-report.json || true
cat audit-report.json
# Job 6: Package Validation
package-validation:
name: NPM Package Validation
runs-on: ubuntu-latest
needs: build-test
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install dependencies
working-directory: ${{ env.PACKAGE_PATH }}
run: npm install
- name: Build package
working-directory: ${{ env.PACKAGE_PATH }}
run: npm run build:all
- name: Pack package
working-directory: ${{ env.PACKAGE_PATH }}
run: |
npm pack
tar -tzf *.tgz | head -50
- name: Validate package contents
working-directory: ${{ env.PACKAGE_PATH }}
run: |
tar -tzf *.tgz > package-contents.txt
echo "Checking for required files..."
grep "package/dist/index.js" package-contents.txt
grep "package/dist/index.cjs" package-contents.txt
grep "package/bin/cli.js" package-contents.txt
grep "package/README.md" package-contents.txt
echo "Package validation passed!"
- name: Test package installation
working-directory: ${{ env.PACKAGE_PATH }}
run: |
PACKAGE_FILE=$(ls *.tgz)
mkdir -p /tmp/test-install
cd /tmp/test-install
npm init -y
npm install $GITHUB_WORKSPACE/${{ env.PACKAGE_PATH }}/$PACKAGE_FILE
node -e "const synth = require('@ruvector/agentic-synth'); console.log('Import successful:', typeof synth)"
# Job 7: Documentation Check
docs:
name: Documentation Validation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check required documentation
working-directory: ${{ env.PACKAGE_PATH }}
run: |
test -f README.md || (echo "README.md missing" && exit 1)
test -f CHANGELOG.md || echo "CHANGELOG.md recommended"
test -f LICENSE || (echo "LICENSE missing" && exit 1)
test -d docs || (echo "docs/ directory missing" && exit 1)
echo "Documentation check passed!"
- name: Validate README
working-directory: ${{ env.PACKAGE_PATH }}
run: |
grep -q "agentic-synth" README.md || (echo "Package name not in README" && exit 1)
grep -q "Installation" README.md || echo "Installation section recommended"
grep -q "Usage" README.md || echo "Usage section recommended"
echo "README validation passed!"
# Job 8: Integration Test Summary
integration-summary:
name: Generate Test Summary
runs-on: ubuntu-latest
needs: [quality, build-test, coverage, security, package-validation, docs]
if: always()
steps:
- name: Generate summary
run: |
echo "## Agentic-Synth CI/CD Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Job Status" >> $GITHUB_STEP_SUMMARY
echo "- Code Quality: ${{ needs.quality.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Build & Test: ${{ needs.build-test.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Coverage: ${{ needs.coverage.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Security: ${{ needs.security.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Package Validation: ${{ needs.package-validation.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Documentation: ${{ needs.docs.result }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Build Info" >> $GITHUB_STEP_SUMMARY
echo "- Branch: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- Node Version: ${{ env.NODE_VERSION }}" >> $GITHUB_STEP_SUMMARY
- name: Check overall status
if: needs.quality.result == 'failure' || needs.build-test.result == 'failure'
run: |
echo "::error::CI pipeline failed. Check individual job results."
exit 1

View File

@@ -0,0 +1,343 @@
name: Benchmarks
on:
pull_request:
paths:
- 'crates/ruvector-postgres/**'
- '.github/workflows/benchmarks.yml'
push:
branches:
- main
- develop
workflow_dispatch:
inputs:
run_sql_benchmarks:
description: 'Run SQL benchmarks'
required: false
default: 'false'
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
permissions:
contents: read
pull-requests: write
issues: write
jobs:
rust-benchmarks:
name: Rust Benchmarks
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-git-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-benchmarks-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-benchmarks-
${{ runner.os }}-cargo-build-
- name: Install PostgreSQL 17
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.6 --locked
- name: Initialize pgrx
working-directory: crates/ruvector-postgres
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
- name: Install criterion
run: cargo install cargo-criterion || true
- name: Run distance benchmarks
working-directory: crates/ruvector-postgres
run: |
cargo bench --features pg17 --bench distance_bench -- --output-format bencher | tee ../../distance_bench.txt
- name: Run index benchmarks
working-directory: crates/ruvector-postgres
run: |
cargo bench --features pg17 --bench index_bench -- --output-format bencher | tee ../../index_bench.txt
- name: Run quantization benchmarks
working-directory: crates/ruvector-postgres
run: |
cargo bench --features pg17 --bench quantization_bench -- --output-format bencher | tee ../../quantization_bench.txt
- name: Run quantized distance benchmarks
working-directory: crates/ruvector-postgres
run: |
cargo bench --features pg17 --bench quantized_distance_bench -- --output-format bencher | tee ../../quantized_distance_bench.txt
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: |
distance_bench.txt
index_bench.txt
quantization_bench.txt
quantized_distance_bench.txt
retention-days: 30
- name: Store benchmark result
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: benchmark-action/github-action-benchmark@v1
with:
name: Rust Benchmarks
tool: 'cargo'
output-file-path: distance_bench.txt
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: true
alert-threshold: '150%'
comment-on-alert: true
fail-on-alert: true
- name: Generate benchmark summary
run: |
cat > benchmark_summary.md <<EOF
# Benchmark Results Summary
## Distance Function Benchmarks
\`\`\`
$(head -n 50 distance_bench.txt)
\`\`\`
## HNSW Index Benchmarks
\`\`\`
$(head -n 50 index_bench.txt)
\`\`\`
## Quantization Benchmarks
\`\`\`
$(head -n 50 quantization_bench.txt)
\`\`\`
See full results in the artifacts.
EOF
- name: Comment PR with results
if: github.event_name == 'pull_request'
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('benchmark_summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
sql-benchmarks:
name: SQL Benchmarks
runs-on: ubuntu-latest
timeout-minutes: 60
if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_sql_benchmarks == 'true'
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: ruvector_bench
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Install pgrx
run: |
cargo install --locked cargo-pgrx
cargo pgrx init --pg16 /usr/lib/postgresql/16/bin/pg_config
- name: Install ruvector extension
working-directory: crates/ruvector-postgres
run: |
cargo pgrx install --release --pg-config /usr/lib/postgresql/16/bin/pg_config
- name: Install pgvector for comparison
run: |
sudo apt-get update
sudo apt-get install -y postgresql-server-dev-16
git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git /tmp/pgvector
cd /tmp/pgvector
make
sudo make install
- name: Setup test database
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: postgres
PGDATABASE: ruvector_bench
run: |
psql -c 'CREATE EXTENSION IF NOT EXISTS ruvector;'
psql -c 'CREATE EXTENSION IF NOT EXISTS pgvector;'
- name: Run quick SQL benchmark
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: postgres
PGDATABASE: ruvector_bench
working-directory: crates/ruvector-postgres
run: |
psql -f benches/sql/quick_benchmark.sql | tee ../../sql_quick_bench.txt
- name: Run full workload benchmark
env:
PGHOST: localhost
PGPORT: 5432
PGUSER: postgres
PGPASSWORD: postgres
PGDATABASE: ruvector_bench
working-directory: crates/ruvector-postgres
run: |
psql -f benches/sql/benchmark_workload.sql | tee ../../sql_workload_bench.txt
- name: Upload SQL benchmark results
uses: actions/upload-artifact@v4
with:
name: sql-benchmark-results
path: |
sql_quick_bench.txt
sql_workload_bench.txt
retention-days: 30
benchmark-comparison:
name: Compare with Baseline
runs-on: ubuntu-latest
needs: rust-benchmarks
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download current benchmarks
uses: actions/download-artifact@v4
with:
name: benchmark-results
path: current
- name: Checkout base branch
run: |
git checkout ${{ github.base_ref }}
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Install PostgreSQL 17
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.6 --locked
- name: Initialize pgrx
working-directory: crates/ruvector-postgres
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
- name: Run baseline benchmarks
working-directory: crates/ruvector-postgres
run: |
cargo bench --features pg17 --bench distance_bench -- --output-format bencher | tee ../../baseline_distance.txt
cargo bench --features pg17 --bench index_bench -- --output-format bencher | tee ../../baseline_index.txt
- name: Compare results
run: |
echo "# Benchmark Comparison" > comparison.md
echo "" >> comparison.md
echo "## Distance Benchmarks" >> comparison.md
echo "" >> comparison.md
echo "### Baseline (main)" >> comparison.md
echo "\`\`\`" >> comparison.md
head -n 20 baseline_distance.txt >> comparison.md
echo "\`\`\`" >> comparison.md
echo "" >> comparison.md
echo "### Current (PR)" >> comparison.md
echo "\`\`\`" >> comparison.md
head -n 20 current/distance_bench.txt >> comparison.md
echo "\`\`\`" >> comparison.md
- name: Comment comparison
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const comparison = fs.readFileSync('comparison.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comparison
});

View File

@@ -0,0 +1,400 @@
name: Build Attention Native Modules
# Trigger build for v0.1.30 release
on:
push:
branches: [main]
paths:
- 'crates/ruvector-attention/**'
- 'crates/ruvector-attention-node/**'
- 'crates/ruvector-attention-wasm/**'
- '.github/workflows/build-attention.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-attention/**'
- 'crates/ruvector-attention-node/**'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: attention-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli
- name: Install dependencies
working-directory: crates/ruvector-attention-node
run: npm install
- name: Build native module
working-directory: crates/ruvector-attention-node
run: napi build --platform --release --target ${{ matrix.settings.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: List built files
shell: bash
run: |
echo "=== Built .node files ==="
find crates/ruvector-attention-node -name "*.node" -type f
ls -la crates/ruvector-attention-node/*.node 2>/dev/null || true
- name: Copy to platform package
shell: bash
run: |
# Find the built .node file
NODE_FILE=$(find crates/ruvector-attention-node -name "*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
exit 1
fi
echo "Found: $NODE_FILE"
# Determine destination based on platform
case "${{ matrix.settings.platform }}" in
linux-x64-gnu)
DEST_DIR="crates/ruvector-attention-node/npm/linux-x64-gnu"
DEST_FILE="attention.linux-x64-gnu.node"
;;
linux-arm64-gnu)
DEST_DIR="crates/ruvector-attention-node/npm/linux-arm64-gnu"
DEST_FILE="attention.linux-arm64-gnu.node"
;;
darwin-x64)
DEST_DIR="crates/ruvector-attention-node/npm/darwin-x64"
DEST_FILE="attention.darwin-x64.node"
;;
darwin-arm64)
DEST_DIR="crates/ruvector-attention-node/npm/darwin-arm64"
DEST_FILE="attention.darwin-arm64.node"
;;
win32-x64-msvc)
DEST_DIR="crates/ruvector-attention-node/npm/win32-x64-msvc"
DEST_FILE="attention.win32-x64-msvc.node"
;;
esac
mkdir -p "$DEST_DIR"
cp -v "$NODE_FILE" "$DEST_DIR/$DEST_FILE"
ls -la "$DEST_DIR/"
- name: Test native module
if: |
(matrix.settings.platform == 'linux-x64-gnu' && runner.os == 'Linux') ||
(matrix.settings.platform == 'darwin-x64' && runner.os == 'macOS' && runner.arch == 'X64') ||
(matrix.settings.platform == 'darwin-arm64' && runner.os == 'macOS' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
shell: bash
run: |
NODE_FILE=$(find crates/ruvector-attention-node -name "*.node" -type f | head -1)
echo "Testing: $NODE_FILE"
node -e "
const native = require('./$NODE_FILE');
console.log('Exports:', Object.keys(native));
console.log('✅ Native module loaded successfully');
"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: attention-${{ matrix.settings.platform }}
path: crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
build-wasm:
name: Build WASM
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: attention-wasm
- name: Build WASM
working-directory: crates/ruvector-attention-wasm
run: wasm-pack build --target nodejs --release
- name: List built files
run: ls -la crates/ruvector-attention-wasm/pkg/
- name: Upload WASM artifact
uses: actions/upload-artifact@v4
with:
name: attention-wasm
path: crates/ruvector-attention-wasm/pkg/
if-no-files-found: error
commit-binaries:
name: Commit Built Binaries
runs-on: ubuntu-22.04
needs: [build, build-wasm]
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy binaries to platform packages
run: |
echo "=== Downloaded artifacts ==="
find artifacts -name "*.node" -o -name "*.wasm"
# Copy native binaries
for platform in linux-x64-gnu linux-arm64-gnu darwin-x64 darwin-arm64 win32-x64-msvc; do
if [ -d "artifacts/attention-${platform}" ]; then
mkdir -p "crates/ruvector-attention-node/npm/${platform}"
cp -v artifacts/attention-${platform}/*.node "crates/ruvector-attention-node/npm/${platform}/" || true
fi
done
# Copy WASM
if [ -d "artifacts/attention-wasm" ]; then
mkdir -p crates/ruvector-attention-wasm/pkg
cp -rv artifacts/attention-wasm/* crates/ruvector-attention-wasm/pkg/
fi
- name: Show binary sizes
run: |
echo "=== Built Binaries ==="
find crates/ruvector-attention-node/npm -name "*.node" -exec ls -lh {} \;
find crates/ruvector-attention-wasm/pkg -name "*.wasm" -exec ls -lh {} \;
- name: Commit and push binaries
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f crates/ruvector-attention-node/npm/ crates/ruvector-attention-wasm/pkg/
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: Update attention NAPI-RS binaries for all platforms
Built from commit ${{ github.sha }}
Platforms updated:
- linux-x64-gnu
- linux-arm64-gnu
- darwin-x64
- darwin-arm64
- win32-x64-msvc
- wasm
🤖 Generated by GitHub Actions"
git push
fi
publish:
name: Publish Attention Platform Packages
runs-on: ubuntu-22.04
needs: [build, build-wasm]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List downloaded artifacts
run: |
echo "=== Downloaded artifacts ==="
find artifacts -name "*.node" -o -name "*.wasm" | head -50
- name: Publish platform packages to npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION=$(node -p "require('./crates/ruvector-attention-node/package.json').version")
echo "Publishing version: $VERSION"
# Publish each platform package
for dir in artifacts/attention-*/; do
platform=$(basename "$dir" | sed 's/attention-//')
# Skip wasm - handled separately
if [ "$platform" = "wasm" ]; then
continue
fi
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -z "$NODE_FILE" ]; then
echo "No .node file found in $dir"
continue
fi
echo "=== Publishing @ruvector/attention-${platform}@${VERSION} ==="
# Create package directory
PKG_DIR="npm-pkg/attention-${platform}"
mkdir -p "$PKG_DIR"
# Determine OS, CPU, and libc based on platform
case "$platform" in
linux-x64-gnu)
OS="linux"; CPU="x64"; LIBC='"libc": ["glibc"],'
NODE_NAME="attention.linux-x64-gnu.node"
;;
linux-arm64-gnu)
OS="linux"; CPU="arm64"; LIBC='"libc": ["glibc"],'
NODE_NAME="attention.linux-arm64-gnu.node"
;;
darwin-x64)
OS="darwin"; CPU="x64"; LIBC=""
NODE_NAME="attention.darwin-x64.node"
;;
darwin-arm64)
OS="darwin"; CPU="arm64"; LIBC=""
NODE_NAME="attention.darwin-arm64.node"
;;
win32-x64-msvc)
OS="win32"; CPU="x64"; LIBC=""
NODE_NAME="attention.win32-x64-msvc.node"
;;
*)
echo "Unknown platform: $platform"
continue
;;
esac
# Copy and rename binary
cp "$NODE_FILE" "$PKG_DIR/$NODE_NAME"
# Create package.json
cat > "$PKG_DIR/package.json" << EOF
{
"name": "@ruvector/attention-${platform}",
"version": "${VERSION}",
"os": ["${OS}"],
"cpu": ["${CPU}"],
${LIBC}
"main": "${NODE_NAME}",
"files": ["${NODE_NAME}"],
"description": "High-performance attention mechanisms - ${platform} platform binary",
"keywords": ["ruvector", "attention", "transformer", "napi-rs"],
"author": "rUv <ruv@ruv.io>",
"license": "MIT OR Apache-2.0",
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector"},
"engines": {"node": ">= 10"},
"publishConfig": {"registry": "https://registry.npmjs.org/", "access": "public"}
}
EOF
# Publish
cd "$PKG_DIR"
npm publish --access public || echo "Failed to publish @ruvector/attention-${platform} (may already exist)"
cd ../..
done
echo "=== Platform package publishing complete ==="
- name: Publish main attention package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
working-directory: crates/ruvector-attention-node
run: |
# Update optionalDependencies to include all ARM64 packages
VERSION=$(node -p "require('./package.json').version")
# Run prepublish to generate artifacts
npm run prepublishOnly || true
# Publish main package
npm publish --access public || echo "Failed to publish @ruvector/attention (may already exist)"
- name: Generate publish summary
run: |
echo "## Attention Package Publishing Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Published Platform Packages:" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention-linux-x64-gnu" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention-linux-arm64-gnu" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention-darwin-x64" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention-darwin-arm64" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention-win32-x64-msvc" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Main Package:" >> $GITHUB_STEP_SUMMARY
echo "- @ruvector/attention" >> $GITHUB_STEP_SUMMARY

View File

@@ -0,0 +1,321 @@
name: Build GNN Native Modules
on:
push:
branches: [main]
paths:
- 'crates/ruvector-gnn/**'
- 'crates/ruvector-gnn-node/**'
- '.github/workflows/build-gnn.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-gnn/**'
- 'crates/ruvector-gnn-node/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm after build'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: x86_64-unknown-linux-musl
platform: linux-x64-musl
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-musl
platform: linux-arm64-musl
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build GNN ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: gnn-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64 GNU)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install cross-compilation tools (Linux x64 musl)
if: matrix.settings.platform == 'linux-x64-musl'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- name: Install cross-compilation tools (Linux ARM64 musl)
if: matrix.settings.platform == 'linux-arm64-musl'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu musl-tools
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli
- name: Install dependencies
working-directory: crates/ruvector-gnn-node
run: npm install --ignore-scripts --omit=optional --force
- name: Build native module
working-directory: crates/ruvector-gnn-node
run: |
napi build --platform --release --target ${{ matrix.settings.target }} -p ruvector-gnn-node
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching for GNN .node files ==="
find crates/ruvector-gnn-node -name "*.node" -type f 2>/dev/null || true
- name: Prepare artifact
shell: bash
run: |
mkdir -p gnn-artifacts/${{ matrix.settings.platform }}
# Find the built .node file
NODE_FILE=$(find crates/ruvector-gnn-node -name "ruvector-gnn.*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
find crates/ruvector-gnn-node -name "*.node" -type f
exit 1
fi
echo "Found: $NODE_FILE"
cp -v "$NODE_FILE" "gnn-artifacts/${{ matrix.settings.platform }}/"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: gnn-bindings-${{ matrix.settings.platform }}
path: gnn-artifacts/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
commit-binaries:
name: Commit Built GNN Binaries
runs-on: ubuntu-22.04
needs: build
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy binaries to platform packages
run: |
echo "=== Downloaded artifacts ==="
find artifacts -name "*.node"
for platform in linux-x64-gnu linux-x64-musl linux-arm64-gnu linux-arm64-musl darwin-x64 darwin-arm64 win32-x64-msvc; do
if [ -d "artifacts/gnn-bindings-${platform}" ]; then
mkdir -p "crates/ruvector-gnn-node/npm/${platform}"
cp -v artifacts/gnn-bindings-${platform}/*.node "crates/ruvector-gnn-node/npm/${platform}/" || true
fi
done
- name: Show binary sizes
run: |
echo "=== Built GNN Binaries ==="
find crates/ruvector-gnn-node/npm -name "*.node" -exec ls -lh {} \; 2>/dev/null || true
- name: Commit and push binaries
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f crates/ruvector-gnn-node/npm/ || true
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: Update GNN NAPI-RS binaries for all platforms
Built from commit ${{ github.sha }}
Platforms updated:
- linux-x64-gnu
- linux-x64-musl
- linux-arm64-gnu
- linux-arm64-musl
- darwin-x64
- darwin-arm64
- win32-x64-msvc
Generated by GitHub Actions"
git push
fi
publish:
name: Publish GNN Platform Packages
runs-on: ubuntu-22.04
needs: [build, commit-binaries]
if: |
inputs.publish == true ||
startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create and publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION=$(node -p "require('./crates/ruvector-gnn-node/package.json').version")
echo "Publishing version: $VERSION"
for dir in artifacts/gnn-bindings-*/; do
platform=$(basename "$dir" | sed 's/gnn-bindings-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -z "$NODE_FILE" ]; then
echo "No .node file found in $dir"
continue
fi
echo "=== Publishing @ruvector/gnn-${platform}@${VERSION} ==="
# Create package directory
PKG_DIR="npm-pkg/gnn-${platform}"
mkdir -p "$PKG_DIR"
# Determine OS, CPU, and binary name
case "$platform" in
linux-x64-gnu)
OS="linux"; CPU="x64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-gnn.linux-x64-gnu.node"
;;
linux-x64-musl)
OS="linux"; CPU="x64"; LIBC='"libc": ["musl"],'
NODE_NAME="ruvector-gnn.linux-x64-musl.node"
;;
linux-arm64-gnu)
OS="linux"; CPU="arm64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-gnn.linux-arm64-gnu.node"
;;
linux-arm64-musl)
OS="linux"; CPU="arm64"; LIBC='"libc": ["musl"],'
NODE_NAME="ruvector-gnn.linux-arm64-musl.node"
;;
darwin-x64)
OS="darwin"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-gnn.darwin-x64.node"
;;
darwin-arm64)
OS="darwin"; CPU="arm64"; LIBC=""
NODE_NAME="ruvector-gnn.darwin-arm64.node"
;;
win32-x64-msvc)
OS="win32"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-gnn.win32-x64-msvc.node"
;;
esac
# Copy and rename binary
cp "$NODE_FILE" "$PKG_DIR/$NODE_NAME"
# Create package.json
cat > "$PKG_DIR/package.json" << EOF
{
"name": "@ruvector/gnn-${platform}",
"version": "${VERSION}",
"os": ["${OS}"],
"cpu": ["${CPU}"],
${LIBC}
"main": "${NODE_NAME}",
"files": ["${NODE_NAME}"],
"description": "Graph Neural Network capabilities for Ruvector - ${platform} platform",
"keywords": ["ruvector", "gnn", "graph-neural-network", "napi-rs"],
"author": "Ruvector Team",
"license": "MIT",
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector"},
"engines": {"node": ">= 10"},
"publishConfig": {"registry": "https://registry.npmjs.org/", "access": "public"}
}
EOF
# Verify binary exists before publish
if [ ! -f "$PKG_DIR/$NODE_NAME" ]; then
echo "ERROR: Binary $NODE_NAME missing from $PKG_DIR"
ls -la "$PKG_DIR/"
exit 1
fi
echo "Binary size: $(wc -c < "$PKG_DIR/$NODE_NAME") bytes"
# Publish
cd "$PKG_DIR"
npm publish --access public || echo "Failed to publish @ruvector/gnn-${platform}"
cd ../..
done
- name: Publish main @ruvector/gnn package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
working-directory: crates/ruvector-gnn-node
run: |
npm install --ignore-scripts --omit=optional --force
npm publish --access public || echo "Failed to publish @ruvector/gnn"

View File

@@ -0,0 +1,168 @@
name: Build Graph Node Native Modules
on:
push:
branches: [main]
paths:
- 'crates/ruvector-graph/**'
- 'crates/ruvector-graph-node/**'
- 'npm/packages/graph-node/**'
- '.github/workflows/build-graph-node.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-graph/**'
- 'crates/ruvector-graph-node/**'
- 'npm/packages/graph-node/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm after build'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build Graph ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: graph-node-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install dependencies
working-directory: npm/packages/graph-node
run: npm install --ignore-scripts --omit=optional --force
- name: Build native module
working-directory: npm/packages/graph-node
run: |
npx napi build --platform --release --cargo-cwd ../../../crates/ruvector-graph-node --target ${{ matrix.settings.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching for Graph .node files ==="
find npm/packages/graph-node -name "*.node" -type f 2>/dev/null || true
- name: Prepare artifact
shell: bash
run: |
mkdir -p graph-artifacts/${{ matrix.settings.platform }}
NODE_FILE=$(find npm/packages/graph-node -name "index.*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
find npm/packages/graph-node -name "*.node" -type f
exit 1
fi
echo "Found: $NODE_FILE"
cp -v "$NODE_FILE" "graph-artifacts/${{ matrix.settings.platform }}/"
- name: Test native module (native platform only)
if: |
(matrix.settings.platform == 'linux-x64-gnu' && runner.os == 'Linux') ||
(matrix.settings.platform == 'darwin-x64' && runner.os == 'macOS' && runner.arch == 'X64') ||
(matrix.settings.platform == 'darwin-arm64' && runner.os == 'macOS' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
working-directory: npm/packages/graph-node
run: npm test
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: graph-node-${{ matrix.settings.platform }}
path: graph-artifacts/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
publish:
name: Publish Graph Node Platform Packages
runs-on: ubuntu-22.04
needs: build
if: inputs.publish == true || startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy binaries to package
run: |
for dir in artifacts/graph-node-*/; do
platform=$(basename "$dir" | sed 's/graph-node-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -n "$NODE_FILE" ]; then
cp -v "$NODE_FILE" "npm/packages/graph-node/index.${platform}.node"
fi
done
ls -la npm/packages/graph-node/*.node
- name: Publish platform packages
working-directory: npm/packages/graph-node
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: node scripts/publish-platforms.js
- name: Publish main package
working-directory: npm/packages/graph-node
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public || echo "Package may already exist"

View File

@@ -0,0 +1,353 @@
name: Build Graph Transformer Native Modules
on:
push:
branches: [main]
paths:
- 'crates/ruvector-graph-transformer/**'
- 'crates/ruvector-graph-transformer-node/**'
- 'crates/ruvector-graph-transformer-wasm/**'
- '.github/workflows/build-graph-transformer.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-graph-transformer/**'
- 'crates/ruvector-graph-transformer-node/**'
- 'crates/ruvector-graph-transformer-wasm/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm after build'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: x86_64-unknown-linux-musl
platform: linux-x64-musl
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-musl
platform: linux-arm64-musl
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: graph-transformer-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64 GNU)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install cross-compilation tools (Linux x64 musl)
if: matrix.settings.platform == 'linux-x64-musl'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- name: Install cross-compilation tools (Linux ARM64 musl)
if: matrix.settings.platform == 'linux-arm64-musl'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu musl-tools
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli
- name: Install dependencies
working-directory: crates/ruvector-graph-transformer-node
run: npm install --ignore-scripts --omit=optional --force
- name: Build native module
working-directory: crates/ruvector-graph-transformer-node
run: |
napi build --platform --release --target ${{ matrix.settings.target }} -p ruvector-graph-transformer-node
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching for graph-transformer .node files ==="
find crates/ruvector-graph-transformer-node -name "*.node" -type f 2>/dev/null || true
- name: Prepare artifact
shell: bash
run: |
mkdir -p gt-artifacts/${{ matrix.settings.platform }}
NODE_FILE=$(find crates/ruvector-graph-transformer-node -name "ruvector-graph-transformer.*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
find crates/ruvector-graph-transformer-node -name "*.node" -type f
exit 1
fi
echo "Found: $NODE_FILE"
cp -v "$NODE_FILE" "gt-artifacts/${{ matrix.settings.platform }}/"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: gt-bindings-${{ matrix.settings.platform }}
path: gt-artifacts/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
build-wasm:
name: Build WASM
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: graph-transformer-wasm
- name: Install wasm-pack
run: cargo install wasm-pack --locked || true
- name: Build WASM
run: |
wasm-pack build crates/ruvector-graph-transformer-wasm --target web --release || \
cargo build -p ruvector-graph-transformer-wasm --target wasm32-unknown-unknown --release
- name: Upload WASM artifact
uses: actions/upload-artifact@v4
with:
name: graph-transformer-wasm
path: crates/ruvector-graph-transformer-wasm/pkg/
if-no-files-found: warn
commit-binaries:
name: Commit Built Binaries
runs-on: ubuntu-22.04
needs: [build, build-wasm]
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy binaries to platform packages
run: |
echo "=== Downloaded artifacts ==="
find artifacts -name "*.node" -o -name "*.wasm"
for platform in linux-x64-gnu linux-x64-musl linux-arm64-gnu linux-arm64-musl darwin-x64 darwin-arm64 win32-x64-msvc; do
if [ -d "artifacts/gt-bindings-${platform}" ]; then
mkdir -p "crates/ruvector-graph-transformer-node/npm/${platform}"
cp -v artifacts/gt-bindings-${platform}/*.node "crates/ruvector-graph-transformer-node/npm/${platform}/" || true
fi
done
if [ -d "artifacts/graph-transformer-wasm" ]; then
mkdir -p crates/ruvector-graph-transformer-wasm/pkg
cp -rv artifacts/graph-transformer-wasm/* crates/ruvector-graph-transformer-wasm/pkg/ || true
fi
- name: Show binary sizes
run: |
echo "=== Built Binaries ==="
find crates/ruvector-graph-transformer-node/npm -name "*.node" -exec ls -lh {} \; 2>/dev/null || true
find crates/ruvector-graph-transformer-wasm/pkg -name "*.wasm" -exec ls -lh {} \; 2>/dev/null || true
- name: Commit and push binaries
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f crates/ruvector-graph-transformer-node/npm/ crates/ruvector-graph-transformer-wasm/pkg/ || true
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: Update graph transformer NAPI-RS binaries for all platforms
Built from commit ${{ github.sha }}
Platforms updated:
- linux-x64-gnu
- linux-x64-musl
- linux-arm64-gnu
- linux-arm64-musl
- darwin-x64
- darwin-arm64
- win32-x64-msvc
- wasm
Generated by GitHub Actions"
git push
fi
publish:
name: Publish Platform Packages
runs-on: ubuntu-22.04
needs: [build, commit-binaries]
if: |
inputs.publish == true ||
startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create and publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION=$(node -p "require('./crates/ruvector-graph-transformer-node/package.json').version")
echo "Publishing version: $VERSION"
for dir in artifacts/gt-bindings-*/; do
platform=$(basename "$dir" | sed 's/gt-bindings-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -z "$NODE_FILE" ]; then
echo "No .node file found in $dir"
continue
fi
echo "=== Publishing @ruvector/graph-transformer-${platform}@${VERSION} ==="
PKG_DIR="npm-pkg/graph-transformer-${platform}"
mkdir -p "$PKG_DIR"
case "$platform" in
linux-x64-gnu)
OS="linux"; CPU="x64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-graph-transformer.linux-x64-gnu.node"
;;
linux-x64-musl)
OS="linux"; CPU="x64"; LIBC='"libc": ["musl"],'
NODE_NAME="ruvector-graph-transformer.linux-x64-musl.node"
;;
linux-arm64-gnu)
OS="linux"; CPU="arm64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-graph-transformer.linux-arm64-gnu.node"
;;
linux-arm64-musl)
OS="linux"; CPU="arm64"; LIBC='"libc": ["musl"],'
NODE_NAME="ruvector-graph-transformer.linux-arm64-musl.node"
;;
darwin-x64)
OS="darwin"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-graph-transformer.darwin-x64.node"
;;
darwin-arm64)
OS="darwin"; CPU="arm64"; LIBC=""
NODE_NAME="ruvector-graph-transformer.darwin-arm64.node"
;;
win32-x64-msvc)
OS="win32"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-graph-transformer.win32-x64-msvc.node"
;;
esac
cp "$NODE_FILE" "$PKG_DIR/$NODE_NAME"
cat > "$PKG_DIR/package.json" << EOF
{
"name": "@ruvector/graph-transformer-${platform}",
"version": "${VERSION}",
"os": ["${OS}"],
"cpu": ["${CPU}"],
${LIBC}
"main": "${NODE_NAME}",
"files": ["${NODE_NAME}"],
"description": "Proof-gated graph transformer - ${platform} platform binary",
"keywords": ["ruvector", "graph-transformer", "napi-rs"],
"author": "Ruvector Team",
"license": "MIT",
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector"},
"engines": {"node": ">= 10"},
"publishConfig": {"registry": "https://registry.npmjs.org/", "access": "public"}
}
EOF
if [ ! -f "$PKG_DIR/$NODE_NAME" ]; then
echo "ERROR: Binary $NODE_NAME missing from $PKG_DIR"
ls -la "$PKG_DIR/"
exit 1
fi
echo "Binary size: $(wc -c < "$PKG_DIR/$NODE_NAME") bytes"
cd "$PKG_DIR"
npm publish --access public || echo "Failed to publish @ruvector/graph-transformer-${platform}"
cd ../..
done
- name: Publish main @ruvector/graph-transformer package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
working-directory: crates/ruvector-graph-transformer-node
run: |
npm install --ignore-scripts --omit=optional --force
npm publish --access public --ignore-scripts || echo "Failed to publish @ruvector/graph-transformer"

View File

@@ -0,0 +1,242 @@
name: Build Native Modules
on:
push:
branches: [main]
tags:
- 'v*'
pull_request:
branches: [main]
workflow_dispatch:
inputs:
skip_commit:
description: 'Skip committing binaries'
required: false
type: boolean
default: false
workflow_call:
inputs:
skip_commit:
description: 'Skip committing binaries'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
build: npm run build:napi -- --target x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
build: npm run build:napi -- --target aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
build: npm run build:napi -- --target x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
build: npm run build:napi -- --target aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
build: npm run build:napi -- --target x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli@^2.18.0
- name: Build native module
working-directory: npm/packages/core
run: ${{ matrix.settings.build }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching entire workspace for .node files ==="
find . -name "*.node" -type f 2>/dev/null || true
echo "=== Checking npm/packages/core ==="
ls -la npm/packages/core/*.node 2>/dev/null || echo "No .node in npm/packages/core/"
ls -R npm/packages/core | grep "\.node" || echo "No .node files found"
- name: Copy binary to platform package
shell: bash
run: |
# NAPI-RS creates files as npm/packages/core/index.{platform}.node
# We need to copy them to npm/core/platforms/{platform}/ruvector.node
# Map platform names (NAPI-RS uses different naming for some platforms)
case "${{ matrix.settings.platform }}" in
linux-x64-gnu)
NAPI_PLATFORM="linux-x64-gnu"
;;
linux-arm64-gnu)
NAPI_PLATFORM="linux-arm64-gnu"
;;
darwin-x64)
NAPI_PLATFORM="darwin-x64"
;;
darwin-arm64)
NAPI_PLATFORM="darwin-arm64"
;;
win32-x64-msvc)
NAPI_PLATFORM="win32-x64-msvc"
;;
esac
SRC_FILE="npm/packages/core/index.${NAPI_PLATFORM}.node"
DEST_DIR="npm/core/platforms/${{ matrix.settings.platform }}"
DEST_FILE="${DEST_DIR}/ruvector.node"
echo "Looking for: $SRC_FILE"
ls -lah "$SRC_FILE" || {
echo "ERROR: Expected file not found: $SRC_FILE"
echo "Searching for any .node files..."
find npm/packages/core -name "*.node" -type f
exit 1
}
echo "Copying $SRC_FILE to $DEST_FILE"
mkdir -p "$DEST_DIR"
cp -v "$SRC_FILE" "$DEST_FILE"
echo "Verifying copy:"
ls -lah "$DEST_FILE"
- name: Test native module (native platform only)
if: |
(matrix.settings.platform == 'linux-x64-gnu' && runner.os == 'Linux') ||
(matrix.settings.platform == 'darwin-x64' && runner.os == 'macOS' && runner.arch == 'X64') ||
(matrix.settings.platform == 'darwin-arm64' && runner.os == 'macOS' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
shell: bash
run: |
# Test the locally built .node file directly
NODE_FILE="npm/packages/core/index.${{ matrix.settings.platform }}.node"
if [ -f "$NODE_FILE" ]; then
echo "Testing native module: $NODE_FILE"
node -e "
const native = require('./$NODE_FILE');
console.log('Native module exports:', Object.keys(native));
console.log('✅ Native module loaded successfully');
"
else
echo "⚠️ Native module not found at $NODE_FILE - skipping test"
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.platform }}
path: npm/core/platforms/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
# NOTE: build-graph job temporarily disabled until ruvector-graph-node compilation issues are fixed
# See PR #15 for details
commit-binaries:
name: Commit Built Binaries
runs-on: ubuntu-22.04
needs: build
if: |
!inputs.skip_commit &&
(github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main'))
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy binaries to platform packages
run: |
for dir in artifacts/bindings-*/; do
platform=$(basename "$dir" | sed 's/bindings-//')
mkdir -p "npm/core/platforms/${platform}"
cp -v "$dir"/*.node "npm/core/platforms/${platform}/"
done
# Also copy linux-x64 to native directory
if [ -f "npm/core/platforms/linux-x64-gnu/ruvector.node" ]; then
mkdir -p npm/core/native/linux-x64
cp -v npm/core/platforms/linux-x64-gnu/ruvector.node npm/core/native/linux-x64/
fi
- name: Show binary sizes
run: |
echo "=== Built Binaries ==="
find npm/core/platforms -name "*.node" -exec ls -lh {} \;
find npm/core/native -name "*.node" -exec ls -lh {} \; 2>/dev/null || true
- name: Commit and push binaries
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f npm/core/platforms/ npm/core/native/
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: Update NAPI-RS binaries for all platforms
Built from commit ${{ github.sha }}
Platforms updated:
- linux-x64-gnu
- linux-arm64-gnu
- darwin-x64
- darwin-arm64
- win32-x64-msvc
🤖 Generated by GitHub Actions"
git push
fi
# NOTE: Publish step removed - packages are published manually
# Use `npm publish` in the respective package directories after downloading
# artifacts from a successful build run

View File

@@ -0,0 +1,244 @@
name: Build Router Native Modules
on:
push:
branches: [main]
paths:
- 'crates/ruvector-router-core/**'
- 'crates/ruvector-router-ffi/**'
- 'npm/packages/router/**'
- '.github/workflows/build-router.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-router-core/**'
- 'crates/ruvector-router-ffi/**'
- 'npm/packages/router/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm after build'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build Router ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: router-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install dependencies
working-directory: npm/packages/router
run: npm install --ignore-scripts --omit=optional --force
- name: Build native module
working-directory: npm/packages/router
run: |
npx napi build --platform --release --cargo-cwd ../../../crates/ruvector-router-ffi --target ${{ matrix.settings.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching for Router .node files ==="
find npm/packages/router -name "*.node" -type f 2>/dev/null || true
find crates/ruvector-router-ffi -name "*.node" -type f 2>/dev/null || true
- name: Prepare artifact
shell: bash
run: |
mkdir -p router-artifacts/${{ matrix.settings.platform }}
# Find the built .node file
NODE_FILE=$(find npm/packages/router -name "*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
NODE_FILE=$(find crates/ruvector-router-ffi -name "*.node" -type f | head -1)
fi
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
exit 1
fi
echo "Found: $NODE_FILE"
cp -v "$NODE_FILE" "router-artifacts/${{ matrix.settings.platform }}/"
- name: Test native module (native platform only)
if: |
(matrix.settings.platform == 'linux-x64-gnu' && runner.os == 'Linux') ||
(matrix.settings.platform == 'darwin-x64' && runner.os == 'macOS' && runner.arch == 'X64') ||
(matrix.settings.platform == 'darwin-arm64' && runner.os == 'macOS' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
working-directory: npm/packages/router
run: npm test
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: router-${{ matrix.settings.platform }}
path: router-artifacts/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
publish:
name: Publish Router Platform Packages
runs-on: ubuntu-22.04
needs: build
if: inputs.publish == true || startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create and publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION=$(node -p "require('./npm/packages/router/package.json').version")
echo "Publishing version: $VERSION"
for dir in artifacts/router-*/; do
platform=$(basename "$dir" | sed 's/router-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -z "$NODE_FILE" ]; then
echo "No .node file found in $dir"
continue
fi
echo "=== Publishing @ruvector/router-${platform}@${VERSION} ==="
# Create package directory
PKG_DIR="npm-pkg/router-${platform}"
mkdir -p "$PKG_DIR"
# Determine OS and CPU
case "$platform" in
linux-x64-gnu)
OS="linux"; CPU="x64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-router.linux-x64-gnu.node"
;;
linux-arm64-gnu)
OS="linux"; CPU="arm64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-router.linux-arm64-gnu.node"
;;
darwin-x64)
OS="darwin"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-router.darwin-x64.node"
;;
darwin-arm64)
OS="darwin"; CPU="arm64"; LIBC=""
NODE_NAME="ruvector-router.darwin-arm64.node"
;;
win32-x64-msvc)
OS="win32"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-router.win32-x64-msvc.node"
;;
esac
# Copy and rename binary
cp "$NODE_FILE" "$PKG_DIR/$NODE_NAME"
# Create package.json
cat > "$PKG_DIR/package.json" << EOF
{
"name": "@ruvector/router-${platform}",
"version": "${VERSION}",
"os": ["${OS}"],
"cpu": ["${CPU}"],
${LIBC}
"main": "${NODE_NAME}",
"files": ["${NODE_NAME}"],
"description": "Semantic router for AI agents - ${platform} platform",
"keywords": ["ruvector", "router", "semantic-router", "napi-rs"],
"author": "ruv.io Team <info@ruv.io>",
"license": "MIT",
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector"},
"engines": {"node": ">= 18"},
"publishConfig": {"registry": "https://registry.npmjs.org/", "access": "public"}
}
EOF
# Publish
cd "$PKG_DIR"
npm publish --access public || echo "Failed to publish @ruvector/router-${platform}"
cd ../..
done
- name: Copy binaries to main package
run: |
for dir in artifacts/router-*/; do
platform=$(basename "$dir" | sed 's/router-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -n "$NODE_FILE" ]; then
cp -v "$NODE_FILE" "npm/packages/router/ruvector-router.${platform}.node"
fi
done
ls -la npm/packages/router/*.node || true
- name: Publish main package
working-directory: npm/packages/router
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public || echo "Package may already exist"

View File

@@ -0,0 +1,205 @@
name: Build RVF Node Native Modules
on:
push:
branches: [main]
paths:
- 'crates/rvf/rvf-node/**'
- 'crates/rvf/rvf-runtime/**'
- 'npm/packages/rvf-node/**'
pull_request:
branches: [main]
paths:
- 'crates/rvf/rvf-node/**'
- 'crates/rvf/rvf-runtime/**'
- 'npm/packages/rvf-node/**'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: rvf-node-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli@^2.18.0
- name: Build rvf-node native module
shell: bash
working-directory: crates/rvf/rvf-node
run: |
napi build --platform --release --target ${{ matrix.settings.target }}
# NAPI CLI may output as index.<platform>.node; rename to rvf-node.<platform>.node
BUILT=$(ls -1 *.*.node 2>/dev/null | head -1)
EXPECTED="rvf-node.${{ matrix.settings.platform }}.node"
if [ -n "$BUILT" ] && [ "$BUILT" != "$EXPECTED" ]; then
mv -v "$BUILT" "$EXPECTED"
fi
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_AARCH64_APPLE_DARWIN_RUSTFLAGS: "-C link-arg=-undefined -C link-arg=dynamic_lookup"
CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS: "-C link-arg=-undefined -C link-arg=dynamic_lookup"
- name: List built artifacts
shell: bash
run: |
echo "=== Built .node files ==="
find crates/rvf/rvf-node -name "*.node" -type f -exec ls -lh {} \;
- name: Copy binary to platform package
shell: bash
run: |
SRC=$(find crates/rvf/rvf-node -maxdepth 1 -name "rvf-node.*.node" -type f | head -1)
FNAME=$(basename "$SRC")
# Copy to npm platform package (avoid same-file error)
PLAT_DIR="crates/rvf/rvf-node/npm/${{ matrix.settings.platform }}"
mkdir -p "$PLAT_DIR"
if [ "$(realpath "$SRC")" != "$(realpath "$PLAT_DIR/$FNAME" 2>/dev/null)" ]; then
cp -v "$SRC" "$PLAT_DIR/$FNAME"
else
echo "Source and dest are same file, skipping copy to platform dir"
fi
# Copy to main rvf-node package
if [ "$(realpath "$SRC")" != "$(realpath "npm/packages/rvf-node/$FNAME" 2>/dev/null)" ]; then
cp -v "$SRC" "npm/packages/rvf-node/$FNAME"
else
echo "Source and dest are same file, skipping copy to main dir"
fi
echo "=== Platform package ==="
ls -lh "$PLAT_DIR/"
echo "=== Main package ==="
ls -lh "npm/packages/rvf-node/$FNAME"
- name: Test native module (native platform only)
if: |
(matrix.settings.platform == 'linux-x64-gnu') ||
(matrix.settings.platform == 'darwin-arm64' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'darwin-x64' && runner.arch == 'X64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
shell: bash
run: |
NODE_FILE=$(find crates/rvf/rvf-node -name "rvf-node.*.node" -type f | head -1)
if [ -f "$NODE_FILE" ]; then
echo "Testing: $NODE_FILE"
node -e "
const m = require('./$NODE_FILE');
console.log('Exports:', Object.keys(m));
if (m.RvfDatabase) {
console.log('RvfDatabase methods:', Object.getOwnPropertyNames(m.RvfDatabase.prototype || {}));
console.log('RvfDatabase static:', Object.keys(m.RvfDatabase));
}
console.log('OK');
"
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: rvf-node-${{ matrix.settings.platform }}
path: |
crates/rvf/rvf-node/npm/${{ matrix.settings.platform }}/rvf-node.*.node
if-no-files-found: error
commit-binaries:
name: Commit RVF Node Binaries
runs-on: ubuntu-22.04
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: main
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
pattern: rvf-node-*
- name: Copy binaries to packages
run: |
for dir in artifacts/rvf-node-*/; do
platform=$(basename "$dir" | sed 's/rvf-node-//')
mkdir -p "crates/rvf/rvf-node/npm/${platform}"
cp -v "$dir"/rvf-node.*.node "crates/rvf/rvf-node/npm/${platform}/"
cp -v "$dir"/rvf-node.*.node "npm/packages/rvf-node/"
done
- name: Show binary sizes
run: |
echo "=== RVF Node Binaries ==="
find crates/rvf/rvf-node/npm -name "*.node" -exec ls -lh {} \;
echo "=== Main package ==="
find npm/packages/rvf-node -name "*.node" -exec ls -lh {} \;
- name: Commit and push
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -f crates/rvf/rvf-node/npm/ npm/packages/rvf-node/*.node
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: Update RVF NAPI-RS binaries for all platforms
Built from commit ${{ github.sha }}
Platforms: linux-x64-gnu, linux-arm64-gnu, darwin-x64, darwin-arm64, win32-x64-msvc
Co-Authored-By: claude-flow <ruv@ruv.net>"
git push
fi

View File

@@ -0,0 +1,244 @@
name: Build Tiny Dancer Native Modules
on:
push:
branches: [main]
paths:
- 'crates/ruvector-tiny-dancer-core/**'
- 'crates/ruvector-tiny-dancer-node/**'
- 'npm/packages/tiny-dancer/**'
- '.github/workflows/build-tiny-dancer.yml'
tags:
- 'v*'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-tiny-dancer-core/**'
- 'crates/ruvector-tiny-dancer-node/**'
- 'npm/packages/tiny-dancer/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm after build'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
name: Build Tiny Dancer ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: tiny-dancer-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install dependencies
working-directory: npm/packages/tiny-dancer
run: npm install --ignore-scripts --omit=optional --force
- name: Build native module
working-directory: npm/packages/tiny-dancer
run: |
npx napi build --platform --release --cargo-cwd ../../../crates/ruvector-tiny-dancer-node --target ${{ matrix.settings.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Find built .node files (debug)
shell: bash
run: |
echo "=== Searching for Tiny Dancer .node files ==="
find npm/packages/tiny-dancer -name "*.node" -type f 2>/dev/null || true
find crates/ruvector-tiny-dancer-node -name "*.node" -type f 2>/dev/null || true
- name: Prepare artifact
shell: bash
run: |
mkdir -p tiny-dancer-artifacts/${{ matrix.settings.platform }}
# Find the built .node file
NODE_FILE=$(find npm/packages/tiny-dancer -name "*.node" -type f | head -1)
if [ -z "$NODE_FILE" ]; then
NODE_FILE=$(find crates/ruvector-tiny-dancer-node -name "*.node" -type f | head -1)
fi
if [ -z "$NODE_FILE" ]; then
echo "ERROR: No .node file found"
exit 1
fi
echo "Found: $NODE_FILE"
cp -v "$NODE_FILE" "tiny-dancer-artifacts/${{ matrix.settings.platform }}/"
- name: Test native module (native platform only)
if: |
(matrix.settings.platform == 'linux-x64-gnu' && runner.os == 'Linux') ||
(matrix.settings.platform == 'darwin-x64' && runner.os == 'macOS' && runner.arch == 'X64') ||
(matrix.settings.platform == 'darwin-arm64' && runner.os == 'macOS' && runner.arch == 'ARM64') ||
(matrix.settings.platform == 'win32-x64-msvc' && runner.os == 'Windows')
continue-on-error: true
working-directory: npm/packages/tiny-dancer
run: npm test
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: tiny-dancer-${{ matrix.settings.platform }}
path: tiny-dancer-artifacts/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
publish:
name: Publish Tiny Dancer Platform Packages
runs-on: ubuntu-22.04
needs: build
if: inputs.publish == true || startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create and publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION="0.1.15"
echo "Publishing version: $VERSION"
for dir in artifacts/tiny-dancer-*/; do
platform=$(basename "$dir" | sed 's/tiny-dancer-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -z "$NODE_FILE" ]; then
echo "No .node file found in $dir"
continue
fi
echo "=== Publishing @ruvector/tiny-dancer-${platform}@${VERSION} ==="
# Create package directory
PKG_DIR="npm-pkg/tiny-dancer-${platform}"
mkdir -p "$PKG_DIR"
# Determine OS and CPU
case "$platform" in
linux-x64-gnu)
OS="linux"; CPU="x64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-tiny-dancer.linux-x64-gnu.node"
;;
linux-arm64-gnu)
OS="linux"; CPU="arm64"; LIBC='"libc": ["glibc"],'
NODE_NAME="ruvector-tiny-dancer.linux-arm64-gnu.node"
;;
darwin-x64)
OS="darwin"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-tiny-dancer.darwin-x64.node"
;;
darwin-arm64)
OS="darwin"; CPU="arm64"; LIBC=""
NODE_NAME="ruvector-tiny-dancer.darwin-arm64.node"
;;
win32-x64-msvc)
OS="win32"; CPU="x64"; LIBC=""
NODE_NAME="ruvector-tiny-dancer.win32-x64-msvc.node"
;;
esac
# Copy and rename binary
cp "$NODE_FILE" "$PKG_DIR/$NODE_NAME"
# Create package.json
cat > "$PKG_DIR/package.json" << EOF
{
"name": "@ruvector/tiny-dancer-${platform}",
"version": "${VERSION}",
"os": ["${OS}"],
"cpu": ["${CPU}"],
${LIBC}
"main": "${NODE_NAME}",
"files": ["${NODE_NAME}"],
"description": "Neural router for AI agent orchestration - ${platform} platform",
"keywords": ["ruvector", "tiny-dancer", "neural-router", "napi-rs"],
"author": "ruv.io Team <info@ruv.io>",
"license": "MIT",
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector"},
"engines": {"node": ">= 18"},
"publishConfig": {"registry": "https://registry.npmjs.org/", "access": "public"}
}
EOF
# Publish
cd "$PKG_DIR"
npm publish --access public || echo "Failed to publish @ruvector/tiny-dancer-${platform}"
cd ../..
done
- name: Copy binaries to main package
run: |
for dir in artifacts/tiny-dancer-*/; do
platform=$(basename "$dir" | sed 's/tiny-dancer-//')
NODE_FILE=$(find "$dir" -name "*.node" | head -1)
if [ -n "$NODE_FILE" ]; then
cp -v "$NODE_FILE" "npm/packages/tiny-dancer/ruvector-tiny-dancer.${platform}.node"
fi
done
ls -la npm/packages/tiny-dancer/*.node || true
- name: Publish main package
working-directory: npm/packages/tiny-dancer
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public || echo "Package may already exist"

View File

@@ -0,0 +1,68 @@
name: ruvector-verified CI
on:
push:
paths:
- "crates/ruvector-verified/**"
- "Cargo.lock"
pull_request:
paths:
- "crates/ruvector-verified/**"
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
check:
runs-on: ubuntu-latest
strategy:
matrix:
feature-set:
- ""
- "--features hnsw-proofs"
- "--features rvf-proofs"
- "--features coherence-proofs"
- "--features all-proofs"
- "--features ultra"
- "--features serde"
- "--all-features"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Check (${{ matrix.feature-set || 'default' }})
run: cargo check -p ruvector-verified ${{ matrix.feature-set }}
test:
runs-on: ubuntu-latest
needs: check
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run tests (all features)
run: cargo test -p ruvector-verified --all-features
- name: Run tests (default features)
run: cargo test -p ruvector-verified
bench:
runs-on: ubuntu-latest
needs: check
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Run benchmarks (dry-run)
run: cargo bench -p ruvector-verified --all-features -- --test
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Clippy (all features)
run: cargo clippy -p ruvector-verified --all-features -- -D warnings

View File

@@ -0,0 +1,27 @@
name: Copilot Setup Steps
on:
workflow_call:
jobs:
copilot-setup:
runs-on: ubuntu-latest
environment: copilot
steps:
- name: Cleanup before git clone
run: rm -rf /home/runner/work/ruvector/ruvector
continue-on-error: true
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install ruvector dependencies
run: npm install -g ruvector
- name: Verify ruvector MCP
run: npx ruvector --version

View File

@@ -0,0 +1,193 @@
# RuVector-Postgres Docker Hub Publication
# Publishes multi-arch Docker images to Docker Hub on release
#
# Triggers:
# - On release creation (v* tags)
# - Manual workflow dispatch
#
# Images published:
# - ruvector/ruvector-postgres:latest
# - ruvector/ruvector-postgres:2.0.0
# - ruvector/ruvector-postgres:2.0.0-pg17
# - ruvector/ruvector-postgres:pg17
# - (Same for pg14, pg15, pg16)
name: Docker Hub Publish
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 2.0.0)'
required: true
default: '2.0.0'
pg_versions:
description: 'PostgreSQL versions (comma-separated)'
required: false
default: '14,15,16,17'
env:
DOCKER_REGISTRY: ruvector
IMAGE_NAME: ruvector-postgres
RUST_VERSION: '1.83'
jobs:
# ============================================================================
# Build and Push Docker Images
# ============================================================================
build-and-push:
name: Build & Push PG${{ matrix.pg_version }}
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
pg_version: [14, 15, 16, 17]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Extract version
id: version
run: |
if [ "${{ github.event_name }}" == "release" ]; then
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
else
VERSION="${{ github.event.inputs.version }}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Building version: $VERSION"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ steps.version.outputs.version }}-pg${{ matrix.pg_version }}
type=raw,value=v${{ steps.version.outputs.version }}-pg${{ matrix.pg_version }}
type=raw,value=pg${{ matrix.pg_version }}
type=raw,value=latest,enable=${{ matrix.pg_version == 17 }}
type=raw,value=${{ steps.version.outputs.version }},enable=${{ matrix.pg_version == 17 }}
type=raw,value=v${{ steps.version.outputs.version }},enable=${{ matrix.pg_version == 17 }}
labels: |
org.opencontainers.image.title=RuVector PostgreSQL Extension v2
org.opencontainers.image.description=High-performance vector database extension for PostgreSQL with 230+ SQL functions
org.opencontainers.image.vendor=ruv.io
ruvector.pg.version=${{ matrix.pg_version }}
ruvector.features=attention,gnn,hybrid,tenancy,healing,learning,hyperbolic,graph,gated-transformer,integrity
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: crates/ruvector-postgres/docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
PG_VERSION=${{ matrix.pg_version }}
RUST_VERSION=${{ env.RUST_VERSION }}
cache-from: type=gha,scope=pg${{ matrix.pg_version }}
cache-to: type=gha,mode=max,scope=pg${{ matrix.pg_version }}
- name: Test published image
run: |
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}-pg${{ matrix.pg_version }}
docker run -d \
--name ruvector-test-${{ matrix.pg_version }} \
-e POSTGRES_USER=ruvector \
-e POSTGRES_PASSWORD=ruvector \
-e POSTGRES_DB=ruvector_test \
${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}-pg${{ matrix.pg_version }}
# Wait for PostgreSQL to start
sleep 30
# Verify extension
docker exec ruvector-test-${{ matrix.pg_version }} \
psql -U ruvector -d ruvector_test -c "CREATE EXTENSION IF NOT EXISTS ruvector; SELECT ruvector_version();"
# Cleanup
docker rm -f ruvector-test-${{ matrix.pg_version }}
# ============================================================================
# Update Docker Hub Description
# ============================================================================
update-description:
name: Update Docker Hub Description
runs-on: ubuntu-latest
needs: build-and-push
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}
readme-filepath: crates/ruvector-postgres/docker/README.md
short-description: "RuVector v2 - High-performance PostgreSQL vector extension with 230+ SQL functions, SIMD, Flash Attention, GNN, hybrid search"
# ============================================================================
# Publication Summary
# ============================================================================
summary:
name: Publication Summary
runs-on: ubuntu-latest
needs: [build-and-push, update-description]
if: always()
steps:
- name: Generate summary
run: |
echo "## Docker Hub Publication Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Published Images" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Image | PostgreSQL | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|------------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| \`${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest\` | 17 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| \`${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:pg17\` | 17 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| \`${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:pg16\` | 16 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| \`${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:pg15\` | 15 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| \`${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:pg14\` | 14 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Quick Start" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo "docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=secret ${{ env.DOCKER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY

View File

@@ -0,0 +1,455 @@
# Edge-Net Model Optimization Workflow
#
# Automatically optimizes ONNX models when a new release is created
# - Quantizes models to INT4 and INT8
# - Uploads to Google Cloud Storage
# - Optionally pins to IPFS
# - Updates registry.json
name: Edge-Net Model Optimization
on:
# Trigger on release creation
release:
types: [published]
# Manual trigger with model selection
workflow_dispatch:
inputs:
models:
description: 'Comma-separated list of model IDs to optimize (or "all")'
required: true
default: 'minilm-l6,distilgpt2'
quantization:
description: 'Quantization types to generate'
required: true
default: 'int4,int8'
type: choice
options:
- 'int4,int8'
- 'int4'
- 'int8'
- 'fp16'
- 'int4,int8,fp16'
upload_ipfs:
description: 'Upload to IPFS'
required: false
default: false
type: boolean
upload_gcs:
description: 'Upload to Google Cloud Storage'
required: false
default: true
type: boolean
env:
NODE_VERSION: '20'
PYTHON_VERSION: '3.11'
GCS_BUCKET: ruvector-models
MODELS_DIR: examples/edge-net/pkg/models
ONNX_CACHE_DIR: /tmp/.ruvector/models/onnx
jobs:
# Determine which models to process
prepare:
name: Prepare Model List
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
quantizations: ${{ steps.set-matrix.outputs.quantizations }}
steps:
- uses: actions/checkout@v4
- name: Set model matrix
id: set-matrix
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
MODELS="${{ github.event.inputs.models }}"
QUANT="${{ github.event.inputs.quantization }}"
else
# On release, optimize tier 1 models by default
MODELS="minilm-l6,e5-small,distilgpt2,tinystories,starcoder-tiny"
QUANT="int4,int8"
fi
if [ "$MODELS" = "all" ]; then
MODELS=$(jq -r '.models | keys | join(",")' ${{ env.MODELS_DIR }}/registry.json)
fi
# Convert to JSON array
MODELS_JSON=$(echo "$MODELS" | tr ',' '\n' | jq -R . | jq -s .)
QUANT_JSON=$(echo "$QUANT" | tr ',' '\n' | jq -R . | jq -s .)
echo "matrix=$MODELS_JSON" >> $GITHUB_OUTPUT
echo "quantizations=$QUANT_JSON" >> $GITHUB_OUTPUT
echo "Models to process: $MODELS"
echo "Quantizations: $QUANT"
# Optimize models in parallel
optimize:
name: Optimize ${{ matrix.model }}
runs-on: ubuntu-latest
needs: prepare
strategy:
fail-fast: false
matrix:
model: ${{ fromJson(needs.prepare.outputs.matrix) }}
quantization: ${{ fromJson(needs.prepare.outputs.quantizations) }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: ${{ env.MODELS_DIR }}/../package-lock.json
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: Install dependencies
working-directory: ${{ env.MODELS_DIR }}/..
run: |
npm ci
pip install onnxruntime onnx onnxruntime-tools
- name: Cache ONNX models
uses: actions/cache@v4
with:
path: ${{ env.ONNX_CACHE_DIR }}
key: onnx-${{ matrix.model }}-${{ hashFiles('**/registry.json') }}
restore-keys: |
onnx-${{ matrix.model }}-
onnx-
- name: Download model
working-directory: ${{ env.MODELS_DIR }}/..
run: |
echo "Downloading model: ${{ matrix.model }}"
node models/models-cli.js download ${{ matrix.model }} --verify
env:
ONNX_CACHE_DIR: ${{ env.ONNX_CACHE_DIR }}
- name: Optimize model
working-directory: ${{ env.MODELS_DIR }}/..
run: |
echo "Optimizing ${{ matrix.model }} with ${{ matrix.quantization }}"
# Create output directory
OUTPUT_DIR="optimized/${{ matrix.model }}/${{ matrix.quantization }}"
mkdir -p "$OUTPUT_DIR"
# Run optimization via CLI
node models/models-cli.js optimize ${{ matrix.model }} \
--quantize ${{ matrix.quantization }} \
--output "$OUTPUT_DIR"
# List output files
echo "Optimized files:"
ls -lh "$OUTPUT_DIR"
env:
ONNX_CACHE_DIR: ${{ env.ONNX_CACHE_DIR }}
- name: Calculate checksums
working-directory: ${{ env.MODELS_DIR }}/..
run: |
OUTPUT_DIR="optimized/${{ matrix.model }}/${{ matrix.quantization }}"
# Generate checksums
cd "$OUTPUT_DIR"
sha256sum *.onnx > checksums.sha256 2>/dev/null || true
echo "Checksums:"
cat checksums.sha256 || echo "No ONNX files found"
- name: Upload optimized model artifact
uses: actions/upload-artifact@v4
with:
name: model-${{ matrix.model }}-${{ matrix.quantization }}
path: ${{ env.MODELS_DIR }}/../optimized/${{ matrix.model }}/${{ matrix.quantization }}
retention-days: 7
# Upload to Google Cloud Storage
upload-gcs:
name: Upload to GCS
runs-on: ubuntu-latest
needs: [prepare, optimize]
if: github.event.inputs.upload_gcs != 'false'
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Authenticate to GCP
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}
- name: Setup gcloud CLI
uses: google-github-actions/setup-gcloud@v2
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
- name: Upload to GCS
run: |
echo "Uploading models to gs://${{ env.GCS_BUCKET }}"
for model_dir in artifacts/model-*; do
if [ -d "$model_dir" ]; then
MODEL_NAME=$(basename "$model_dir" | sed 's/model-//' | sed 's/-int[48]//' | sed 's/-fp16//')
QUANT=$(basename "$model_dir" | grep -oE '(int4|int8|fp16)')
echo "Uploading $MODEL_NAME ($QUANT)"
gsutil -m cp -r "$model_dir/*" "gs://${{ env.GCS_BUCKET }}/$MODEL_NAME/$QUANT/"
fi
done
echo "Upload complete!"
gsutil ls -l "gs://${{ env.GCS_BUCKET }}/"
# Upload to IPFS via Pinata
upload-ipfs:
name: Upload to IPFS
runs-on: ubuntu-latest
needs: [prepare, optimize]
if: github.event.inputs.upload_ipfs == 'true'
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Pin to IPFS via Pinata
run: |
echo "Pinning models to IPFS via Pinata"
for model_dir in artifacts/model-*; do
if [ -d "$model_dir" ]; then
MODEL_NAME=$(basename "$model_dir")
echo "Pinning $MODEL_NAME"
# Create a tar archive for the model
tar -czf "${MODEL_NAME}.tar.gz" -C "$model_dir" .
# Pin to Pinata
RESPONSE=$(curl -s -X POST \
-H "pinata_api_key: ${{ secrets.PINATA_API_KEY }}" \
-H "pinata_secret_api_key: ${{ secrets.PINATA_SECRET }}" \
-F "file=@${MODEL_NAME}.tar.gz" \
-F "pinataMetadata={\"name\":\"${MODEL_NAME}\",\"keyvalues\":{\"type\":\"onnx-model\",\"repo\":\"ruvector\"}}" \
"https://api.pinata.cloud/pinning/pinFileToIPFS")
CID=$(echo "$RESPONSE" | jq -r '.IpfsHash')
echo " IPFS CID: $CID"
echo " Gateway URL: https://ipfs.io/ipfs/$CID"
# Save CID for registry update
echo "$MODEL_NAME=$CID" >> ipfs_cids.txt
fi
done
env:
PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }}
PINATA_SECRET: ${{ secrets.PINATA_SECRET }}
- name: Upload IPFS CIDs
uses: actions/upload-artifact@v4
with:
name: ipfs-cids
path: ipfs_cids.txt
retention-days: 30
# Update registry with new model information
update-registry:
name: Update Registry
runs-on: ubuntu-latest
needs: [optimize, upload-gcs]
if: always() && needs.optimize.result == 'success'
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref || github.ref_name }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Update registry.json
working-directory: ${{ env.MODELS_DIR }}
run: |
echo "Updating registry with new model artifacts"
# Load current registry
REGISTRY=$(cat registry.json)
for model_dir in ../../../artifacts/model-*; do
if [ -d "$model_dir" ]; then
MODEL_INFO=$(basename "$model_dir" | sed 's/model-//')
MODEL_NAME=$(echo "$MODEL_INFO" | sed 's/-int[48]$//' | sed 's/-fp16$//')
QUANT=$(echo "$MODEL_INFO" | grep -oE '(int4|int8|fp16)' || echo "original")
echo "Processing: $MODEL_NAME ($QUANT)"
# Get file sizes
TOTAL_SIZE=0
FILES_JSON="[]"
for file in "$model_dir"/*.onnx; do
if [ -f "$file" ]; then
FILENAME=$(basename "$file")
SIZE=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file")
HASH=$(sha256sum "$file" | cut -d' ' -f1)
FILES_JSON=$(echo "$FILES_JSON" | jq --arg f "$FILENAME" --argjson s "$SIZE" --arg h "$HASH" \
'. + [{"file": $f, "size": $s, "sha256": $h}]')
TOTAL_SIZE=$((TOTAL_SIZE + SIZE))
fi
done
# Update registry
REGISTRY=$(echo "$REGISTRY" | jq \
--arg model "$MODEL_NAME" \
--arg quant "$QUANT" \
--argjson files "$FILES_JSON" \
--arg size "$TOTAL_SIZE" \
--arg updated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg gcs "https://storage.googleapis.com/${{ env.GCS_BUCKET }}/$MODEL_NAME/$QUANT" \
'.models[$model].artifacts[$quant] = {
"files": $files,
"totalSize": ($size | tonumber),
"gcsUrl": $gcs,
"updated": $updated
} | .updated = $updated')
fi
done
# Save updated registry
echo "$REGISTRY" | jq '.' > registry.json
echo "Registry updated:"
jq '.models | to_entries[] | "\(.key): \(.value.artifacts | keys)"' registry.json
- name: Commit registry updates
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add ${{ env.MODELS_DIR }}/registry.json
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore(models): update registry with optimized models
Updated models: ${{ needs.prepare.outputs.matrix }}
Quantizations: ${{ needs.prepare.outputs.quantizations }}
[skip ci]"
git push
fi
# Run benchmarks on optimized models
benchmark:
name: Benchmark Models
runs-on: ubuntu-latest
needs: [optimize]
if: github.event_name == 'release'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: ${{ env.MODELS_DIR }}/../package-lock.json
- name: Install dependencies
working-directory: ${{ env.MODELS_DIR }}/..
run: npm ci
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Run benchmarks
working-directory: ${{ env.MODELS_DIR }}/..
run: |
echo "Running model benchmarks"
RESULTS="[]"
for model_dir in ../artifacts/model-*; do
if [ -d "$model_dir" ]; then
MODEL_INFO=$(basename "$model_dir" | sed 's/model-//')
MODEL_NAME=$(echo "$MODEL_INFO" | sed 's/-int[48]$//' | sed 's/-fp16$//')
echo "Benchmarking: $MODEL_NAME"
# Run benchmark
RESULT=$(node models/models-cli.js benchmark "$MODEL_NAME" \
--iterations 5 \
--warmup 1 \
--output /tmp/bench_${MODEL_NAME}.json 2>/dev/null || echo "{}")
if [ -f "/tmp/bench_${MODEL_NAME}.json" ]; then
RESULTS=$(echo "$RESULTS" | jq --slurpfile r "/tmp/bench_${MODEL_NAME}.json" '. + $r')
fi
fi
done
# Save all results
echo "$RESULTS" | jq '.' > benchmark_results.json
echo "Benchmark Results:"
jq '.' benchmark_results.json
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: ${{ env.MODELS_DIR }}/../benchmark_results.json
retention-days: 30
- name: Comment on release
if: github.event_name == 'release'
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.release.id }}
body: |
## Model Optimization Complete
Optimized models have been processed and uploaded.
**Models processed:**
${{ needs.prepare.outputs.matrix }}
**Quantizations:**
${{ needs.prepare.outputs.quantizations }}
**Artifacts:**
- GCS: `gs://${{ env.GCS_BUCKET }}/`
- Benchmark results available in workflow artifacts

View File

@@ -0,0 +1,214 @@
name: Hooks CI
on:
push:
branches: [main, claude/*]
paths:
- 'crates/ruvector-cli/src/cli/hooks.rs'
- 'crates/ruvector-cli/tests/hooks_tests.rs'
- 'npm/packages/cli/**'
- '.github/workflows/hooks-ci.yml'
pull_request:
branches: [main]
paths:
- 'crates/ruvector-cli/**'
- 'npm/packages/cli/**'
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
rust-cli-tests:
name: Rust CLI Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build CLI
run: cargo build -p ruvector-cli --release
- name: Run hooks unit tests
run: cargo test -p ruvector-cli hooks --release
- name: Test hooks commands
run: |
./target/release/ruvector hooks --help
./target/release/ruvector hooks stats
./target/release/ruvector hooks session-start
./target/release/ruvector hooks pre-edit src/main.rs
./target/release/ruvector hooks post-edit --success src/main.rs
./target/release/ruvector hooks remember --memory-type test "CI test content"
./target/release/ruvector hooks recall "CI test"
./target/release/ruvector hooks learn test-state test-action --reward 0.5
./target/release/ruvector hooks suggest edit-rs --actions coder,reviewer
./target/release/ruvector hooks route "test task"
./target/release/ruvector hooks should-test src/lib.rs
./target/release/ruvector hooks swarm-register ci-agent-1 rust-dev
./target/release/ruvector hooks swarm-stats
./target/release/ruvector hooks session-end
npm-cli-tests:
name: npm CLI Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
# Copy CLI package to temp location to avoid workspace interference
cp -r npm/packages/cli /tmp/cli
cd /tmp/cli
npm install --ignore-scripts
cp -r node_modules $GITHUB_WORKSPACE/npm/packages/cli/
- name: Build CLI
working-directory: npm/packages/cli
run: npm run build
- name: Test hooks commands
working-directory: npm/packages/cli
run: |
node dist/cli.js hooks --help
node dist/cli.js hooks stats
node dist/cli.js hooks session-start
node dist/cli.js hooks pre-edit src/test.ts
node dist/cli.js hooks post-edit --success src/test.ts
node dist/cli.js hooks remember --type test "CI test content"
node dist/cli.js hooks recall "CI test"
node dist/cli.js hooks learn test-state test-action --reward 0.5
node dist/cli.js hooks suggest edit-ts --actions coder,reviewer
node dist/cli.js hooks route "test task"
node dist/cli.js hooks should-test src/lib.ts
node dist/cli.js hooks swarm-register ci-agent typescript-dev
node dist/cli.js hooks swarm-coordinate ci-agent other-agent --weight 0.8
node dist/cli.js hooks swarm-optimize "task1,task2"
node dist/cli.js hooks swarm-recommend "typescript"
node dist/cli.js hooks swarm-stats
node dist/cli.js hooks session-end
postgres-schema-validation:
name: PostgreSQL Schema Validation
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: ruvector_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Install PostgreSQL client
run: sudo apt-get install -y postgresql-client
- name: Create ruvector type stub
run: |
psql "postgresql://test:test@localhost:5432/ruvector_test" <<EOF
-- Create a stub type for ruvector (actual extension not needed for schema validation)
CREATE DOMAIN ruvector AS REAL[];
-- Create stub operator for vector distance
CREATE FUNCTION ruvector_distance(ruvector, ruvector) RETURNS REAL AS \$\$
SELECT 0.0::REAL;
\$\$ LANGUAGE SQL;
CREATE OPERATOR <=> (
LEFTARG = ruvector,
RIGHTARG = ruvector,
FUNCTION = ruvector_distance
);
EOF
- name: Validate hooks schema
run: |
psql "postgresql://test:test@localhost:5432/ruvector_test" -f crates/ruvector-cli/sql/hooks_schema.sql
- name: Test schema functions
run: |
psql "postgresql://test:test@localhost:5432/ruvector_test" <<EOF
-- Test Q-learning update
SELECT ruvector_hooks_update_q('test_state', 'test_action', 0.8);
-- Test pattern retrieval
SELECT * FROM ruvector_hooks_patterns WHERE state = 'test_state';
-- Test agent registration
SELECT ruvector_hooks_swarm_register('test-agent', 'developer', ARRAY['rust', 'python']);
-- Test swarm stats
SELECT * FROM ruvector_hooks_swarm_stats();
-- Test session start
SELECT * FROM ruvector_hooks_session_start();
-- Verify stats
SELECT * FROM ruvector_hooks_get_stats();
EOF
feature-parity-check:
name: Feature Parity Check
runs-on: ubuntu-latest
needs: [rust-cli-tests, npm-cli-tests]
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Build both CLIs
run: |
cargo build -p ruvector-cli --release
# Install CLI deps in temp to avoid workspace interference
cp -r npm/packages/cli /tmp/cli
cd /tmp/cli && npm install --ignore-scripts && npm run build
cp -r /tmp/cli/node_modules npm/packages/cli/
cp -r /tmp/cli/dist npm/packages/cli/
- name: Compare command counts
run: |
RUST_COUNT=$(./target/release/ruvector hooks --help | grep -E "^ [a-z]" | wc -l)
NPM_COUNT=$(cd npm/packages/cli && node dist/cli.js hooks --help | grep -E "^ [a-z]" | wc -l)
echo "Rust CLI commands: $RUST_COUNT"
echo "npm CLI commands: $NPM_COUNT"
if [ "$RUST_COUNT" -ne "$NPM_COUNT" ]; then
echo "⚠️ Feature parity mismatch: Rust has $RUST_COUNT, npm has $NPM_COUNT"
echo "This is informational only - some commands may be Rust-specific"
else
echo "✅ Feature parity: Both CLIs have $RUST_COUNT commands"
fi

View File

@@ -0,0 +1,286 @@
name: PostgreSQL Extension CI
on:
push:
branches: [main, develop, "claude/**", "fix/**"]
paths:
- 'crates/ruvector-postgres/**'
- '.github/workflows/postgres-extension-ci.yml'
pull_request:
branches: [main, develop]
paths:
- 'crates/ruvector-postgres/**'
- '.github/workflows/postgres-extension-ci.yml'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
permissions:
contents: read
pull-requests: write
jobs:
# Build and test matrix for multiple PostgreSQL versions
test:
name: Test PostgreSQL ${{ matrix.pg_version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
pg_version: [17]
rust: [stable]
include:
# Test on macOS for pg17
- os: macos-latest
pg_version: 17
rust: stable
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy
- name: Install PostgreSQL (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-${{ matrix.pg_version }} postgresql-server-dev-${{ matrix.pg_version }}
echo "/usr/lib/postgresql/${{ matrix.pg_version }}/bin" >> $GITHUB_PATH
- name: Install PostgreSQL (macOS)
if: runner.os == 'macOS'
run: |
brew install postgresql@${{ matrix.pg_version }}
echo "/opt/homebrew/opt/postgresql@${{ matrix.pg_version }}/bin" >> $GITHUB_PATH
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-index-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ matrix.pg_version }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-target-${{ matrix.pg_version }}-
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.9 --locked
- name: Initialize pgrx (Ubuntu)
if: runner.os == 'Linux'
run: cargo pgrx init --pg${{ matrix.pg_version }}=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Initialize pgrx (macOS)
if: runner.os == 'macOS'
run: cargo pgrx init --pg${{ matrix.pg_version }}=/opt/homebrew/opt/postgresql@${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Check code formatting
run: cargo fmt --all -- --check
working-directory: crates/ruvector-postgres
- name: Run clippy
run: cargo clippy --no-default-features --features pg${{ matrix.pg_version }} -- -D warnings
working-directory: crates/ruvector-postgres
- name: Build extension
run: cargo build --no-default-features --features pg${{ matrix.pg_version }} --release
working-directory: crates/ruvector-postgres
- name: Run tests
run: cargo pgrx test pg${{ matrix.pg_version }} --no-default-features --features pg${{ matrix.pg_version }}
working-directory: crates/ruvector-postgres
# Test with all features enabled
test-all-features:
name: Test All Features (PostgreSQL 17)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Install PostgreSQL
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.9 --locked
- name: Initialize pgrx
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Build with all features
run: |
cargo build --no-default-features --features pg17,index-all,quant-all --release
working-directory: crates/ruvector-postgres
- name: Test with all features
run: |
cargo pgrx test pg17 --no-default-features --features pg17,index-all,quant-all
working-directory: crates/ruvector-postgres
# Benchmark on pull requests
benchmark:
name: Benchmark
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Install PostgreSQL
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.9 --locked
- name: Initialize pgrx
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Run benchmarks
run: cargo bench --no-default-features --features pg17 -- --output-format bencher | tee benchmark-output.txt
working-directory: crates/ruvector-postgres
- name: Store benchmark result
uses: benchmark-action/github-action-benchmark@v1
with:
name: Rust Benchmark
tool: 'cargo'
output-file-path: crates/ruvector-postgres/benchmark-output.txt
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: false
# Security audit
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Run cargo audit
uses: rustsec/audit-check@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
working-directory: crates/ruvector-postgres
# Package the extension
package:
name: Package Extension
runs-on: ubuntu-latest
needs: [test, test-all-features]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
matrix:
pg_version: [17]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Install PostgreSQL
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-${{ matrix.pg_version }} postgresql-server-dev-${{ matrix.pg_version }}
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version 0.12.9 --locked
- name: Initialize pgrx
run: cargo pgrx init --pg${{ matrix.pg_version }}=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Package extension
run: cargo pgrx package --no-default-features --features pg${{ matrix.pg_version }}
working-directory: crates/ruvector-postgres
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ruvector-postgres-pg${{ matrix.pg_version }}
path: target/release/ruvector-postgres-pg${{ matrix.pg_version }}/
retention-days: 30
# Integration tests with Docker
integration-test:
name: Integration Test (Docker)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
file: crates/ruvector-postgres/Dockerfile
push: false
tags: ruvector-postgres:test
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run integration tests
run: |
docker run --rm ruvector-postgres:test psql --version
docker run --rm ruvector-postgres:test pg_config --version

View File

@@ -0,0 +1,552 @@
name: Build & Publish All Packages
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 0.1.31)'
required: true
type: string
publish_crates:
description: 'Publish to crates.io'
required: false
type: boolean
default: true
publish_npm:
description: 'Publish to npm'
required: false
type: boolean
default: true
dry_run:
description: 'Dry run (build only, no publish)'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ============================================================================
# Phase 1: Validate and Test
# ============================================================================
validate:
name: Validate & Test
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache Rust
uses: Swatinem/rust-cache@v2
- name: Run tests
run: |
cargo test -p ruvector-math -p ruvector-attention --all-features
echo "✅ All tests passed" >> $GITHUB_STEP_SUMMARY
# ============================================================================
# Phase 2: Build Native Binaries (Node.js NAPI)
# ============================================================================
build-native:
name: Build ${{ matrix.settings.platform }}
runs-on: ${{ matrix.settings.host }}
needs: validate
strategy:
fail-fast: false
matrix:
settings:
- host: ubuntu-22.04
target: x86_64-unknown-linux-gnu
platform: linux-x64-gnu
node_file: attention.linux-x64-gnu.node
- host: ubuntu-22.04
target: aarch64-unknown-linux-gnu
platform: linux-arm64-gnu
node_file: attention.linux-arm64-gnu.node
- host: macos-14
target: x86_64-apple-darwin
platform: darwin-x64
node_file: attention.darwin-x64.node
- host: macos-14
target: aarch64-apple-darwin
platform: darwin-arm64
node_file: attention.darwin-arm64.node
- host: windows-2022
target: x86_64-pc-windows-msvc
platform: win32-x64-msvc
node_file: attention.win32-x64-msvc.node
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.settings.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: native-${{ matrix.settings.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.settings.platform == 'linux-arm64-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install NAPI-RS CLI
run: npm install -g @napi-rs/cli
- name: Install dependencies
working-directory: crates/ruvector-attention-node
run: npm install
- name: Build native module
working-directory: crates/ruvector-attention-node
run: napi build --platform --release --target ${{ matrix.settings.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Copy to platform package
shell: bash
run: |
NODE_FILE=$(find crates/ruvector-attention-node -name "*.node" -type f | head -1)
mkdir -p "crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}"
cp -v "$NODE_FILE" "crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}/${{ matrix.settings.node_file }}"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.settings.platform }}
path: crates/ruvector-attention-node/npm/${{ matrix.settings.platform }}/*.node
if-no-files-found: error
# ============================================================================
# Phase 3: Build WASM Packages
# ============================================================================
build-wasm:
name: Build WASM
runs-on: ubuntu-22.04
needs: validate
strategy:
matrix:
package:
- name: ruvector-math-wasm
path: crates/ruvector-math-wasm
- name: ruvector-attention-wasm
path: crates/ruvector-attention-wasm
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: wasm-${{ matrix.package.name }}
- name: Build WASM (web target)
working-directory: ${{ matrix.package.path }}
run: wasm-pack build --target web --release
- name: Upload WASM artifact
uses: actions/upload-artifact@v4
with:
name: wasm-${{ matrix.package.name }}
path: ${{ matrix.package.path }}/pkg/
if-no-files-found: error
# ============================================================================
# Phase 4: Publish to crates.io
# ============================================================================
publish-crates:
name: Publish to crates.io
runs-on: ubuntu-22.04
needs: [build-native, build-wasm]
if: ${{ !inputs.dry_run && (inputs.publish_crates || github.event_name == 'push') }}
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Publish ruvector-math
run: cargo publish -p ruvector-math --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
continue-on-error: true
- name: Wait for crates.io index
run: sleep 30
- name: Publish ruvector-attention
run: cargo publish -p ruvector-attention --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
continue-on-error: true
- name: Wait for crates.io index
run: sleep 30
- name: Publish ruvector-math-wasm
run: cargo publish -p ruvector-math-wasm --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
continue-on-error: true
- name: Publish ruvector-attention-wasm
run: cargo publish -p ruvector-attention-wasm --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
continue-on-error: true
- name: Summary
run: |
echo "## crates.io Publishing" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-math" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-attention" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-math-wasm" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-attention-wasm" >> $GITHUB_STEP_SUMMARY
# ============================================================================
# Phase 5: Publish to npm
# ============================================================================
publish-npm:
name: Publish to npm
runs-on: ubuntu-22.04
needs: [build-native, build-wasm]
if: ${{ !inputs.dry_run && (inputs.publish_npm || github.event_name == 'push') }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List downloaded artifacts
run: find artifacts -type f -name "*.node" -o -name "*.wasm" | head -50
# --- Publish WASM packages ---
- name: Publish @ruvector/math-wasm to npm
run: |
cd artifacts/wasm-ruvector-math-wasm
# Update package name to scoped
jq '.name = "@ruvector/math-wasm"' package.json > tmp.json && mv tmp.json package.json
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Publish @ruvector/attention-wasm to npm
run: |
cd artifacts/wasm-ruvector-attention-wasm
# Update package name to scoped
jq '.name = "@ruvector/attention-wasm"' package.json > tmp.json && mv tmp.json package.json
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
# --- Publish platform-specific native packages ---
- name: Prepare and publish @ruvector/attention-linux-x64-gnu
run: |
mkdir -p publish/linux-x64-gnu
cp artifacts/native-linux-x64-gnu/*.node publish/linux-x64-gnu/
cd publish/linux-x64-gnu
cat > package.json << 'EOF'
{
"name": "@ruvector/attention-linux-x64-gnu",
"version": "${{ inputs.version || '0.1.31' }}",
"os": ["linux"],
"cpu": ["x64"],
"main": "attention.linux-x64-gnu.node",
"files": ["attention.linux-x64-gnu.node"],
"description": "Linux x64 GNU native module for @ruvector/attention",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector"
}
EOF
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Prepare and publish @ruvector/attention-linux-arm64-gnu
run: |
mkdir -p publish/linux-arm64-gnu
cp artifacts/native-linux-arm64-gnu/*.node publish/linux-arm64-gnu/
cd publish/linux-arm64-gnu
cat > package.json << 'EOF'
{
"name": "@ruvector/attention-linux-arm64-gnu",
"version": "${{ inputs.version || '0.1.31' }}",
"os": ["linux"],
"cpu": ["arm64"],
"main": "attention.linux-arm64-gnu.node",
"files": ["attention.linux-arm64-gnu.node"],
"description": "Linux ARM64 GNU native module for @ruvector/attention",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector"
}
EOF
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Prepare and publish @ruvector/attention-darwin-x64
run: |
mkdir -p publish/darwin-x64
cp artifacts/native-darwin-x64/*.node publish/darwin-x64/
cd publish/darwin-x64
cat > package.json << 'EOF'
{
"name": "@ruvector/attention-darwin-x64",
"version": "${{ inputs.version || '0.1.31' }}",
"os": ["darwin"],
"cpu": ["x64"],
"main": "attention.darwin-x64.node",
"files": ["attention.darwin-x64.node"],
"description": "macOS Intel x64 native module for @ruvector/attention",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector"
}
EOF
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Prepare and publish @ruvector/attention-darwin-arm64
run: |
mkdir -p publish/darwin-arm64
cp artifacts/native-darwin-arm64/*.node publish/darwin-arm64/
cd publish/darwin-arm64
cat > package.json << 'EOF'
{
"name": "@ruvector/attention-darwin-arm64",
"version": "${{ inputs.version || '0.1.31' }}",
"os": ["darwin"],
"cpu": ["arm64"],
"main": "attention.darwin-arm64.node",
"files": ["attention.darwin-arm64.node"],
"description": "macOS Apple Silicon ARM64 native module for @ruvector/attention",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector"
}
EOF
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Prepare and publish @ruvector/attention-win32-x64-msvc
run: |
mkdir -p publish/win32-x64-msvc
cp artifacts/native-win32-x64-msvc/*.node publish/win32-x64-msvc/
cd publish/win32-x64-msvc
cat > package.json << 'EOF'
{
"name": "@ruvector/attention-win32-x64-msvc",
"version": "${{ inputs.version || '0.1.31' }}",
"os": ["win32"],
"cpu": ["x64"],
"main": "attention.win32-x64-msvc.node",
"files": ["attention.win32-x64-msvc.node"],
"description": "Windows x64 MSVC native module for @ruvector/attention",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector"
}
EOF
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
# --- Publish main @ruvector/attention package ---
- name: Publish @ruvector/attention (main package)
run: |
mkdir -p publish/attention-main
cd publish/attention-main
cat > package.json << 'EOF'
{
"name": "@ruvector/attention",
"version": "${{ inputs.version || '0.1.31' }}",
"description": "High-performance attention mechanisms with 7 mathematical theories: Optimal Transport, Mixed Curvature, Topology, Information Geometry, Information Bottleneck, PDE/Diffusion, Unified Diagnostics",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
"repository": "https://github.com/ruvnet/ruvector",
"keywords": ["attention", "transformer", "machine-learning", "optimal-transport", "hyperbolic", "topology"],
"optionalDependencies": {
"@ruvector/attention-linux-x64-gnu": "${{ inputs.version || '0.1.31' }}",
"@ruvector/attention-linux-arm64-gnu": "${{ inputs.version || '0.1.31' }}",
"@ruvector/attention-darwin-x64": "${{ inputs.version || '0.1.31' }}",
"@ruvector/attention-darwin-arm64": "${{ inputs.version || '0.1.31' }}",
"@ruvector/attention-win32-x64-msvc": "${{ inputs.version || '0.1.31' }}"
}
}
EOF
# Create index.js that loads the correct platform binary
cat > index.js << 'INDEXJS'
const { platform, arch } = process;
const platformPackages = {
'linux-x64': '@ruvector/attention-linux-x64-gnu',
'linux-arm64': '@ruvector/attention-linux-arm64-gnu',
'darwin-x64': '@ruvector/attention-darwin-x64',
'darwin-arm64': '@ruvector/attention-darwin-arm64',
'win32-x64': '@ruvector/attention-win32-x64-msvc',
};
const key = `${platform}-${arch}`;
const pkg = platformPackages[key];
if (!pkg) {
throw new Error(`Unsupported platform: ${key}. Supported: ${Object.keys(platformPackages).join(', ')}`);
}
module.exports = require(pkg);
INDEXJS
# Create TypeScript definitions
cat > index.d.ts << 'INDEXDTS'
export interface AttentionConfig {
dim: number;
numHeads?: number;
dropout?: number;
}
export function scaledDotProductAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[]): Float32Array;
export function multiHeadAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], config: AttentionConfig): Float32Array;
export function flashAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], blockSize?: number): Float32Array;
export function hyperbolicAttention(query: Float32Array, keys: Float32Array[], values: Float32Array[], curvature?: number): Float32Array;
INDEXDTS
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
continue-on-error: true
- name: Summary
run: |
echo "## npm Publishing" >> $GITHUB_STEP_SUMMARY
echo "### WASM Packages" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/math-wasm" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-wasm" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Native Packages" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-linux-x64-gnu" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-linux-arm64-gnu" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-darwin-x64" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-darwin-arm64" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention-win32-x64-msvc" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Main Package" >> $GITHUB_STEP_SUMMARY
echo "✅ @ruvector/attention" >> $GITHUB_STEP_SUMMARY
# ============================================================================
# Phase 6: Create GitHub Release
# ============================================================================
create-release:
name: Create GitHub Release
runs-on: ubuntu-22.04
needs: [publish-crates, publish-npm]
if: ${{ !inputs.dry_run && github.event_name == 'push' }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create release archives
run: |
mkdir -p release-assets
# Create platform archives
for platform in linux-x64-gnu linux-arm64-gnu darwin-x64 darwin-arm64 win32-x64-msvc; do
if [ -d "artifacts/native-${platform}" ]; then
tar -czvf "release-assets/ruvector-attention-${platform}.tar.gz" -C "artifacts/native-${platform}" .
fi
done
# Create WASM archives
for pkg in ruvector-math-wasm ruvector-attention-wasm; do
if [ -d "artifacts/wasm-${pkg}" ]; then
tar -czvf "release-assets/${pkg}.tar.gz" -C "artifacts/wasm-${pkg}" .
fi
done
- name: Create Release
uses: softprops/action-gh-release@v1
with:
name: Release ${{ github.ref_name }}
body: |
## RuVector Release ${{ github.ref_name }}
### Published Packages
#### crates.io
- `ruvector-math` - Advanced math primitives
- `ruvector-attention` - 7-theory attention mechanisms
- `ruvector-math-wasm` - WASM bindings for math
- `ruvector-attention-wasm` - WASM bindings for attention
#### npm
- `@ruvector/math-wasm` - Browser WASM package
- `@ruvector/attention` - Main Node.js package (auto-selects platform)
- `@ruvector/attention-wasm` - Browser WASM package
- Platform-specific: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64
### Installation
```bash
# Rust
cargo add ruvector-math ruvector-attention
# Node.js (auto-selects correct binary)
npm install @ruvector/attention
# Browser (WASM)
npm install @ruvector/math-wasm @ruvector/attention-wasm
```
files: release-assets/*
draft: false
prerelease: false

View File

@@ -0,0 +1,171 @@
name: Release RVF CLI
on:
push:
tags:
- 'rvf-v*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g. rvf-v0.1.0)'
required: true
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-22.04
name: rvf-linux-x64
ext: ''
- target: aarch64-unknown-linux-gnu
os: ubuntu-22.04
name: rvf-linux-arm64
ext: ''
cross: true
- target: x86_64-apple-darwin
os: macos-14
name: rvf-darwin-x64
ext: ''
- target: aarch64-apple-darwin
os: macos-14
name: rvf-darwin-arm64
ext: ''
- target: x86_64-pc-windows-msvc
os: windows-2022
name: rvf-windows-x64
ext: .exe
name: Build ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
key: rvf-cli-${{ matrix.target }}
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Build
shell: bash
run: cargo build -p rvf-cli --release --target ${{ matrix.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Package
shell: bash
run: |
BINARY="target/${{ matrix.target }}/release/rvf${{ matrix.ext }}"
ARCHIVE="${{ matrix.name }}${{ matrix.ext }}"
if [ "${{ matrix.ext }}" = ".exe" ]; then
cp "$BINARY" "$ARCHIVE"
else
chmod +x "$BINARY"
cp "$BINARY" "$ARCHIVE"
fi
ls -lh "$ARCHIVE"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}
path: ${{ matrix.name }}${{ matrix.ext }}
if-no-files-found: error
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-22.04
if: startsWith(github.ref, 'refs/tags/rvf-v') || github.event_name == 'workflow_dispatch'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release
for dir in artifacts/*/; do
name=$(basename "$dir")
file=$(ls "$dir" | head -1)
cp "$dir/$file" "release/$file"
done
ls -lh release/
- name: Compute checksums
working-directory: release
run: |
sha256sum * > checksums-sha256.txt
cat checksums-sha256.txt
- name: Determine tag
id: tag
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT"
else
echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
fi
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.tag.outputs.tag }}
name: "RVF CLI ${{ steps.tag.outputs.tag }}"
body: |
## RVF CLI Release
Standalone vector database CLI for creating, querying, and managing RVF stores.
### Download
| Platform | Binary |
|----------|--------|
| Linux x64 | `rvf-linux-x64` |
| Linux ARM64 | `rvf-linux-arm64` |
| macOS x64 (Intel) | `rvf-darwin-x64` |
| macOS ARM64 (Apple Silicon) | `rvf-darwin-arm64` |
| Windows x64 | `rvf-windows-x64.exe` |
### Quick start
```bash
# Download (macOS ARM64 example)
curl -L -o rvf https://github.com/ruvnet/ruvector/releases/download/${{ steps.tag.outputs.tag }}/rvf-darwin-arm64
chmod +x rvf
# Create a store and query
./rvf create mydb.rvf --dimension 128 --metric cosine
./rvf status mydb.rvf
```
See the [CLI README](https://github.com/ruvnet/ruvector/tree/main/crates/rvf/rvf-cli) for full documentation.
files: release/*
draft: false
prerelease: false

View File

@@ -0,0 +1,621 @@
name: Release Pipeline
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 0.1.3)'
required: true
type: string
skip_tests:
description: 'Skip test validation'
required: false
type: boolean
default: false
dry_run:
description: 'Dry run (no publishing)'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# Job 1: Validate code quality and run tests
validate:
name: Validate Code Quality
runs-on: ubuntu-22.04
if: ${{ !inputs.skip_tests }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt, clippy
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
prefix-key: 'v1-rust'
shared-key: 'validate'
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run Clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: Run Rust tests
run: cargo test --workspace --all-features
env:
RUST_TEST_THREADS: 2
- name: Install npm dependencies
working-directory: npm
run: npm ci
- name: Run npm tests
working-directory: npm
run: npm run test:unit || true
- name: Generate validation summary
if: always()
run: |
echo "## Validation Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Code formatting checked" >> $GITHUB_STEP_SUMMARY
echo "✅ Clippy lints passed" >> $GITHUB_STEP_SUMMARY
echo "✅ Rust tests completed" >> $GITHUB_STEP_SUMMARY
echo "✅ npm tests completed" >> $GITHUB_STEP_SUMMARY
# Job 2: Build and test Rust crates
build-crates:
name: Build Rust Crates
runs-on: ubuntu-22.04
needs: validate
if: always() && (needs.validate.result == 'success' || needs.validate.result == 'skipped')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
prefix-key: 'v1-rust'
shared-key: 'build-crates'
- name: Build all crates
run: cargo build --workspace --release
- name: Run crate tests
run: cargo test --workspace --release
env:
RUST_TEST_THREADS: 2
- name: Generate crate build summary
run: |
echo "## Crate Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Built Crates:" >> $GITHUB_STEP_SUMMARY
cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | "- \(.name) v\(.version)"' >> $GITHUB_STEP_SUMMARY
# Job 3: Build WASM packages
build-wasm:
name: Build WASM Packages
runs-on: ubuntu-22.04
needs: validate
if: always() && (needs.validate.result == 'success' || needs.validate.result == 'skipped')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: npm/package-lock.json
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
prefix-key: 'v1-rust'
shared-key: 'wasm'
- name: Cache wasm-pack
uses: actions/cache@v4
with:
path: |
~/.cargo/.crates.toml
~/.cargo/.crates2.json
~/.cargo/bin/wasm-pack
key: ${{ runner.os }}-wasm-pack-${{ hashFiles('**/Cargo.lock') }}
- name: Build ruvector-wasm
working-directory: crates/ruvector-wasm
run: wasm-pack build --target nodejs --out-dir ../../npm/packages/wasm/wasm-pkg
- name: Build ruvector-gnn-wasm
working-directory: crates/ruvector-gnn-wasm
run: wasm-pack build --target nodejs --release
- name: Build ruvector-graph-wasm
working-directory: crates/ruvector-graph-wasm
run: bash build.sh
- name: Build ruvector-tiny-dancer-wasm
working-directory: crates/ruvector-tiny-dancer-wasm
run: wasm-pack build --target nodejs --release
- name: Upload WASM artifacts
uses: actions/upload-artifact@v4
with:
name: wasm-packages
path: |
npm/packages/wasm/wasm-pkg/**
crates/ruvector-gnn-wasm/pkg/**
crates/ruvector-graph-wasm/pkg/**
crates/ruvector-tiny-dancer-wasm/pkg/**
if-no-files-found: error
retention-days: 7
- name: Generate WASM build summary
run: |
echo "## WASM Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-wasm built" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-gnn-wasm built" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-graph-wasm built" >> $GITHUB_STEP_SUMMARY
echo "✅ ruvector-tiny-dancer-wasm built" >> $GITHUB_STEP_SUMMARY
# Job 4: Build native Node.js modules (reuse existing workflow)
build-native:
name: Build Native Modules
needs: validate
if: always() && (needs.validate.result == 'success' || needs.validate.result == 'skipped')
uses: ./.github/workflows/build-native.yml
with:
skip_commit: true
# Job 5: Publish crates to crates.io
publish-crates:
name: Publish Rust Crates
runs-on: ubuntu-22.04
needs: [validate, build-crates]
if: |
always() &&
(needs.validate.result == 'success' || needs.validate.result == 'skipped') &&
needs.build-crates.result == 'success' &&
(startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') &&
!inputs.dry_run
environment:
name: crates-io
url: https://crates.io/crates/ruvector-core
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
prefix-key: 'v1-rust'
shared-key: 'publish'
- name: Verify CARGO_REGISTRY_TOKEN
run: |
if [ -z "${{ secrets.CARGO_REGISTRY_TOKEN }}" ]; then
echo "❌ CARGO_REGISTRY_TOKEN is not set"
exit 1
fi
echo "✅ CARGO_REGISTRY_TOKEN is configured"
- name: Publish crates in dependency order
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
set -e
# Define publishing order (dependencies first)
CRATES=(
"ruvector-core"
"ruvector-metrics"
"ruvector-filter"
"ruvector-snapshot"
"ruvector-collections"
"ruvector-router-core"
"ruvector-raft"
"ruvector-cluster"
"ruvector-replication"
"ruvector-gnn"
"ruvector-graph"
"ruvector-server"
"ruvector-tiny-dancer-core"
"ruvector-router-cli"
"ruvector-router-ffi"
"ruvector-router-wasm"
"ruvector-cli"
"ruvector-bench"
"ruvector-wasm"
"ruvector-node"
"ruvector-gnn-wasm"
"ruvector-gnn-node"
"ruvector-graph-wasm"
"ruvector-graph-node"
"ruvector-tiny-dancer-wasm"
"ruvector-tiny-dancer-node"
)
echo "## Crate Publishing Progress" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for crate in "${CRATES[@]}"; do
echo "Publishing $crate..."
# Check if crate exists
if [ ! -d "crates/$crate" ]; then
echo "⏭️ Skipping $crate (not found)" >> $GITHUB_STEP_SUMMARY
continue
fi
cd "crates/$crate"
# Try to publish, continue if already published
if cargo publish --token "$CARGO_REGISTRY_TOKEN" --allow-dirty; then
echo "✅ Published $crate" >> $GITHUB_STEP_SUMMARY
# Wait to avoid rate limiting
sleep 10
else
echo "⚠️ Failed to publish $crate (may already exist)" >> $GITHUB_STEP_SUMMARY
fi
cd ../..
done
- name: Verify published crates
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Verification" >> $GITHUB_STEP_SUMMARY
echo "Check published crates at: https://crates.io/search?q=ruvector" >> $GITHUB_STEP_SUMMARY
# Job 6: Prepare npm packages for manual publishing
# NOTE: Automatic npm publishing disabled - packages are published manually
prepare-npm:
name: Prepare npm Packages
runs-on: ubuntu-22.04
needs: [validate, build-native, build-wasm]
if: |
always() &&
(needs.validate.result == 'success' || needs.validate.result == 'skipped') &&
needs.build-native.result == 'success' &&
needs.build-wasm.result == 'success' &&
(startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Download native binaries
uses: actions/download-artifact@v4
with:
pattern: bindings-*
path: artifacts
- name: Download WASM packages
uses: actions/download-artifact@v4
with:
name: wasm-packages
path: wasm-artifacts
- name: Copy native binaries to platform packages
run: |
for dir in artifacts/bindings-*/; do
platform=$(basename "$dir" | sed 's/bindings-//')
mkdir -p "npm/core/platforms/${platform}"
cp -v "$dir"/*.node "npm/core/platforms/${platform}/" || true
done
# Copy linux-x64 to native directory
if [ -f "npm/core/platforms/linux-x64-gnu/ruvector.node" ]; then
mkdir -p npm/core/native/linux-x64
cp -v npm/core/platforms/linux-x64-gnu/ruvector.node npm/core/native/linux-x64/
fi
- name: Copy WASM packages
run: |
# Copy main WASM package
if [ -d "wasm-artifacts/npm/packages/wasm/wasm-pkg" ]; then
cp -r wasm-artifacts/npm/packages/wasm/wasm-pkg/* npm/packages/wasm/wasm-pkg/
fi
- name: Install dependencies
working-directory: npm
run: npm ci || npm install --ignore-scripts
- name: Build npm packages
working-directory: npm
run: npm run build || echo "Build step skipped"
- name: Package artifacts for manual publishing
run: |
mkdir -p npm-publish-ready
# Copy platform binaries
cp -r npm/core/platforms npm-publish-ready/ || true
cp -r npm/core/native npm-publish-ready/ || true
# Create manifest
echo "# NPM Packages Ready for Publishing" > npm-publish-ready/README.md
echo "" >> npm-publish-ready/README.md
echo "## Platform binaries included:" >> npm-publish-ready/README.md
find npm-publish-ready/platforms -name "*.node" 2>/dev/null | while read f; do
echo "- $(basename $f)" >> npm-publish-ready/README.md
done
echo "" >> npm-publish-ready/README.md
echo "## Manual publishing commands:" >> npm-publish-ready/README.md
echo "\`\`\`bash" >> npm-publish-ready/README.md
echo "# Login to npm" >> npm-publish-ready/README.md
echo "npm login" >> npm-publish-ready/README.md
echo "" >> npm-publish-ready/README.md
echo "# Publish packages" >> npm-publish-ready/README.md
echo "cd npm/packages/core && npm publish --access public" >> npm-publish-ready/README.md
echo "cd npm/packages/wasm && npm publish --access public" >> npm-publish-ready/README.md
echo "cd npm/packages/cli && npm publish --access public" >> npm-publish-ready/README.md
echo "cd npm/packages/ruvector && npm publish --access public" >> npm-publish-ready/README.md
echo "\`\`\`" >> npm-publish-ready/README.md
- name: Upload npm-ready artifacts
uses: actions/upload-artifact@v4
with:
name: npm-publish-ready
path: npm-publish-ready/
retention-days: 30
- name: Generate npm preparation summary
run: |
echo "## npm Package Preparation Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Native binaries copied to platform packages" >> $GITHUB_STEP_SUMMARY
echo "✅ WASM packages prepared" >> $GITHUB_STEP_SUMMARY
echo "✅ Packages ready for manual publishing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Manual Publishing Required" >> $GITHUB_STEP_SUMMARY
echo "Download the \`npm-publish-ready\` artifact and run:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "npm login" >> $GITHUB_STEP_SUMMARY
echo "npm publish --access public" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# Job 7: Create GitHub release
create-release:
name: Create GitHub Release
runs-on: ubuntu-22.04
needs: [build-crates, build-native, build-wasm, publish-crates, prepare-npm]
if: |
always() &&
needs.build-crates.result == 'success' &&
needs.build-native.result == 'success' &&
needs.build-wasm.result == 'success' &&
(startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch')
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download native binaries
uses: actions/download-artifact@v4
with:
pattern: bindings-*
path: release-artifacts
- name: Download WASM packages
uses: actions/download-artifact@v4
with:
name: wasm-packages
path: release-artifacts/wasm
- name: Package artifacts for release
run: |
mkdir -p release-packages
# Package native binaries
for dir in release-artifacts/bindings-*/; do
platform=$(basename "$dir" | sed 's/bindings-//')
tar -czf "release-packages/ruvector-native-${platform}.tar.gz" -C "$dir" .
done
# Package WASM
tar -czf release-packages/ruvector-wasm.tar.gz -C release-artifacts/wasm .
- name: Generate release notes
id: release_notes
run: |
VERSION="${{ github.ref_name }}"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="v${{ inputs.version }}"
fi
cat > release_notes.md <<EOF
# RuVector ${VERSION}
## 🚀 What's New
This release includes:
- High-performance Rust vector database core
- Node.js native bindings for all major platforms
- WebAssembly support for browser and Node.js
- Graph neural network capabilities
- Distributed clustering support
## 📦 Packages Published
### Rust Crates (crates.io)
- \`ruvector-core\` - Core vector database functionality
- \`ruvector-graph\` - Graph database capabilities
- \`ruvector-gnn\` - Graph neural networks
- \`ruvector-cluster\` - Distributed clustering
- And 20+ more specialized crates
### npm Packages
- \`@ruvector/core\` - Main Node.js package with platform-specific binaries
- \`@ruvector/wasm\` - WebAssembly bindings
- \`@ruvector/cli\` - Command-line interface
- \`@ruvector/extensions\` - Additional extensions
## 🏗️ Platform Support
### Native Node.js Modules
- ✅ Linux x64 (GNU)
- ✅ Linux ARM64 (GNU)
- ✅ macOS x64 (Intel)
- ✅ macOS ARM64 (Apple Silicon)
- ✅ Windows x64 (MSVC)
### WebAssembly
- ✅ All platforms via WASM
## 📥 Installation
\`\`\`bash
# Node.js
npm install @ruvector/core
# WASM
npm install @ruvector/wasm
# CLI
npm install -g @ruvector/cli
# Rust
cargo add ruvector-core
\`\`\`
## 🔗 Links
- [npm Package](https://www.npmjs.com/package/@ruvector/core)
- [crates.io](https://crates.io/crates/ruvector-core)
- [Documentation](https://github.com/ruvnet/ruvector)
- [Repository](https://github.com/ruvnet/ruvector)
## 📊 Metrics
- Total Rust Crates: 26
- Total npm Packages: 4+
- Supported Platforms: 5 native + WASM
- Binary Size: ~2-5 MB per platform
---
Built with ❤️ by the RuVector team
EOF
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.release_notes.outputs.version }}
name: RuVector ${{ steps.release_notes.outputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ contains(steps.release_notes.outputs.version, 'alpha') || contains(steps.release_notes.outputs.version, 'beta') }}
files: |
release-packages/*.tar.gz
token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate release summary
run: |
echo "## 🎉 Release Created Successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Version: ${{ steps.release_notes.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Published Artifacts:" >> $GITHUB_STEP_SUMMARY
ls -lh release-packages/ >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Release URL:" >> $GITHUB_STEP_SUMMARY
echo "https://github.com/${{ github.repository }}/releases/tag/${{ steps.release_notes.outputs.version }}" >> $GITHUB_STEP_SUMMARY
# Summary job to report overall status
release-summary:
name: Release Summary
runs-on: ubuntu-22.04
needs: [validate, build-crates, build-native, build-wasm, publish-crates, prepare-npm, create-release]
if: always()
steps:
- name: Generate final summary
run: |
echo "# 🚀 RuVector Release Pipeline Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Job Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Validate | ${{ needs.validate.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build Crates | ${{ needs.build-crates.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build Native | ${{ needs.build-native.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build WASM | ${{ needs.build-wasm.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Publish Crates | ${{ needs.publish-crates.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Prepare npm | ${{ needs.prepare-npm.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Create Release | ${{ needs.create-release.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.create-release.result }}" = "success" ]; then
echo "## ✅ Release completed successfully!" >> $GITHUB_STEP_SUMMARY
else
echo "## ⚠️ Release completed with some warnings or failures" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Next Steps" >> $GITHUB_STEP_SUMMARY
echo "- Verify packages on [crates.io](https://crates.io/search?q=ruvector)" >> $GITHUB_STEP_SUMMARY
echo "- Verify packages on [npm](https://www.npmjs.com/search?q=%40ruvector)" >> $GITHUB_STEP_SUMMARY
echo "- Check [GitHub releases](https://github.com/${{ github.repository }}/releases)" >> $GITHUB_STEP_SUMMARY
echo "- Update documentation if needed" >> $GITHUB_STEP_SUMMARY

View File

@@ -0,0 +1,494 @@
# RuVector-Postgres CI/CD Pipeline
# Build, test, and package the PostgreSQL vector extension
#
# Features:
# - Matrix testing across PostgreSQL 16, 17 (LTS versions)
# - Docker-based integration tests
# - Performance regression detection
# - Automated packaging for releases
name: RuVector-Postgres CI/CD
on:
push:
branches: [main, develop, "feat/**", "claude/**", "fix/**"]
paths:
- 'crates/ruvector-postgres/**'
- '.github/workflows/ruvector-postgres-ci.yml'
pull_request:
branches: [main, develop]
paths:
- 'crates/ruvector-postgres/**'
- '.github/workflows/ruvector-postgres-ci.yml'
workflow_dispatch:
inputs:
run_benchmarks:
description: 'Run performance benchmarks'
required: false
default: 'false'
type: boolean
pg_version:
description: 'PostgreSQL version to test (empty for matrix)'
required: false
default: ''
type: string
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
PGRX_VERSION: '0.12.9'
RUST_VERSION: 'stable'
# Concurrency control - cancel in-progress runs for same PR
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ============================================================================
# Code Quality Checks
# ============================================================================
lint:
name: Lint & Format
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
components: rustfmt, clippy
- name: Install PostgreSQL 17 dev headers
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-lint-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-lint-
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version ${{ env.PGRX_VERSION }} --locked
- name: Initialize pgrx
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Check formatting
run: cargo fmt -- --check
working-directory: crates/ruvector-postgres
- name: Run Clippy
run: |
cargo clippy --features pg17 -- -D warnings \
-A clippy::too_many_arguments \
-A clippy::should_implement_trait \
-A clippy::collapsible_str_replace \
-A clippy::useless_format \
-A clippy::needless_range_loop \
-A clippy::comparison_chain \
-A clippy::not_unsafe_ptr_arg_deref \
-A clippy::derivable_impls \
-A clippy::redundant_closure \
-A clippy::manual_div_ceil \
-A clippy::unnecessary_cast \
-A clippy::unwrap_or_default
working-directory: crates/ruvector-postgres
# ============================================================================
# Matrix Build & Test
# ============================================================================
test:
name: Test PG${{ matrix.pg_version }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: lint
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
pg_version: [17]
include:
# macOS tests for pg17
- os: macos-latest
pg_version: 17
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install PostgreSQL (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-${{ matrix.pg_version }} postgresql-server-dev-${{ matrix.pg_version }}
echo "/usr/lib/postgresql/${{ matrix.pg_version }}/bin" >> $GITHUB_PATH
- name: Install PostgreSQL (macOS)
if: runner.os == 'macOS'
run: |
brew install postgresql@${{ matrix.pg_version }}
echo "/opt/homebrew/opt/postgresql@${{ matrix.pg_version }}/bin" >> $GITHUB_PATH
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-test-pg${{ matrix.pg_version }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-test-pg${{ matrix.pg_version }}-
${{ runner.os }}-cargo-test-
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version ${{ env.PGRX_VERSION }} --locked
- name: Initialize pgrx (Ubuntu)
if: runner.os == 'Linux'
run: cargo pgrx init --pg${{ matrix.pg_version }}=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Initialize pgrx (macOS)
if: runner.os == 'macOS'
run: cargo pgrx init --pg${{ matrix.pg_version }}=/opt/homebrew/opt/postgresql@${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Build extension
run: cargo build --no-default-features --features pg${{ matrix.pg_version }} --release
working-directory: crates/ruvector-postgres
# Note: cargo test --lib is skipped because #[pg_test] tests require PostgreSQL runtime
# and cause linker errors (undefined symbols) when compiled outside pgrx test harness.
# All tests are run via cargo pgrx test instead.
- name: Run pgrx tests
run: cargo pgrx test pg${{ matrix.pg_version }} --no-default-features
working-directory: crates/ruvector-postgres
# ============================================================================
# All Features Test
# ============================================================================
test-all-features:
name: Test All Features (PG17)
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install PostgreSQL 17
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-allfeatures-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version ${{ env.PGRX_VERSION }} --locked
- name: Initialize pgrx
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Build with all features
run: cargo build --features pg17,index-all,quant-all,graph-complete --release
working-directory: crates/ruvector-postgres
- name: Test with all features
run: cargo pgrx test pg17 --features index-all,quant-all,graph-complete
working-directory: crates/ruvector-postgres
# ============================================================================
# Docker Integration Tests
# ============================================================================
docker-integration:
name: Docker Integration (PG${{ matrix.pg_version }})
runs-on: ubuntu-latest
needs: test
strategy:
fail-fast: false
matrix:
pg_version: [17]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
file: crates/ruvector-postgres/docker/Dockerfile
build-args: |
PG_VERSION=${{ matrix.pg_version }}
push: false
load: true
tags: ruvector-postgres:pg${{ matrix.pg_version }}-test
cache-from: type=gha,scope=pg${{ matrix.pg_version }}
cache-to: type=gha,mode=max,scope=pg${{ matrix.pg_version }}
- name: Start PostgreSQL container
run: |
docker run -d \
--name ruvector-test \
-p 5432:5432 \
-e POSTGRES_USER=ruvector \
-e POSTGRES_PASSWORD=ruvector \
-e POSTGRES_DB=ruvector_test \
ruvector-postgres:pg${{ matrix.pg_version }}-test
# Wait for PostgreSQL to be ready
for i in {1..30}; do
if docker exec ruvector-test pg_isready -U ruvector -d ruvector_test; then
echo "PostgreSQL is ready"
break
fi
echo "Waiting for PostgreSQL..."
sleep 2
done
- name: Verify extension installation
run: |
docker exec ruvector-test psql -U ruvector -d ruvector_test -c "CREATE EXTENSION IF NOT EXISTS ruvector;"
docker exec ruvector-test psql -U ruvector -d ruvector_test -c "SELECT ruvector_version();"
docker exec ruvector-test psql -U ruvector -d ruvector_test -c "SELECT ruvector_simd_info();"
- name: Run integration tests
run: |
docker exec ruvector-test psql -U ruvector -d ruvector_test << 'EOF'
-- Test vector operations
SELECT '[1,2,3]'::real[] AS test_vector;
SELECT l2_distance_arr(ARRAY[1.0,2.0,3.0]::real[], ARRAY[4.0,5.0,6.0]::real[]) AS l2_dist;
SELECT cosine_distance_arr(ARRAY[1.0,0.0,0.0]::real[], ARRAY[0.0,1.0,0.0]::real[]) AS cosine_dist;
SELECT inner_product_arr(ARRAY[1.0,2.0,3.0]::real[], ARRAY[1.0,2.0,3.0]::real[]) AS inner_prod;
-- Test table creation and queries
CREATE TABLE test_vectors (id SERIAL PRIMARY KEY, embedding real[]);
INSERT INTO test_vectors (embedding) VALUES
(ARRAY[1.0,2.0,3.0]::real[]),
(ARRAY[4.0,5.0,6.0]::real[]),
(ARRAY[7.0,8.0,9.0]::real[]);
SELECT id, l2_distance_arr(embedding, ARRAY[1.0,2.0,3.0]::real[]) AS distance
FROM test_vectors
ORDER BY distance
LIMIT 3;
DROP TABLE test_vectors;
SELECT 'Integration tests passed!' AS result;
EOF
- name: Collect container logs
if: always()
run: docker logs ruvector-test
- name: Cleanup
if: always()
run: docker rm -f ruvector-test || true
# ============================================================================
# Performance Benchmarks
# ============================================================================
benchmark:
name: Performance Benchmarks
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'pull_request' || github.event.inputs.run_benchmarks == 'true'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install PostgreSQL 17
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-17 postgresql-server-dev-17
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-bench-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version ${{ env.PGRX_VERSION }} --locked
- name: Initialize pgrx
run: cargo pgrx init --pg17=/usr/lib/postgresql/17/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Run benchmarks
run: |
cargo bench --features pg17 -- --output-format bencher | tee benchmark-results.txt
working-directory: crates/ruvector-postgres
- name: Store benchmark results
uses: benchmark-action/github-action-benchmark@v1
with:
name: RuVector-Postgres Benchmarks
tool: 'cargo'
output-file-path: crates/ruvector-postgres/benchmark-results.txt
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: false
alert-threshold: '150%'
comment-on-alert: true
fail-on-alert: false
- name: Upload benchmark artifacts
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: crates/ruvector-postgres/benchmark-results.txt
retention-days: 30
# ============================================================================
# Security Audit
# ============================================================================
security:
name: Security Audit
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Run cargo audit
run: |
cargo install cargo-audit
cargo audit --ignore RUSTSEC-2020-0071 || true
working-directory: crates/ruvector-postgres
# ============================================================================
# Package Extension
# ============================================================================
package:
name: Package PG${{ matrix.pg_version }}
runs-on: ubuntu-latest
needs: [test, docker-integration]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
strategy:
matrix:
pg_version: [17]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install PostgreSQL
run: |
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-${{ matrix.pg_version }} postgresql-server-dev-${{ matrix.pg_version }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-package-pg${{ matrix.pg_version }}-${{ hashFiles('**/Cargo.lock') }}
- name: Install cargo-pgrx
run: cargo install cargo-pgrx --version ${{ env.PGRX_VERSION }} --locked
- name: Initialize pgrx
run: cargo pgrx init --pg${{ matrix.pg_version }}=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
working-directory: crates/ruvector-postgres
- name: Package extension
run: cargo pgrx package --no-default-features --features pg${{ matrix.pg_version }},graph-complete
working-directory: crates/ruvector-postgres
- name: Upload package artifacts
uses: actions/upload-artifact@v4
with:
name: ruvector-postgres-pg${{ matrix.pg_version }}
path: crates/ruvector-postgres/target/release/ruvector-pg${{ matrix.pg_version }}/
retention-days: 30
# ============================================================================
# Summary Job
# ============================================================================
summary:
name: CI Summary
runs-on: ubuntu-latest
needs: [lint, test, test-all-features, docker-integration, security]
if: always()
steps:
- name: Check job statuses
run: |
echo "## CI Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Test Matrix | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| All Features | ${{ needs.test-all-features.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Docker Integration | ${{ needs.docker-integration.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Security Audit | ${{ needs.security.result }} |" >> $GITHUB_STEP_SUMMARY
- name: Fail if any job failed
if: contains(needs.*.result, 'failure')
run: exit 1

View File

@@ -0,0 +1,268 @@
name: RuvLLM Benchmarks
on:
pull_request:
paths:
- 'crates/ruvllm/**'
- '.github/workflows/ruvllm-benchmarks.yml'
push:
branches:
- main
- develop
paths:
- 'crates/ruvllm/**'
workflow_dispatch:
inputs:
run_ane_benchmarks:
description: 'Run ANE benchmarks (macOS only)'
required: false
default: 'true'
type: boolean
run_full_suite:
description: 'Run full benchmark suite (takes longer)'
required: false
default: 'false'
type: boolean
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
permissions:
contents: read
pull-requests: write
issues: write
jobs:
# macOS ARM64 benchmarks (Apple Silicon with ANE)
macos-arm64-benchmarks:
name: macOS ARM64 Benchmarks (M-series)
runs-on: macos-14 # M1/M2 runner
timeout-minutes: 45
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-ruvllm-bench-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-ruvllm-bench-
${{ runner.os }}-cargo-build-
- name: Build ruvllm with ANE support
run: |
cargo build --release -p ruvllm --features "coreml,accelerate"
- name: Run ANE vs NEON benchmarks
if: github.event.inputs.run_ane_benchmarks != 'false'
working-directory: crates/ruvllm
run: |
# Run the ANE comparison benchmarks
cargo bench --features "coreml,accelerate" --bench ane_bench -- \
--output-format bencher 2>&1 | tee ../../ane_bench_results.txt
- name: Run crossover detection benchmark
if: github.event.inputs.run_full_suite == 'true'
working-directory: crates/ruvllm
run: |
cargo bench --features "coreml,accelerate" --bench ane_bench -- \
crossover_detection --output-format bencher 2>&1 | tee -a ../../ane_bench_results.txt
- name: Run hybrid pipeline benchmark
if: github.event.inputs.run_full_suite == 'true'
working-directory: crates/ruvllm
run: |
cargo bench --features "coreml,accelerate" --bench ane_bench -- \
hybrid_pipeline --output-format bencher 2>&1 | tee -a ../../ane_bench_results.txt
- name: Run matmul benchmarks
working-directory: crates/ruvllm
run: |
cargo bench --features "coreml,accelerate" --bench matmul_bench -- \
--output-format bencher 2>&1 | tee ../../matmul_bench_results.txt
- name: Run attention benchmarks
working-directory: crates/ruvllm
run: |
cargo bench --features "coreml,accelerate" --bench attention_bench -- \
--output-format bencher 2>&1 | tee ../../attention_bench_results.txt
- name: Generate benchmark summary
run: |
cat > benchmark_summary.md << 'EOF'
# RuvLLM Benchmark Results (macOS ARM64 with ANE)
## System Information
- Runner: macOS 14 (Apple Silicon M-series)
- Features: coreml, accelerate
## ANE vs NEON Performance
The ANE (Apple Neural Engine) benchmarks measure:
- Matrix multiplication at various sizes
- Activation functions (SiLU, GELU, Softmax)
- Normalization (LayerNorm, RMSNorm)
- Hybrid pipeline (ANE + GPU coordination)
### Expected Performance Characteristics (M4 Pro)
| Matrix Size | ANE Advantage |
|-------------|---------------|
| < 512 | +30-50% faster |
| 512-1024 | +10-30% faster |
| 1024-1536 | ~Similar |
| 1536-2048 | GPU preferred |
| > 2048 | GPU wins 30-50%|
## Results
### ANE Benchmark Results
```
EOF
head -n 100 ane_bench_results.txt >> benchmark_summary.md
cat >> benchmark_summary.md << 'EOF'
```
### Matrix Multiplication Results
```
EOF
head -n 50 matmul_bench_results.txt >> benchmark_summary.md
cat >> benchmark_summary.md << 'EOF'
```
### Attention Results
```
EOF
head -n 50 attention_bench_results.txt >> benchmark_summary.md
echo '```' >> benchmark_summary.md
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: ruvllm-macos-arm64-benchmarks
path: |
ane_bench_results.txt
matmul_bench_results.txt
attention_bench_results.txt
benchmark_summary.md
retention-days: 30
- name: Comment PR with results
if: github.event_name == 'pull_request'
continue-on-error: true
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = fs.readFileSync('benchmark_summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
# Linux benchmarks (NEON only baseline)
linux-benchmarks:
name: Linux Benchmarks (NEON baseline)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
target
key: ${{ runner.os }}-cargo-ruvllm-bench-${{ hashFiles('**/Cargo.lock') }}
- name: Run matmul benchmarks (NEON simulation)
working-directory: crates/ruvllm
run: |
cargo bench --bench matmul_bench -- --output-format bencher 2>&1 | tee ../../linux_matmul_bench.txt
- name: Run attention benchmarks
working-directory: crates/ruvllm
run: |
cargo bench --bench attention_bench -- --output-format bencher 2>&1 | tee ../../linux_attention_bench.txt
- name: Upload Linux benchmark results
uses: actions/upload-artifact@v4
with:
name: ruvllm-linux-benchmarks
path: |
linux_matmul_bench.txt
linux_attention_bench.txt
retention-days: 30
# Benchmark comparison job
benchmark-comparison:
name: Compare Benchmarks
runs-on: ubuntu-latest
needs: [macos-arm64-benchmarks, linux-benchmarks]
if: github.event_name == 'pull_request'
steps:
- name: Download macOS results
uses: actions/download-artifact@v4
with:
name: ruvllm-macos-arm64-benchmarks
path: macos-results
- name: Download Linux results
uses: actions/download-artifact@v4
with:
name: ruvllm-linux-benchmarks
path: linux-results
- name: Generate comparison report
run: |
cat > comparison.md << 'EOF'
# Cross-Platform Benchmark Comparison
## macOS ARM64 (Apple Silicon with ANE)
```
EOF
head -n 30 macos-results/ane_bench_results.txt >> comparison.md
cat >> comparison.md << 'EOF'
```
## Linux x86_64 (Baseline)
```
EOF
head -n 30 linux-results/linux_matmul_bench.txt >> comparison.md
echo '```' >> comparison.md
- name: Upload comparison
uses: actions/upload-artifact@v4
with:
name: benchmark-comparison
path: comparison.md
retention-days: 30

View File

@@ -0,0 +1,235 @@
name: RuvLLM Build & Publish
on:
push:
tags:
- 'ruvllm-v*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish'
required: false
default: ''
env:
DEBUG: napi:*
APP_NAME: ruvllm
MACOSX_DEPLOYMENT_TARGET: '10.13'
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: |
cd examples/ruvLLM
cargo build --release --features napi
strip -x ../../target/release/libruvllm.dylib || true
artifact: libruvllm.dylib
artifact_name: ruvllm.darwin-x64.node
- host: macos-latest
target: aarch64-apple-darwin
build: |
cd examples/ruvLLM
cargo build --release --features napi --target aarch64-apple-darwin
strip -x ../../target/aarch64-apple-darwin/release/libruvllm.dylib || true
artifact: target/aarch64-apple-darwin/release/libruvllm.dylib
artifact_name: ruvllm.darwin-arm64.node
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
build: |
cd examples/ruvLLM
cargo build --release --features napi
strip ../../target/release/libruvllm.so
artifact: libruvllm.so
artifact_name: ruvllm.linux-x64-gnu.node
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: |
cd examples/ruvLLM
cargo build --release --features napi --target aarch64-unknown-linux-gnu
aarch64-linux-gnu-strip ../../target/aarch64-unknown-linux-gnu/release/libruvllm.so || true
artifact: target/aarch64-unknown-linux-gnu/release/libruvllm.so
artifact_name: ruvllm.linux-arm64-gnu.node
- host: windows-latest
target: x86_64-pc-windows-msvc
build: |
cd examples/ruvLLM
cargo build --release --features napi
artifact: ruvllm.dll
artifact_name: ruvllm.win32-x64-msvc.node
name: Build - ${{ matrix.settings.target }}
runs-on: ${{ matrix.settings.host }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
targets: ${{ matrix.settings.target }}
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.settings.target }}
- name: Build (Native)
if: ${{ !matrix.settings.docker }}
shell: bash
run: ${{ matrix.settings.build }}
- name: Build (Docker)
if: ${{ matrix.settings.docker }}
uses: addnab/docker-run-action@v3
with:
image: ${{ matrix.settings.docker }}
options: --user 0:0 -v ${{ github.workspace }}:/workspace -w /workspace
run: ${{ matrix.settings.build }}
- name: Copy artifact
shell: bash
run: |
mkdir -p npm/packages/ruvllm/npm/${{ matrix.settings.target }}
if [ -f "target/release/${{ matrix.settings.artifact }}" ]; then
cp target/release/${{ matrix.settings.artifact }} npm/packages/ruvllm/npm/${{ matrix.settings.target }}/${{ matrix.settings.artifact_name }}
elif [ -f "${{ matrix.settings.artifact }}" ]; then
cp ${{ matrix.settings.artifact }} npm/packages/ruvllm/npm/${{ matrix.settings.target }}/${{ matrix.settings.artifact_name }}
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: npm/packages/ruvllm/npm/${{ matrix.settings.target }}/${{ matrix.settings.artifact_name }}
if-no-files-found: error
publish:
name: Publish npm packages
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Move artifacts to npm directories
run: |
# Darwin x64
mkdir -p npm/packages/ruvllm/npm/darwin-x64
cp artifacts/bindings-x86_64-apple-darwin/ruvllm.darwin-x64.node npm/packages/ruvllm/npm/darwin-x64/ || true
# Darwin arm64
mkdir -p npm/packages/ruvllm/npm/darwin-arm64
cp artifacts/bindings-aarch64-apple-darwin/ruvllm.darwin-arm64.node npm/packages/ruvllm/npm/darwin-arm64/ || true
# Linux x64
mkdir -p npm/packages/ruvllm/npm/linux-x64-gnu
cp artifacts/bindings-x86_64-unknown-linux-gnu/ruvllm.linux-x64-gnu.node npm/packages/ruvllm/npm/linux-x64-gnu/ || true
# Linux arm64
mkdir -p npm/packages/ruvllm/npm/linux-arm64-gnu
cp artifacts/bindings-aarch64-unknown-linux-gnu/ruvllm.linux-arm64-gnu.node npm/packages/ruvllm/npm/linux-arm64-gnu/ || true
# Windows x64
mkdir -p npm/packages/ruvllm/npm/win32-x64-msvc
cp artifacts/bindings-x86_64-pc-windows-msvc/ruvllm.win32-x64-msvc.node npm/packages/ruvllm/npm/win32-x64-msvc/ || true
- name: Install dependencies
run: |
cd npm/packages/ruvllm
npm install
- name: Build TypeScript
run: |
cd npm/packages/ruvllm
npm run build
- name: Publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
# Publish darwin-arm64
cd npm/packages/ruvllm/npm/darwin-arm64
npm publish --access public || true
cd -
# Publish darwin-x64
cd npm/packages/ruvllm/npm/darwin-x64
npm publish --access public || true
cd -
# Publish linux-x64-gnu
cd npm/packages/ruvllm/npm/linux-x64-gnu
npm publish --access public || true
cd -
# Publish linux-arm64-gnu
cd npm/packages/ruvllm/npm/linux-arm64-gnu
npm publish --access public || true
cd -
# Publish win32-x64-msvc
cd npm/packages/ruvllm/npm/win32-x64-msvc
npm publish --access public || true
cd -
- name: Publish main package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
cd npm/packages/ruvllm
npm publish --access public
test:
name: Test npm package
runs-on: ${{ matrix.os }}
needs: publish
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20]
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
registry-url: 'https://registry.npmjs.org'
- name: Test installation
run: |
npm install @ruvector/ruvllm
node -e "const { RuvLLM, version } = require('@ruvector/ruvllm'); console.log('Version:', version()); const llm = new RuvLLM(); console.log('Native:', llm.isNativeLoaded()); console.log('SIMD:', llm.simdCapabilities());"
- name: Test CLI
run: |
npx @ruvector/ruvllm info
npx @ruvector/ruvllm benchmark --iterations 100

View File

@@ -0,0 +1,163 @@
name: RuvLLM Native Build
on:
push:
tags:
- 'ruvllm-v*'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm'
required: false
default: 'false'
type: boolean
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
node_file: ruvllm.linux-x64-gnu.node
npm_package: ruvllm-linux-x64-gnu
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
node_file: ruvllm.linux-arm64-gnu.node
npm_package: ruvllm-linux-arm64-gnu
- target: x86_64-apple-darwin
os: macos-13
node_file: ruvllm.darwin-x64.node
npm_package: ruvllm-darwin-x64
- target: aarch64-apple-darwin
os: macos-14
node_file: ruvllm.darwin-arm64.node
npm_package: ruvllm-darwin-arm64
- target: x86_64-pc-windows-msvc
os: windows-latest
node_file: ruvllm.win32-x64-msvc.node
npm_package: ruvllm-win32-x64-msvc
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install napi-rs CLI
run: npm install -g @napi-rs/cli
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Setup cross-compilation env (Linux ARM64)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV
- name: Build native library with napi
shell: bash
run: |
cd examples/ruvLLM
# Use cargo directly with --lib to avoid building binaries
cargo build --release --lib --features napi --target ${{ matrix.target }}
# napi artifacts command to copy the output
napi artifacts --build-output-dir ../../target/${{ matrix.target }}/release || true
- name: Copy artifact (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
mkdir -p npm/packages/${{ matrix.npm_package }}
# Try napi output first, then cargo output
if ls examples/ruvLLM/*.node 1>/dev/null 2>&1; then
cp examples/ruvLLM/*.node npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
elif [ "${{ matrix.target }}" = "x86_64-unknown-linux-gnu" ] || [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
cp target/${{ matrix.target }}/release/libruvllm.so npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
else
cp target/${{ matrix.target }}/release/libruvllm.dylib npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
fi
- name: Copy artifact (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path npm/packages/${{ matrix.npm_package }}
# Try napi output first, then cargo output
if (Test-Path examples/ruvLLM/*.node) {
Copy-Item examples/ruvLLM/*.node npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
} else {
Copy-Item target/${{ matrix.target }}/release/ruvllm.dll npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.npm_package }}
path: npm/packages/${{ matrix.npm_package }}/${{ matrix.node_file }}
publish:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/ruvllm-v') || github.event.inputs.publish == 'true'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Copy artifacts to packages
run: |
cp artifacts/ruvllm-linux-x64-gnu/ruvllm.linux-x64-gnu.node npm/packages/ruvllm-linux-x64-gnu/
cp artifacts/ruvllm-linux-arm64-gnu/ruvllm.linux-arm64-gnu.node npm/packages/ruvllm-linux-arm64-gnu/
cp artifacts/ruvllm-darwin-x64/ruvllm.darwin-x64.node npm/packages/ruvllm-darwin-x64/
cp artifacts/ruvllm-darwin-arm64/ruvllm.darwin-arm64.node npm/packages/ruvllm-darwin-arm64/
cp artifacts/ruvllm-win32-x64-msvc/ruvllm.win32-x64-msvc.node npm/packages/ruvllm-win32-x64-msvc/
- name: Publish platform packages
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
for pkg in ruvllm-linux-x64-gnu ruvllm-linux-arm64-gnu ruvllm-darwin-x64 ruvllm-darwin-arm64 ruvllm-win32-x64-msvc; do
cd npm/packages/$pkg
npm publish --access public || true
cd ../../..
done
- name: Build and publish main package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
cd npm/packages/ruvllm
npm install
npm run build
npm publish --access public || true

View File

@@ -0,0 +1,404 @@
name: RuvLTRA-Small Tests
on:
push:
branches: [main, develop]
paths:
- 'crates/ruvllm/**'
- 'crates/ruvllm-cli/**'
- '.github/workflows/ruvltra-tests.yml'
pull_request:
branches: [main, develop]
paths:
- 'crates/ruvllm/**'
- 'crates/ruvllm-cli/**'
workflow_dispatch:
inputs:
run_benchmarks:
description: 'Run performance benchmarks'
required: false
default: 'false'
type: boolean
run_stress_tests:
description: 'Run stress tests'
required: false
default: 'false'
type: boolean
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ============================================================================
# Unit Tests - Model Loading, Quantization, SONA, ANE Dispatch
# ============================================================================
unit-tests:
name: Unit Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: ubuntu-latest
features: ""
- os: macos-latest
features: "coreml"
- os: windows-latest
features: ""
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-unit-tests
- name: Run RuvLTRA Unit Tests
run: |
cargo test --package ruvllm ruvltra_tests \
${{ matrix.features && format('--features {0}', matrix.features) || '' }} \
-- --nocapture
env:
RUST_LOG: debug
- name: Run Quantization Tests
run: |
cargo test --package ruvllm quantization_accuracy \
-- --nocapture
- name: Run SONA Integration Tests
run: |
cargo test --package ruvllm sona_integration \
-- --nocapture
- name: Run ANE Dispatch Tests
if: matrix.os == 'macos-latest'
run: |
cargo test --package ruvllm ane_dispatch --features coreml \
-- --nocapture
# ============================================================================
# End-to-End Tests - Full Inference Pipeline
# ============================================================================
e2e-tests:
name: E2E Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-e2e-tests
- name: Run E2E Pipeline Tests
run: |
cargo test --package ruvllm ruvltra_e2e::full_inference_pipeline \
-- --nocapture
- name: Run Streaming Tests
run: |
cargo test --package ruvllm ruvltra_e2e::streaming_generation \
-- --nocapture
- name: Run Quality Validation Tests
run: |
cargo test --package ruvllm ruvltra_e2e::quality_validation \
-- --nocapture
- name: Run Memory Validation Tests
run: |
cargo test --package ruvllm ruvltra_e2e::memory_validation \
-- --nocapture
# ============================================================================
# Apple Silicon Specific Tests
# ============================================================================
apple-silicon-tests:
name: Apple Silicon Tests
runs-on: macos-14 # M1/M2 runners
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: macos-arm64-tests
- name: Check Architecture
run: |
uname -m
sysctl -n machdep.cpu.brand_string || true
- name: Run ANE Integration Tests
run: |
cargo test --package ruvllm --features coreml,hybrid-ane \
ane_integration -- --nocapture
- name: Run SONA on Apple Silicon
run: |
cargo test --package ruvllm --features coreml \
sona_integration -- --nocapture
- name: Run Full RuvLTRA Test Suite
run: |
cargo test --package ruvllm --features coreml \
ruvltra_tests -- --nocapture
- name: Verify ANE Capabilities Detection
run: |
cargo test --package ruvllm --features coreml \
test_ane_capabilities_detection -- --nocapture --exact
# ============================================================================
# Quantization Accuracy Tests
# ============================================================================
quantization-tests:
name: Quantization Accuracy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: quantization-tests
- name: Test All Quantization Formats
run: |
cargo test --package ruvllm quantization \
-- --nocapture
- name: Test Q4_K Accuracy
run: |
cargo test --package ruvllm test_q4_k_dequantization \
-- --nocapture --exact
- name: Test Q8_0 Accuracy
run: |
cargo test --package ruvllm test_q8_0_dequantization \
-- --nocapture --exact
- name: Test Tensor Size Calculations
run: |
cargo test --package ruvllm test_tensor_size \
-- --nocapture
# ============================================================================
# Thread Safety Tests
# ============================================================================
thread-safety-tests:
name: Thread Safety
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: thread-safety-tests
- name: Run Thread Safety Tests
run: |
cargo test --package ruvllm thread_safety \
-- --nocapture --test-threads=4
- name: Run Concurrent Inference Tests
run: |
cargo test --package ruvllm ruvltra_e2e::stress_tests::test_concurrent_inference \
-- --nocapture --exact
# ============================================================================
# Performance Benchmarks (Optional)
# ============================================================================
benchmarks:
name: Performance Benchmarks
runs-on: macos-14
if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_benchmarks == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: benchmarks
- name: Run Performance Benchmarks
run: |
cargo test --package ruvllm --release --features coreml \
-- --ignored --nocapture 2>&1 | tee benchmark-results.txt
- name: Upload Benchmark Results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: benchmark-results.txt
# ============================================================================
# Stress Tests (Optional)
# ============================================================================
stress-tests:
name: Stress Tests
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && github.event.inputs.run_stress_tests == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: stress-tests
- name: Run Stress Tests
run: |
cargo test --package ruvllm --release \
ruvltra_e2e::stress_tests -- --nocapture --test-threads=1
timeout-minutes: 30
# ============================================================================
# Code Quality
# ============================================================================
code-quality:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: code-quality
- name: Check Formatting
run: |
cargo fmt --package ruvllm -- --check
- name: Run Clippy
run: |
cargo clippy --package ruvllm --all-targets -- -D warnings
- name: Check Documentation
run: |
cargo doc --package ruvllm --no-deps
env:
RUSTDOCFLAGS: -D warnings
# ============================================================================
# Test Coverage
# ============================================================================
coverage:
name: Test Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
key: coverage
- name: Generate Coverage Report
run: |
cargo llvm-cov --package ruvllm \
--html --output-dir coverage \
-- --nocapture
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
- name: Check Coverage Threshold
run: |
COVERAGE=$(cargo llvm-cov --package ruvllm --json 2>/dev/null | jq -r '.data[0].totals.lines.percent // 0')
echo "Coverage: ${COVERAGE}%"
# Require at least 60% line coverage
if (( $(echo "$COVERAGE < 60" | bc -l) )); then
echo "Coverage ${COVERAGE}% is below threshold of 60%"
exit 1
fi
continue-on-error: true
# ============================================================================
# Summary Job
# ============================================================================
test-summary:
name: Test Summary
runs-on: ubuntu-latest
needs: [unit-tests, e2e-tests, quantization-tests, thread-safety-tests, code-quality]
if: always()
steps:
- name: Check Test Results
run: |
echo "## RuvLTRA-Small Test Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Test Suite | Status |" >> $GITHUB_STEP_SUMMARY
echo "|------------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Unit Tests | ${{ needs.unit-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| E2E Tests | ${{ needs.e2e-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Quantization | ${{ needs.quantization-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Thread Safety | ${{ needs.thread-safety-tests.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Code Quality | ${{ needs.code-quality.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
- name: Fail if Any Test Failed
if: |
needs.unit-tests.result == 'failure' ||
needs.e2e-tests.result == 'failure' ||
needs.quantization-tests.result == 'failure' ||
needs.thread-safety-tests.result == 'failure' ||
needs.code-quality.result == 'failure'
run: exit 1

View File

@@ -0,0 +1,298 @@
name: SONA NAPI Build & Publish
on:
push:
tags:
- 'sona-v*'
paths:
- 'crates/sona/**'
- 'npm/packages/sona/**'
- '.github/workflows/sona-napi.yml'
pull_request:
paths:
- 'crates/sona/**'
- 'npm/packages/sona/**'
workflow_dispatch:
inputs:
publish:
description: 'Publish to npm'
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
# Linux x64 GNU
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
node-file: sona.linux-x64-gnu.node
# Linux x64 MUSL
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
node-file: sona.linux-x64-musl.node
# Linux ARM64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
node-file: sona.linux-arm64-gnu.node
# macOS x64
- os: macos-13
target: x86_64-apple-darwin
node-file: sona.darwin-x64.node
# macOS ARM64
- os: macos-14
target: aarch64-apple-darwin
node-file: sona.darwin-arm64.node
# Windows x64
- os: windows-latest
target: x86_64-pc-windows-msvc
node-file: sona.win32-x64-msvc.node
# Windows ARM64
- os: windows-latest
target: aarch64-pc-windows-msvc
node-file: sona.win32-arm64-msvc.node
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install musl tools (Linux MUSL)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- name: Install napi-rs CLI
run: npm install -g @napi-rs/cli
- name: Build native module (cross-compile)
if: matrix.target == 'aarch64-unknown-linux-gnu'
working-directory: npm/packages/sona
run: |
npx napi build --platform --release -p ruvector-sona --manifest-path ../../../crates/sona/Cargo.toml --output-dir . -F napi --target ${{ matrix.target }} --use-napi-cross
- name: Build native module (macOS)
if: startsWith(matrix.target, 'x86_64-apple-darwin') || startsWith(matrix.target, 'aarch64-apple-darwin')
working-directory: npm/packages/sona
env:
CARGO_BUILD_TARGET: ${{ matrix.target }}
RUSTFLAGS: '-C link-arg=-undefined -C link-arg=dynamic_lookup'
run: |
npx napi build --platform --release -p ruvector-sona --manifest-path ../../../crates/sona/Cargo.toml --output-dir . -F napi --target ${{ matrix.target }}
- name: Build native module (other)
if: "!startsWith(matrix.target, 'x86_64-apple-darwin') && !startsWith(matrix.target, 'aarch64-apple-darwin') && matrix.target != 'aarch64-unknown-linux-gnu'"
working-directory: npm/packages/sona
env:
CARGO_BUILD_TARGET: ${{ matrix.target }}
run: |
npx napi build --platform --release -p ruvector-sona --manifest-path ../../../crates/sona/Cargo.toml --output-dir . -F napi --target ${{ matrix.target }}
- name: List built files
working-directory: npm/packages/sona
shell: bash
run: ls -la *.node || echo "No .node files"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.target }}
path: npm/packages/sona/${{ matrix.node-file }}
if-no-files-found: error
# Build universal macOS binary
universal-macos:
runs-on: macos-14
name: Universal macOS
needs: build
steps:
- uses: actions/checkout@v4
- name: Download x64 artifact
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-apple-darwin
path: artifacts/x64
- name: Download ARM64 artifact
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-apple-darwin
path: artifacts/arm64
- name: Create universal binary
run: |
mkdir -p artifacts/universal
lipo -create \
artifacts/x64/sona.darwin-x64.node \
artifacts/arm64/sona.darwin-arm64.node \
-output artifacts/universal/sona.darwin-universal.node
- name: Upload universal artifact
uses: actions/upload-artifact@v4
with:
name: bindings-darwin-universal
path: artifacts/universal/sona.darwin-universal.node
# Publish to npm
publish:
runs-on: ubuntu-latest
name: Publish npm packages
needs: [build, universal-macos]
if: startsWith(github.ref, 'refs/tags/sona-v') || github.event.inputs.publish == 'true'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install napi-rs CLI
run: npm install -g @napi-rs/cli
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List artifacts
run: |
echo "=== All downloaded artifacts ==="
find artifacts -name "*.node" -ls
- name: Copy .node files to npm package
working-directory: npm/packages/sona
run: |
# Copy all .node files from artifacts to the package directory
cp ../../../artifacts/bindings-x86_64-unknown-linux-gnu/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-x86_64-unknown-linux-musl/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-aarch64-unknown-linux-gnu/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-x86_64-apple-darwin/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-aarch64-apple-darwin/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-x86_64-pc-windows-msvc/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-aarch64-pc-windows-msvc/*.node . 2>/dev/null || true
cp ../../../artifacts/bindings-darwin-universal/*.node . 2>/dev/null || true
echo "=== .node files in package ==="
ls -la *.node
- name: Create and publish platform packages
working-directory: npm/packages/sona
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
VERSION=$(node -p "require('./package.json').version")
echo "Publishing version: $VERSION"
mkdir -p npm
publish_platform() {
local name=$1
local node_file=$2
local os_val=$3
local cpu_val=$4
local libc_val=$5
if [ -f "$node_file" ]; then
local dir_name=$(echo "$name" | sed 's/@ruvector\/sona-//')
mkdir -p "npm/$dir_name"
cp "$node_file" "npm/$dir_name/"
if [ -n "$libc_val" ]; then
node -e "require('fs').writeFileSync('npm/$dir_name/package.json', JSON.stringify({name:'$name',version:'$VERSION',os:['$os_val'],cpu:['$cpu_val'],libc:['$libc_val'],main:'$node_file',files:['$node_file'],license:'MIT OR Apache-2.0',repository:{type:'git',url:'https://github.com/ruvnet/ruvector.git'}},null,2))"
else
node -e "require('fs').writeFileSync('npm/$dir_name/package.json', JSON.stringify({name:'$name',version:'$VERSION',os:['$os_val'],cpu:['$cpu_val'],main:'$node_file',files:['$node_file'],license:'MIT OR Apache-2.0',repository:{type:'git',url:'https://github.com/ruvnet/ruvector.git'}},null,2))"
fi
echo "Publishing $name..."
cd "npm/$dir_name"
npm publish --access public || echo "Warning: $name may already exist"
cd ../..
fi
}
publish_platform "@ruvector/sona-linux-x64-gnu" "sona.linux-x64-gnu.node" "linux" "x64" ""
publish_platform "@ruvector/sona-linux-x64-musl" "sona.linux-x64-musl.node" "linux" "x64" "musl"
publish_platform "@ruvector/sona-linux-arm64-gnu" "sona.linux-arm64-gnu.node" "linux" "arm64" ""
publish_platform "@ruvector/sona-darwin-x64" "sona.darwin-x64.node" "darwin" "x64" ""
publish_platform "@ruvector/sona-darwin-arm64" "sona.darwin-arm64.node" "darwin" "arm64" ""
publish_platform "@ruvector/sona-win32-x64-msvc" "sona.win32-x64-msvc.node" "win32" "x64" ""
publish_platform "@ruvector/sona-win32-arm64-msvc" "sona.win32-arm64-msvc.node" "win32" "arm64" ""
echo "=== Platform packages published ==="
- name: Update main package with optionalDependencies
working-directory: npm/packages/sona
run: |
VERSION=$(node -p "require('./package.json').version")
# Add optionalDependencies to package.json
node -e "
const pkg = require('./package.json');
pkg.optionalDependencies = {
'@ruvector/sona-linux-x64-gnu': '$VERSION',
'@ruvector/sona-linux-x64-musl': '$VERSION',
'@ruvector/sona-linux-arm64-gnu': '$VERSION',
'@ruvector/sona-darwin-x64': '$VERSION',
'@ruvector/sona-darwin-arm64': '$VERSION',
'@ruvector/sona-win32-x64-msvc': '$VERSION',
'@ruvector/sona-win32-arm64-msvc': '$VERSION'
};
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n');
"
echo "=== Updated package.json ==="
cat package.json
- name: Publish main package
working-directory: npm/packages/sona
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
echo "=== Main package contents ==="
ls -la
# Publish main package
npm publish --access public
# Test installation on all platforms
test-install:
runs-on: ${{ matrix.os }}
name: Test ${{ matrix.os }}
needs: publish
if: startsWith(github.ref, 'refs/tags/sona-v')
strategy:
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Wait for npm propagation
run: sleep 30
- name: Test npm install
run: |
npm init -y
npm install @ruvector/sona@latest
node -e "const sona = require('@ruvector/sona'); console.log('SONA loaded successfully!'); console.log('SonaEngine:', typeof sona.SonaEngine);"

View File

@@ -0,0 +1,62 @@
name: thermorust CI
on:
push:
paths:
- "crates/thermorust/**"
- ".github/workflows/thermorust-ci.yml"
pull_request:
paths:
- "crates/thermorust/**"
- ".github/workflows/thermorust-ci.yml"
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-thermorust-${{ hashFiles('crates/thermorust/Cargo.toml') }}
restore-keys: ${{ runner.os }}-cargo-thermorust-
- name: Check formatting
run: cargo fmt --package thermorust -- --check
- name: Clippy
run: cargo clippy --package thermorust --all-targets -- -D warnings
- name: Build
run: cargo build --package thermorust
- name: Run tests
run: cargo test --package thermorust
bench-check:
name: Benchmarks compile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Check benchmarks compile
run: cargo bench --package thermorust --no-run

View File

@@ -0,0 +1,57 @@
name: Validate Package Lock File
on:
pull_request:
paths:
- 'npm/package.json'
- 'npm/package-lock.json'
push:
branches:
- main
- develop
paths:
- 'npm/package.json'
- 'npm/package-lock.json'
jobs:
validate-lockfile:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Validate lock file exists
run: |
cd npm
if [ ! -f package-lock.json ]; then
echo "❌ package-lock.json does not exist"
exit 1
fi
echo "✅ package-lock.json exists"
- name: Check lock file version
run: |
cd npm
LOCKFILE_VERSION=$(jq -r '.lockfileVersion' package-lock.json)
echo "Lock file version: $LOCKFILE_VERSION"
if [ "$LOCKFILE_VERSION" -lt 2 ]; then
echo "⚠️ Consider upgrading lock file version to 3 (npm 7+)"
fi
echo "✅ Lock file version check passed"
- name: Verify package names match
run: |
cd npm
PKG_NAME=$(jq -r '.name' package.json)
LOCK_NAME=$(jq -r '.name' package-lock.json)
if [ "$PKG_NAME" != "$LOCK_NAME" ]; then
echo "❌ Package names don't match: $PKG_NAME vs $LOCK_NAME"
exit 1
fi
echo "✅ Package names match: $PKG_NAME"

View File

@@ -0,0 +1,28 @@
name: WASM Dedup Check
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
check-wasm-dedup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install --ignore-scripts --omit=optional 2>&1 || true
working-directory: npm
env:
npm_config_optional: false
- name: Check for duplicate WASM artifacts
run: |
count=$(find node_modules -name "rvf_wasm_bg.wasm" 2>/dev/null | wc -l)
if [ "$count" -gt 1 ]; then
echo "ERROR: Found $count copies of rvf_wasm_bg.wasm"
find node_modules -name "rvf_wasm_bg.wasm"
exit 1
fi
echo "OK: $count WASM artifact(s) found"
working-directory: npm