# Releasing noodlelab A release starts when you push a version tag. Everything after that is automated in [`.github/workflows/release.yml`](../.github/workflows/release.yml): ``` git tag v0.3.0 → checks → build → smoke → GitHub Release → PyPI (→ MCP Registry) + Docker images + docs → verify ``` | Step | What it does | |---|---| | **checks** | Runs all of [CI](../.github/workflows/ci.yml) against the tagged commit: ruff, pytest on Python 3.11–3.13, the editor's typecheck and build, and every installation tier on its own (only its own packs load, and its examples run). | | **build** | Builds the editor into the package and runs `uv build`. It checks that the wheel's version equals the tag, that the editor is inside the wheel, and runs `twine check`. | | **smoke** | Installs the wheel with `uv tool install` on Linux, macOS and Windows (the basic tier, plus the full tier on Linux). It checks `noodlelab --version` and `noodlelab tiers`, then starts the server and calls `/api/health`. | | **github-release** | Creates the GitHub Release for the tag with generated notes and attaches the wheel and sdist. | | **publish-pypi** | Final versions: uploads to [PyPI](https://pypi.org/project/noodlelab/) with trusted publishing, so no API token is stored anywhere. | | **publish-testpypi** | Pre-releases (`a`, `b`, `rc`): uploads to [TestPyPI](https://test.pypi.org/project/noodlelab/) instead. | | **publish-mcp-registry** | Final versions: stamps the version into [`server.json`](../server.json) and publishes it to the [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.nkalis/noodlelab`, logging in with GitHub OIDC. The registry confirms the PyPI package is ours from the `mcp-name:` comment at the top of the README, so keep that line. | | **docker** | Builds one image per tier for amd64 and arm64 and pushes it to `ghcr.io//noodlelab`. | | **docs** | Final versions: builds the documentation at the tag and publishes it to GitHub Pages as `//` and `/stable/` (see [the documentation site](#the-documentation-site)). | | **verify** | Runs `uvx "noodlelab[maths]=="` from the package index, retrying while the index catches up, and runs the pushed images. | If a step fails, nothing after it runs. For example, a failed smoke test means nothing is published. Re-running a failed workflow is safe: - the GitHub Release is updated rather than created again; - `uv publish --check-url` skips files that are already on the index; - the images are simply pushed again. ## Versions come from the tag `pyproject.toml` has no version number. [hatch-vcs](https://github.com/ofek/hatch-vcs) reads it from git: - tag `v0.3.0` builds `0.3.0`; - the commits after it build `0.3.1.devN+g`; - the installed package reports its version through `noodlelab --version`, `/api/health` and the admin **System** tab. Tags must look like `vX.Y.Z` or `vX.Y.Z` followed by `aN`, `bN` or `rcN`. The build step rejects anything else. ## Cutting a release ```bash git switch main && git pull git tag v0.3.0rc1 && git push origin v0.3.0rc1 # optional: rehearse on TestPyPI git tag v0.3.0 && git push origin v0.3.0 # the release ``` The live demo on Render builds without git history, so it cannot read the tag. Its version is pinned as `NOODLELAB_VERSION` in [`render.yaml`](../render.yaml): set it to the new version in a commit on `main`, and the next deploy reports it. Watch it under **Actions → Release**. When it finishes, users can install it: ```bash uvx "noodlelab[full]" . # or any tier: maths, science, engineering, geo uv tool install "noodlelab[engineering]" pip install "noodlelab[science]" docker run -p 8000:8000 ghcr.io//noodlelab:0.3.0 ``` Install a pre-release from TestPyPI (its dependencies still come from PyPI): ```bash uvx --index https://test.pypi.org/simple/ --index-strategy unsafe-best-match \ --from "noodlelab[maths]==0.3.0rc1" noodlelab ``` ## The documentation site The site is built with Sphinx from `docs/` (the guides), the README (the home page) and the code (the Python API, every node and the command line), and served by GitHub Pages from the `gh-pages` branch, one folder per version: | Folder | What | Published by | |---|---|---| | `/dev/` | `main` | [`docs.yml`](../.github/workflows/docs.yml), after every green CI run on `main` | | `/0.3/` | The latest 0.3.x release | the release workflow's **docs** step | | `/stable/` | The latest final release; the site's root redirects here | the release workflow's **docs** step | Pre-releases are not published. CI builds the site on every pull request with warnings as errors (a broken link, a docstring autodoc can't read) and keeps the HTML as the `docs-html` artifact. To build it locally: ```bash uv sync --all-extras --group docs make docs # docs/_build/html/index.html ``` To republish `main` by hand, run **Actions → Docs → Run workflow**. ## Docker image tags | Tag | Image | |---|---| | `0.3.0`, `0.3.0-full` | The full tier of this release. | | `0.3.0-` | One tier of this release: `basic`, `maths`, `science`, `engineering` or `geo`. | | `0.3`, `0.3-` | The latest patch release of 0.3. Final releases only. | | `latest`, `` | The latest final release. | ## One-time setup 1. **PyPI trusted publisher.** - On PyPI, go to *Your account → Publishing* and add a pending publisher (or go to *Manage project → Publishing* once the project exists). - Settings: owner `nkalis`, repository `noodlelab`, workflow `release.yml`, environment `pypi`. 2. **TestPyPI trusted publisher.** Do the same on [test.pypi.org](https://test.pypi.org), with environment `testpypi`. 3. **GitHub environments.** - Under *Settings → Environments*, create `pypi` and `testpypi`. - Add required reviewers to `pypi` if you want to approve each upload by hand. The workflow waits at that step. 4. **Container images.** - The workflow pushes with the built-in `GITHUB_TOKEN`, so nothing needs configuring. - After the first release, open the package under *Your profile → Packages → noodlelab → Package settings*. - Make it public so `docker pull` works without logging in, and link it to the repository. 5. **GitHub Pages.** - Merge to `main` once so that the Docs workflow creates the `gh-pages` branch. - Under *Settings → Pages → Build and deployment*, choose *Deploy from a branch*, then `gh-pages` and `/ (root)`. - The site is then at `https://nkalis.github.io/noodlelab/`. Pages is free for public repositories; a private one needs a paid GitHub plan.