Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 <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..."
Expand Down
47 changes: 23 additions & 24 deletions docs/release.md
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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.
Comment thread
simongdavies marked this conversation as resolved.

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

Expand Down
Loading