Releasing¶
Three independent release flows: the package (PyPI), the datasets (Dataverse, for protected data), and the human validation sign‑off.
1. The package → PyPI¶
The package builds cleanly and passes twine check (sdist + platform-specific wheels — maturin bundles
the native nirs4all_datasets._n4ds pyo3 extension, so wheels are per-platform, not py3-none-any). It
depends only on published packages — nirs4all is an optional [nirs4all] extra, so
pip install nirs4all-datasets resolves without the unpublished siblings.
One‑time setup (no API token — Trusted Publishing / OIDC)¶
Reserve the name / first upload. Either create the project on PyPI by doing one manual upload from a maintainer machine:
python -m build && python -m twine check dist/* python -m twine upload dist/* # asks for your PyPI token once
…or create an empty project + a pending Trusted Publisher (PyPI now supports project‑less pending publishers).
Add the Trusted Publisher on PyPI → Your project → Publishing → Add a GitHub publisher:
Owner
GBeurier, repositorynirs4all-datasets, workflowrelease.yml, environmentpypi.
Create the GitHub environment
pypi(repo → Settings → Environments) — optionally require manual approval so a tag does not publish unattended.
Cut a release¶
# 1. bump the version
# pyproject.toml: version = "0.2.0" (drop the .devN suffix for a real release)
# 2. commit + tag
git commit -am "release: v0.2.0"
git tag v0.2.0
git push origin main --tags
The tag triggers .github/workflows/release.yml: it builds, runs
twine check, and publishes to PyPI via OIDC (gated on the pypi environment). Verify with
pip install nirs4all-datasets in a clean venv.
Caveat — runtime catalog. The wheel ships the code and the bundled cross-language
catalog/index.json, but the assembled catalog (catalog/datasets.yaml), descriptors, cards, and manifests still live in the registry checkout. A pip-installed Python consumer therefore still pointsget(root=<checkout>)at a clone of this repo for the high-levelget()/list()/card()surface. Non-Python bindings can consume the bundled or committedcatalog/index.jsondirectly.
2. The datasets → Dataverse (protected data)¶
Public datasets are not published here — they are linked to their origin. Private / anonymized
datasets can later be uploaded to a personal Dataverse so consumers can get(token=…) them. The list of
datasets awaiting upload is generated locally by n4a-datasets status (a maintainer-only worklist, not
published here).
Token:
NIRS4ALL_DATAVERSE_TOKENenv var, or~/.config/nirs4all-datasets/config.toml(chmod 600), or a project.env. The token travels only inX-Dataverse-key, is never logged, and is never sent on an S3 redirect. Prefer the sandbox (demo.recherche.data.gouv.fr) before production.Locally:
n4a-datasets publish <id> --collection <alias> --contact-email you@example.org # mints a DOI (first time) n4a-datasets restrict <id> # access-gate all files, publish a minor version n4a-datasets grant <id> --to @user # let a user download restricted files
In CI: the manual
publish.ymlworkflow (workflow_dispatch, gated on the protecteddataverse-publishenvironment; token = theDATAVERSE_TOKENsecret).The governance gate (
validate.py --check-publish) refuses a public dataset that is not openly licensed/sourced. Full walkthrough:PUBLISHING.md.
On success the minted DOI is written back into catalog/datasets/<id>.yaml, so the dataset moves from
upload_pending to on_dataverse in the status reports automatically.
3. Human validation sign‑off¶
Validation is tracked in catalog/validation.yaml (never touched by bootstrap). To review a dataset,
edit its record and bump validation pending → reviewed → approved (add reviewed_by / reviewed_at /
notes), then refresh the reports:
n4a-datasets status --root . # rewrites docs/DATASET_STATUS.md + docs/PRIVATE_DATASETS.md
git add catalog/validation.yaml docs/DATASET_STATUS.md docs/PRIVATE_DATASETS.md && git commit
Release checklist¶
Green gate:
ruff check .·mypy --config-file pyproject.toml src·validate.py(+--check-publish) ·pytest -qcatalog,health-check,statusre‑run and committed (the index/health/status reports are up to date)version bumped in
pyproject.toml;python -m build && twine check dist/*cleantag
vX.Y.Zpushed (PyPI) /publish.ymldispatched per dataset (Dataverse)