bootstrap/core/build_steps/
suggest.rs

1//! Attempt to magically identify good tests to run
2
3use std::path::PathBuf;
4use std::str::FromStr;
5
6use clap::Parser;
7
8use crate::core::build_steps::tool::Tool;
9use crate::core::builder::Builder;
10
11/// Suggests a list of possible `x.py` commands to run based on modified files in branch.
12pub fn suggest(builder: &Builder<'_>, run: bool) {
13    let git_config = builder.config.git_config();
14    let suggestions = builder
15        .tool_cmd(Tool::SuggestTests)
16        .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
17        .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
18        .run_capture_stdout(builder)
19        .stdout();
20
21    let suggestions = suggestions
22        .lines()
23        .map(|line| {
24            let mut sections = line.split_ascii_whitespace();
25
26            // this code expects one suggestion per line in the following format:
27            // <x_subcommand> {some number of flags} [optional stage number]
28            let cmd = sections.next().unwrap();
29            let stage = sections.next_back().and_then(|s| str::parse(s).ok());
30            let paths: Vec<PathBuf> = sections.map(|p| PathBuf::from_str(p).unwrap()).collect();
31
32            (cmd, stage, paths)
33        })
34        .collect::<Vec<_>>();
35
36    if !suggestions.is_empty() {
37        println!("==== SUGGESTIONS ====");
38        for sug in &suggestions {
39            print!("x {} ", sug.0);
40            if let Some(stage) = sug.1 {
41                print!("--stage {stage} ");
42            }
43
44            for path in &sug.2 {
45                print!("{} ", path.display());
46            }
47            println!();
48        }
49        println!("=====================");
50    } else {
51        println!("No suggestions found!");
52        return;
53    }
54
55    if run {
56        for sug in suggestions {
57            let mut build: crate::Build = builder.build.clone();
58            build.config.paths = sug.2;
59            build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd;
60            if let Some(stage) = sug.1 {
61                build.config.stage = stage;
62            }
63            build.build();
64        }
65    } else {
66        println!("HELP: consider using the `--run` flag to automatically run suggested tests");
67    }
68}