From 622194234e5e2568c78db6040b91a0aac250a291 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Fri, 3 Jul 2026 12:52:45 +0100 Subject: [PATCH] chore(release): make just set-version bump Cargo + npm + all lockfiles just set-version now updates every workspace crate and the root Cargo.lock, the excluded extended_runtime fixture Cargo.lock, and the npm main package, 3 platform packages, optionalDependencies and package-lock.json in one atomic step, so a version bump cannot leave a stale lockfile that breaks CI (cargo --locked and npm ci --omit=optional). Add a check-fixture-lock recipe wired into test-native-modules to fail fast on fixture-lock drift instead of a cryptic poisoned-LazyLock panic. Rewrite docs/release.md to match the real flow: pushing a vX.Y.Z tag triggers CreateRelease.yml, which creates the release branch and publishes to crates.io and npm via OIDC trusted publishing; use just set-version for bumps. Signed-off-by: Simon Davies --- Justfile | 47 ++++++++++++++++++++++++++++++++++++++++++++++- docs/release.md | 47 +++++++++++++++++++++++------------------------ 2 files changed, 69 insertions(+), 25 deletions(-) diff --git a/Justfile b/Justfile index a10861f0..aac81250 100644 --- a/Justfile +++ b/Justfile @@ -178,7 +178,7 @@ test-js-host-api target=default-target features="": (build-js-host-api target fe # Base path to the extended runtime fixture target directory extended_runtime_target := replace(justfile_dir(), "\\", "/") + "/src/hyperlight-js-runtime/tests/fixtures/extended_runtime/target/x86_64-hyperlight-none" -test-native-modules target=default-target: (ensure-tools) (_test-native-modules-unit target) (_test-native-modules-build-guest target) (_test-native-modules-vm target) (_test-native-modules-restore target) +test-native-modules target=default-target: (ensure-tools) (check-fixture-lock) (_test-native-modules-unit target) (_test-native-modules-build-guest target) (_test-native-modules-vm target) (_test-native-modules-restore target) [private] _test-native-modules-unit target=default-target: @@ -200,6 +200,51 @@ _test-native-modules-restore target=default-target: @echo "Rebuilding hyperlight-js with default guest runtime..." cd src/hyperlight-js && cargo build --profile={{ if target == "debug" {"dev"} else { target } }} +# ── Version bumping & fixture-lock consistency ────────────────────────────── +# The extended_runtime test fixture is a separate `[workspace]` that is excluded +# from the root workspace (see the root Cargo.toml `exclude`), so it keeps its +# OWN committed Cargo.lock. `cargo set-version` bumps the workspace crates + the +# root lock but cannot reach the excluded fixture, leaving its lock pinning the +# old version — which then fails the native_modules `--locked` build. These two +# recipes keep them in lockstep. + +# Bump the version of EVERYTHING in lockstep so a release PR can't end up in a +# half-bumped, CI-breaking state. In one step this updates: +# * all workspace crates + the root Cargo.lock (via cargo-edit) +# * the excluded extended_runtime fixture's own Cargo.lock (cargo can't reach it) +# * the npm main package, the 3 platform packages, and their optionalDependencies +# * the npm package-lock.json (regenerated; the not-yet-published platform +# optionals are omitted, matching CI's `npm ci --omit=optional`) +# Requires cargo-edit (`cargo install cargo-edit`). ALWAYS use this instead of a +# bare `cargo set-version` / `npm version` when preparing a release. +set-version version: + # Rust: workspace crates + root lock, then the excluded fixture lock + cargo set-version {{ version }} + cargo update \ + --manifest-path src/hyperlight-js-runtime/tests/fixtures/extended_runtime/Cargo.toml \ + -p hyperlight-js-runtime -p hyperlight-js-common + # npm: main + the 3 platform package.json versions (--ignore-scripts avoids needing node_modules) + cd src/js-host-api && npm version {{ version }} --no-git-tag-version --allow-same-version --ignore-scripts + cd src/js-host-api/npm/linux-x64-gnu && npm version {{ version }} --no-git-tag-version --allow-same-version --ignore-scripts + cd src/js-host-api/npm/linux-x64-musl && npm version {{ version }} --no-git-tag-version --allow-same-version --ignore-scripts + cd src/js-host-api/npm/win32-x64-msvc && npm version {{ version }} --no-git-tag-version --allow-same-version --ignore-scripts + # npm: point the main package's optionalDependencies at the new version + cd src/js-host-api && npm pkg set \ + "optionalDependencies.@hyperlight-dev/js-host-api-linux-x64-gnu={{ version }}" \ + "optionalDependencies.@hyperlight-dev/js-host-api-linux-x64-musl={{ version }}" \ + "optionalDependencies.@hyperlight-dev/js-host-api-win32-x64-msvc={{ version }}" + # npm: regenerate package-lock.json so `npm ci --omit=optional` stays in sync + cd src/js-host-api && npm install --package-lock-only --omit=optional --ignore-scripts + +# Fail fast if the excluded fixture lock has drifted from the workspace version. +# Without this, drift only surfaces as a cryptic poisoned-LazyLock panic inside +# the native_modules unit tests. Fix drift with `just set-version `. +# Wired into `test-native-modules` so CI catches it before the confusing failure. +check-fixture-lock: + cargo metadata --locked --format-version 1 \ + --manifest-path src/hyperlight-js-runtime/tests/fixtures/extended_runtime/Cargo.toml \ + {{ if os() == "windows" { "> $null" } else { "> /dev/null" } }} + # Run js-host-api examples (simple.js, calculator.js, unload.js, interrupt.js, cpu-timeout.js, host-functions.js) run-js-host-api-examples target=default-target features="": (build-js-host-api target features) @echo "Running js-host-api examples..." diff --git a/docs/release.md b/docs/release.md index 0520c38b..0f60a6f1 100644 --- a/docs/release.md +++ b/docs/release.md @@ -1,29 +1,36 @@ # Create a new hyperlight-js release -This document details the process of releasing a new version of hyperlight-js to [crates.io](https://crates.io/). It's intended to be used as a checklist for the developer doing the release. The checklist is represented in the below sections. +This document details the process of releasing a new version of hyperlight-js to [crates.io](https://crates.io/) and [npmjs.com](https://www.npmjs.com/). It's intended to be used as a checklist for the developer doing the release. -## Update cargo.toml Versions +## Update versions -The first step in the release process is to update the version numbers of the crates you are releasing. +The first step in the release process is to bump the version numbers — the Rust crates **and** the npm packages — keeping them all in sync. -Update the `version` field in the `[workspace.package]` section of the root `Cargo.toml`, as well as the `hyperlight-js-runtime` entry in `[workspace.dependencies]`. +Do this with the `just set-version` recipe. **Always use this instead of bumping by hand** (`cargo set-version`, `npm version`, editing `package.json`): piecemeal bumps are exactly what leaves a lockfile stale and breaks CI mid-release. In one step it updates: -The easiest way to do this is with the `cargo-edit` crate, which provides a `cargo set-version` command. Install it with: +- every workspace crate's `version` and the root `Cargo.lock`, +- the excluded `extended_runtime` fixture's own `Cargo.lock` (a bare `cargo set-version` can't reach it, and a stale one fails the `native_modules --locked` build), +- the npm main package, the three platform packages, and their `optionalDependencies`, +- `src/js-host-api/package-lock.json` (a stale one fails `npm ci` in the publish job). + +It uses `cargo set-version` from the `cargo-edit` crate under the hood, so install that first: ```console cargo install cargo-edit ``` -Then update the version number: +Then bump everything: ```console -cargo set-version 0.18.0 +just set-version 0.18.0 ``` -For simplicity, we keep the version number consistent across all crates in the repository. +We keep the version number consistent across all crates and npm packages in the repository. Create a PR with these changes and merge it into the `main` branch. +> **Note:** The `CreateRelease` workflow *also* sets the npm packages to the tag's version at publish time (via `npm version`), so the published artifacts always match the tag regardless. Bumping them in the repo with `just set-version` is what keeps `npm ci` from failing *during* the release — don't skip it. + ## Create a tag When the `main` branch has reached a state in which you want to release a new Cargo version, you should create a tag. Although you can do this from the GitHub releases page, we currently recommend doing the tag from the command line. Do so with the following commands: @@ -36,26 +43,18 @@ git push origin v0.18.0 # if you've named your git remote for the hyperlight-dev >Note: we'll use `v0.18.0` as the version for the above and all subsequent instructions. You should replace this with the version you're releasing. Make sure your version follows [SemVer](https://semver.org) conventions as closely as possible, and is prefixed with a `v` character. *In particular do not use a patch version unless you are patching an issue in a release branch, releases from main should always be minor or major versions*. If you are creating a patch release see the instructions [here](#patching-a-release). -## Create a release branch (no manual steps) - -After you push your new tag in the previous section, the ["Create a Release Branch"](https://github.com/hyperlight-dev/hyperlight-js/blob/main/.github/workflows/CreateReleaseBranch.yml) CI job will automatically run. When this job completes, a new `release/v0.18.0` branch will be automatically created for you. - -## Create a new GitHub release and publish the crates - -After the previous CI job runs to create the new release branch, go to the ["Create a Release"](https://github.com/hyperlight-dev/hyperlight-js/actions/workflows/CreateRelease.yml) Github actions workflow and do the following: -1. Click the "Run workflow" button near the top right -1. In the Use workflow from dropdown, select the `release/v0.18.0` branch -1. Click the green **Run workflow** button - -When this job is done, a new [GitHub release](https://github.com/hyperlight-dev/hyperlight-js/releases) will be created for you. +## What happens when you push the tag -This release contains the benchmark results and the source code for the release along with automatically generated release notes. +Pushing a `vX.Y.Z` tag is the **only** manual trigger you need — you do **not** run any workflow by hand. The tag push starts the ["Create a Release"](https://github.com/hyperlight-dev/hyperlight-js/actions/workflows/CreateRelease.yml) workflow ([`CreateRelease.yml`](https://github.com/hyperlight-dev/hyperlight-js/blob/main/.github/workflows/CreateRelease.yml)), which reads the version from the tag and then does everything else automatically: -In addition, the hyperlight-js crates will be published to crates.io in dependency order (`hyperlight-js-common` → `hyperlight-js-runtime` → `hyperlight-js`). You can verify this by going to the [hyperlight-js page on crates.io](https://crates.io/crates/hyperlight-js) and checking that the new version is listed. +1. **Creates the release branch** — a `release/v0.18.0` branch is created and pushed for you. +2. **Creates the GitHub release** — a new [GitHub release](https://github.com/hyperlight-dev/hyperlight-js/releases) is published with automatically generated release notes and the benchmark results attached. +3. **Publishes the crates to crates.io** — in dependency order (`hyperlight-js-common` → `hyperlight-js-runtime` → `hyperlight-js`). Verify on the [hyperlight-js page on crates.io](https://crates.io/crates/hyperlight-js). +4. **Publishes the npm packages to npmjs.com** — `@hyperlight-dev/js-host-api` and its platform-specific binary packages, with their versions set from the tag. Verify on the [npmjs.com package page](https://www.npmjs.com/package/@hyperlight-dev/js-host-api). -The npm packages (`@hyperlight-dev/js-host-api` and platform-specific binaries) are also published automatically as part of this workflow. Publishing uses [npm trusted publishing (OIDC)](https://docs.npmjs.com/trusted-publishers) — no `NPM_TOKEN` secret is needed for the `CreateRelease` workflow. Provenance attestations are generated automatically. +Both crates.io and npm publishing use trusted publishing (OIDC), so no `NPM_TOKEN` or crates.io token secret is needed for the `CreateRelease` workflow. Provenance attestations are generated automatically for the npm packages. -You can verify the npm publish by checking the [npmjs.com package page](https://www.npmjs.com/package/@hyperlight-dev/js-host-api). +> **Note:** Only a `vX.Y.Z` **tag** push triggers a real release. Pushing to `main`, or running the workflow manually with **Run workflow**, performs a **dry run** — it builds and validates everything but publishes nothing. ### npm trusted publishing setup