Eternaltwin

Home | Contributing

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.version is 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 covers packages/* and sdk/node/*.
  • PHP: for each package in sdk/php, the version field and the internal entries of require and require-dev are set to the new version. eternaltwin/path-tools is 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_cli and php_lib_eternaltwin_cli. These are the packages needed to build the main executable in bin/. The executables are excluded, because the GitLab CI job publishes them first.
  • exe expands to the four precompiled executables: x86_64-apple-darwin, x86_64-pc-windows-gnu, x86_64-unknown-linux-gnu and x86_64-unknown-linux-musl. This is what the CI job passes.
  • Any other argument is a component id, such as rs_lib_eternaltwin_core or ts_lib_eternaltwin_website. The full list is the node list of dependencies.dot, regenerated by cargo xtask codegen structure. An unknown id aborts the run.
  • --recursive walks 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

KindRegistryChecked and published with
Rust cratecrates.iocargo_client, cargo publish
Node packagenpmnpm_client, yarn npm publish --tolerate-republish
PHP packagePackagistpackagist_client, composer run-script publish
ExecutableGitLab generic package registry of eternaltwin/eternaltwingitlab_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.