11//! Tidy check to ensure below in UI test directories:
22//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
33//! - there are no stray `.stderr` files
4-
54use ignore:: Walk ;
65use lazy_static:: lazy_static;
76use regex:: Regex ;
8- use std:: collections:: { HashMap , HashSet } ;
7+ use std:: collections:: { BTreeSet , HashMap } ;
98use std:: ffi:: OsStr ;
109use std:: fs;
10+ use std:: io:: Write ;
1111use std:: path:: { Path , PathBuf } ;
1212
1313// FIXME: GitHub's UI truncates file lists that exceed 1000 entries, so these
@@ -97,14 +97,17 @@ fn check_entries(tests_path: &Path, bad: &mut bool) {
9797 }
9898}
9999
100- pub fn check ( path : & Path , bad : & mut bool ) {
100+ pub fn check ( path : & Path , bless : bool , bad : & mut bool ) {
101101 check_entries ( & path, bad) ;
102102
103103 // the list of files in ui tests that are allowed to start with `issue-XXXX`
104- let mut allowed_issue_filenames: HashSet < String > = HashSet :: from (
104+ // BTreeSet because we would like a stable ordering so --bless works
105+ let allowed_issue_names = BTreeSet :: from (
105106 include ! ( "issues.txt" ) . map ( |path| path. replace ( "/" , std:: path:: MAIN_SEPARATOR_STR ) ) ,
106107 ) ;
107108
109+ let mut remaining_issue_names: BTreeSet < String > = allowed_issue_names. clone ( ) ;
110+
108111 let ( ui, ui_fulldeps) = ( path. join ( "ui" ) , path. join ( "ui-fulldeps" ) ) ;
109112 let paths = [ ui. as_path ( ) , ui_fulldeps. as_path ( ) ] ;
110113 crate :: walk:: walk_no_read ( & paths, |_, _| false , & mut |entry| {
@@ -156,7 +159,7 @@ pub fn check(path: &Path, bad: &mut bool) {
156159 if let Some ( test_name) = ISSUE_NAME_REGEX . captures ( testname) {
157160 // these paths are always relative to the passed `path` and always UTF8
158161 let stripped_path = file_path. strip_prefix ( path) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
159- if !allowed_issue_filenames . remove ( stripped_path) {
162+ if !remaining_issue_names . remove ( stripped_path) {
160163 tidy_error ! (
161164 bad,
162165 "file `{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`" ,
@@ -169,8 +172,30 @@ pub fn check(path: &Path, bad: &mut bool) {
169172 } ) ;
170173
171174 // if an excluded file is renamed, it must be removed from this list
172- if allowed_issue_filenames. len ( ) > 0 {
173- for file_name in allowed_issue_filenames {
175+ // do this automatically on bless, otherwise issue a tidy error
176+ if bless {
177+ let issues_txt_header = r#"
178+ /*
179+ ============================================================
180+ ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️
181+ ============================================================
182+ */
183+ [
184+ "# ;
185+ let tidy_src = std:: env:: current_dir ( ) . unwrap ( ) . join ( "src/tools/tidy/src" ) ;
186+ // instead of overwriting the file, recreate it and use an "atomic rename"
187+ // so we don't bork things on panic or a contributor using Ctrl+C
188+ let blessed_issues_path = tidy_src. join ( "issues_blessed.txt" ) ;
189+ let mut blessed_issues_txt = fs:: File :: create ( & blessed_issues_path) . unwrap ( ) ;
190+ blessed_issues_txt. write ( issues_txt_header. as_bytes ( ) ) . unwrap ( ) ;
191+ for filename in allowed_issue_names. difference ( & remaining_issue_names) {
192+ write ! ( blessed_issues_txt, "\" {filename}\" ,\n " ) . unwrap ( ) ;
193+ }
194+ write ! ( blessed_issues_txt, "]\n " ) . unwrap ( ) ;
195+ let old_issues_path = tidy_src. join ( "issues.txt" ) ;
196+ fs:: rename ( blessed_issues_path, old_issues_path) . unwrap ( ) ;
197+ } else {
198+ for file_name in remaining_issue_names {
174199 let mut p = PathBuf :: from ( path) ;
175200 p. push ( file_name) ;
176201 tidy_error ! (
0 commit comments