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_GIT_REPOSITORY", git_config.git_repository)
17        .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
18        .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
19        .run_capture_stdout(builder)
20        .stdout();
21
22    let suggestions = suggestions
23        .lines()
24        .map(|line| {
25            let mut sections = line.split_ascii_whitespace();
26
27            // this code expects one suggestion per line in the following format:
28            // <x_subcommand> {some number of flags} [optional stage number]
29            let cmd = sections.next().unwrap();
30            let stage = sections.next_back().and_then(|s| str::parse(s).ok());
31            let paths: Vec<PathBuf> = sections.map(|p| PathBuf::from_str(p).unwrap()).collect();
32
33            (cmd, stage, paths)
34        })
35        .collect::<Vec<_>>();
36
37    if !suggestions.is_empty() {
38        println!("==== SUGGESTIONS ====");
39        for sug in &suggestions {
40            print!("x {} ", sug.0);
41            if let Some(stage) = sug.1 {
42                print!("--stage {stage} ");
43            }
44
45            for path in &sug.2 {
46                print!("{} ", path.display());
47            }
48            println!();
49        }
50        println!("=====================");
51    } else {
52        println!("No suggestions found!");
53        return;
54    }
55
56    if run {
57        for sug in suggestions {
58            let mut build: crate::Build = builder.build.clone();
59            build.config.paths = sug.2;
60            build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd;
61            if let Some(stage) = sug.1 {
62                build.config.stage = stage;
63            }
64            build.build();
65        }
66    } else {
67        println!("HELP: consider using the `--run` flag to automatically run suggested tests");
68    }
69}