Skip to main content

Publishing

The repository uses one lockstep SemVer version for the Rust crates, Nebulus, WASM npm metadata, and the docs site.

Use cargo release with the workspace release.toml to update the shared version, update Bun lockfiles, update the changelog, create the release commit, and create the annotated Git tag.

Install it once on your machine:

cargo install cargo-release git-cliff

Preview a release:

cargo release patch --workspace

Create the version bump commit, annotated Git tag, and push both:

cargo release patch --workspace --execute

Create the release commit and tag locally without pushing:

cargo release patch --workspace --execute --no-push

release.toml has publish = false, so local release commands do not publish to crates.io. The release hook updates the Bun-managed package.json versions, regenerates the docs bun.lock with bun install --lockfile-only, and prepends release notes to CHANGELOG.md with git-cliff.

cargo release atomically pushes the release commit and its annotated tag. The single master workflow detects that v0.2.0 points at the pushed commit. After validation and site deployment pass, it calls the reusable release workflow to publish crates.io packages, publish @openipc-rs/web through npm trusted publishing, and upload Nebulus desktop and Android artifacts.

Required release secret:

  • CARGO_REGISTRY_TOKEN

Configure npm trusted publishing for @openipc-rs/web on npmjs.com:

FieldValue
PublisherGitHub Actions
Organization or userneelsani
Repositoryopenipc-rs
Workflow filenameci.yml
Allowed actionnpm publish

The publish job is implemented in reusable release.yml, but npm validates the calling workflow for workflow_call, so the configured filename remains ci.yml.

The existing Cloudflare secrets are required for deployments from master:

  • CLOUDFLARE_API_TOKEN
  • CLOUDFLARE_ACCOUNT_ID

CI deploys the public sites:

Release commits use the same workflow run as ordinary master commits. The release tag adds publishing and platform packaging after validation and site deployment; it does not create a second tag-triggered workflow run.

Release Checklist

  1. Make normal source commits.

  2. Run a dry run:

    cargo release patch --workspace
  3. Review the planned version bump, changelog, and files touched by the hook.

  4. Execute the release:

    cargo release patch --workspace --execute
  5. Watch the GitHub Actions run for the release commit on master.

Use minor or major instead of patch when the public API or package contract changes enough to require it.

The release hook syncs JavaScript package versions with Bun. If you ever need to manually align one package, use the same shape:

bun pm version 0.2.0 --cwd docs --no-git-tag-version --allow-same-version

Generated Artifacts

Generated artifacts are ignored by git:

  • Rust target/,
  • .cargo-tools/,
  • crates/openipc-web/pkg/,
  • app node_modules/ and dist/,
  • docs node_modules/, .docusaurus/, and build/,
  • stray package-lock.json files,
  • root-level package tarballs.

Clean them with:

sh scripts/clean-generated.sh

WASM npm Package

Build before packing or publishing:

bun run --cwd crates/openipc-web build
bun pm pack --cwd crates/openipc-web/pkg --dry-run

Publish when ready:

npm publish crates/openipc-web/pkg --access public --provenance

CI performs this automatically when the master commit carries the matching annotated v* tag. The workflow builds the package with Bun, installs npm only for the publish step, and runs npm publish so npm trusted publishing can issue the release token.

Cargo Crates

The library crates are intended for crates.io publication:

  • openipc-core
  • openipc-rtl88xx
  • openipc-video
  • openipc-web
  • wfb-rs
  • nebulus

apps/openipc-cli is versioned with the workspace but marked publish = false. The published Nebulus package contains its internal decode-worker binary target; Trunk bundles that target into the site instead of publishing another crate.

openipc-core is the easiest crate to publish because it owns protocol logic and does not need USB access. openipc-video has target-specific decoder dependencies for desktop, Android, and WebAssembly. openipc-rtl88xx, openipc-web, and wfb-rs depend on the published nusb-webusb package while importing it as nusb:

nusb = { package = "nusb-webusb", version = "0.2.3" }

Dry-run the workspace publish before publishing:

cargo publish --workspace --dry-run

Publish after logging in to crates.io or configuring CARGO_REGISTRY_TOKEN:

cargo publish --workspace

Nebulus is published as a Cargo package for source installation and reuse, and is also distributed as ready-to-run GitHub Release artifacts. Its versioned path dependencies resolve to the corresponding crates.io versions when Cargo packages it.

Desktop Releases

Nebulus desktop builds are uploaded to the GitHub Release for each v* tag. Artifacts have explicit operating-system and architecture names:

nebulus-[platform]-[architecture]-[version].[ext]

Build targets:

Release labelGitHub runnerRust target
linux-x64ubuntu-24.04x86_64-unknown-linux-gnu
linux-arm64ubuntu-24.04-armaarch64-unknown-linux-gnu
macos-apple-siliconmacos-15aarch64-apple-darwin
macos-intelmacos-15-intelx86_64-apple-darwin
windows-x64windows-2025x86_64-pc-windows-msvc
windows-arm64windows-11-armaarch64-pc-windows-msvc

Linux releases are built on Ubuntu runners and published as architecture-named executables; they are not separate per-distribution builds or AppImages. macOS releases are .dmg disk images, Windows releases are installer .exe files, and Android is one APK containing arm64-v8a, armeabi-v7a, x86_64, and x86.

The .app inside each macOS disk image is ad-hoc signed. Windows installers and Linux executables are not code-signed. Users may see operating-system warnings until platform signing and macOS notarization are configured.

Nebulus Web App

The hosted browser/WebUSB ground station is Nebulus. Build it with Trunk:

cd apps/nebulus
trunk build --release

The deployable output is apps/nebulus/dist. GitHub Actions builds it once and deploys that artifact to the nebulus Cloudflare Pages project on master pushes, including release commits. Deployment does not require a local script.