Releasing¶
This guide covers the current PyPI release workflow for nyc311.
Release discipline¶
- Current stable line:
1.x(first major tag shipped 2026-04-19) - Version source: git tags via Hatch VCS
- Preferred publish trigger: GitHub Release publication
- SemVer rubric: see
.claude/skills/release-bump.md— patch for docs / CI / dev-tooling, minor for additive public API, major for renames / removals / Python-minor drops / factor-factory major bumps.
Patch releases in the 1.x line are the default path for docs polish, workflow
updates, packaging fixes, and backward-compatible behavior changes. Cut a new
minor release when the public workflow or package surface expands in a
meaningful way. Bump major only when the rubric above triggers.
Pre-release checks¶
Before cutting a release tag, make sure the repo passes:
make ci
make audit
make docs-build
make smoke-dist
That covers:
- lint, typing, and public API checks
- docs build validation
- source and wheel builds
- PyPI long-description validation
- installed-wheel smoke testing for the CLI and packaged resources
The CI workflow runs the full test matrix across ubuntu / macOS / Windows ×
Python 3.12 / 3.13. Required GitHub Actions pins (match factor-factory v1.0.2
parity):
actions/checkout@v6astral-sh/setup-uv@v8.1.0(exact tag — no moving tag)actions/upload-artifact@v7actions/download-artifact@v8pypa/gh-action-pypi-publish@release/v1
If the release touches nyc311.geographies or dependency ranges, also verify
the current nyc-geo-toolkit compatibility path before tagging.
If the release touches the two factor-factory bridges
(PanelDataset.to_factor_factory_panel() or
Pipeline.as_factor_factory_estimate()) or the factor-factory / jellycell
pins, invoke factor-compat-auditor before cutting the tag.
After publishing a new nyc-geo-toolkit line that raises the minimum useful
version (for example a release that adds shared basemap helpers), bump
dependencies.nyc-geo-toolkit in pyproject.toml if you want uv lock to
resolve that floor, then run uv lock and commit the updated uv.lock.
Release path¶
The standard production path is:
- create the final release tag, for example
v1.0.1 - push the tag
- optionally run the
CDworkflow against TestPyPI first - publish the matching GitHub Release
- let the
release.publishedtrigger publish to real PyPI
If you prefer the manual route, run the CD workflow from the same tag with:
publish=truerepository=pypi
Trusted publishing setup¶
This repo uses trusted publishing through .github/workflows/cd.yml and the
pypi GitHub environment.
If you ever need to recreate that setup, verify:
- owner:
random-walks - repository:
nyc311 - workflow:
.github/workflows/cd.yml - environment:
pypi
Repository-admin setup such as PyPI project creation, trusted publisher registration, Read the Docs project linking, and GitHub sidebar metadata is managed manually outside the repo and is intentionally not duplicated here.
TestPyPI Dry Run¶
For routine releases, do one dry run from the final release tag:
- Create the release tag, for example
v1.0.1. - Push the tag.
- Run the
CDworkflow manually from that tag with: publish=truerepository=testpypi- Verify installation from TestPyPI in a clean environment.
Example validation commands:
python -m venv .venv-testpypi-check
.venv-testpypi-check/bin/python -m pip install --upgrade pip
.venv-testpypi-check/bin/python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple nyc311
.venv-testpypi-check/bin/nyc311 --help
If you want the optional stacks too:
.venv-testpypi-check/bin/python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple "nyc311[all]"
Post-Release Verification¶
After the release lands on PyPI:
- Install
nyc311from PyPI in a clean environment. - Run
nyc311 --help. - Verify at least one packaged-resource path:
nyc311.samples.load_sample_service_requests()nyc311.geographies.load_nyc_boundaries("borough")- Confirm the PyPI project page renders the README correctly.
- Confirm the docs site, GitHub release notes, and README badges all reflect the public release.