Publish
This article documents how to publish a release.
A release goes out in three steps: bump the versions, tag the commit, then
publish the packages. The first and third steps are cargo xtask subcommands,
run from the repository root. The full list of subcommands is codegen, dns,
docs, precompile, publish, release and backend.
1. Create a release
cargo xtask release <version>
This rewrites the version in every manifest of the workspace:
- Rust: for each crate and for
bin/,package.versionis set to the new version, and every dependency or dev-dependency pointing at another crate of the workspace has its version updated too. - Node: it runs
yarn workspaces foreach --all version <version>, which coverspackages/*andsdk/node/*. - PHP: for each package in
sdk/php, theversionfield and the internal entries ofrequireandrequire-devare set to the new version.eternaltwin/path-toolsis deliberately left alone: it is versioned independently.
The command only edits files. It does not commit, and it does not tag.
Review the result, update CHANGELOG.md, commit, and send the branch to
GitLab. The publication step happens once the change is merged into main.
2. Tag
Once the release commit is on main, tag it v<version> and push the tag.
The tag is what drives the GitLab CI: the four x86_64-* build jobs and the
release job only run when $CI_COMMIT_TAG is set. Those jobs cross-compile
the executable for each supported target and run
cargo xtask publish --gitlab-job-token "${CI_JOB_TOKEN}" exe, which uploads
the binaries. Wait for them before publishing the libraries by hand.
3. Publish the packages
cargo xtask publish --recursive --gitlab-private-token <TOKEN>
publish takes a list of components, and publishes each one to the registry
matching its kind.
Which components
- With no component named, the roots are the three command line interface
packages:
rs_lib_eternaltwin_cli,ts_lib_eternaltwin_cliandphp_lib_eternaltwin_cli. These are the packages needed to build the main executable inbin/. The executables are excluded, because the GitLab CI job publishes them first. exeexpands to the four precompiled executables:x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-unknown-linux-gnuandx86_64-unknown-linux-musl. This is what the CI job passes.- Any other argument is a component id, such as
rs_lib_eternaltwin_coreorts_lib_eternaltwin_website. The full list is the node list ofdependencies.dot, regenerated bycargo xtask codegen structure. An unknown id aborts the run. --recursivewalks the dependencies of the roots and publishes them first. Without it, only the named components are published, which fails as soon as one of them depends on a version that is not on the registry yet.
Components are published in topological order, dependencies first.
Which registries
| Kind | Registry | Checked and published with |
|---|---|---|
| Rust crate | crates.io | cargo_client, cargo publish |
| Node package | npm | npm_client, yarn npm publish --tolerate-republish |
| PHP package | Packagist | packagist_client, composer run-script publish |
| Executable | GitLab generic package registry of eternaltwin/eternaltwin | gitlab_client |
Before publishing anything, publish asks each registry whether the local
version is already there, and prints the list of components with a
[published] marker. Only the missing ones are published, so re-running the
command after a failure resumes where it stopped rather than starting over.
After each Rust crate, the command sleeps for ten seconds: crates.io needs a
moment before the new version is visible to the next cargo publish.
Executables
Publishing an executable does more than an upload. The target is precompiled,
then the binary and its meta.json are pushed to the GitLab generic package
registry under the package name eternaltwin-<target>. The command then
creates the GitLab release for the tag v<version> with a link to that
package, or, if the release already exists, adds the link to it.
This is the only kind that needs authentication: pass either
--gitlab-private-token or --gitlab-job-token. The command aborts if an
executable is in the list and neither is provided.
The eternaltwin_app crate
crates/app is a special case, handled by its own code path. It must never be
published by hand, because the files it ships are built rather than committed.
When cargo xtask publish reaches it, the command runs yarn run minimal:build
in packages/website, copies the resulting dist/minimal/browser into
crates/app/browser, and publishes with --allow-dirty so the freshly copied
directory does not stop cargo publish. It also rewrites publish = false to
publish = true in the manifest and restores it afterwards; the manifest
currently carries publish = true already, so that rewrite does nothing today.
Building the executables locally
cargo xtask precompile [targets...]
With no target, it builds all of them. --clean removes the build artifacts
afterwards. The output lands in dist/<target>/, next to the meta.json that
publish uploads.