Commit Graph

21 Commits

Author SHA1 Message Date
kingchenc a4d8c40dc2 E6: extend the Python release matrix to musl and Windows arm64
python-wheels built only glibc Linux (x86_64/aarch64), macOS, and
Windows x64 — Alpine/musl users and Windows arm64 had no wheel.

Add musllinux_1_2 wheels for x86_64 and aarch64 Linux and an
aarch64 wheel on the windows-11-arm runner. The upload artifact name
now includes the manylinux value so the glibc and musl builds of the
same architecture do not collide. The Node release matrix already
covers linux-arm64 and win32-arm64 (added in B11); Node musl is left
out, as B11 documented, because it needs a cross/container setup.
2026-05-22 16:45:20 +02:00
kingchenc 5568596e18 E8: add code coverage to CI
CI had no coverage measurement, and although .gitignore listed coverage
artefacts nothing produced them.

Add a `coverage` job that runs cargo-llvm-cov over the three pure-Rust
crates (with wickra-data's live-binance feature so the Binance parser
tests count), emits lcov, and uploads to Codecov. The Codecov upload
uses fail_ci_if_error: false so a Codecov outage cannot break CI. Both
new actions (taiki-e/install-action, codecov/codecov-action) are
SHA-pinned. Add a coverage badge to the README.
2026-05-22 16:38:01 +02:00
kingchenc 71e46a1ea6 E10: add cargo-deny supply-chain checks
The repository had no supply-chain auditing — no deny.toml and no CI
job to catch vulnerable, unmaintained, wrongly-licensed, or
unexpectedly-sourced dependencies.

Add deny.toml covering advisories, bans, licenses and sources:

- licenses: an allow-list of the permissive licenses the dependency
  tree actually uses, plus the workspace's own PolyForm-Noncommercial
  license and a scoped LLVM-exception for target-lexicon.
- bans: warn on duplicate versions, deny external wildcard deps
  (internal path deps are allowed).
- sources: only crates.io.
- advisories: RUSTSEC-2025-0020 (pyo3 0.22) is ignored with a documented
  reason — it is reachable only through bindings/python and the pyo3
  upgrade is tracked separately; the published crates do not use pyo3.

Add a `supply-chain` CI job running cargo-deny-action (SHA-pinned).
`cargo deny check` passes locally: advisories/bans/licenses/sources ok.
2026-05-22 16:25:58 +02:00
kingchenc 53b8b6e282 E2: add an MSRV verification job to CI
Every CI job used dtolnay/rust-toolchain on stable, so the declared
minimum supported Rust version was never exercised — an accidental use
of a newer API would only break for downstream users on an older
compiler.

Add an `msrv` job with a two-row matrix: the workspace crates
(wickra-core, wickra, wickra-data) build and test on Rust 1.75, and the
node binding on Rust 1.77, matching the rust-version each manifest
declares. Both rows use the SHA-pinned toolchain action.
2026-05-22 12:37:15 +02:00
kingchenc 9b11d73273 D1: pin all GitHub Actions to commit SHAs
Every action in ci.yml and release.yml was pinned to a movable tag
(actions/checkout@v4, dtolnay/rust-toolchain@stable, ...). A compromised
upstream tag would run with access to the crates.io / PyPI / npm
publish tokens.

Pin every `uses:` to the full 40-character commit SHA the referenced
ref currently resolves to, with the human-readable version kept as a
trailing comment so Dependabot can still bump them:

  actions/checkout            v4.3.1
  actions/setup-python        v5.6.0
  actions/setup-node          v4.4.0
  actions/upload-artifact     v4.6.2
  actions/download-artifact   v4.3.0
  dtolnay/rust-toolchain      stable branch @ 2026-03-27
  Swatinem/rust-cache         v2
  jetli/wasm-pack-action      v0.4.0
  PyO3/maturin-action         v1.51.0
  softprops/action-gh-release v2.6.2

SHAs were resolved against the GitHub API. The github-actions Dependabot
ecosystem that keeps these pins current is added with E3.
2026-05-22 12:35:02 +02:00
kingchenc 0d451ac584 D2: gate the publish jobs behind a protected environment
release.yml triggers on every v* tag push and the four publish jobs
(crates.io, PyPI, npm, wasm) inject long-lived registry tokens straight
from secrets with no environment, no reviewer and no tag restriction.

Bind all four jobs to a `release` GitHub environment. With the
environment's protection rules (required reviewers, tag/branch
restrictions) configured under repo Settings -> Environments, the
registry secrets become reachable only from an approved release run
rather than from any workflow execution.
2026-05-22 12:32:47 +02:00
kingchenc 8ccb885906 D4: pass --ignore-scripts to per-platform npm publish/pack
The main npm package already publishes and packs with --ignore-scripts,
but the per-platform subpackage loop did not: `npm publish --access
public`, its retry, and the per-platform `npm pack` all ran lifecycle
scripts from the package directory with the npm token in scope.

Add --ignore-scripts to all three, matching the main package, so no
prepublish/prepare hook can execute during a release.
2026-05-22 12:32:23 +02:00
kingchenc ad17915e49 D3: drop --allow-dirty --no-verify from release cargo package
The release workflow built the .crate attachments with
`cargo package --allow-dirty --no-verify`, so the attached artefact
could diverge from the tagged tree and was never proven to build.

Remove both flags. actions/checkout provides a clean tree and no prior
step mutates it, so --allow-dirty is unnecessary. The crates are
published to crates.io earlier in the same job, so the verification
build now resolves workspace dependencies from the registry and
confirms each .crate compiles before it is attached.
2026-05-22 12:32:04 +02:00
kingchenc 2fc7a90ec0 B11: ship npm binaries for linux-arm64 and win32-arm64
The napi loader resolves wickra-linux-arm64-gnu and
wickra-win32-arm64-msvc, but neither was published, so require('wickra')
failed on those platforms. Adds both to napi.triples and
optionalDependencies, adds their npm/ package templates, and extends the
release node-build matrix to build them on GitHub's native ARM runners
(ubuntu-24.04-arm, windows-11-arm).
2026-05-22 04:17:23 +02:00
kingchenc 8192e576cf B6: add a WASM binding test suite
The WASM binding had no tests; CI only checked that artefacts existed.
Adds a wasm-bindgen-test suite covering SMA reference values, EMA
batch==streaming equivalence, RSI pure-uptrend behaviour, fallible
constructors returning JsError, and the unequal-length batch guards from
B3. Wires wasm-pack test --node into the CI wasm job. The suite
type-checks on the host; it executes under wasm-pack in CI (the local
environment is a non-rustup Rust install without the wasm32 target).
2026-05-22 04:05:15 +02:00
kingchenc 323e9ce153 ci(release): attach all build artefacts to the GitHub Release
The Releases page previously showed only the source archives GitHub
auto-generates for every tag. Add an explicit github-release job that
runs after every publish job finishes, downloads every uploaded
artefact, and attaches them all to the release.

New per-publish-job upload-artifact additions:
- cargo-publish: 'cargo package' each crate and upload the .crate files
- wasm-publish:  'npm pack' inside pkg/ and upload the wickra-wasm tgz
- node-publish:  'npm pack' the main package + each per-platform subpackage,
                  upload all six tgz files (main + linux + 2*darwin + win32)

Wheels and .node binaries were already being uploaded earlier in the
matrix builds, so the new job just consumes them via download-artifact.

github-release job:
- Runs on tag pushes (normal) AND workflow_dispatch (so we can backfill
  assets to an existing release without rebumping the version).
- Resolves the target tag from github.ref on a tag push, or from
  'git tag --sort=-v:refname | head' on dispatch.
- Stages all files into release-assets/, uses softprops/action-gh-release
  to create or update the release. generate_release_notes lets GitHub
  fill in the commit-list changelog automatically.
2026-05-21 22:28:25 +02:00
kingchenc 5c40acd288 ci+loader: build with --platform; ship napi-generated loader
The Windows Node 18 and Node 20 CI jobs failed because:

- ci.yml ran 'napi build --release' (no --platform), which produces a
  filename without the target triple ('wickra.node').
- The committed loader at bindings/node/index.js looked for the
  triple-suffixed file ('wickra.win32-x64-msvc.node') and then for the
  per-platform npm subpackage as a fallback.
- 'wickra-win32-x64-msvc' isn't on npm yet (blocked by the spam filter),
  so Windows had nothing to load. Linux and macOS passed only because
  their optionalDependencies do exist on npm and got fetched.

Two-part fix:

- ci.yml now runs 'napi build --platform --release', matching release.yml.
  --platform encodes the target triple in the filename, so the loader's
  primary lookup always finds the freshly built binary on every host.

- bindings/node/index.js is now the canonical napi-rs auto-generated
  loader (it gets regenerated by 'napi build'). It covers all the platforms
  napi knows about (linux glibc/musl, Android, FreeBSD, ARM, etc.) rather
  than just the four we publish, so unsupported platforms get a clear
  'this binding isn't built for your system' error instead of a confusing
  ENOENT.

Local sanity: 'npx napi build --platform --release' then 'node --test
__tests__/' succeeds end to end on Windows; the eight existing tests
pass.
2026-05-21 21:53:49 +02:00
kingchenc de39415413 ci(release): drop prepublishOnly hook + ignore-scripts on main publish
The root cause of the previous failure was the package.json
"prepublishOnly": "napi prepublish -t npm" script. When the workflow
ran `npm publish` for the main wickra package it implicitly invoked
that hook, which re-attempted to publish every platform subpackage and
hit 403 "cannot publish over 0.1.2" because they were already on
the registry. The error trail looked like it came from the main
publish step but the failing command was actually the hook.

Two-part fix:
- Remove prepublishOnly entirely from bindings/node/package.json. The
  release workflow already does the per-platform publish itself, in a
  loop, idempotently.
- Belt-and-braces: pass --ignore-scripts when publishing the main
  package so any prepublish-hook drift in the future is suppressed.
2026-05-21 21:43:57 +02:00
kingchenc 827cdc7a6b ci(release): make the main-package publish step tolerant of 'npm view' 404
GitHub Actions runs shell steps with bash -e, so when npm view wickra@<v>
returned exit 1 (because the package was not yet on the registry) the
whole step aborted before reaching npm publish. Switch the step to
`set +e` and capture the rc explicitly, so a 404 from npm view is
treated as 'not published yet, go publish' instead of a fatal error.
Also adds a single retry after 30s for spam-filter blocks.
2026-05-21 21:39:05 +02:00
kingchenc ccf2b46482 ci(release): per-platform idempotent npm publish + spam-filter retry
The previous 'napi prepublish -t npm' step was atomic — one failure killed
the whole step, and on retry it tried to republish already-uploaded
versions which 403'd. v0.1.2 left 3 of 4 platform packages and the wasm
package on npm but the main 'wickra' package and 'wickra-win32-x64-msvc'
never got out.

Replace it with a small bash loop that:

- Walks every npm/<platform>/ directory.
- Skips the publish if 'npm view <pkg>@<version>' confirms the version
  is already on the registry (idempotent re-runs).
- Tolerates per-package failures (sets rc but always returns 0 from the
  helper) so spam-filter blocks on one platform don't take down the
  others. A 30-second retry handles transient rate-limit spam blocks.
- Publishes the main 'wickra' meta-package as a separate step with the
  same skip-existing guard.

Same publishing semantics, just deconstructed into individually
recoverable steps.
2026-05-21 21:34:33 +02:00
kingchenc 1aa7df1c97 fix(node): commit npm/<platform>/ templates + optionalDependencies
`napi create-npm-dir` failed in CI with both invocations we tried:
positional arg form (`-t <triple> .`) was rejected as extraneous,
and the no-arg form crashed with "path must be a string, received
undefined". The fix used by every napi-rs reference project: commit
the four platform package.json templates directly under
bindings/node/npm/<target>/ instead of generating them at publish time.

- bindings/node/npm/{linux-x64-gnu,darwin-x64,darwin-arm64,win32-x64-msvc}/
  each contain a static package.json with the correct os / cpu / libc
  filters so npm only installs the right binary per platform.
- Main package.json gains optionalDependencies referencing all four
  platform packages by version, so `npm install wickra` pulls the
  matching binary on each user's machine.
- Release workflow drops the broken `create-npm-dir` loop. The
  `napi artifacts` step now just copies the .node files from the
  build artefacts into the existing npm/ directories before publish.

Bump every version to 0.1.2; cargo / pypi / wickra-wasm jobs are
idempotent so they accept the 0.1.1 they already published while still
emitting the new 0.1.2.
2026-05-21 21:16:33 +02:00
kingchenc 371d338a8b Release 0.1.1: fix Node publish + bump everything
v0.1.0 reached crates.io, PyPI, and the wickra-wasm npm package, but
the wickra Node binding never published because the workflow called
`napi create-npm-dirs` (plural). The actual napi CLI command is
`create-npm-dir` (singular, per target).

Changes that make the next tag's release actually finish:

- workflow: replace the broken step with a loop that runs
  `napi create-npm-dir -t <triple>` for each of our four build targets.

- workflow: every registry publish step now treats "version already
  uploaded" as success. That makes re-runs (and partial-failure
  recoveries) safe instead of failing the whole job.

- bindings/node/package.json: trim the napi.triples list to the four
  platforms we actually build (linux-x64-gnu, darwin-x64, darwin-arm64,
  win32-x64-msvc). The previous defaults+9-extras configuration would
  have made napi prepublish expect platform packages we never produced.

- bindings/node/index.js: switch from local-only binary lookup to the
  proper napi loader that tries the local `.node` file first and falls
  back to the per-platform npm subpackage that's installed as an
  optional dependency in production.

- Versions across all four published packages bumped to 0.1.1 so the
  Node binding can publish for the first time alongside refreshed
  cargo/pypi/wasm artefacts.
2026-05-21 21:06:42 +02:00
kingchenc 24a9ff8244 ci(release): three fixes after the first v0.1.0 attempt
Three blockers surfaced when the first tag actually ran the pipeline:

1. PyPI sdist build refused the `readme = "../../README.md"` path
   in bindings/python/pyproject.toml. maturin sdist forbids `..`
   inside archive entries. Solution: add a Python-specific README at
   bindings/python/README.md (covers the Python install + pointers to
   the main repo) and point the project.readme key at the local file.

2. Node publish job hit ENOENT on npm/<platform>/wickra.<...>.node
   because napi's per-platform scaffolding directories did not exist
   yet when `napi artifacts` ran. Insert `napi create-npm-dirs` as
   its own step before `napi artifacts` so the platform package layout
   is in place before binaries get moved into it.

3. and 4. (crates.io email + npm 2FA-bypass) are registry-side account
   settings that have to be done in the user's browser; no code change
   needed for those. They'll be sorted before the next tag push.
2026-05-21 20:51:30 +02:00
kingchenc 1295b63e1f 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.
2026-05-21 20:35:18 +02:00
kingchenc d42a0d7ad5 ci: fix maturin and wasm-pack jobs
Two unrelated failures in the post-release CI run:

- Python jobs: `maturin develop` requires an activated virtualenv on
  CI runners that don't have a system Python set up that way. Switch
  to `maturin build --release --out dist` followed by `pip install
  --find-links dist`, which is venv-agnostic and OS-portable.

- WASM job: the wasm-opt bundled with wasm-pack is older than the WASM
  features rustc 1.92 enables by default. The fix is to opt every feature
  in explicitly via the package metadata — reference-types, multivalue,
  bulk-memory, sign-ext, mutable-globals, nontrapping-float-to-int — so
  wasm-opt accepts the input.

Same code as before; only the build steps and the wasm-opt config changed.
2026-05-21 18:04:57 +02:00
kingchenc 3be267cb03 Wickra 0.1.0: streaming-first technical indicators
A multi-language technical analysis library: 25 indicators across trend,
momentum, volatility, and volume families, every one a state machine with
O(1) per-tick updates. Batch evaluation is provided by a blanket extension
trait over the streaming primitive, so live trading bots and historical
backtests run the same code path.

What ships in this initial drop:

  crates/wickra-core   - 25 indicators, Indicator/BatchExt/Chain traits,
                          OHLCV types with validation; 171 unit tests,
                          property tests, Wilder/Bollinger textbook tests.
  crates/wickra        - top-level facade + criterion benches for every
                          indicator at 1K/10K/100K series sizes.
  crates/wickra-data   - streaming CSV reader, tick-to-candle aggregator,
                          multi-timeframe resampler, Binance Spot kline
                          WebSocket adapter behind feature live-binance;
                          11 unit + 1 doctest.
  bindings/python      - PyO3 + maturin, NumPy I/O, type stubs (.pyi),
                          56 pytest tests including streaming==batch
                          equivalence, Wilder reference values, lifecycle.
  bindings/node        - napi-rs native module, TypeScript .d.ts
                          auto-generated, 7 node --test cases.
  bindings/wasm        - wasm-bindgen ES module for browser/bundler/Node;
                          interactive HTML demo at examples/index.html.
  examples/            - Python and Rust scripts: backtest, live trading,
                          parallel multi-asset, multi-timeframe, Binance.
  benchmarks/          - cross-library comparison against TA-Lib,
                          pandas-ta, finta, talipp; Wickra wins every
                          category by 11-1030x (batch) and 17x+ streaming.
  .github/workflows/   - CI matrix (Rust + Python + Node + WASM on
                          Linux/macOS/Windows), release pipeline for
                          PyPI wheels and npm.

Indicators (25):
  Trend       SMA EMA WMA DEMA TEMA HMA KAMA
  Momentum    RSI MACD Stochastic CCI ROC WilliamsR ADX MFI TRIX
              AwesomeOscillator Aroon
  Volatility  BollingerBands ATR Keltner Donchian PSAR
  Volume      OBV VWAP (cumulative + rolling)

cargo clippy --workspace --all-targets -D warnings is clean. License: Apache-2.0.
2026-05-21 17:50:45 +02:00