Use this when shipping both the Rust crate and the
Python package (python-wrapper/). For
Rust-only or Python-only hotfixes, follow the relevant sections
only.
Bump all of these to the same
SemVer (e.g. 0.3.3):
| File | Field |
|---|---|
Cargo.toml (repo root) |
[package] version |
python-wrapper/pyproject.toml |
[project] version |
python-wrapper/Cargo.toml |
[package] version |
bindings/java/VERSION |
single line (no -SNAPSHOT at release) |
bindings/java/rust-data-processing-jvm/pom.xml |
<version> (main artifact) |
bindings/java/rust-data-processing-jvm/gradle.properties |
version= |
The release script scripts/release.py
(or ./scripts/release_tag.sh /
./scripts/release_tag.ps1) updates all of
the above plus Cargo.lock (root +
python-wrapper/),
python-wrapper/uv.lock, and inserts a
CHANGELOG.md stub. Edit the changelog body
after the script runs (before confirming), or edit on main
before the next release.
PyPI uses pyproject.toml as the
distribution version; the extension crate version should match for
maintainability.
README assets: Keep scope infographics under
docs/images/ (repository root).
README_CRATE.md (crates.io / docs.rs) and
python-wrapper/README_PYPI.md (PyPI) use
the Phase 3 hero
phase-3-scope-overview.png; keep
phase-2-scope-overview.png and
phase-1-scope-overview.png for historical
posts or docs that still reference earlier phases. Language doc indexes
(docs/rust/README.md,
docs/python/README.md,
docs/java/README.md) use the same Phase 3
graphic via relative paths. Registry READMEs use
raw.githubusercontent.com for the hero image so
PyPI/crates.io always resolve the current graphic (PyPI avoids bundling
a duplicate PNG in sdist; crates.io/docs.rs avoid stale or missing
relative-path renders). The Planning/ tree is gitignored
and is not a publish source for this asset.
CHANGELOG.md
(replace the stub line if the script added one) (Keep a Changelog).Rust CI
(.github/workflows/rust_ci.yml — fmt, clippy, tests, ubuntu
--features ci_expanded)Python wrapper CI (maturin +
pytest)Documentation
(.github/workflows/docs.yml — rustdoc + pdoc build; on
main, refreshes GitHub Pages if configured — see DOCUMENTATION.md)main.Preferred: after merging to
main, push tag
v* (use
scripts/release.py /
./scripts/release_tag.sh /
./scripts/release_tag.ps1 - see §4) —
rust_release.yml publishes via
CRATES_IO_TOKEN.
Manual alternative (from repo root, after merge):
cargo fmt --check
cargo clippy -- -D warnings
cargo test
cargo publish --dry-run
cargo publishcargo publish fails if that version already exists —
bump and repeat. If you use CI for this version, do not
also run cargo publish locally.
rdp-jvm-sys + Maven + Gradle) — Phase 3| Location | Bump / notes |
|---|---|
bindings/java/VERSION |
Single source — sync pom.xml,
gradle.properties,
bindings/java/rdp-jvm-sys/pom.xml |
bindings/jvm-sys/Cargo.toml |
Native crate semver (coordinate with FFI ABI
rdp_ffi_abi_version) |
bindings/java/rust-data-processing-jvm/pom.xml |
<version> after
VERSION edit |
Consistency guard (run before tagging):
python scripts/check_java_version_consistency.py
python scripts/check_jvm_ffi_manifest.pySmoke build (mirror CI — explicit native path on each runner):
# Java formatting (same gate as Maven Central release `validate` / `mvn deploy`)
mvn -f bindings/java/rust-data-processing-jvm spotless:check
# on failure: mvn -f bindings/java/rust-data-processing-jvm spotless:apply
cargo build --release --manifest-path bindings/jvm-sys/Cargo.toml --features full
export RDP_JVM_SYS="$(pwd)/bindings/jvm-sys/target/release/librdp_jvm_sys.so"
mvn -f bindings/java/rust-data-processing-jvm -q verify
( cd bindings/java/rust-data-processing-jvm && ./gradlew check publishToMavenLocal --no-daemon )Native classifier smoke (Linux x86_64 — validates
classpath loading without
RDP_JVM_SYS):
./scripts/test_native_classifier_local.shCentral publication (Java API JAR): docs/java/MAVEN_CENTRAL_PUBLISHING.md
(namespace io.github.scorpio-datalake,
tokens, GPG). CI: .github/workflows/jvm_maven_central_release.yml
— runs when a GitHub Release is published and tag
v{bindings/java/VERSION} matches a
non-SNAPSHOT VERSION.
Central publication (native classifiers): CI:
.github/workflows/jvm_native_maven_release.yml
— same v{VERSION} gate; builds five
platform classifiers and deploys via
scripts/deploy_rdp_jvm_sys_native_jars.sh.
Consumer docs: docs/java/NATIVE_ARTIFACT_PACKAGING.md.
Workflow: .github/workflows/jvm_bindings_ci.yml
(Ubuntu / Windows / macOS × JDK
21).
Add two repository secrets under Settings →
Secrets and variables → Actions (step-by-step: How_TO_deploy.md §
GitHub: add secrets for crates.io and PyPI). Once
CRATES_IO_TOKEN and
PYPI_API_TOKEN are set, tagged releases
can publish without further token setup.
| Secret name | Used by | Created at |
|---|---|---|
CRATES_IO_TOKEN |
.github/workflows/rust_release.yml |
crates.io → account → API tokens |
PYPI_API_TOKEN |
.github/workflows/python_release.yml |
pypi.org → account → API tokens |
Releases are not automatic on every merge: you
choose when to cut a tag after main
already contains the version bump and green CI.
Use one flow: complete steps 1–2
(changelog + merge to main), then run the
release script (or the raw git commands below). The script can
bump versions and commit in one step,
or you can bump manually first. Do not also
cargo publish locally for the same version, or the GitHub
job will fail with “already uploaded”.
Confirm
python-wrapper/pyproject.toml version
matches the Rust crate (step 1), or let the release script bump
them.
Merge your release PR into main and
ensure CI is green. Push main to
origin so HEAD matches
origin/main (unless the script will push
main and bump for you).
From repo root, on main, run the
release script (interactive: shows last v* tag, prompts for
new SemVer, writes files, commits, pushes
main, pushes
v*):
./scripts/release_tag.shWindows PowerShell:
./scripts/release_tag.ps1Or: python scripts/release.py /
python scripts/release.py 0.2.0 --comment "Release notes" -y
See --help for --dry-run,
--skip-git (bump only),
--no-commit,
--allow-dirty.
Equivalent manual commands:
git fetch origin main
git checkout main && git pull --ff-only origin main
git tag -a v0.2.0 -m "Release v0.2.0"
git push origin v0.2.0Actions runs:
rust_release.yml — verifies the tag is
on origin/main, then
cargo publish --locked.python_release.yml — same guard, then
builds wheels and uploads to PyPI.jvm_maven_central_release.yml — when
the script publishes a GitHub Release for
v{VERSION} (requires
gh CLI locally:
gh auth login). Deploys
rust-data-processing-jvm to Maven
Central when
bindings/java/VERSION matches the tag (no
-SNAPSHOT). Use
--skip-github-release to tag only and
publish the GitHub Release manually later.Tags pointing at commits not on
main are rejected (no publish).
cargo publish
(optional)If you publish the Rust crate from your machine instead of
rust_release.yml, skip pushing a tag until
you are ready, or disable that workflow temporarily — avoid
double-publishing the same version.
cd python-wrapper
uv run maturin build --release -o dist --find-interpreter --sdist
# Inspect python-wrapper/dist/*.whl and .tar.gzmaturin build --features db (see
python-wrapper/README_DEV.md). Default CI
wheels do not enable db
unless you change [tool.maturin] /
workflow args.vX.Y.Z; paste
CHANGELOG notes.[package.metadata.docs.rs] cargo-args = ["-j", "1"]
in the root Cargo.toml. Publish a
patch (e.g. 0.1.6) after that change so
docs.rs rebuilds. For compiler errors, fix the reported
issue and republish.pip install rust-data-processing==X.Y.Z works.How_TO_deploy.md —
packaging details, CI matrix, abi3 note,
feature flags.python-wrapper/PARITY.md — Rust ↔︎
Python API matrix.