Wire release pipeline to crates.io, PyPI, and npm

On every v* tag push the release workflow now publishes the project to
all three public registries in parallel:

- crates.io: wickra-core then wickra-data then wickra, with a 45-second
  sleep between each so the registry index can refresh before the next
  publish step asserts the previous version is available.

- PyPI: maturin-action builds wheels for Linux x86_64 + aarch64, macOS
  x86_64 + aarch64, and Windows x64, plus an sdist; all artefacts upload
  to PyPI via MATURIN_PYPI_TOKEN.

- npm: napi-rs builds a native binary per platform (linux-x64-gnu,
  darwin-x64, darwin-arm64, win32-x64-msvc), publishes each as its own
  platform package, then publishes the main `wickra` meta-package
  that resolves to the right platform at install time.

- WASM: wasm-pack builds the bundler-target package and publishes it as
  `wickra-wasm` on npm, with the auto-generated package.json enriched
  with the author/repo/license metadata.

Package metadata was unified so all targets point at kingchenc/wickra
on GitHub; the Node binding is now plain `wickra` (the @wickra/ scope
was unnecessary because the bare name was free). README install table
updated to match.
This commit is contained in:
kingchenc
2026-05-21 20:35:18 +02:00
parent 82d9c3608e
commit 1295b63e1f
6 changed files with 212 additions and 52 deletions
+190 -43
View File
@@ -2,83 +2,230 @@ name: Release
on:
push:
tags:
- "v*"
tags: ["v*"]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
build-wheels:
name: Wheels ${{ matrix.os }} ${{ matrix.target }}
runs-on: ${{ matrix.os }}
# --------------------------------------------------------------------------
# crates.io: three crates in dependency order
# --------------------------------------------------------------------------
cargo-publish:
name: Publish to crates.io
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Publish wickra-core
run: cargo publish -p wickra-core --token "$CARGO_REGISTRY_TOKEN"
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Wait for crates.io index to refresh
run: sleep 45
- name: Publish wickra-data
run: cargo publish -p wickra-data --token "$CARGO_REGISTRY_TOKEN"
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Wait for crates.io index to refresh
run: sleep 45
- name: Publish wickra
run: cargo publish -p wickra --token "$CARGO_REGISTRY_TOKEN"
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
# --------------------------------------------------------------------------
# PyPI: cross-platform wheels + sdist
# --------------------------------------------------------------------------
python-wheels:
name: Build wheels (${{ matrix.target }} on ${{ matrix.os }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64
- os: ubuntu-latest
target: aarch64
- os: macos-latest
target: x86_64
- os: macos-latest
target: aarch64
- os: windows-latest
target: x64
- { os: ubuntu-latest, target: x86_64, manylinux: auto }
- { os: ubuntu-latest, target: aarch64, manylinux: auto }
- { os: macos-latest, target: x86_64, manylinux: auto }
- { os: macos-latest, target: aarch64, manylinux: auto }
- { os: windows-latest, target: x64, manylinux: auto }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Build wheels
uses: PyO3/maturin-action@v1
- uses: PyO3/maturin-action@v1
with:
working-directory: bindings/python
target: ${{ matrix.target }}
args: --release --strip --out dist
sccache: "true"
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v4
manylinux: ${{ matrix.manylinux }}
- uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.os }}-${{ matrix.target }}
path: bindings/python/dist/
path: bindings/python/dist/*
sdist:
name: Source distribution
python-sdist:
name: Build Python sdist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
- uses: PyO3/maturin-action@v1
with:
working-directory: bindings/python
command: sdist
args: --out dist
- uses: actions/upload-artifact@v4
with:
name: sdist
path: bindings/python/dist/
name: wheels-sdist
path: bindings/python/dist/*
publish:
python-publish:
name: Publish to PyPI
needs: [build-wheels, sdist]
needs: [python-wheels, python-sdist]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
path: dist
pattern: wheels-*
merge-multiple: true
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Upload to PyPI
uses: PyO3/maturin-action@v1
with:
packages-dir: dist/
command: upload
args: --skip-existing dist/*
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
# --------------------------------------------------------------------------
# npm: per-platform native binaries + main meta-package
# --------------------------------------------------------------------------
node-build:
name: Node build (${{ matrix.target }})
strategy:
fail-fast: false
matrix:
include:
- { host: ubuntu-latest, target: x86_64-unknown-linux-gnu }
- { host: macos-latest, target: x86_64-apple-darwin }
- { host: macos-latest, target: aarch64-apple-darwin }
- { host: windows-latest, target: x86_64-pc-windows-msvc }
runs-on: ${{ matrix.host }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- name: Install Node deps
working-directory: bindings/node
run: npm install
- name: Build native module
working-directory: bindings/node
run: npx napi build --platform --release --target ${{ matrix.target }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.target }}
path: bindings/node/wickra.*.node
if-no-files-found: error
node-publish:
name: Publish to npm
needs: node-build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
- name: Install Node deps
working-directory: bindings/node
run: npm install
- name: Download all platform binaries
uses: actions/download-artifact@v4
with:
path: bindings/node/artifacts
pattern: bindings-*
- name: Move binaries into platform package layout
working-directory: bindings/node
run: npx napi artifacts --dir artifacts
- name: Prepublish platform packages to npm
working-directory: bindings/node
run: npx napi prepublish -t npm --skip-gh-release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish main package to npm
working-directory: bindings/node
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# --------------------------------------------------------------------------
# WASM: wasm-pack build + npm publish (as `wickra-wasm`)
# --------------------------------------------------------------------------
wasm-publish:
name: Publish wickra-wasm to npm
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- uses: jetli/wasm-pack-action@v0.4.0
- name: Build WASM package (bundler target)
run: wasm-pack build bindings/wasm --target bundler --release --features panic-hook
- name: Enrich generated package.json with author + repo metadata
working-directory: bindings/wasm/pkg
run: |
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json'));
pkg.author = 'kingchenc <kingchencp@gmail.com>';
pkg.repository = { type: 'git', url: 'https://github.com/kingchenc/wickra' };
pkg.homepage = 'https://github.com/kingchenc/wickra';
pkg.bugs = { url: 'https://github.com/kingchenc/wickra/issues' };
pkg.license = 'SEE LICENSE IN LICENSE';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
"
- name: Publish wickra-wasm to npm
working-directory: bindings/wasm/pkg
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+2 -2
View File
@@ -16,8 +16,8 @@ authors = ["Wickra Contributors"]
edition = "2021"
rust-version = "1.75"
license = "PolyForm-Noncommercial-1.0.0"
repository = "https://github.com/wickra/wickra"
homepage = "https://github.com/wickra/wickra"
repository = "https://github.com/kingchenc/wickra"
homepage = "https://github.com/kingchenc/wickra"
readme = "README.md"
keywords = ["finance", "trading", "indicators", "technical-analysis", "ta"]
categories = ["finance", "mathematics", "science"]
+2 -2
View File
@@ -107,8 +107,8 @@ inherit it automatically.
| Binding | Install | Example |
|-------------------|-----------------------------------------------|---------|
| Python (PyO3) | `pip install wickra` | `examples/python/backtest.py` |
| Node.js (napi-rs) | `npm install @wickra/wickra` | `bindings/node/__tests__/smoke.test.js` |
| Browser / WASM | `wasm-pack build bindings/wasm --target web` | `bindings/wasm/examples/index.html` |
| Node.js (napi-rs) | `npm install wickra` | `bindings/node/__tests__/smoke.test.js` |
| Browser / WASM | `npm install wickra-wasm` | `bindings/wasm/examples/index.html` |
| Rust | `cargo add wickra` | `examples/rust/backtest.rs` |
The wickra-core crate is `unsafe`-forbidden, so every binding inherits a
+10 -2
View File
@@ -1,7 +1,8 @@
{
"name": "@wickra/wickra",
"name": "wickra",
"version": "0.1.0",
"description": "Streaming-first technical indicators: incremental, fast, install-free. Node bindings powered by Rust.",
"author": "kingchenc <kingchencp@gmail.com>",
"main": "index.js",
"types": "index.d.ts",
"license": "SEE LICENSE IN LICENSE",
@@ -16,8 +17,12 @@
],
"repository": {
"type": "git",
"url": "https://github.com/wickra/wickra"
"url": "https://github.com/kingchenc/wickra"
},
"bugs": {
"url": "https://github.com/kingchenc/wickra/issues"
},
"homepage": "https://github.com/kingchenc/wickra",
"files": [
"index.js",
"index.d.ts",
@@ -47,7 +52,10 @@
"scripts": {
"build": "napi build --platform --release",
"build:debug": "napi build --platform",
"artifacts": "napi artifacts",
"prepublishOnly": "napi prepublish -t npm",
"universal": "napi universal",
"version": "napi version",
"test": "node --test __tests__/"
},
"devDependencies": {
+3 -3
View File
@@ -45,9 +45,9 @@ bench = [
]
[project.urls]
Homepage = "https://github.com/wickra/wickra"
Repository = "https://github.com/wickra/wickra"
Issues = "https://github.com/wickra/wickra/issues"
Homepage = "https://github.com/kingchenc/wickra"
Repository = "https://github.com/kingchenc/wickra"
Issues = "https://github.com/kingchenc/wickra/issues"
[tool.maturin]
manifest-path = "Cargo.toml"
+5
View File
@@ -34,6 +34,11 @@ console_error_panic_hook = { version = "0.1", optional = true }
default = []
panic-hook = ["dep:console_error_panic_hook"]
[package.metadata.wasm-pack.profile.release.wasm-bindgen]
debug-js-glue = false
demangle-name-section = true
dwarf-debug-info = false
[package.metadata.wasm-pack.profile.release]
# The wasm-opt that ships with wasm-pack is older than the WebAssembly
# features rustc enables by default (reference-types, multivalue,