@@ -10,6 +10,7 @@ use std::io::{BufRead, BufReader, Read, Write};
1010use std:: process:: { ChildStdout , Stdio } ;
1111use std:: time:: Duration ;
1212
13+ use build_helper:: ci:: CiEnv ;
1314use termcolor:: { Color , ColorSpec , WriteColor } ;
1415
1516use crate :: core:: builder:: Builder ;
@@ -91,7 +92,9 @@ struct Renderer<'a> {
9192 /// Number of tests that were skipped due to already being up-to-date
9293 /// (i.e. no relevant changes occurred since they last ran).
9394 up_to_date_tests : usize ,
95+ ignored_tests : usize ,
9496 terse_tests_in_line : usize ,
97+ ci_latest_logged_percentage : f64 ,
9598}
9699
97100impl < ' a > Renderer < ' a > {
@@ -104,7 +107,9 @@ impl<'a> Renderer<'a> {
104107 tests_count : None ,
105108 executed_tests : 0 ,
106109 up_to_date_tests : 0 ,
110+ ignored_tests : 0 ,
107111 terse_tests_in_line : 0 ,
112+ ci_latest_logged_percentage : 0.0 ,
108113 }
109114 }
110115
@@ -160,8 +165,11 @@ impl<'a> Renderer<'a> {
160165 self . executed_tests += 1 ;
161166
162167 // Keep this in sync with the "up-to-date" ignore message inserted by compiletest.
163- if let Outcome :: Ignored { reason : Some ( "up-to-date" ) } = outcome {
164- self . up_to_date_tests += 1 ;
168+ if let Outcome :: Ignored { reason } = outcome {
169+ self . ignored_tests += 1 ;
170+ if reason == Some ( "up-to-date" ) {
171+ self . up_to_date_tests += 1 ;
172+ }
165173 }
166174
167175 #[ cfg( feature = "build-metrics" ) ]
@@ -180,7 +188,11 @@ impl<'a> Renderer<'a> {
180188 if self . builder . config . verbose_tests {
181189 self . render_test_outcome_verbose ( outcome, test) ;
182190 } else {
183- self . render_test_outcome_terse ( outcome, test) ;
191+ if CiEnv :: is_ci ( ) {
192+ self . render_test_outcome_ci ( outcome, test) ;
193+ } else {
194+ self . render_test_outcome_terse ( outcome, test) ;
195+ }
184196 }
185197 }
186198
@@ -209,6 +221,31 @@ impl<'a> Renderer<'a> {
209221 let _ = std:: io:: stdout ( ) . flush ( ) ;
210222 }
211223
224+ fn render_test_outcome_ci ( & mut self , outcome : Outcome < ' _ > , test : & TestOutcome ) {
225+ if let Some ( total) = self . tests_count {
226+ let percent = self . executed_tests as f64 / total as f64 ;
227+
228+ if self . ci_latest_logged_percentage + 0.10 < percent {
229+ let total = total. to_string ( ) ;
230+ let executed = format ! ( "{:>width$}" , self . executed_tests - 1 , width = total. len( ) ) ;
231+ let pretty_percent = format ! ( "{:.0}%" , percent * 100.0 ) ;
232+ let passed_tests = self . executed_tests - self . failures . len ( ) ;
233+ println ! (
234+ "{:<4} -- {executed}/{total}, {:>total_indent$} passed, {} failed, {} ignored" ,
235+ pretty_percent,
236+ passed_tests,
237+ self . failures. len( ) ,
238+ self . ignored_tests,
239+ total_indent = total. len( )
240+ ) ;
241+ self . ci_latest_logged_percentage += 0.10 ;
242+ }
243+ }
244+
245+ self . builder . colored_stdout ( |stdout| outcome. write_ci ( stdout, & test. name ) ) . unwrap ( ) ;
246+ let _ = std:: io:: stdout ( ) . flush ( ) ;
247+ }
248+
212249 fn render_suite_outcome ( & self , outcome : Outcome < ' _ > , suite : & SuiteOutcome ) {
213250 // The terse output doesn't end with a newline, so we need to add it ourselves.
214251 if !self . builder . config . verbose_tests {
@@ -378,6 +415,17 @@ impl Outcome<'_> {
378415 }
379416 writer. reset ( )
380417 }
418+
419+ fn write_ci ( & self , writer : & mut dyn WriteColor , name : & str ) -> Result < ( ) , std:: io:: Error > {
420+ match self {
421+ Outcome :: Ok | Outcome :: BenchOk | Outcome :: Ignored { .. } => { }
422+ Outcome :: Failed => {
423+ writer. set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Red ) ) ) ?;
424+ writeln ! ( writer, " {name} ... FAILED" ) ?;
425+ }
426+ }
427+ writer. reset ( )
428+ }
381429}
382430
383431#[ derive( serde_derive:: Deserialize ) ]
0 commit comments