|
1 | | -# Releasing nemo-oo-agents |
| 1 | +# Releasing |
2 | 2 |
|
3 | | -Three workspace packages — `nemo-oo-agents`, `nooa-cli`, and |
4 | | -`nemo-oo-agents-benchmarks` — release together from the same git commit. |
5 | | -Version is derived from `git describe` at build time by |
6 | | -[`uv-dynamic-versioning`](https://github.com/ninoseki/uv-dynamic-versioning). |
| 3 | +Four workspace packages release together from the same git commit: |
| 4 | + |
| 5 | +- **`nooa`** — the core framework |
| 6 | +- **`nooa-cli`** — the `nooa` command and REPL |
| 7 | +- **`nooa-memory`** — the long-term memory subsystem |
| 8 | +- **`nooa-bench`** — the benchmark agent and Harbor runner |
7 | 9 |
|
8 | | -There is no `version = "..."` in any pyproject.toml and no manual bump step |
9 | | -between releases. **Tagging the commit is the entire release ceremony.** |
| 10 | +The version is derived from the git **tag** at build time by |
| 11 | +[`uv-dynamic-versioning`](https://github.com/ninoseki/uv-dynamic-versioning). |
| 12 | +There is no `version = "..."` in any `pyproject.toml` and no manual bump step. |
| 13 | +**Tagging the commit is the release ceremony.** |
10 | 14 |
|
11 | | -## Continuous publishes (every main commit) |
| 15 | +## Versioning |
12 | 16 |
|
13 | | -Every push to `main` triggers `build-package-*` and `publish-package-*` jobs. |
14 | | -The published version is derived from the last `vX.Y.Z` tag reachable from |
15 | | -the commit, plus the distance to that tag: |
| 17 | +The version comes from the last `vX.Y.Z` tag reachable from the commit, plus |
| 18 | +the distance to that tag: |
16 | 19 |
|
17 | | -| Repo state | Wheel version | |
| 20 | +| Repo state | Version | |
18 | 21 | |---|---| |
19 | | -| Exactly on tag `v0.3.0` | `0.3.0` | |
20 | | -| 5 commits past `v0.3.0` | `0.3.1.dev5` | |
21 | | -| No `vX.Y.Z` tag reachable yet | `0.0.1.dev<commit-count>` (until first tag — see "Bootstrapping") | |
| 22 | +| Exactly on tag `v0.0.6` | `0.0.6` | |
| 23 | +| 5 commits past `v0.0.6` | `0.0.7.dev5` | |
| 24 | +| No `vX.Y.Z` tag reachable yet | `0.0.1.dev<distance>` | |
22 | 25 |
|
23 | | -> Note: the `fallback-version = "0.0.6"` in pyproject.toml is the version |
24 | | -> used only when git itself is unavailable (e.g. building from an unpacked |
25 | | -> sdist with no `.git` dir). In CI git is always present, so the version |
26 | | -> is always derived from `git describe` — the fallback never fires. |
| 26 | +> `fallback-version = "0.0.6"` in `pyproject.toml` is used **only** when git |
| 27 | +> is unavailable (e.g. building from an unpacked sdist with no `.git/`). |
| 28 | +> Whenever git is present, the version is derived from `git describe`. |
27 | 29 |
|
28 | | -Dev versions sort *above* the latest stable release and *below* the next |
29 | | -stable, so `--pre` consumers always get the freshest dev: |
| 30 | +This is a `0.x` **research preview** — the public API is not yet stable and may |
| 31 | +change between releases (per [SemVer](https://semver.org/), `0.y.z` signals |
| 32 | +initial development). |
30 | 33 |
|
31 | | -```bash |
32 | | -# Latest dev wheel from main |
33 | | -uv add nemo-oo-agents --pre |
| 34 | +## Cutting a release |
34 | 35 |
|
35 | | -# Pin to a specific dev wheel |
36 | | -uv add nemo-oo-agents==0.3.1.dev5 |
| 36 | +```bash |
| 37 | +git checkout main && git pull |
| 38 | +git tag -a v0.0.6 -m "NOOA 0.0.6 — research preview" |
| 39 | +git push origin v0.0.6 |
37 | 40 | ``` |
38 | 41 |
|
39 | | -`uv add nemo-oo-agents` (no `--pre`) keeps picking the last stable release. |
40 | | - |
41 | | -## Bootstrapping (one-time, after this MR merges) |
42 | | - |
43 | | -Until a `vX.Y.Z` tag exists in the repo, dev publishes ship as |
44 | | -`0.0.1.dev<commit-count>` — derived from "0 tags reachable" + the `bump = true` |
45 | | -config. To switch dev publishes to a meaningful base, cut the first tag: |
| 42 | +Build the four packages from the tagged commit: |
46 | 43 |
|
47 | 44 | ```bash |
48 | | -git checkout main |
49 | | -git pull |
50 | | -git tag -a v0.2.0 -m "Initial release with dynamic versioning" |
51 | | -git push origin v0.2.0 |
| 45 | +rm -rf dist |
| 46 | +for p in nooa nooa-cli nooa-memory nooa-bench; do |
| 47 | + uv build --package "$p" --out-dir dist |
| 48 | +done |
52 | 49 | ``` |
53 | 50 |
|
54 | | -Subsequent main pushes will then publish as `0.2.1.dev<distance>`. After |
55 | | -that, the rest of this doc is the entire release process. |
56 | | - |
57 | | -## Cutting a stable release |
| 51 | +**Smoke-test the wheels in a clean environment** before publishing: |
58 | 52 |
|
59 | 53 | ```bash |
60 | | -git checkout main |
61 | | -git pull |
62 | | -git tag -a v0.3.0 -m "Release 0.3.0" |
63 | | -git push origin v0.3.0 |
| 54 | +python3.12 -m venv /tmp/nooa-smoke && . /tmp/nooa-smoke/bin/activate |
| 55 | +pip install dist/nooa-*.whl dist/nooa_cli-*.whl dist/nooa_memory-*.whl dist/nooa_bench-*.whl |
| 56 | +python -c "import nooa, nooa_cli, nooa_memory, nooa_bench; print(nooa.__version__)" |
| 57 | +nooa --version |
| 58 | +deactivate |
64 | 59 | ``` |
65 | 60 |
|
66 | | -That's it. The tag pipeline builds and publishes `0.3.0` of all three |
67 | | -packages to the GitLab Package Registry. No pyproject changes, no follow-up |
68 | | -MRs, no version bumps anywhere. |
69 | | - |
70 | 61 | ### Pre-release tags |
71 | 62 |
|
72 | | -CI accepts annotated tags matching `^v\d+\.\d+\.\d+([.-][a-zA-Z0-9]+)?$`, |
73 | | -which covers pre-release suffixes: |
74 | | - |
75 | | -```bash |
76 | | -git tag -a v0.3.0-rc1 -m "Release candidate" |
77 | | -git push origin v0.3.0-rc1 |
78 | | -``` |
| 63 | +Annotated tags like `v0.0.6-rc1` build as `0.0.6rc1` (PEP 440 normalized). |
79 | 64 |
|
80 | | -The wheel ships as `0.3.0-rc1` (PEP 440 normalizes to `0.3.0rc1`). |
| 65 | +## Distribution |
81 | 66 |
|
82 | | -## Cross-package dependencies |
| 67 | +The packages are currently distributed as **source** — install directly from |
| 68 | +GitHub at a tag: |
83 | 69 |
|
84 | | -`nooa-cli` and `nemo-oo-agents-benchmarks` declare their |
85 | | -dependency on core as a static lower-bound floor in their pyproject.toml: |
86 | | - |
87 | | -```toml |
88 | | -"nemo-oo-agents>=0.2.0", |
| 70 | +```bash |
| 71 | +uv add "nooa @ git+https://github.com/NVIDIA-NeMo/labs-OO-Agents.git@v0.0.6" |
89 | 72 | ``` |
90 | 73 |
|
91 | | -The floor reflects the actual minimum-compatible core version. **Bump it in |
92 | | -a normal MR when the package starts to require a newer core API** — same as |
93 | | -you would for any third-party dep. CI does not rewrite this declaration. |
| 74 | +Optionally attach the built wheels to a **GitHub Release** for the tag. |
94 | 75 |
|
95 | | -## Republishing a main commit |
| 76 | +> **PyPI publishing is not yet enabled.** When it is, a GitHub Actions workflow |
| 77 | +> (PyPI Trusted Publishing) will build and upload all four packages on each |
| 78 | +> `vX.Y.Z` tag. The names `nooa`, `nooa-cli`, `nooa-memory`, and `nooa-bench` |
| 79 | +> are available on PyPI and can be reserved ahead of the first publish. |
96 | 80 |
|
97 | | -`uv publish` is not idempotent against the GitLab Package Registry — a |
98 | | -second attempt with the same version returns HTTP 400. CI does not retry |
99 | | -publish jobs. |
100 | | - |
101 | | -If a transient failure leaves a dev publish broken, **push an empty commit** |
102 | | -to advance the dev version: |
103 | | - |
104 | | -```bash |
105 | | -git commit --allow-empty -m "ci: re-trigger publish" |
106 | | -git push |
107 | | -``` |
| 81 | +## Cross-package dependencies |
108 | 82 |
|
109 | | -Do NOT use the GitLab "Retry pipeline" button on the build stage — it |
110 | | -rebuilds at the same git HEAD and therefore the same derived version, which |
111 | | -then 400s on publish. |
| 83 | +`nooa-cli`, `nooa-memory`, and `nooa-bench` depend on the core `nooa` package. |
| 84 | +They are always released together at the same derived version, so their |
| 85 | +dependency on `nooa` carries **no version floor** — CI never rewrites it. |
0 commit comments