bootstrap/core/build_steps/
suggest.rs

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