sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit 47656467f15b1d21b06f6b6159a8f70cb40c0d28
parent 735ecaa2d0d3a9ef4d294f3c41fdbdf3761b3c36
Author: triesap <tyson@radroots.org>
Date:   Mon,  3 Aug 2026 22:31:22 +0000

release: qualify both Rust front doors

- derive both public matrices from the architecture catalog
- check default no-default individual and all-feature profiles
- gate the ordinary example behind the client feature
- consume the canonical trade json feature

Diffstat:
MCargo.toml | 2+-
Mcrates/radroots/Cargo.toml | 1+
Mtools/xtask/src/main.rs | 10+++++++++-
Atools/xtask/src/release_qualification.rs | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 146 insertions(+), 2 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -86,7 +86,7 @@ radroots_sdk = { path = "crates/sdk", version = "=0.1.0-alpha", default-features radroots_sdk_sql_wasm_runtime = { path = "crates/sql_wasm_runtime", version = "=0.1.0-alpha" } radroots_sql_core = { version = "=0.1.0-alpha", default-features = false } radroots_trade = { package = "radroots_trade", version = "=0.1.0-alpha", default-features = false, features = [ - "serde_json", + "json", "std", ] } diff --git a/crates/radroots/Cargo.toml b/crates/radroots/Cargo.toml @@ -48,3 +48,4 @@ full = ["radroots_sdk/full"] [[example]] name = "ordinary_memory" path = "examples/ordinary_memory.rs" +required-features = ["client"] diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs @@ -13,6 +13,7 @@ mod manifest; mod output; mod package_matrix; mod package_metadata; +mod release_qualification; mod smoke; mod ts; mod wasm; @@ -29,6 +30,7 @@ enum CommandAction<'a> { GenerateWasm(&'a [String]), GeneratePackageMetadata, Coverage(&'a [String]), + QualifyFeatures, Check, Smoke(&'a [String]), } @@ -61,6 +63,9 @@ fn run(args: impl IntoIterator<Item = String>) -> Result<(), String> { CommandAction::GenerateWasm(rest) => wasm::generate(rest), CommandAction::GeneratePackageMetadata => generate::generate_package_metadata(), CommandAction::Coverage(rest) => coverage::run(rest), + CommandAction::QualifyFeatures => { + release_qualification::run_feature_matrix(&fs::workspace_root()?) + } CommandAction::Check => check::check(), CommandAction::Smoke(rest) => smoke::run(rest), } @@ -88,6 +93,9 @@ fn command_action(args: &[String]) -> Result<CommandAction<'_>, String> { Ok(CommandAction::GeneratePackageMetadata) } [command, rest @ ..] if command == "coverage" => Ok(CommandAction::Coverage(rest)), + [command, target] if command == "release" && target == "qualify-features" => { + Ok(CommandAction::QualifyFeatures) + } [command] if command == "check" => Ok(CommandAction::Check), [command, rest @ ..] if command == "smoke" => Ok(CommandAction::Smoke(rest)), [] => Err(usage()), @@ -96,7 +104,7 @@ fn command_action(args: &[String]) -> Result<CommandAction<'_>, String> { } fn usage() -> String { - "usage: cargo xtask architecture | cargo xtask architecture-ci | cargo xtask check-api-boundaries | cargo xtask check-dependency-boundaries | cargo xtask generate | cargo xtask generate ts | cargo xtask generate wasm [--package <key>] | cargo xtask generate bindings <swift|kotlin> | cargo xtask generate package-metadata | cargo xtask check | cargo xtask smoke facade-rust-local | sdk-rust-local | front-doors-rust-local | cargo xtask coverage run" + "usage: cargo xtask architecture | cargo xtask architecture-ci | cargo xtask check-api-boundaries | cargo xtask check-dependency-boundaries | cargo xtask generate | cargo xtask generate ts | cargo xtask generate wasm [--package <key>] | cargo xtask generate bindings <swift|kotlin> | cargo xtask generate package-metadata | cargo xtask check | cargo xtask smoke facade-rust-local | sdk-rust-local | front-doors-rust-local | cargo xtask coverage run | cargo xtask release qualify-features" .to_owned() } diff --git a/tools/xtask/src/release_qualification.rs b/tools/xtask/src/release_qualification.rs @@ -0,0 +1,135 @@ +use std::{fs, path::Path, process::Command}; + +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +struct Architecture { + repositories: Repositories, + package: Vec<Package>, +} + +#[derive(Debug, Deserialize)] +struct Repositories { + sdk: Repository, +} + +#[derive(Debug, Deserialize)] +struct Repository { + packages: Vec<String>, +} + +#[derive(Debug, Deserialize)] +struct Package { + name: String, + features: Vec<String>, +} + +#[derive(Debug, PartialEq, Eq)] +struct CargoInvocation { + args: Vec<String>, +} + +pub fn run_feature_matrix(workspace_root: &Path) -> Result<(), String> { + for invocation in feature_matrix(workspace_root)? { + eprintln!("cargo {}", invocation.args.join(" ")); + let status = Command::new("cargo") + .args(&invocation.args) + .current_dir(workspace_root) + .status() + .map_err(|error| format!("failed to start cargo: {error}"))?; + if !status.success() { + return Err(format!( + "public feature qualification failed: cargo {}", + invocation.args.join(" ") + )); + } + } + Ok(()) +} + +fn feature_matrix(workspace_root: &Path) -> Result<Vec<CargoInvocation>, String> { + let path = workspace_root.join("docs/specs/radroots_crates_release_v1.toml"); + let raw = fs::read_to_string(&path) + .map_err(|error| format!("failed to read {}: {error}", path.display()))?; + let architecture = toml::from_str::<Architecture>(&raw) + .map_err(|error| format!("failed to parse {}: {error}", path.display()))?; + let mut packages = architecture + .package + .into_iter() + .filter(|package| { + architecture + .repositories + .sdk + .packages + .contains(&package.name) + }) + .collect::<Vec<_>>(); + packages.sort_by(|left, right| left.name.cmp(&right.name)); + if packages.len() != 2 { + return Err(format!( + "SDK feature qualification requires exactly 2 public packages, found {}", + packages.len() + )); + } + + let mut invocations = Vec::new(); + for package in packages { + invocations.push(check_invocation(&package.name, None, true)); + invocations.push(check_invocation(&package.name, None, false)); + for feature in package.features { + invocations.push(check_invocation(&package.name, Some(&feature), true)); + } + invocations.push(CargoInvocation { + args: vec![ + "check".to_owned(), + "-p".to_owned(), + package.name, + "--all-targets".to_owned(), + "--all-features".to_owned(), + "--locked".to_owned(), + ], + }); + } + Ok(invocations) +} + +fn check_invocation( + package: &str, + feature: Option<&str>, + no_default_features: bool, +) -> CargoInvocation { + let mut args = vec!["check".to_owned(), "-p".to_owned(), package.to_owned()]; + if no_default_features { + args.push("--lib".to_owned()); + args.push("--no-default-features".to_owned()); + } else { + args.push("--all-targets".to_owned()); + } + if let Some(feature) = feature { + args.push("--features".to_owned()); + args.push(feature.to_owned()); + } + args.push("--locked".to_owned()); + CargoInvocation { args } +} + +#[cfg(test)] +mod tests { + use super::feature_matrix; + + #[test] + fn current_catalog_generates_both_front_door_feature_matrices() { + let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .and_then(std::path::Path::parent) + .expect("workspace root"); + let matrix = feature_matrix(root).expect("feature matrix"); + assert!(matrix.len() > 20); + for package in ["radroots", "radroots_sdk"] { + assert!(matrix.iter().any(|entry| { + entry.args.windows(2).any(|pair| pair == ["-p", package]) + && entry.args.iter().any(|arg| arg == "--all-features") + })); + } + } +}