|
1 | 1 | # Package Release Guide |
2 | 2 |
|
3 | | -The OSS release process for Core AI Optimization is still being defined. This page will document the workflow for publishing to PyPI once the public release infrastructure is finalized. |
| 3 | +Releases are cut and published by the [release managers team](https://github.com/orgs/apple/teams/coreai-optimization-release-managers). |
4 | 4 |
|
5 | 5 | The following commands are available locally: |
6 | 6 |
|
7 | 7 | ```bash |
8 | | -make build # build the canonical, publishable wheel + sdist (uv build --no-sources) |
9 | | -make build-dev # build a timestamped dev wheel (e.g. 0.2.2.dev202607231430+abc1234) |
10 | | -make version # show the development version carried on the tree (e.g. 0.2.2.dev0) |
| 8 | +make build # build the artifacts for the current release to be published |
| 9 | +make build-dev # build a nightly or local development wheel (e.g. 1.1.0.dev202607231430+abc1234) |
| 10 | +make version # show the version a release would publish (e.g. 1.1.0) |
| 11 | +make version-dev # show the development version carried on the tree (e.g. 1.1.0.dev0) |
11 | 12 | make clean # remove build artifacts |
12 | 13 | ``` |
13 | 14 |
|
14 | 15 | ## Version scheme |
15 | 16 |
|
16 | | -`main` always carries the version planned for the _next_ release. This ensures that ongoing development is never mistaken for an already-published version, and that a release can be stabilized, tested, and published on its own branch, independently of later changes on `main`. (The release-branch workflow itself — branch naming, tagging, and backporting fixes to `main` — will be documented separately in the release schedule doc; this section covers only the version-string mechanics.) |
| 17 | +`main` always carries the version of the *next* release, never the one that already shipped. |
17 | 18 |
|
18 | | -`src/coreai_opt/_about.py` stores `latest_released_version` (the last tagged release, e.g. `"0.2.1"`) and computes `__version__` from it by incrementing its last number by one and adding a `.dev0` suffix (e.g. `"0.2.2.dev0"`). A pre-commit hook (`check-about-version`) verifies that `__version__` always follows this rule and that `latest_released_version` matches the repo's latest release tag. As a result, `__version__` can never look as though a release has shipped when it hasn't. The `.dev0` suffix is only a marker on the tree; it never appears in a built wheel. |
| 19 | +There are three version formats: |
19 | 20 |
|
20 | | -- `make build` builds the release that `__version__` implies, e.g. `0.2.2`. A release is cut by tagging it (`v0.2.2`); `latest_released_version` is then hard-coded to `"0.2.2"`, which bumps `__version__` to the next candidate (`0.2.3.dev0`). |
21 | | -- `make build-dev` builds that same release but with a unique `.dev<UTC-timestamp>+<short-sha>` suffix instead. It is used by contributors, smoke tests, and the nightly pipeline. `DEV_VERSION=<version>` uses that version exactly instead. |
| 21 | +| Format | Example | What it is | |
| 22 | +| -------------------------------------- | ------------------------------- | -------------------------------------------- | |
| 23 | +| `X.Y.Z` | `1.0.0` | a published release | |
| 24 | +| `X.Y.Z.dev0` | `1.1.0.dev0` | the version `main` carries in the repo | |
| 25 | +| `X.Y.Z.dev<UTC-timestamp>+<short-sha>` | `1.1.0.dev202607231430+abc1234` | a dev artifact, built from a specific commit | |
22 | 26 |
|
23 | | -Sorting is preserved: `0.2.2.dev0 < 0.2.2.dev202607231430+abc1234 < 0.2.2`. |
| 27 | +Say `1.0.0` has just been released. `main` then carries `1.0.1.dev0`. That reads as "working toward a release after `1.0.0`, which has not shipped": the `.dev0` suffix marks the tree as unreleased and never appears in a built wheel. Nothing on `main` can be mistaken for a published version. |
24 | 28 |
|
25 | | -### Extending the scheme downstream |
| 29 | +`main`'s `.dev0` always defaults to the last digit plus one, so after `1.0.0` it is `1.0.1.dev0`. Once the version of the next release is known — usually a minor — a PR sets `__version__` to it before the release branch is cut. |
| 30 | + |
| 31 | +The flow below traces one cycle. At the cut, `main` and the release branch diverge and never rejoin: the branch keeps the version it was cut with, and only `main` moves on. |
| 32 | + |
| 33 | +```mermaid |
| 34 | +--- |
| 35 | +title: Version change flow |
| 36 | +--- |
| 37 | +flowchart TB |
| 38 | + prev["previous release schedule"] --> m1["main: 1.0.1.dev0<br/>placeholder, last digit + 1"] |
| 39 | + prev --> r0("1.0.0 released") |
| 40 | + m1 -->|"ready for release"| ask{"is the placeholder the<br/>version we want?"} |
| 41 | + ask -->|"No, usually a minor"| pr["PR sets __version__"] |
| 42 | + ask -->|Yes| fin |
| 43 | + pr --> fin["main: 1.1.0.dev0<br/>assume we release 1.1.0;<br/>it could also stay 1.0.1"] |
| 44 | + fin --> nxt["main: 1.1.1.dev0<br/>placeholder, last digit + 1"] |
| 45 | + fin -->|cut| rb["release/1.1.0<br/>set latest_released_version = 1.1.0"] |
| 46 | + rb --> stab["stabilize"] |
| 47 | + stab -->|"tag v1.1.0"| rel("1.1.0 released") |
| 48 | + nxt --> nextsched["next release schedule"] |
| 49 | + rel --> nextsched |
| 50 | + nextsched -.->|"the process repeats"| prev |
| 51 | +``` |
| 52 | + |
| 53 | +`src/coreai_opt/_about.py` holds the last released version and `__version__`. Both are set together in one PR when `main` moves forward: the last released version becomes the release just branched, and `__version__` becomes the one after it. The `check-about-version` pre-commit hook enforces the relation between them: `__version__` must be the last released version with exactly one of its numbers raised by one, every number after that reset to zero, and `.dev0` on the end. From `1.0.0` it accepts `1.0.1.dev0`, `1.1.0.dev0`, or `2.0.0.dev0`, and nothing else. Any other value fails the commit, and the message prints the accepted ones, so there is nothing to work out by hand. |
| 54 | + |
| 55 | +- `make build` builds the artifacts for the current release to be published. |
| 56 | +- `make build-dev` builds the wheel for the nightly build, and local wheels for development and testing, each carrying a unique `.dev<UTC-timestamp>+<short-sha>` suffix. |
| 57 | + |
| 58 | +Therefore, we have the following order: |
| 59 | + |
| 60 | +```text |
| 61 | +1.1.0.dev0 < 1.1.0.dev202607231430+abc1234 < 1.1.0 |
| 62 | +``` |
| 63 | + |
| 64 | +This is the order we want. `1.1.0.dev0` is the bare marker `main` carries, so it sorts below every wheel actually built for `1.1.0`. Each nightly sorts above it, and above the nightly before it, because the timestamp only grows. The published `1.1.0` sorts highest of all, so installers pick it over any dev wheel. |
| 65 | + |
| 66 | +A release branch is the one place where the two match: it sets `latest_released_version` to the release it produces, so `__version__` is that same version plus `.dev0` rather than a next candidate. On `main` they always differ, which is what tells a release branch apart — and what lets a repo that vendors this one pin to a release branch and still resolve the right baseline. |
| 67 | + |
| 68 | +`__version__` must always be a literal string, never an expression. |
26 | 69 |
|
27 | | -A repo that uses this one as a submodule and includes this `Makefile` — building one combined wheel from both trees — can add its own 4th number. Set `COREAI_OPT_VERSION_EXTENSION` to the number it's about to release next (e.g. `"1"` for its first release off a given OSS release, then `"2"` for the one after that). Then call `make build`, `make build-dev`, or `make version` unchanged: |
| 70 | +### Release branches |
| 71 | + |
| 72 | +1. `release/<version>` is created from `main`, once the version of the next release has been decided — that is, which digit gets one added to it. Its first commit sets `latest_released_version` to that version, so the branch names its own release. |
| 73 | +2. The tag is created on the `release/<version>` branch, never on `main`. |
| 74 | +3. After the cut, `main` continues on to the next release's `.dev0`. |
| 75 | +4. The `check-about-version` pre-commit hook enforces the version rules on every commit. |
| 76 | +5. After the cut, the release branch takes no new commits, unless a must-fix issue comes up. Those commits are later cherry-picked back to `main`. |
| 77 | + |
| 78 | +Cut the branch before moving `main` to the next dev release. |
| 79 | + |
| 80 | +### Extending the scheme downstream |
28 | 81 |
|
29 | | -- `latest_released_version` `"0.2.1"` + extension `"1"` -> candidate: `0.2.1.1.dev0` |
30 | | -- `make build` -> `0.2.1.1` |
31 | | -- `make build-dev` -> `0.2.1.1.dev<UTC-timestamp>+<short-sha>` |
| 82 | +A repo that uses this one as a submodule and includes this `Makefile` — building one combined wheel from both trees — can add its own 4th number. Set `COREAI_OPT_VERSION_EXTENSION` to the number it's about to release next, then call `make build`, `make build-dev`, or `make version` unchanged. |
32 | 83 |
|
33 | | -The extra number is used exactly as given (`scripts/release/release_utils.apply_version_extension`); `latest_released_version`'s own last number is only bumped for OSS's own `main`, when no extension is set. |
| 84 | +The extension anchors the release to the last *published* release instead of the one `__version__` is working toward: |
34 | 85 |
|
35 | | -There is still only one `_about.py` (this package's own); the extra number is a plain string handled entirely in `scripts/release/release_utils.next_release_base` — no other file or package is involved. |
| 86 | +| `latest_released_version` | `__version__` | `COREAI_OPT_VERSION_EXTENSION` | Release built | |
| 87 | +| ------------------------- | ------------- | ------------------------------ | ------------- | |
| 88 | +| `1.0.0` | `1.1.0.dev0` | unset | `1.1.0` | |
| 89 | +| `1.0.0` | `1.1.0.dev0` | `1` | `1.0.0.1` | |
| 90 | +| `1.0.0` | `1.1.0.dev0` | `2` | `1.0.0.2` | |
36 | 91 |
|
37 | | -<!-- TODO: Document the chosen OSS release workflow (PyPI trusted publishing, twine upload, or uv publish). --> |
| 92 | +The extension is used exactly as given, and starts at `1`, not `0`. `make build-dev` adds the usual `.dev<UTC-timestamp>+<short-sha>` suffix on top. |
0 commit comments