Publishing Checklist

Package names to reserve or create:

Target

Registry

Name

Artifact

Workflow

Python

PyPI

nirs4all-core

wheel + sdist from bindings/python

release-python.yml

JavaScript/WASM

npm

nirs4all

npm package from bindings/wasm

release-npm.yml

Rust

crates.io

nirs4all

crate from bindings/rust/nirs4all

release-crates.yml

R

CRAN / R-universe

nirs4all

source tarball from bindings/r

release-r.yml

MATLAB/Octave

GitHub Releases

nirs4all-matlab-octave-<version>.zip

zip from bindings/matlab

release-matlab.yml

Source + SBOM

GitHub Releases

nirs4all-core-<version>-src.*

git-archive + CycloneDX + SHA256SUMS

release-source.yml

How releases are cut

The single source of truth for the version is the Rust crate (bindings/rust/nirs4all/Cargo.toml); scripts/bump_version.sh propagates it to the Python, npm, and R manifests (with the spelling each ecosystem needs) and scripts/bump_version.sh --check fails CI on drift.

On a non-pre-release tag vX.Y.Z the six release-*.yml workflows run and:

  • publish PyPI nirs4all-core via OIDC Trusted Publishing (GitHub environment pypi, id-token: write — no API token),

  • publish npm nirs4all (needs the NPM_TOKEN secret),

  • publish crates.io nirs4all (needs the CARGO_REGISTRY_TOKEN secret),

  • build + attach the R nirs4all source tarball, the MATLAB/Octave zip, and the source + SBOM bundle to the GitHub Release.

A pre-release tag (anything with a -, e.g. v0.1.0-alpha.1) builds and attaches artifacts but publishes to no registry. workflow_dispatch runs every workflow in dry-run mode (build/validate only).

The PyPI Trusted Publisher must be created once by the maintainer for project nirs4all-core with: owner GBeurier, repo nirs4all-core, workflow release-python.yml, environment pypi. Release blocker: the nirs4all-core project/publisher does not exist yet; the old nirs4all-lite publisher does not carry over. The legacy nirs4all-lite PyPI project stays installable — its final release becomes a thin alias depending on nirs4all-core (see CORE_RENAME.md Phase R2); never yank existing versions.

nirs4all-datasets is external/optional everywhere and is never bundled: a Python extra (nirs4all-core[datasets], excluded from [all]), an R Suggests (resolved from R-universe via Additional_repositories), an optional npm peer dependency, and an off-by-default Cargo feature (datasets).

Python / PyPI

Build:

python -m pip install build twine
python -m build bindings/python --outdir dist/python
python -m twine check dist/python/*

Publish after the PyPI project nirs4all-core exists and trusted publishing or an API token is configured:

python -m twine upload dist/python/*

npm

Build:

npm test --prefix bindings/wasm
npm pack ./bindings/wasm --pack-destination dist/npm

Publish after the npm package nirs4all is owned by the project:

npm publish dist/npm/nirs4all-*.tgz --access public

Rust / crates.io

Validate:

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo package -p nirs4all

Publish after the crate name nirs4all is reserved:

cargo publish -p nirs4all

R / CRAN

Build and check:

mkdir -p dist/r
cd dist/r && R CMD build ../../bindings/r && cd ../..
R CMD check --as-cran dist/r/nirs4all_*.tar.gz

The R package is pure R (NeedsCompilation: no) — no Rust/cargo, so none of the “Using Rust” CRAN considerations apply. R CMD check --as-cran is clean (0 ERROR / 0 WARNING; one expected new-submission NOTE). It Imports only jsonlite + yaml; the ecosystem bindings (nirs4allformats, nirs4allio, nirs4alldatasets, n4m, dagmldata) are Suggests, resolved from R-universe via Additional_repositories. Because those upstreams are not on mainstream CRAN yet, the natural channel today is R-universe; the tarball is written CRAN-submittable for when they land on CRAN. See bindings/r/cran-comments.md.

release-r.yml builds and attaches nirs4all_<version>.tar.gz to the Release; the maintainer downloads it and submits via CRAN’s web form when appropriate.

R-universe

R-universe is configured through GBeurier/GBeurier.r-universe.dev. packages.json tracks this package as:

{
  "package": "nirs4all",
  "url": "https://github.com/GBeurier/nirs4all-core",
  "subdir": "bindings/r"
}

Publish only after R CMD check is green in CI.

MATLAB/Octave

Build:

scripts/build-matlab-package.sh dist/matlab

release-matlab.yml runs make test-matlab-parity against the pinned nirs4all-methods ref before attaching the zip to the GitHub Release. A .mltbx can be added later when the MATLAB toolbox metadata is ready; the current portable artifact is Octave-safe.