2026-03-23 23:34:28 +05:30
# Release Playbook
This document describes the step-by-step process for cutting a new **ferro-ta** release.
Follow every step in order to produce a consistent, reproducible release.
2026-03-23 23:57:30 +05:30
For the packaging and release overview, see [PACKAGING.md ](PACKAGING.md ).
2026-03-23 23:34:28 +05:30
---
## Publish matrix (all automatic on release)
| Artifact | How |
|-------------|-----|
2026-03-23 23:57:30 +05:30
| **PyPI** | CI job `publish` using PyPI Trusted Publishing (OIDC) |
2026-03-23 23:34:28 +05:30
| **npm (WASM)** | Workflow `wasm-publish` |
| **crates.io** | CI job `publish-cratesio` |
2026-03-24 01:00:17 +05:30
PyPI releases are expected to include:
- Wheels for CPython 3.10, 3.11, 3.12, and 3.13
- Linux x86_64 (`manylinux_2_17` )
- macOS universal2
- Windows x86_64
- One source distribution (`sdist` )
2026-03-23 23:34:28 +05:30
---
## Pre-release checklist
Before starting a release:
- [ ] All CI checks are green on `main` : Rust (fmt, clippy), tests (with coverage gate),
lint (ruff), typecheck (mypy, pyright), docs (Sphinx), WASM, audit (cargo-audit,
pip-audit), fuzz (no crashes).
- [ ] **Security audit clean:** Run `cargo audit` and `pip-audit` locally and confirm
no high/critical vulnerabilities. Address any findings before tagging.
```bash
cargo audit
pip-audit # or: uv run --with pip-audit pip-audit
` ``
- [ ] No open blocking issues or PRs that must land first.
- [ ] ` CHANGELOG.md` has a ` ## [X.Y.Z]` section (not ` [Unreleased]`) with all
changes since the last release documented under ` ### Added`, ` ### Changed`,
` ### Fixed`, ` ### Removed` headings.
2026-03-24 11:09:48 +05:30
- [ ] Public docs match the release: ` docs/conf.py`, ` docs/changelog.rst`, and
` docs/support_matrix.rst` reflect the version and current support status.
2026-03-23 23:34:28 +05:30
---
## Step 1 — Decide the version number
Follow [Semantic Versioning 2.0.0](https://semver.org/) and the policy in
[VERSIONING.md](VERSIONING.md):
| Change type | Version component to bump |
|---|---|
| Breaking API change (indicator removed, parameter renamed, return type changed) | **MAJOR** |
| New indicators, features, or bindings (backward-compatible) | **MINOR** |
| Bug fixes, performance, docs-only, dependency bumps | **PATCH** |
Example: current version is ` 0.1.0` and you are adding new indicators → new version is ` 0.2.0`.
---
## Step 2 — Sync version everywhere
2026-03-24 11:09:48 +05:30
These files must carry **the same version string** (e.g. ` 0.2.0`). The easiest
way to do that is:
` ``bash
python3 scripts/bump_version.py 0.2.0
python3 scripts/bump_version.py --check
` ``
That script updates the tracked release-version carriers for you.
Files covered by the bump script:
2026-03-23 23:34:28 +05:30
| File | Location |
|------|----------|
| ` Cargo.toml` | Root (source of truth) |
| ` crates/ferro_ta_core/Cargo.toml` | Same version for crates.io publish |
2026-03-24 11:09:48 +05:30
| ` crates/ferro_ta_core/README.md` | Installation snippet should show the current crate version |
2026-03-23 23:34:28 +05:30
| ` pyproject.toml` | Root |
2026-03-24 11:09:48 +05:30
| ` wasm/package.json` | Package version |
| ` conda/meta.yaml` | Conda recipe version |
| ` docs/conf.py` | Default Sphinx release must resolve to the same version |
2026-03-23 23:34:28 +05:30
**` Cargo.toml`** (root):
` ``toml
[package]
name = "ferro_ta"
2026-03-24 11:09:48 +05:30
version = "X.Y.Z" # ← or use scripts/bump_version.py X.Y.Z
2026-03-23 23:34:28 +05:30
` ``
**` pyproject.toml`**:
` ``toml
[project]
2026-03-24 11:09:48 +05:30
version = "X.Y.Z" # ← must match Cargo.toml exactly
2026-03-23 23:34:28 +05:30
` ``
> **Rule:** ` Cargo.toml` is the source of truth. Sync the others to match before tagging.
---
## Step 3 — Update CHANGELOG.md
1. Open ` CHANGELOG.md`.
2026-03-24 11:09:48 +05:30
2. Rename the ` [Unreleased]` section to ` [X.Y.Z] — YYYY-MM-DD` (today's date).
2026-03-23 23:34:28 +05:30
3. Add a fresh empty ` [Unreleased]` section at the top.
4. Update the comparison links at the bottom:
` ``markdown
2026-03-24 11:09:48 +05:30
[Unreleased]: https://github.com/pratikbhadane24/ferro-ta/compare/vX.Y.Z...HEAD
[X.Y.Z]: https://github.com/pratikbhadane24/ferro-ta/compare/vPREVIOUS...vX.Y.Z
2026-03-23 23:34:28 +05:30
` ``
Follow the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format:
` Added`, ` Changed`, ` Deprecated`, ` Removed`, ` Fixed`, ` Security`.
2026-03-24 11:09:48 +05:30
Also update the docs-facing release surfaces for the same version:
- ` docs/changelog.rst` with a concise release-notes entry
- ` docs/support_matrix.rst` if supported versions, tested wheels, or module
stability changed
2026-03-23 23:34:28 +05:30
---
## Step 4 — Commit the version bump
` ``bash
git add Cargo.toml crates/ferro_ta_core/Cargo.toml pyproject.toml wasm/package.json CHANGELOG.md
git commit -m "chore: release v0.2.0"
git push origin main
` ``
Wait for CI to pass on this commit before proceeding.
---
## Step 5 — Create and push the tag
` ``bash
git tag v0.2.0
git push origin v0.2.0
` ``
> Tags must be in the form ` vMAJOR.MINOR.PATCH` (e.g. ` v0.2.0`).
---
## Step 6 — Create a GitHub Release
1. Go to **Releases → Draft a new release** in the GitHub UI.
2. Select the tag ` v0.2.0` you just pushed.
3. Set the release title to ` v0.2.0`.
4. Paste the changelog section for ` v0.2.0` into the release notes.
5. Click **Publish release**.
2026-03-24 01:00:17 +05:30
Publishing the release triggers the CI wheel build jobs, ` build-sdist`, and ` publish`
2026-03-23 23:57:30 +05:30
automatically (the workflow responds to ` release: published`). The PyPI upload
uses Trusted Publishing via GitHub OIDC, so no ` PYPI_API_TOKEN` secret is used.
2026-03-23 23:34:28 +05:30
---
## Step 7 — Monitor CI and verify PyPI
2026-03-24 01:00:17 +05:30
1. Watch the **Actions** tab: the release wheel jobs, ` build-sdist`, ` publish` (PyPI), ` publish-cratesio` (crates.io), and the **wasm-publish** workflow (npm).
2026-03-23 23:34:28 +05:30
2. After the ` publish` job succeeds, verify the package is live:
` ``bash
pip install ferro-ta==0.2.0
python -c "import ferro_ta; print(ferro_ta.__version__ if hasattr(ferro_ta,'__version__') else 'ok')"
` ``
2026-03-24 01:00:17 +05:30
For version-specific verification, also check at least one install on each
supported Python line, for example:
` ``bash
uv venv --python 3.13 .venv-313
. .venv-313/bin/activate
uv pip install ferro-ta==0.2.0
python -c "import ferro_ta; print(ferro_ta.SMA([1.0, 2.0, 3.0], 2))"
` ``
2026-03-23 23:34:28 +05:30
3. If anything fails: fix the issue, bump to a patch version (` 0.2.1`), and repeat.
---
---
## Hotfix releases
For urgent bug fixes on a released version:
1. Branch from the release tag: ` git checkout -b hotfix/0.1.1 v0.1.0`
2. Apply the fix, bump to ` 0.1.1`, update CHANGELOG.
3. Merge the branch into ` main`.
4. Tag and release as above.
---
> **Note:** ` ferro_ta_core` is published to crates.io automatically by the CI job ` publish-cratesio` when you publish a release (requires ` CARGO_REGISTRY_TOKEN` secret).
---
## See also
- [VERSIONING.md ](VERSIONING.md ) — versioning policy and breaking-change rules
- [CHANGELOG.md ](CHANGELOG.md ) — changelog history
- [CONTRIBUTING.md ](CONTRIBUTING.md ) — development setup and PR guidelines