Build and release
Four scripts do all of the work. Each script stops at the first error, and each script tells you why it stopped.
| Script | Function |
|---|---|
./build.sh |
The gate. It builds, tests and inspects everything. |
./wasm.sh |
It builds the WebAssembly module and compares it with Python. |
./install.sh |
It installs the wheels into your system Python. |
./publish.sh |
It makes a release. |
The gate
./build.sh
The script does these steps:
- It confirms that all of the necessary files are present.
- It confirms that all of the manifests agree about the version.
- It runs
cargo fmt --check,cargo clippy -D warnings,cargo testand the documentation tests. - It builds the crate again without PyO3, because Rust users and the WebAssembly build use it in that form.
- It builds both wheels, and it inspects the metadata of each one.
- It installs the wheels in a new temporary environment, and then it runs the Python tests there.
- It runs
./wasm.sh, which compares the WebAssembly module with Python. - It confirms that the repository did not change.
Step 8 is important. A release depends on a build that writes into no tracked file. If the check fails, something wrote into the repository.
The log goes to build.log.txt.
To skip the WebAssembly step, for example on a machine without Node:
MILKWASH_SKIP_WASM=1 ./build.sh
The WebAssembly module
./wasm.sh # build and compare; docs/ does not change
./wasm.sh --refresh # build, compare, and write the new module into docs/
The comparison is the interesting part. The Python extension module writes a reference file with the seed, the spans, the prompt choice and the chunk text for five examples. Node then gives the same sentences to the WebAssembly module and compares every value. If the two disagree, the browser and a sweep make different chunks.
docs/assets/wasm/ holds the module that the demonstration page uses. The file
docs/assets/wasm/VERSION holds its version, and ./build.sh compares that
version with the manifests. Run ./wasm.sh --refresh after each change to the
Rust code, and then commit the result.
You need these tools: wasm-pack, node, and the wasm32-unknown-unknown
target.
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
Versions
The git tag is the only source of the version number.
scripts/release-manifests.py is the only program that may change a version in a
tracked file. It keeps these places identical:
milkwashr/Cargo.tomlmilkwashr-wasm/Cargo.toml, and its pin onmilkwashrmilkwashy/pyproject.toml, and its pin onmilkwashrmilkwashy/src/milkwashy/__init__.py
python3 scripts/release-manifests.py check # print the agreed version
python3 scripts/release-manifests.py sync 1.2.3 # write one version everywhere
A release
./publish.sh # a test run: it changes nothing
./publish.sh --real # a release: it cannot be undone
The test run is safe. Do it first, and read the predicted version.
A real release does these steps in this order:
- It confirms the state: branch
main, upstreamorigin/main, no conflicts, and a remote that is not in front of your work. - It predicts the next version. The rule is the same as the rule in
gitnextver: the highestvtag plus one patch, or1.0.0when the repository has no tag. - It commits your work, so that the release points to a commit.
- It runs all of the gates at the version that is in the manifests now.
- It writes the new version into the manifests, and then it runs
./build.shagain. A change to any other file stops the release. - It calls
uvx gitnextver@1.0.1. That program makes one commit, one tag, and one push. - It confirms that the local tag, the remote branch and the remote tag point to the same commit.
- It uploads: first the crate to crates.io, then
milkwashrto PyPI, thenmilkwashyto PyPI. After each upload it waits until the registry serves the new version.
Do not commit the version change yourself.
gitnextvermakes a tag only when the repository has a change to commit. The version change is that change.
A real release needs two tokens in the environment:
export CARGO_REGISTRY_TOKEN=...
export UV_PUBLISH_TOKEN=...
If an upload fails, the script prints the artifacts that it published before the failure. You cannot remove them from the registries, so the next release must use a new version.
The documentation site
The site is the docs/ directory. GitHub Pages builds it with Jekyll, and it
loads the Just the Docs theme from GitHub. The
repository holds no copy of the theme.
To see the site on your computer:
cd docs
bundle init
bundle add jekyll jekyll-remote-theme jekyll-seo-tag
bundle exec jekyll serve --baseurl ""
The demonstration page needs a server, because a browser refuses to load a
WebAssembly module from a file: address. The Jekyll server above gives the
complete page.
A plain static server also serves the module and the scripts, and it is sufficient to test them:
python3 -m http.server --directory docs 8000
That server does not run Jekyll, so it shows the Markdown files as text.