Files

299 lines
11 KiB
YAML

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);"