21c86f348f
* examples(node): add RSI mean-reversion strategy
Node counterpart of strategy_rsi_mean_reversion.{py,rs}: RSI(14) < 30 long,
> 70 exit, 0.1% fees, hourly BTCUSDT. Output verified byte-identical to the
Rust reference (37 trades W24/L13, -17.84% return, 46.89% max drawdown).
* examples(node): add MACD + ADX trend-filter strategy
Node counterpart of strategy_macd_adx.{py,rs}: MACD(12,26,9) histogram
crossover entries gated by ADX(14) > 20, hourly BTCUSDT, 0.1% fees. Output
verified byte-identical to the Rust reference (246 trades W90/L156, -47.19%
return, 53.75% max drawdown).
* examples(node): add Bollinger-squeeze breakout strategy
Node counterpart of strategy_bollinger_squeeze.{py,rs}: enter on a fresh
180-bar Bollinger-bandwidth low + close above the upper band, exit on a
2*ATR(14) stop or upper-band collapse, daily BTCUSDT, 0.1% fees. Output
verified byte-identical to the Rust reference (1 trade, -7.82% return,
13.01% max drawdown).
* examples(wasm): add RSI mean-reversion strategy demo
Browser counterpart of strategy_rsi_mean_reversion.{py,js,rs}: RSI(14) < 30
long, > 70 exit, 0.1% fees, summary table. Same signal/fill/PnL/equity loop as
the runtime-verified Node example; loads via the established wickra_wasm.js
init + fetch-CSV pattern. (wasm32 build runs in CI.)
* examples(wasm): add MACD + ADX trend-filter strategy demo
Browser counterpart of strategy_macd_adx.{py,js,rs}: MACD(12,26,9) histogram
crossover gated by ADX(14) > 20, hourly BTCUSDT, 0.1% fees. Logic identical to
the runtime-verified Node example; standard wickra_wasm.js init + fetch-CSV
loader. (wasm32 build runs in CI.)
* examples(wasm): add Bollinger-squeeze breakout strategy demo
Browser counterpart of strategy_bollinger_squeeze.{py,js,rs}: fresh 180-bar
Bollinger-bandwidth low + upper-band breakout, 2*ATR(14) stop, daily BTCUSDT,
0.1% fees. Logic identical to the runtime-verified Node example; standard
wickra_wasm.js init + fetch-CSV loader. (wasm32 build runs in CI.)
* ci: add examples syntax-smoke job (P2.3)
The Rust examples are built by 'cargo build -p wickra-examples --bins'; the
Node, browser-WASM and Python examples had no build gate. New job parse-checks
every examples/{node,wasm}/*.js, extracts and node --checks each WASM .html
module script, and python -m py_compile's every examples/python/*.py — so a
broken example edit fails CI instead of landing silently.
* docs(examples): list the new Node + WASM strategy examples
Add the three Node strategy scripts and three WASM strategy demos to the
examples README tables, bringing Node and WASM to parity with the existing
Rust and Python strategy rows.
* chore(examples): refresh examples/node lockfile for the linked wickra binding
npm install rewrote the file: dependency snapshot of the local wickra binding
that the examples link against (version 0.1.4 -> 0.3.1, license + engines
fields), which had gone stale in the committed lockfile.
* test(node): add input-validation suite
Node counterpart of bindings/python/tests/test_input_validation.py: invalid
constructor parameters (ATR zero period, MACD non-increasing fast/slow,
BollingerBands negative multiplier, PSAR step > max, ValueArea period/pct,
InitialBalance/OpeningRange zero period, Ichimoku non-increasing periods,
Ehlers-family ordering) and unequal-length candle/ValueArea batch inputs all
throw a JS Error. Validated against the built binding.
* test(node): add indicator completeness contract
Introspects every exported indicator class and asserts the full interface
(update / batch / reset / isReady / warmupPeriod) plus the pre-warmup contract
for zero-arg indicators, and guards that the full catalogue (>= 200 classes)
is exported. Catches a new indicator wired without the standard methods, or a
stale/partial native build dropping exports, with no per-indicator boilerplate.
* test(wasm): broaden scalar streaming-vs-batch coverage
Extend the inline wasm-bindgen-test suite with a streaming==batch check across
~70 scalar indicators spanning moving averages, momentum, volatility,
statistics/regression, Ehlers/cycle and risk/performance families (previously
only EMA + the candle-input group were covered per-indicator), plus four more
invalid-constructor assertions. Constructor args mirror the CI-passing Node
factories. Host-compiles (cargo test -p wickra-wasm --no-run); executed in CI
via wasm-pack test --node.
* bench(node): add indicator throughput benchmark
Node counterpart of the Rust criterion benches / Python compare_libraries:
measures streaming (per-tick update) and batch throughput in Mupd/s across a
representative indicator set over a synthetic OHLCV series (--bars, default
200k). Dependency-free; wired as 'npm run bench'.
* docs(wasm): list strategy demos + document the benchmark story
Add the three new strategy demos to the WASM examples table and a Performance
section: parallel_assets.html is the in-browser benchmark, with raw throughput
covered by the Rust criterion / Python / Node benchmarks (the WASM engine is the
same core compiled to wasm32).
450 lines
17 KiB
YAML
450 lines
17 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
RUSTFLAGS: "-D warnings"
|
|
|
|
jobs:
|
|
rust:
|
|
name: Rust ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
components: rustfmt, clippy
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
- name: Format check
|
|
run: cargo fmt --all -- --check
|
|
|
|
- name: Clippy (workspace, all targets)
|
|
run: cargo clippy -p wickra-core -p wickra -p wickra-data -p wickra-wasm --all-targets -- -D warnings
|
|
|
|
- name: Build
|
|
run: cargo build -p wickra-core -p wickra -p wickra-data --verbose
|
|
|
|
- name: Tests (default features)
|
|
run: cargo test -p wickra-core -p wickra -p wickra-data --verbose
|
|
|
|
- name: Tests (live-binance feature)
|
|
run: cargo test -p wickra-data --features live-binance --verbose
|
|
|
|
- name: Compile benches (smoke)
|
|
run: cargo build -p wickra --benches --verbose
|
|
|
|
- name: Compile examples
|
|
# All runnable examples now live in the dedicated wickra-examples crate
|
|
# (examples/rust/src/bin/*.rs) which enables the live-binance feature
|
|
# on its wickra-data dep, so a single --bins build covers backtest,
|
|
# live_binance, fetch_btcusdt, multi_timeframe, parallel_assets and
|
|
# streaming.
|
|
run: cargo build -p wickra-examples --bins
|
|
|
|
# Syntax/parse smoke for the non-Rust examples. The Rust examples are built
|
|
# in the `rust` job above (`cargo build -p wickra-examples --bins`); the Node,
|
|
# browser-WASM and Python examples otherwise have no build gate, so a broken
|
|
# edit could land unnoticed. This is a parse-only smoke — actually running the
|
|
# examples needs the built native binding / wasm module / wheel, which the
|
|
# binding jobs provide separately.
|
|
examples-smoke:
|
|
name: Examples (syntax smoke)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: "20"
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Node examples — syntax check
|
|
run: |
|
|
shopt -s nullglob
|
|
count=0
|
|
for f in examples/node/*.js examples/wasm/*.js; do
|
|
echo "node --check $f"
|
|
node --check "$f"
|
|
count=$((count + 1))
|
|
done
|
|
echo "checked $count Node/WASM .js files"
|
|
|
|
- name: WASM demo module scripts — syntax check
|
|
# The .html demos embed an ES module; extract it and parse-check so a
|
|
# broken edit to the in-page strategy logic fails CI.
|
|
run: |
|
|
shopt -s nullglob
|
|
count=0
|
|
for f in examples/wasm/*.html; do
|
|
node -e 'const fs=require("fs");const h=fs.readFileSync(process.argv[1],"utf8");const m=h.match(/<script type="module">([\s\S]*?)<\/script>/);if(!m){console.error("no <script type=module> in "+process.argv[1]);process.exit(1);}fs.writeFileSync("module-check.mjs",m[1]);' "$f"
|
|
echo "node --check (module of) $f"
|
|
node --check module-check.mjs
|
|
count=$((count + 1))
|
|
done
|
|
rm -f module-check.mjs
|
|
echo "checked $count WASM .html module scripts"
|
|
|
|
- name: Python examples — byte-compile
|
|
run: |
|
|
shopt -s nullglob
|
|
count=0
|
|
for f in examples/python/*.py; do
|
|
echo "py_compile $f"
|
|
python -m py_compile "$f"
|
|
count=$((count + 1))
|
|
done
|
|
echo "compiled $count Python files"
|
|
|
|
# Clippy for the Python and Node bindings. These are kept out of the main
|
|
# `rust` job because PyO3 / napi build scripts need a Python interpreter and
|
|
# a Node toolchain on PATH, which the 3-OS matrix job does not provision.
|
|
# Ubuntu-only is sufficient: the lints are platform-independent.
|
|
clippy-bindings:
|
|
name: Clippy bindings
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
components: clippy
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: "20"
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
- name: Clippy (bindings, all targets)
|
|
run: cargo clippy -p wickra-node -p wickra-python --all-targets -- -D warnings
|
|
|
|
# Verify the crates still build and test on their declared minimum supported
|
|
# Rust version. The workspace pins rust-version = "1.86" — that floor is
|
|
# set by criterion 0.8.2 (the bench dev-dep), which itself rolled past the
|
|
# clap_lex 1.1.0 / edition2024 / Rust 1.85 floor and now needs 1.86; the
|
|
# earlier rayon-core 1.13.0 (1.80) and clap_lex (1.85) requirements are
|
|
# subsumed. bindings/node pins rust-version = "1.88" because napi-build
|
|
# 2.3.2 requires it (and that subsumes the older 1.77 floor needed for
|
|
# `cargo::` directives). Without this job an accidental use of a newer
|
|
# API would only surface for downstream users.
|
|
msrv:
|
|
name: ${{ matrix.name }}
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- name: MSRV workspace (Rust 1.86)
|
|
toolchain: "1.86"
|
|
packages: "-p wickra-core -p wickra -p wickra-data"
|
|
- name: MSRV node binding (Rust 1.88)
|
|
toolchain: "1.88"
|
|
packages: "-p wickra-node"
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust ${{ matrix.toolchain }}
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
toolchain: ${{ matrix.toolchain }}
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
- name: Build on MSRV
|
|
run: cargo build ${{ matrix.packages }} --verbose
|
|
|
|
- name: Test on MSRV
|
|
run: cargo test ${{ matrix.packages }} --verbose
|
|
|
|
# Code coverage for the pure-Rust crates, uploaded to Codecov.
|
|
coverage:
|
|
name: Coverage
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
components: llvm-tools-preview
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
- name: Install cargo-llvm-cov
|
|
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
|
with:
|
|
tool: cargo-llvm-cov
|
|
|
|
- name: Generate coverage (lcov)
|
|
run: >
|
|
cargo llvm-cov
|
|
-p wickra-core -p wickra -p wickra-data
|
|
--features wickra-data/live-binance
|
|
--lcov --output-path lcov.info
|
|
|
|
- name: Upload to Codecov
|
|
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
|
|
with:
|
|
files: lcov.info
|
|
fail_ci_if_error: false
|
|
env:
|
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
|
|
# Supply-chain audit: security advisories, license policy, banned crates,
|
|
# and source restrictions. Configured by deny.toml at the repo root.
|
|
supply-chain:
|
|
name: Supply-chain (cargo-deny)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: cargo-deny
|
|
uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2.0.20
|
|
with:
|
|
command: check
|
|
|
|
# Time-boxed fuzz smoke. Each target runs for ~30 s with libfuzzer; any panic
|
|
# fails the job. The goal is to catch a regression in the harness (e.g. a
|
|
# newly added indicator that panics on a particular input shape), not to
|
|
# discover novel bugs — long fuzz campaigns should be run on dedicated
|
|
# infrastructure with persistent corpora.
|
|
fuzz-smoke:
|
|
name: Fuzz (smoke)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install nightly Rust
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
toolchain: nightly
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
with:
|
|
workspaces: fuzz
|
|
|
|
- name: Install cargo-fuzz
|
|
# Use the prebuilt binary from taiki-e/install-action instead of
|
|
# `cargo install cargo-fuzz --locked`. The latter resolves the
|
|
# version graph from cargo-fuzz's own Cargo.lock, which pins to
|
|
# rustix 0.36.5 — a version that still uses internal `rustc_*`
|
|
# attributes the modern nightly compiler rejects, so the install
|
|
# never gets off the ground. The prebuilt binary avoids the entire
|
|
# transitive-dep compile.
|
|
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
|
with:
|
|
tool: cargo-fuzz
|
|
|
|
- name: Fuzz csv_reader (30 s)
|
|
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu csv_reader -- -max_total_time=30
|
|
working-directory: fuzz
|
|
|
|
- name: Fuzz binance_envelope (30 s)
|
|
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu binance_envelope -- -max_total_time=30
|
|
working-directory: fuzz
|
|
|
|
- name: Fuzz indicator_update (30 s)
|
|
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu indicator_update -- -max_total_time=30
|
|
working-directory: fuzz
|
|
|
|
- name: Fuzz indicator_update_candle (30 s)
|
|
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu indicator_update_candle -- -max_total_time=30
|
|
working-directory: fuzz
|
|
|
|
- name: Fuzz tick_aggregator (30 s)
|
|
run: cargo +nightly fuzz run --target x86_64-unknown-linux-gnu tick_aggregator -- -max_total_time=30
|
|
working-directory: fuzz
|
|
|
|
python:
|
|
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
python-version: ["3.9", "3.11", "3.12", "3.13"]
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
# setup-python downloads the interpreter from the Actions tool cache /
|
|
# nodejs CDN and occasionally hangs or 5xx's on the Windows runners.
|
|
# Run it with continue-on-error, then retry once after a backoff so a
|
|
# single CDN flake does not fail the whole job (see also: GitHub
|
|
# Actions runner-images#7061).
|
|
- name: Set up Python
|
|
id: setup_python
|
|
continue-on-error: true
|
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
|
|
- name: Wait before Python retry
|
|
if: steps.setup_python.outcome == 'failure'
|
|
shell: bash
|
|
run: |
|
|
echo "::warning::setup-python failed (likely CDN flake), waiting 30s before retry..."
|
|
sleep 30
|
|
|
|
- name: Set up Python (retry)
|
|
if: steps.setup_python.outcome == 'failure'
|
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
|
|
- name: Install Python dev dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
python -m pip install maturin pytest numpy hypothesis
|
|
|
|
- name: Build wheel
|
|
working-directory: bindings/python
|
|
run: maturin build --release --out dist
|
|
|
|
- name: Install wheel
|
|
shell: bash
|
|
working-directory: bindings/python
|
|
# --no-index forces pip to ignore PyPI; --no-deps skips re-resolving
|
|
# numpy (already installed in the previous step). Without --no-index
|
|
# pip prefers the PyPI 0.2.x wheel over our freshly built one when
|
|
# platform tags overlap (e.g. macOS arm64), so tests would run
|
|
# against the released package and miss any new symbols the PR adds.
|
|
run: python -m pip install --no-index --find-links dist --force-reinstall --no-deps wickra
|
|
|
|
- name: Run Python tests
|
|
working-directory: bindings/python
|
|
run: pytest -v
|
|
|
|
wasm:
|
|
name: WASM build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain (with wasm target)
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
with:
|
|
targets: wasm32-unknown-unknown
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
- name: Install wasm-pack
|
|
# jetli/wasm-pack-action@v0.4.0 with no `version:` input installs an
|
|
# old wasm-pack (~0.10.x) whose `build` subcommand does not yet accept
|
|
# `--features`, so `wasm-pack build … --features panic-hook` fails
|
|
# with "Found argument '--features' which wasn't expected". Use the
|
|
# same taiki-e prebuilt-binary installer we already use for
|
|
# cargo-llvm-cov and cargo-fuzz; it tracks the latest wasm-pack
|
|
# release, which has `--features` as a top-level flag (since 0.12).
|
|
uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15
|
|
with:
|
|
tool: wasm-pack
|
|
|
|
- name: Build WASM package
|
|
run: wasm-pack build bindings/wasm --target web --release --features panic-hook
|
|
|
|
- name: Run WASM tests
|
|
run: wasm-pack test --node bindings/wasm
|
|
|
|
- name: Verify generated artefacts
|
|
run: |
|
|
test -f bindings/wasm/pkg/wickra_wasm.js
|
|
test -f bindings/wasm/pkg/wickra_wasm_bg.wasm
|
|
test -f bindings/wasm/pkg/wickra_wasm.d.ts
|
|
|
|
node:
|
|
name: Node ${{ matrix.node-version }} on ${{ matrix.os }}
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
node-version: ["18", "20"]
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Install Rust toolchain
|
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable branch, 2026-03-27
|
|
|
|
- name: Cache cargo
|
|
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
|
|
|
|
# setup-node downloads Node from nodejs.org and we've seen it fail on
|
|
# Windows runners with "Attempting to download 18..." followed by a
|
|
# silent hang or curl error. Retry once after a backoff so a single
|
|
# CDN flake does not fail the whole job.
|
|
- name: Set up Node
|
|
id: setup_node
|
|
continue-on-error: true
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: ${{ matrix.node-version }}
|
|
|
|
- name: Wait before Node retry
|
|
if: steps.setup_node.outcome == 'failure'
|
|
shell: bash
|
|
run: |
|
|
echo "::warning::setup-node failed (likely CDN flake), waiting 30s before retry..."
|
|
sleep 30
|
|
|
|
- name: Set up Node (retry)
|
|
if: steps.setup_node.outcome == 'failure'
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: ${{ matrix.node-version }}
|
|
|
|
- name: Install Node dependencies
|
|
working-directory: bindings/node
|
|
run: npm install
|
|
|
|
- name: Build native module
|
|
working-directory: bindings/node
|
|
# --platform puts the target triple into the filename so the loader's
|
|
# `wickra.<target>.node` lookup finds the freshly built binary instead
|
|
# of falling back to the per-platform npm subpackage (which doesn't
|
|
# exist yet for win32-x64-msvc).
|
|
run: npx napi build --platform --release
|
|
|
|
- name: Run Node tests
|
|
working-directory: bindings/node
|
|
run: node --test __tests__/
|
|
|
|
# The cross-library benchmark has moved to a dedicated scheduled workflow
|
|
# (.github/workflows/bench.yml) — see audit finding R10. It runs nightly
|
|
# at 03:00 UTC and on-demand via `workflow_dispatch`, and is no longer on
|
|
# the every-push / every-PR critical path.
|