tidy/
triagebot.rs

1//! Tidy check to ensure paths mentioned in triagebot.toml exist in the project.
2
3use std::path::Path;
4
5use toml::Value;
6
7pub fn check(path: &Path, bad: &mut bool) {
8    let triagebot_path = path.join("triagebot.toml");
9
10    // This check is mostly to catch broken path filters *within* `triagebot.toml`, and not enforce
11    // the existence of `triagebot.toml` itself (which is more obvious), as distribution tarballs
12    // will not include non-essential bits like `triagebot.toml`.
13    if !triagebot_path.exists() {
14        return;
15    }
16
17    let contents = std::fs::read_to_string(&triagebot_path).unwrap();
18    let config: Value = toml::from_str(&contents).unwrap();
19
20    // Check [mentions."*"] sections, i.e. [mentions."compiler/rustc_const_eval/src/"]
21    if let Some(Value::Table(mentions)) = config.get("mentions") {
22        for path_str in mentions.keys() {
23            // Remove quotes from the path
24            let clean_path = path_str.trim_matches('"');
25            let full_path = path.join(clean_path);
26
27            if !full_path.exists() {
28                tidy_error!(
29                    bad,
30                    "triagebot.toml [mentions.*] contains path '{}' which doesn't exist",
31                    clean_path
32                );
33            }
34        }
35    } else {
36        tidy_error!(
37            bad,
38            "triagebot.toml missing [mentions.*] section, this wrong for rust-lang/rust repo."
39        );
40    }
41
42    // Check [assign.owners] sections, i.e.
43    // [assign.owners]
44    // "/.github/workflows" = ["infra-ci"]
45    if let Some(Value::Table(assign)) = config.get("assign") {
46        if let Some(Value::Table(owners)) = assign.get("owners") {
47            for path_str in owners.keys() {
48                // Remove quotes and leading slash from the path
49                let clean_path = path_str.trim_matches('"').trim_start_matches('/');
50                let full_path = path.join(clean_path);
51
52                if !full_path.exists() {
53                    tidy_error!(
54                        bad,
55                        "triagebot.toml [assign.owners] contains path '{}' which doesn't exist",
56                        clean_path
57                    );
58                }
59            }
60        } else {
61            tidy_error!(
62                bad,
63                "triagebot.toml missing [assign.owners] section, this wrong for rust-lang/rust repo."
64            );
65        }
66    }
67
68    // Verify that trigger_files in [autolabel."*"] exist in the project, i.e.
69    // [autolabel."A-rustdoc-search"]
70    // trigger_files = [
71    //    "src/librustdoc/html/static/js/search.js",
72    //    "tests/rustdoc-js",
73    //    "tests/rustdoc-js-std",
74    // ]
75    if let Some(Value::Table(autolabels)) = config.get("autolabel") {
76        for (label, content) in autolabels {
77            if let Some(trigger_files) = content.get("trigger_files").and_then(|v| v.as_array()) {
78                for file in trigger_files {
79                    if let Some(file_str) = file.as_str() {
80                        let full_path = path.join(file_str);
81
82                        // Handle both file and directory paths
83                        if !full_path.exists() {
84                            tidy_error!(
85                                bad,
86                                "triagebot.toml [autolabel.{}] contains trigger_files path '{}' which doesn't exist",
87                                label,
88                                file_str
89                            );
90                        }
91                    }
92                }
93            }
94        }
95    }
96}