@@ -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
@@ -159,9 +164,12 @@ impl<'a> Renderer<'a> {
159164 fn render_test_outcome ( & mut self , outcome : Outcome < ' _ > , test : & TestOutcome ) {
160165 self . executed_tests += 1 ;
161166
162- // 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 ;
167+ if let Outcome :: Ignored { reason } = outcome {
168+ self . ignored_tests += 1 ;
169+ // Keep this in sync with the "up-to-date" ignore message inserted by compiletest.
170+ if reason == Some ( "up-to-date" ) {
171+ self . up_to_date_tests += 1 ;
172+ }
165173 }
166174
167175 #[ cfg( feature = "build-metrics" ) ]
@@ -179,6 +187,8 @@ impl<'a> Renderer<'a> {
179187
180188 if self . builder . config . verbose_tests {
181189 self . render_test_outcome_verbose ( outcome, test) ;
190+ } else if CiEnv :: is_ci ( ) {
191+ self . render_test_outcome_ci ( outcome, test) ;
182192 } else {
183193 self . render_test_outcome_terse ( outcome, test) ;
184194 }
@@ -209,6 +219,31 @@ impl<'a> Renderer<'a> {
209219 let _ = std:: io:: stdout ( ) . flush ( ) ;
210220 }
211221
222+ fn render_test_outcome_ci ( & mut self , outcome : Outcome < ' _ > , test : & TestOutcome ) {
223+ if let Some ( total) = self . tests_count {
224+ let percent = self . executed_tests as f64 / total as f64 ;
225+
226+ if self . ci_latest_logged_percentage + 0.10 < percent {
227+ let total = total. to_string ( ) ;
228+ let executed = format ! ( "{:>width$}" , self . executed_tests, width = total. len( ) ) ;
229+ let pretty_percent = format ! ( "{:.0}%" , percent * 100.0 ) ;
230+ let passed_tests = self . executed_tests - ( self . failures . len ( ) + self . ignored_tests ) ;
231+ println ! (
232+ "{:<4} -- {executed}/{total}, {:>total_indent$} passed, {} failed, {} ignored" ,
233+ pretty_percent,
234+ passed_tests,
235+ self . failures. len( ) ,
236+ self . ignored_tests,
237+ total_indent = total. len( )
238+ ) ;
239+ self . ci_latest_logged_percentage += 0.10 ;
240+ }
241+ }
242+
243+ self . builder . colored_stdout ( |stdout| outcome. write_ci ( stdout, & test. name ) ) . unwrap ( ) ;
244+ let _ = std:: io:: stdout ( ) . flush ( ) ;
245+ }
246+
212247 fn render_suite_outcome ( & self , outcome : Outcome < ' _ > , suite : & SuiteOutcome ) {
213248 // The terse output doesn't end with a newline, so we need to add it ourselves.
214249 if !self . builder . config . verbose_tests {
@@ -378,6 +413,17 @@ impl Outcome<'_> {
378413 }
379414 writer. reset ( )
380415 }
416+
417+ fn write_ci ( & self , writer : & mut dyn WriteColor , name : & str ) -> Result < ( ) , std:: io:: Error > {
418+ match self {
419+ Outcome :: Ok | Outcome :: BenchOk | Outcome :: Ignored { .. } => { }
420+ Outcome :: Failed => {
421+ writer. set_color ( ColorSpec :: new ( ) . set_fg ( Some ( Color :: Red ) ) ) ?;
422+ writeln ! ( writer, " {name} ... FAILED" ) ?;
423+ }
424+ }
425+ writer. reset ( )
426+ }
381427}
382428
383429#[ derive( serde_derive:: Deserialize ) ]
0 commit comments