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
18 changes: 7 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,8 @@ jobs:
npm ci --prefix crates/workshop
npm ci --prefix crates/gateway/config-ui/ui

- name: Build featureless Gateway
run: cargo build --locked -p gateway --no-default-features

- name: Stage Gateway sidecar
run: node tools/stage-gateway-sidecar.mjs stage --target x86_64-pc-windows-msvc --source target/debug/runvil-gateway.exe
- name: Stage a stub Gateway sidecar
run: node tools/fetch-gateway-sidecar.mjs --stub --target x86_64-pc-windows-msvc

# workshop-server-api is the desktop app's re-export view of workshop-server,
# so it runs in this partition with the crates it fronts and stays
Expand Down Expand Up @@ -228,11 +225,8 @@ jobs:
npm ci --prefix crates/workshop
npm ci --prefix crates/gateway/config-ui/ui

- name: Build featureless Gateway
run: cargo build --locked -p gateway --no-default-features

- name: Stage Gateway sidecar
run: node tools/stage-gateway-sidecar.mjs stage --target x86_64-unknown-linux-gnu --source target/debug/runvil-gateway
- name: Stage a stub Gateway sidecar
run: node tools/fetch-gateway-sidecar.mjs --stub --target x86_64-unknown-linux-gnu

- name: Build (workshop, Linux)
run: cargo build --locked -p workshop
Expand Down Expand Up @@ -317,7 +311,9 @@ jobs:
# crypto backend, aws-lc-rs. This fails when `ring` re-enters its
# normal-edge closure (through a reqwest bump or a Tauri plugin default)
# and when `cargo tree` itself cannot run; only a successful, ring-free
# result passes.
# result passes. This is a Gateway-side check: it reads the Gateway
# crate's dependency closure, which moves with the Gateway, so it stays
# here until that check moves too.
- name: One rustls crypto backend in the gateway
shell: bash
run: |
Expand Down
34 changes: 13 additions & 21 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ jobs:
working-directory: crates/workshop
run: npm ci

- name: Install config UI dependencies
working-directory: crates/gateway/config-ui/ui
run: npm ci

- name: Install Tauri system packages
if: startsWith(matrix.name, 'linux')
run: |
Expand All @@ -179,30 +175,26 @@ jobs:

# tauri.conf.json ships the gateway via bundle.externalBin, which
# resolves binaries/runvil-gateway-<target-triple> at bundle
# time; build and stage it before tauri-action runs.
- name: Build and stage the gateway sidecar
# time; stage the pinned release binary before tauri-action runs.
#
# gateway-pin/pin.json must name a published Gateway release before
# this job can run: the fetch verifies the asset's sha256 against the
# pin and refuses a placeholder. Fill it with
# `node tools/bump-gateway.mjs <tag>`.
- name: Stage the pinned Gateway sidecar
shell: bash
run: |
set -e
case "${{ matrix.name }}" in
windows) triple="x86_64-pc-windows-msvc"; ext=".exe" ;;
macos-arm) triple="aarch64-apple-darwin"; ext="" ;;
macos-intel) triple="x86_64-apple-darwin"; ext="" ;;
windows) triple="x86_64-pc-windows-msvc"; ext=".exe" ;;
macos-arm) triple="aarch64-apple-darwin"; ext="" ;;
macos-intel) triple="x86_64-apple-darwin"; ext="" ;;
linux) triple="x86_64-unknown-linux-gnu"; ext="" ;;
linux-arm) triple="aarch64-unknown-linux-gnu"; ext="" ;;
esac
case "${{ matrix.args }}" in
*--target*)
cargo build --release --locked -p gateway --target "$triple"
src="target/$triple/release/runvil-gateway$ext"
;;
*)
cargo build --release --locked -p gateway
src="target/release/runvil-gateway$ext"
;;
esac
mkdir -p crates/workshop/desktop/binaries
cp "$src" "crates/workshop/desktop/binaries/runvil-gateway-$triple$ext"
node tools/fetch-gateway-sidecar.mjs --target "$triple"
staged="crates/workshop/desktop/binaries/runvil-gateway-$triple$ext"
[ -f "$staged" ] || { echo "no staged sidecar at $staged"; exit 1; }

- name: Build the app
uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0
Expand Down
41 changes: 16 additions & 25 deletions .github/workflows/release-workshop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,6 @@ jobs:
working-directory: crates/workshop
run: npm ci

# The gateway sidecar build needs the config UI's esbuild pipeline
# (default `config-ui` feature).
- name: Install config UI dependencies
working-directory: crates/gateway/config-ui/ui
run: npm ci

- name: Install Tauri system packages
if: startsWith(matrix.name, 'linux')
run: |
Expand All @@ -142,34 +136,31 @@ jobs:

# tauri.conf.json ships the gateway via bundle.externalBin, which
# resolves binaries/runvil-gateway-<target-triple> at bundle
# time; build and stage it before tauri-action runs.
- name: Build and stage the gateway sidecar
# time; stage the pinned release binary before tauri-action runs.
#
# gateway-pin/pin.json must name a published Gateway release before
# this job can run: the fetch verifies the asset's sha256 against the
# pin and refuses a placeholder. Fill it with
# `node tools/bump-gateway.mjs <tag>`.
- name: Stage the pinned Gateway sidecar
shell: bash
run: |
set -e
case "${{ matrix.name }}" in
windows) triple="x86_64-pc-windows-msvc"; ext=".exe" ;;
macos-arm) triple="aarch64-apple-darwin"; ext="" ;;
macos-intel) triple="x86_64-apple-darwin"; ext="" ;;
windows) triple="x86_64-pc-windows-msvc"; ext=".exe" ;;
macos-arm) triple="aarch64-apple-darwin"; ext="" ;;
macos-intel) triple="x86_64-apple-darwin"; ext="" ;;
linux) triple="x86_64-unknown-linux-gnu"; ext="" ;;
linux-arm) triple="aarch64-unknown-linux-gnu"; ext="" ;;
esac
case "${{ matrix.args }}" in
*--target*)
cargo build --release --locked -p gateway --target "$triple"
src="target/$triple/release/runvil-gateway$ext"
;;
*)
cargo build --release --locked -p gateway
src="target/release/runvil-gateway$ext"
;;
esac
mkdir -p crates/workshop/desktop/binaries
node tools/fetch-gateway-sidecar.mjs --target "$triple"
# The staged Gateway must be the release the pin names. The pin
# is the only Gateway version authority now: Workshop and the
# Gateway release on their own schedules.
staged="crates/workshop/desktop/binaries/runvil-gateway-$triple$ext"
cp "$src" "$staged"
[ -f "$staged" ] || { echo "no staged sidecar at $staged"; exit 1; }
expected="runvil-gateway $(node -e 'console.log(require("./gateway-pin/pin.json").version)')"
output=$("$staged" --version)
version="${{ needs.prepare.outputs.version }}"
expected="runvil-gateway $version"
[ "$output" = "$expected" ] || { echo "staged Gateway printed '$output', expected '$expected'"; exit 1; }

- name: Build the signed release app
Expand Down
15 changes: 10 additions & 5 deletions .github/workflows/workshop-installer-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
- crates/build-workshop/**
- crates/workshop/desktop/installer.nsi
- crates/workshop/desktop/tauri*.conf.json
- gateway-pin/**
- tools/fetch-gateway-sidecar.mjs
- tools/gateway-archive.mjs
- tools/gateway-pin.mjs
- tools/stage-gateway-sidecar.mjs
workflow_dispatch:

Expand All @@ -31,11 +35,12 @@ jobs:
working-directory: crates/workshop
run: npm ci

- name: Build featureless Gateway
run: cargo build --locked -p gateway --no-default-features

- name: Stage Gateway sidecar
run: node tools/stage-gateway-sidecar.mjs stage --target x86_64-pc-windows-msvc --source target/debug/runvil-gateway.exe
# This job compiles the unsigned NSIS installer and installs and runs
# nothing, so the sidecar only has to exist: tauri-build needs a file
# at the externalBin path, and the bundler needs one to package. A
# stub costs nothing and needs no Gateway release.
- name: Stage a stub Gateway sidecar
run: node tools/fetch-gateway-sidecar.mjs --stub --target x86_64-pc-windows-msvc

- name: Compile unsigned debug NSIS installer
uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0
Expand Down
71 changes: 63 additions & 8 deletions crates/build-workshop/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
//! Builds the Runvil Gateway, stages it for Tauri, builds Workshop,
//! and removes the temporary staged sidecar.
//! Builds Workshop and stages its Gateway sidecar for Tauri.
//!
//! The sidecar comes from one of four places, in this order: the
//! `--gateway-binary` flag, the `RUNVIL_GATEWAY_SIDECAR` environment
//! variable, a sidecar already staged under `crates/workshop/desktop/binaries/`,
//! or a Gateway built from this workspace. Only the last compiles the
//! Gateway, so a machine with a downloaded or hand-staged Gateway builds
//! Workshop without touching Gateway source.

use std::ffi::OsString;
use std::fmt;
Expand All @@ -17,16 +23,27 @@ mod runner;
use pipeline::build_workshop;
use runner::install_interrupt_handler;

/// The environment variable naming a Gateway binary to stage, so CI can
/// point at a staged file without passing a flag through Tauri.
const GATEWAY_SIDECAR_VARIABLE: &str = "RUNVIL_GATEWAY_SIDECAR";

const USAGE: &str = "\
Build Runvil Gateway and Workshop together.
Build Workshop, staging its Gateway sidecar.

USAGE:
cargo workshop [--release] [--target <triple>]
cargo workshop [--release] [--target <triple>] [--gateway-binary <path>]

OPTIONS:
--release Build both products with Cargo's release profile
--target <triple> Build both products for this target triple
-h, --help Print this help
--release Build Workshop with Cargo's release profile
--target <triple> Build for this target triple
--gateway-binary <path> Stage this Gateway binary instead of building one
-h, --help Print this help

The Gateway sidecar comes from --gateway-binary, then the
RUNVIL_GATEWAY_SIDECAR environment variable, then a sidecar already staged
under crates/workshop/desktop/binaries/, and only otherwise from
`cargo build -p gateway`. A sidecar that was already staged is left in
place, so the next build reuses it.
";

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand All @@ -48,6 +65,7 @@ impl Profile {
struct BuildRequest {
profile: Profile,
target: Option<String>,
gateway_binary: Option<PathBuf>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand All @@ -61,6 +79,7 @@ struct CommandSpec {
program: PathBuf,
args: Vec<OsString>,
current_dir: PathBuf,
env: Vec<(OsString, OsString)>,
output_mode: OutputMode,
}

Expand Down Expand Up @@ -113,6 +132,10 @@ struct BuildEnvironment {
target_root: PathBuf,
cargo: PathBuf,
node: PathBuf,
/// The Gateway binary named by `RUNVIL_GATEWAY_SIDECAR`, when set: the
/// path a CI job stages and points the build at, so no flag has to pass
/// through Tauri.
gateway_sidecar: Option<PathBuf>,
}

impl BuildEnvironment {
Expand Down Expand Up @@ -152,11 +175,21 @@ impl BuildEnvironment {
.ok_or_else(|| {
anyhow::anyhow!("Cargo did not provide the executable used for this command")
})?;
let gateway_sidecar = match std::env::var_os(GATEWAY_SIDECAR_VARIABLE) {
Some(value) if value.is_empty() => {
return Err(anyhow::anyhow!(
"{GATEWAY_SIDECAR_VARIABLE} must not be empty"
));
}
Some(value) => Some(PathBuf::from(value)),
None => None,
};
Ok(Self {
workspace_root,
target_root,
cargo,
node: PathBuf::from("node"),
gateway_sidecar,
})
}
}
Expand Down Expand Up @@ -188,6 +221,7 @@ fn parse_arguments(args: &[String]) -> Result<BuildRequest, anyhow::Error> {
let mut profile = Profile::Debug;
let mut release_seen = false;
let mut target = None;
let mut gateway_binary = None;
let mut index = 0;
while index < args.len() {
match args[index].as_str() {
Expand All @@ -214,14 +248,35 @@ fn parse_arguments(args: &[String]) -> Result<BuildRequest, anyhow::Error> {
target = Some(value.clone());
index += 2;
}
"--gateway-binary" if gateway_binary.is_some() => {
return Err(anyhow::anyhow!(
"duplicate argument `--gateway-binary`\n\n{USAGE}"
));
}
"--gateway-binary" => {
let value = args.get(index + 1).ok_or_else(|| {
anyhow::anyhow!("argument `--gateway-binary` needs a path\n\n{USAGE}")
})?;
if value.starts_with('-') || value.trim().is_empty() {
return Err(anyhow::anyhow!(
"argument `--gateway-binary` needs a path, got `{value}`\n\n{USAGE}"
));
}
gateway_binary = Some(PathBuf::from(value));
index += 2;
}
argument => {
return Err(anyhow::anyhow!(
"unsupported argument `{argument}`\n\n{USAGE}"
));
}
}
}
Ok(BuildRequest { profile, target })
Ok(BuildRequest {
profile,
target,
gateway_binary,
})
}

fn valid_target_triple(target: &str) -> bool {
Expand Down
Loading
Loading