Cargo test --workspace // only test modified crates

I have cargo test --workspace running inside a cargo watch.

Is there a way to instruct this to only run unit tests of crates where:

  1. the crate changed OR
  2. some dependency of the crate changed ?

So this workspace has 70+ crates, and it is silly that on every change, all unit tests from all crates run. I would prefer that the only crates that get unit tested be:

  1. the crate that was modified

  2. dependents of the modified crate

Thanks!

I'm gonna mute this in favor of the duplicate Cargo test --workspace // only show failed tests?

Actually, could you unmute this? I have a solution I am about to post here.

No warranty. Not liable for damages. Appears to work for me:

use glob::glob;
use notify::{Config, Event, INotifyWatcher, RecommendedWatcher, RecursiveMode, Watcher};
use std::process::{Command, Stdio};
use std::sync::mpsc::Receiver;
use std::time::Duration;

const ROOT: &str = "/workspace/";

pub fn get_dirs() -> Vec<String> {
    let mut out = vec![];
    let suffix = "Cargo.toml";

    for entry in glob(&format!("{}/*/**/{}", ROOT, suffix)).expect("Failed to read glob pattern") {
        match entry {
            Err(e) => {}
            Ok(v) => {
                let s = v.to_str().unwrap();
                if s.ends_with(suffix) {
                    out.push(s[0..(s.len() - suffix.len())].to_string());
                }
            }
        }
    }

    out
}

pub struct My_Watcher {
    path: String,
    rx: Receiver<Result<Event, notify::Error>>,
    watcher: INotifyWatcher,
}

impl My_Watcher {
    pub fn new(p: &str) -> My_Watcher {
        let (tx, rx) = std::sync::mpsc::channel();
        let mut watcher = RecommendedWatcher::new(tx, Config::default()).unwrap();
        watcher.watch(p.as_ref(), RecursiveMode::Recursive).unwrap();
        My_Watcher {
            path: p.to_string(),
            rx,
            watcher,
        }
    }
}

fn main() {
    let paths = get_dirs();
    let mut watchers = paths.iter().map(|x| My_Watcher::new(x)).collect::<Vec<_>>();

    println!("watching : {:?} dirs", paths.len());

    loop {
        for mut w in watchers.iter_mut() {
            if w.rx.try_iter().count() > 0 {
                Command::new("cargo").current_dir(&w.path).args(["test"]).stdout(Stdio::inherit()).spawn();
            }
        }

        std::thread::sleep(Duration::from_millis(100));
    }
}
1 Like