From 72b6700384d603e9678100cc329ff5013e47aaff Mon Sep 17 00:00:00 2001 From: Illia Kripaka Date: Tue, 12 May 2026 12:57:34 +0300 Subject: [PATCH 1/3] simplexup: add cargo-nextest installation --- simplexup/simplexup | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/simplexup/simplexup b/simplexup/simplexup index 4947901..ef27f83 100755 --- a/simplexup/simplexup +++ b/simplexup/simplexup @@ -4,6 +4,7 @@ set -eo pipefail # NOTE: if you make modifications to this script, please increment the version number. # WARNING: the SemVer pattern: major.minor.patch must be followed as we use it to determine if the script is up to date. SIMPLEXUP_INSTALLER_VERSION="0.0.4" +NEXTEST_VERSION="0.9.133" BASE_DIR=${XDG_CONFIG_HOME:-$HOME} SIMPLEX_DIR=${SIMPLEX_DIR:-"$BASE_DIR/.simplex"} @@ -63,6 +64,9 @@ main() { LATEST_TAG=$(latest_tag) SIMPLEX_VERSION=${SIMPLEX_VERSION:-$LATEST_TAG} + # Install default version of nextest for simplex + install_nextest_version "$NEXTEST_VERSION" + # Check if the requested version exists if [[ "${SIMPLEX_VERSION}" != "${LATEST_TAG}" ]]; then validate_tag_version "${SIMPLEX_VERSION}" "${SIMPLEX_REPO}" @@ -601,6 +605,26 @@ install_simplex_from_commit() { rm -rf "${tmp_dir}" } +install_nextest_version() { + local nextest_version=$1 + + # Check if cargo-nextest is already installed and matches the required version + say "Installing cargo-nextest version..." + if check_cmd cargo-nextest --no-pager; then + local current_version + current_version=$(cargo nextest show-config version --no-pager | head -n 1 | awk '{print $4}') + + if [[ "$current_version" == "$nextest_version" ]]; then + say "cargo-nextest $nextest_version is already installed, skipping installation." + return 0 + fi + fi + + say "Installing cargo-nextest version $nextest_version..." + ensure cargo install cargo-nextest --version "$nextest_version" --locked --force + return 0 +} + # Form a comma separated list with 'and' for user experience form_str_list() { local STR_LIST=("$@") From c60bc8164770b4047ca4e5fb4d52e6a467e3d447 Mon Sep 17 00:00:00 2001 From: Illia Kripaka Date: Tue, 12 May 2026 17:27:34 +0300 Subject: [PATCH 2/3] cli: migrate from `cargo test` to `cargo nextest` --- crates/cli/src/commands/test.rs | 64 ++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/crates/cli/src/commands/test.rs b/crates/cli/src/commands/test.rs index 0e4ca98..763f7c8 100644 --- a/crates/cli/src/commands/test.rs +++ b/crates/cli/src/commands/test.rs @@ -1,12 +1,16 @@ use std::path::PathBuf; use std::process::Stdio; +use smplx_test::TestConfig; use smplx_test::config::Verbosity; -use smplx_test::{SMPLX_TEST_MARKER, TestConfig}; use super::core::{TestArguments, TestFlags}; use super::error::CommandError; +// TODO: it's impossible to insert "_smplx_test" constant value in concat macro, remove or reuse constant +/// Nextest dsl variable to filter and use only simplex tests +const SMPLX_DSL_TEST_MARKER: &str = concat!("test(/", "_smplx_test", "$/)"); + pub struct Test {} impl Test { @@ -52,9 +56,10 @@ impl Test { flags: &TestFlags, ) -> std::process::Command { let mut cargo_test_command = std::process::Command::new("cargo"); - cargo_test_command.arg("test"); + cargo_test_command.arg("nextest"); + cargo_test_command.arg("run"); - cargo_test_command.args(Self::build_cargo_test_args(args, flags)); + cargo_test_command.args(Self::build_cargo_nextest_args(args, flags)); cargo_test_command.args(Self::build_test_bin_args(args, flags)); cargo_test_command @@ -66,55 +71,56 @@ impl Test { cargo_test_command } - fn build_cargo_test_args(args: &TestArguments, flags: &TestFlags) -> Vec { + fn build_cargo_nextest_args(args: &TestArguments, flags: &TestFlags) -> Vec { let mut cargo_test_args = Vec::new(); - if let Some(target) = &args.target { - cargo_test_args.push("--test".into()); - cargo_test_args.push(target.clone()); + if args.filters.is_empty() { + cargo_test_args.push("--filterset".into()); + + if let Some(target) = &args.target { + cargo_test_args.push(format!("binary({target}) and {SMPLX_DSL_TEST_MARKER}")); + } else { + cargo_test_args.push(SMPLX_DSL_TEST_MARKER.into()); + } + } else { + cargo_test_args.extend(args.filters.iter().cloned()); } if flags.no_fail_fast { cargo_test_args.push("--no-fail-fast".into()); } + if flags.nocapture { + cargo_test_args.push("--nocapture".into()); + } + if flags.quiet { + cargo_test_args.push("--cargo-quiet".into()); + } + if flags.verbose { + cargo_test_args.push("--verbose".into()); + } cargo_test_args } - fn build_test_bin_args(args: &TestArguments, flags: &TestFlags) -> Vec { + fn build_test_bin_args(_args: &TestArguments, flags: &TestFlags) -> Vec { let mut test_bin_args = Vec::new(); - test_bin_args.push("--".into()); - - // TODO: custom filters may run non-simplex tests due to cargo limitations. Figure out how to fix this - if args.filters.is_empty() { - test_bin_args.push(SMPLX_TEST_MARKER.to_string()); - } else { - test_bin_args.extend(args.filters.iter().cloned()); - } - test_bin_args.extend(Self::build_test_bin_flags(flags)); + if !test_bin_args.is_empty() { + test_bin_args.insert(0, "--".into()); + } test_bin_args } fn build_test_bin_flags(flags: &TestFlags) -> Vec { - let mut test_bin_args = Vec::new(); + let mut test_bin_flags = Vec::new(); - if flags.nocapture { - test_bin_args.push("--nocapture".into()); - } - if flags.show_output { - test_bin_args.push("--show-output".into()); - } if flags.ignored { - test_bin_args.push("--ignored".into()); - } - if flags.quiet { - test_bin_args.push("--quiet".into()); + test_bin_flags.push("--ignored".into()); } - test_bin_args + test_bin_flags } fn get_test_config_cache_name() -> Result { From eee805e571a7d6eefedc5d442506c5757504fb8f Mon Sep 17 00:00:00 2001 From: Illia Kripaka Date: Thu, 14 May 2026 10:17:25 +0300 Subject: [PATCH 3/3] cli: add formal nextest version check fix simplexup version check commands --- Cargo.lock | 5 ++-- crates/cli/Cargo.toml | 1 + crates/cli/src/commands/error.rs | 23 +++++++++++++++++ crates/cli/src/commands/test.rs | 44 +++++++++++++++++++++++++++++++- crates/test/src/config.rs | 10 ++++++++ simplexup/simplexup | 4 +-- 6 files changed, 82 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 153444d..5322cc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1174,9 +1174,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -1319,6 +1319,7 @@ dependencies = [ "ctrlc", "dotenvy", "minreq", + "semver", "serde", "serde_json", "smplx-build", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index a558313..dc2b104 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -31,3 +31,4 @@ clap = { version = "4", features = ["derive", "env"] } toml_edit = { version = "0.23.9" } ctrlc = { version = "3.5.2", features = ["termination"] } serde_json = { version = "1.0.149" } +semver = { version = "1.0.28" } diff --git a/crates/cli/src/commands/error.rs b/crates/cli/src/commands/error.rs index 38e27c1..93d0714 100644 --- a/crates/cli/src/commands/error.rs +++ b/crates/cli/src/commands/error.rs @@ -20,6 +20,9 @@ pub enum CommandError { #[error(transparent)] Clean(#[from] CleanError), + #[error(transparent)] + NextestVersionCheck(#[from] NextestVersionCheckError), + #[error("IO error: {0}")] Io(#[from] std::io::Error), } @@ -62,3 +65,23 @@ pub enum CleanError { #[error("Failed to remove file '{1}': {0}")] RemoveFile(std::io::Error, PathBuf), } + +#[derive(thiserror::Error, Debug)] +pub enum NextestVersionCheckError { + #[error("Nextest is not installed. Please run `simplexup` to install.")] + NextestNotInstalled, + + #[error("Failed to parse nextest version string '{0}': {1}")] + NextestVersionParseError(String, semver::Error), + + #[error("Failed to parse the required version bound '{0}': {1}")] + NextestVersionReqParseError(String, semver::Error), + + #[error( + "Your nextest version {current_version} does not meet the requirement: {required_bound}. Please run `simplexup` to install." + )] + UnsupportedNextestVersion { + current_version: String, + required_bound: String, + }, +} diff --git a/crates/cli/src/commands/test.rs b/crates/cli/src/commands/test.rs index 763f7c8..23904f6 100644 --- a/crates/cli/src/commands/test.rs +++ b/crates/cli/src/commands/test.rs @@ -1,11 +1,12 @@ use std::path::PathBuf; use std::process::Stdio; +use semver::{Version, VersionReq}; use smplx_test::TestConfig; use smplx_test::config::Verbosity; use super::core::{TestArguments, TestFlags}; -use super::error::CommandError; +use super::error::{CommandError, NextestVersionCheckError}; // TODO: it's impossible to insert "_smplx_test" constant value in concat macro, remove or reuse constant /// Nextest dsl variable to filter and use only simplex tests @@ -22,6 +23,8 @@ impl Test { /// # Panics /// Panics if the output of the cargo test command is not valid UTF-8. pub fn run(mut config: TestConfig, args: &TestArguments, flags: &TestFlags) -> Result<(), CommandError> { + Test::enforce_nextest_version(&config.nextest_semver_requirement)?; + let cache_path = Self::get_test_config_cache_name()?; if flags.verbose { @@ -71,6 +74,45 @@ impl Test { cargo_test_command } + /// Builds `cargo nextest --version` + fn build_nextest_version_command() -> std::process::Command { + let mut nextest_version_command = std::process::Command::new("cargo"); + nextest_version_command.arg("nextest").arg("--version"); + + nextest_version_command + } + + fn enforce_nextest_version(required_bound: &str) -> Result<(), CommandError> { + let output = Self::build_nextest_version_command().output()?; + + if !output.status.success() { + Err(NextestVersionCheckError::NextestNotInstalled)?; + } + + let version_output = String::from_utf8(output.stdout).unwrap_or_default(); + + // Parse "cargo-nextest 0.9.133 (65e806bd5 2026-04-14)" + let version_str = version_output + .split_whitespace() + .nth(1) + .expect("Expected to have at least 2 arguments to obtain the nextest version"); + + let current_version = Version::parse(version_str) + .map_err(|e| NextestVersionCheckError::NextestVersionParseError(version_str.into(), e))?; + + let requirement = VersionReq::parse(required_bound) + .map_err(|e| NextestVersionCheckError::NextestVersionReqParseError(required_bound.into(), e))?; + + if !requirement.matches(¤t_version) { + Err(NextestVersionCheckError::UnsupportedNextestVersion { + current_version: current_version.to_string(), + required_bound: required_bound.to_string(), + })?; + } + + Ok(()) + } + fn build_cargo_nextest_args(args: &TestArguments, flags: &TestFlags) -> Vec { let mut cargo_test_args = Vec::new(); diff --git a/crates/test/src/config.rs b/crates/test/src/config.rs index f410c87..023862c 100644 --- a/crates/test/src/config.rs +++ b/crates/test/src/config.rs @@ -14,6 +14,7 @@ use super::error::TestError; pub const TEST_ENV_NAME: &str = "SIMPLEX_TEST_ENV"; pub const DEFAULT_TEST_MNEMONIC: &str = "exist carry drive collect lend cereal occur much tiger just involve mean"; pub const DEFAULT_BITCOINS: u64 = 10_000_000; +const DEFAULT_NEXTEST_SEMVER_REQUIREMENT: &str = "=0.9.133"; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] @@ -23,6 +24,9 @@ pub struct TestConfig { pub esplora: Option, pub rpc: Option, pub verbosity: Option, + #[doc(hidden)] + #[serde(skip, default = "get_default_nextest_semver_requirement")] + pub nextest_semver_requirement: String, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -98,6 +102,12 @@ impl Default for TestConfig { esplora: None, rpc: None, verbosity: Some(Verbosity(3)), + nextest_semver_requirement: get_default_nextest_semver_requirement(), } } } + +#[inline] +fn get_default_nextest_semver_requirement() -> String { + DEFAULT_NEXTEST_SEMVER_REQUIREMENT.into() +} diff --git a/simplexup/simplexup b/simplexup/simplexup index ef27f83..ce51ca9 100755 --- a/simplexup/simplexup +++ b/simplexup/simplexup @@ -610,9 +610,9 @@ install_nextest_version() { # Check if cargo-nextest is already installed and matches the required version say "Installing cargo-nextest version..." - if check_cmd cargo-nextest --no-pager; then + if check_cmd cargo-nextest nextest; then local current_version - current_version=$(cargo nextest show-config version --no-pager | head -n 1 | awk '{print $4}') + current_version=$(cargo nextest show-config version | head -n 1 | awk '{print $4}') if [[ "$current_version" == "$nextest_version" ]]; then say "cargo-nextest $nextest_version is already installed, skipping installation."