|
| 1 | +.. SPDX-FileCopyrightText: Copyright (c) 2026 The Newton Developers |
| 2 | +.. SPDX-License-Identifier: CC-BY-4.0 |
| 3 | +
|
| 4 | +Release Process |
| 5 | +=============== |
| 6 | + |
| 7 | +This document describes how to prepare, publish, and follow up on a Newton |
| 8 | +release. It is intended for release engineers and maintainers. |
| 9 | + |
| 10 | +Overview |
| 11 | +-------- |
| 12 | + |
| 13 | +Newton uses `PEP 440 <https://peps.python.org/pep-0440/>`__ versioning |
| 14 | +(``Major.Minor.Micro``), consistent with warp-lang: |
| 15 | + |
| 16 | +.. list-table:: |
| 17 | + :widths: 25 30 45 |
| 18 | + :header-rows: 1 |
| 19 | + |
| 20 | + * - Kind |
| 21 | + - Example |
| 22 | + - When |
| 23 | + * - Stable |
| 24 | + - ``1.0.0`` |
| 25 | + - Tagged GA releases published to PyPI |
| 26 | + * - Release candidate |
| 27 | + - ``1.0.0rc1`` |
| 28 | + - Pre-release builds for QA validation |
| 29 | + * - Development |
| 30 | + - ``1.1.0.dev0`` |
| 31 | + - ``main`` between releases |
| 32 | + |
| 33 | +Releases are published to `PyPI <https://pypi.org/p/newton>`__ and |
| 34 | +documentation is deployed to |
| 35 | +`GitHub Pages <https://newton-physics.github.io/newton/>`__. |
| 36 | + |
| 37 | +Version source of truth |
| 38 | +^^^^^^^^^^^^^^^^^^^^^^^ |
| 39 | + |
| 40 | +The version string lives in ``newton/_version.py``. All other version |
| 41 | +references (PyPI metadata, documentation) are derived from this file. |
| 42 | + |
| 43 | +Dependency versioning strategy |
| 44 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 45 | + |
| 46 | +``pyproject.toml`` specifies **minimum** compatible versions |
| 47 | +(e.g. ``warp-lang>=1.12.0``). ``uv.lock`` pins the **latest known-good** |
| 48 | +versions for reproducible installs. |
| 49 | + |
| 50 | +Exception: on the **release branch**, ``mujoco`` and ``mujoco-warp`` are |
| 51 | +pinned to **exact** versions (e.g. ``mujoco==3.5.0``) because Newton is |
| 52 | +tightly coupled to the MuJoCo API surface. ``main`` uses a version floor |
| 53 | +like other dependencies. |
| 54 | + |
| 55 | + |
| 56 | +Pre-release planning |
| 57 | +-------------------- |
| 58 | + |
| 59 | +.. rubric:: Checklist |
| 60 | + |
| 61 | +.. list-table:: |
| 62 | + :widths: 5 95 |
| 63 | + :header-rows: 0 |
| 64 | + |
| 65 | + * - ☐ |
| 66 | + - Determine target version (``X.Y.Z``). |
| 67 | + * - ☐ |
| 68 | + - Confirm dependency versions and availability: warp-lang, mujoco, |
| 69 | + mujoco-warp, newton-usd-schemas, newton-actuators. |
| 70 | + * - ☐ |
| 71 | + - Set timeline: code freeze → RC1 → testing window → GA. |
| 72 | + * - ☐ |
| 73 | + - Conduct public API audit: |
| 74 | + |
| 75 | + - Review all new/changed symbols since the last release for unintended |
| 76 | + breaking changes. |
| 77 | + - Verify deprecated symbols carry proper deprecation warnings and |
| 78 | + migration guidance. |
| 79 | + - Confirm new public API has complete docstrings and is included in |
| 80 | + Sphinx docs (run ``docs/generate_api.py``). |
| 81 | + * - ☐ |
| 82 | + - Communicate the timeline to contributors. |
| 83 | + |
| 84 | + |
| 85 | +Code freeze and release branch creation |
| 86 | +--------------------------------------- |
| 87 | + |
| 88 | +1. Create the ``release-X.Y`` branch from ``main``. |
| 89 | +2. On **main**: bump ``newton/_version.py`` to ``X.(Y+1).0.dev0`` and run |
| 90 | + ``docs/generate_api.py``. |
| 91 | +3. On **release-X.Y**: bump ``newton/_version.py`` to ``X.Y.ZrcN`` and run |
| 92 | + ``docs/generate_api.py``. |
| 93 | +4. On **release-X.Y**: update dependencies in ``pyproject.toml`` from dev |
| 94 | + to RC versions where applicable, then regenerate ``uv.lock`` |
| 95 | + (``uv lock``) and commit it. |
| 96 | +5. Push tag ``vX.Y.ZrcN``. This triggers the ``release.yml`` workflow |
| 97 | + (build wheel → PyPI publish with manual approval). |
| 98 | + |
| 99 | +.. rubric:: Checklist |
| 100 | + |
| 101 | +.. list-table:: |
| 102 | + :widths: 5 95 |
| 103 | + :header-rows: 0 |
| 104 | + |
| 105 | + * - ☐ |
| 106 | + - ``release-X.Y`` branch created and pushed. |
| 107 | + * - ☐ |
| 108 | + - ``main`` bumped to next dev version; ``generate_api.py`` run. |
| 109 | + * - ☐ |
| 110 | + - RC1 version set on release branch; ``generate_api.py`` run. |
| 111 | + * - ☐ |
| 112 | + - Dependencies updated from dev to RC versions; ``uv.lock`` regenerated. |
| 113 | + * - ☐ |
| 114 | + - Tag ``vX.Y.Zrc1`` pushed. |
| 115 | + * - ☐ |
| 116 | + - RC1 published to PyPI (approve in GitHub environment). |
| 117 | + |
| 118 | + |
| 119 | +Release candidate stabilization |
| 120 | +------------------------------- |
| 121 | + |
| 122 | +Bug fixes merge to ``main`` first, then are cherry-picked to |
| 123 | +``release-X.Y``. Cherry-pick relevant commits from ``main`` onto a feature |
| 124 | +branch and open a pull request targeting ``release-X.Y`` — never push |
| 125 | +directly to the release branch. |
| 126 | + |
| 127 | +For each new RC (``rc2``, ``rc3``, …) bump the version in |
| 128 | +``newton/_version.py`` and run ``docs/generate_api.py``, then tag and push. |
| 129 | +Iterate until CI is green and QA signs off. |
| 130 | + |
| 131 | +.. rubric:: Checklist |
| 132 | + |
| 133 | +.. list-table:: |
| 134 | + :widths: 5 95 |
| 135 | + :header-rows: 0 |
| 136 | + |
| 137 | + * - ☐ |
| 138 | + - All release-targeted fixes cherry-picked from ``main``. |
| 139 | + * - ☐ |
| 140 | + - CI passing on release branch. |
| 141 | + * - ☐ |
| 142 | + - QA sign-off obtained. |
| 143 | + * - ☐ |
| 144 | + - No outstanding release-blocking issues. |
| 145 | + |
| 146 | + |
| 147 | +.. _final-release: |
| 148 | + |
| 149 | +Final release |
| 150 | +------------- |
| 151 | + |
| 152 | +1. Finalize ``CHANGELOG.md``: rename ``[Unreleased]`` → |
| 153 | + ``[X.Y.Z] - YYYY-MM-DD``. |
| 154 | +2. Update documentation links to point to versioned URLs where appropriate. |
| 155 | +3. Verify all dependency pins in ``pyproject.toml`` use stable |
| 156 | + (non-pre-release) versions. |
| 157 | +4. Regenerate ``uv.lock`` (``uv lock``) and verify that no pre-release |
| 158 | + dependencies remain in the lock file. |
| 159 | +5. Bump ``newton/_version.py`` to ``X.Y.Z`` (remove the RC suffix) and run |
| 160 | + ``docs/generate_api.py``. |
| 161 | +6. Commit and push tag ``vX.Y.Z``. |
| 162 | +7. Automated workflows trigger: |
| 163 | + |
| 164 | + - ``release.yml``: builds wheel, publishes to PyPI (requires manual |
| 165 | + approval), creates a draft GitHub Release. |
| 166 | + - ``docs-release.yml``: deploys docs to ``/X.Y.Z/`` and ``/stable/`` |
| 167 | + on gh-pages, updates ``switcher.json``. |
| 168 | + |
| 169 | +8. Review and publish (un-draft) the GitHub Release. |
| 170 | + |
| 171 | +.. rubric:: Checklist |
| 172 | + |
| 173 | +.. list-table:: |
| 174 | + :widths: 5 95 |
| 175 | + :header-rows: 0 |
| 176 | + |
| 177 | + * - ☐ |
| 178 | + - Changelog finalized with release date. |
| 179 | + * - ☐ |
| 180 | + - All dependency pins in ``pyproject.toml`` use stable (non-pre-release) |
| 181 | + versions. |
| 182 | + * - ☐ |
| 183 | + - ``uv.lock`` regenerated and verified free of pre-release dependencies. |
| 184 | + * - ☐ |
| 185 | + - Version bumped to ``X.Y.Z``; ``generate_api.py`` run. |
| 186 | + * - ☐ |
| 187 | + - Tag ``vX.Y.Z`` pushed. |
| 188 | + * - ☐ |
| 189 | + - PyPI publish approved and verified: ``pip install newton==X.Y.Z``. |
| 190 | + * - ☐ |
| 191 | + - GitHub Release un-drafted and published. |
| 192 | + * - ☐ |
| 193 | + - Docs live at ``/X.Y.Z/`` and ``/stable/``: verify links and version |
| 194 | + switcher. |
| 195 | + |
| 196 | + |
| 197 | +Post-release |
| 198 | +------------ |
| 199 | + |
| 200 | +1. Compare ``CHANGELOG.md`` between ``release-X.Y`` and ``main``. The |
| 201 | + release branch has the finalized ``[X.Y.Z]`` section, while ``main`` |
| 202 | + still has those entries under ``[Unreleased]``. |
| 203 | +2. On **main**: merge back the changelog from the release branch so that |
| 204 | + all entries included in the release are moved from ``[Unreleased]`` to |
| 205 | + the ``[X.Y.Z]`` section. (The ``[Unreleased]`` header already exists |
| 206 | + on ``main`` from the post-branch-creation bump.) |
| 207 | +3. Verify PyPI installation works in a clean environment. |
| 208 | +4. Verify published docs render correctly. |
| 209 | + |
| 210 | +.. rubric:: Checklist |
| 211 | + |
| 212 | +.. list-table:: |
| 213 | + :widths: 5 95 |
| 214 | + :header-rows: 0 |
| 215 | + |
| 216 | + * - ☐ |
| 217 | + - ``CHANGELOG.md`` on ``main`` updated: released entries moved from |
| 218 | + ``[Unreleased]`` to ``[X.Y.Z]`` section. |
| 219 | + * - ☐ |
| 220 | + - PyPI install verified. |
| 221 | + * - ☐ |
| 222 | + - Published docs verified. |
| 223 | + |
| 224 | + |
| 225 | +Patch releases |
| 226 | +-------------- |
| 227 | + |
| 228 | +Patch releases (``X.Y.Z+1``) continue cherry-picking fixes to the existing |
| 229 | +``release-X.Y`` branch. Follow the same :ref:`final-release` flow — bump |
| 230 | +version, update changelog, tag, and push. There is no need to create a new |
| 231 | +branch or bump ``main``. |
0 commit comments