@@ -12,6 +12,8 @@ pub mod debug;
12
12
mod text;
13
13
#[ cfg( feature = "gha" ) ]
14
14
pub use gha:: * ;
15
+ #[ cfg( feature = "gha" ) ]
16
+ mod gha;
15
17
16
18
/// A generic way to handle the output of this crate.
17
19
pub trait StatusEmitter : Sync + RefUnwindSafe {
@@ -139,320 +141,6 @@ impl TestStatus for SilentStatus {
139
141
}
140
142
}
141
143
142
- #[ cfg( feature = "gha" ) ]
143
- mod gha {
144
- use crate :: { diagnostics:: Message , display, Error , Errors } ;
145
-
146
- use crate :: github_actions;
147
- use bstr:: ByteSlice ;
148
- use spanned:: { Span , Spanned } ;
149
- use std:: {
150
- fmt:: { Debug , Write as _} ,
151
- io:: Write as _,
152
- num:: NonZeroUsize ,
153
- path:: { Path , PathBuf } ,
154
- } ;
155
-
156
- use super :: { RevisionStyle , StatusEmitter , Summary , TestStatus } ;
157
- fn gha_error ( error : & Error , test_path : & str , revision : & str ) {
158
- let file = Spanned :: read_from_file ( test_path) . unwrap ( ) ;
159
- let line = |span : & Span | {
160
- let line = file
161
- . lines ( )
162
- . position ( |line| line. span . bytes . contains ( & span. bytes . start ) )
163
- . unwrap ( ) ;
164
- NonZeroUsize :: new ( line + 1 ) . unwrap ( )
165
- } ;
166
- match error {
167
- Error :: ExitStatus {
168
- status,
169
- expected,
170
- reason,
171
- } => {
172
- let mut err = github_actions:: error (
173
- test_path,
174
- format ! ( "test{revision} got {status}, but expected {expected}" ) ,
175
- ) ;
176
- err. write_str ( reason) . unwrap ( ) ;
177
- }
178
- Error :: Command { kind, status } => {
179
- github_actions:: error ( test_path, format ! ( "{kind}{revision} failed with {status}" ) ) ;
180
- }
181
- Error :: PatternNotFound { pattern, .. } => {
182
- github_actions:: error ( test_path, format ! ( "Pattern not found{revision}" ) )
183
- . line ( line ( & pattern. span ) ) ;
184
- }
185
- Error :: CodeNotFound { code, .. } => {
186
- github_actions:: error ( test_path, format ! ( "Diagnostic code not found{revision}" ) )
187
- . line ( line ( & code. span ) ) ;
188
- }
189
- Error :: NoPatternsFound => {
190
- github_actions:: error (
191
- test_path,
192
- format ! ( "expexted error patterns, but found none{revision}" ) ,
193
- ) ;
194
- }
195
- Error :: PatternFoundInPassTest { .. } => {
196
- github_actions:: error (
197
- test_path,
198
- format ! ( "error pattern found in pass test{revision}" ) ,
199
- ) ;
200
- }
201
- Error :: OutputDiffers {
202
- path : output_path,
203
- actual,
204
- expected,
205
- bless_command,
206
- } => {
207
- if expected. is_empty ( ) {
208
- let mut err = github_actions:: error (
209
- test_path,
210
- "test generated output, but there was no output file" ,
211
- ) ;
212
- if let Some ( bless_command) = bless_command {
213
- writeln ! (
214
- err,
215
- "you likely need to bless the tests with `{bless_command}`"
216
- )
217
- . unwrap ( ) ;
218
- }
219
- return ;
220
- }
221
-
222
- let mut line = 1 ;
223
- for r in
224
- prettydiff:: diff_lines ( expected. to_str ( ) . unwrap ( ) , actual. to_str ( ) . unwrap ( ) )
225
- . diff ( )
226
- {
227
- use prettydiff:: basic:: DiffOp :: * ;
228
- match r {
229
- Equal ( s) => {
230
- line += s. len ( ) ;
231
- continue ;
232
- }
233
- Replace ( l, r) => {
234
- let mut err = github_actions:: error (
235
- display ( output_path) ,
236
- "actual output differs from expected" ,
237
- )
238
- . line ( NonZeroUsize :: new ( line + 1 ) . unwrap ( ) ) ;
239
- writeln ! ( err, "this line was expected to be `{}`" , r[ 0 ] ) . unwrap ( ) ;
240
- line += l. len ( ) ;
241
- }
242
- Remove ( l) => {
243
- let mut err = github_actions:: error (
244
- display ( output_path) ,
245
- "extraneous lines in output" ,
246
- )
247
- . line ( NonZeroUsize :: new ( line + 1 ) . unwrap ( ) ) ;
248
- writeln ! (
249
- err,
250
- "remove this line and possibly later ones by blessing the test"
251
- )
252
- . unwrap ( ) ;
253
- line += l. len ( ) ;
254
- }
255
- Insert ( r) => {
256
- let mut err = github_actions:: error (
257
- display ( output_path) ,
258
- "missing line in output" ,
259
- )
260
- . line ( NonZeroUsize :: new ( line + 1 ) . unwrap ( ) ) ;
261
- writeln ! ( err, "bless the test to create a line containing `{}`" , r[ 0 ] )
262
- . unwrap ( ) ;
263
- // Do not count these lines, they don't exist in the original file and
264
- // would thus mess up the line number.
265
- }
266
- }
267
- }
268
- }
269
- Error :: ErrorsWithoutPattern { path, msgs } => {
270
- if let Some ( ( path, line) ) = path. as_ref ( ) {
271
- let path = display ( path) ;
272
- let mut err =
273
- github_actions:: error ( path, format ! ( "Unmatched diagnostics{revision}" ) )
274
- . line ( * line) ;
275
- for Message {
276
- level,
277
- message,
278
- line : _,
279
- span : _,
280
- code : _,
281
- } in msgs
282
- {
283
- writeln ! ( err, "{level:?}: {message}" ) . unwrap ( ) ;
284
- }
285
- } else {
286
- let mut err = github_actions:: error (
287
- test_path,
288
- format ! ( "Unmatched diagnostics outside the testfile{revision}" ) ,
289
- ) ;
290
- for Message {
291
- level,
292
- message,
293
- line : _,
294
- span : _,
295
- code : _,
296
- } in msgs
297
- {
298
- writeln ! ( err, "{level:?}: {message}" ) . unwrap ( ) ;
299
- }
300
- }
301
- }
302
- Error :: InvalidComment { msg, span } => {
303
- let mut err = github_actions:: error ( test_path, format ! ( "Could not parse comment" ) )
304
- . line ( line ( span) ) ;
305
- writeln ! ( err, "{msg}" ) . unwrap ( ) ;
306
- }
307
- Error :: MultipleRevisionsWithResults { kind, lines } => {
308
- github_actions:: error ( test_path, format ! ( "multiple {kind} found" ) )
309
- . line ( line ( & lines[ 0 ] ) ) ;
310
- }
311
- Error :: Bug ( _) => { }
312
- Error :: Aux {
313
- path : aux_path,
314
- errors,
315
- } => {
316
- github_actions:: error ( test_path, format ! ( "Aux build failed" ) )
317
- . line ( line ( & aux_path. span ) ) ;
318
- for error in errors {
319
- gha_error ( error, & display ( aux_path) , "" )
320
- }
321
- }
322
- Error :: Rustfix ( error) => {
323
- github_actions:: error (
324
- test_path,
325
- format ! ( "failed to apply suggestions with rustfix: {error}" ) ,
326
- ) ;
327
- }
328
- Error :: ConfigError ( msg) => {
329
- github_actions:: error ( test_path, msg. clone ( ) ) ;
330
- }
331
- }
332
- }
333
-
334
- /// Emits Github Actions Workspace commands to show the failures directly in the github diff view.
335
- /// If the const generic `GROUP` boolean is `true`, also emit `::group` commands.
336
- pub struct Gha < const GROUP : bool > {
337
- /// Show a specific name for the final summary.
338
- pub name : String ,
339
- }
340
-
341
- #[ derive( Clone ) ]
342
- struct PathAndRev < const GROUP : bool > {
343
- path : PathBuf ,
344
- revision : String ,
345
- }
346
-
347
- impl < const GROUP : bool > TestStatus for PathAndRev < GROUP > {
348
- fn path ( & self ) -> & Path {
349
- & self . path
350
- }
351
-
352
- fn for_revision ( & self , revision : & str , _style : RevisionStyle ) -> Box < dyn TestStatus > {
353
- Box :: new ( Self {
354
- path : self . path . clone ( ) ,
355
- revision : revision. to_owned ( ) ,
356
- } )
357
- }
358
-
359
- fn for_path ( & self , path : & Path ) -> Box < dyn TestStatus > {
360
- Box :: new ( Self {
361
- path : path. to_path_buf ( ) ,
362
- revision : self . revision . clone ( ) ,
363
- } )
364
- }
365
-
366
- fn failed_test ( & self , _cmd : & str , _stderr : & [ u8 ] , _stdout : & [ u8 ] ) -> Box < dyn Debug > {
367
- if GROUP {
368
- Box :: new ( github_actions:: group ( format_args ! (
369
- "{}:{}" ,
370
- display( & self . path) ,
371
- self . revision
372
- ) ) )
373
- } else {
374
- Box :: new ( ( ) )
375
- }
376
- }
377
-
378
- fn revision ( & self ) -> & str {
379
- & self . revision
380
- }
381
- }
382
-
383
- impl < const GROUP : bool > StatusEmitter for Gha < GROUP > {
384
- fn register_test ( & self , path : PathBuf ) -> Box < dyn TestStatus > {
385
- Box :: new ( PathAndRev :: < GROUP > {
386
- path,
387
- revision : String :: new ( ) ,
388
- } )
389
- }
390
-
391
- fn finalize (
392
- & self ,
393
- _failures : usize ,
394
- succeeded : usize ,
395
- ignored : usize ,
396
- filtered : usize ,
397
- // Can't aborted on gha
398
- _aborted : bool ,
399
- ) -> Box < dyn Summary > {
400
- struct Summarizer < const GROUP : bool > {
401
- failures : Vec < String > ,
402
- succeeded : usize ,
403
- ignored : usize ,
404
- filtered : usize ,
405
- name : String ,
406
- }
407
-
408
- impl < const GROUP : bool > Summary for Summarizer < GROUP > {
409
- fn test_failure ( & mut self , status : & dyn TestStatus , errors : & Errors ) {
410
- let revision = if status. revision ( ) . is_empty ( ) {
411
- "" . to_string ( )
412
- } else {
413
- format ! ( " (revision: {})" , status. revision( ) )
414
- } ;
415
- for error in errors {
416
- gha_error ( error, & display ( status. path ( ) ) , & revision) ;
417
- }
418
- self . failures
419
- . push ( format ! ( "{}{revision}" , display( status. path( ) ) ) ) ;
420
- }
421
- }
422
- impl < const GROUP : bool > Drop for Summarizer < GROUP > {
423
- fn drop ( & mut self ) {
424
- if let Some ( mut file) = github_actions:: summary ( ) {
425
- writeln ! ( file, "### {}" , self . name) . unwrap ( ) ;
426
- for line in & self . failures {
427
- writeln ! ( file, "* {line}" ) . unwrap ( ) ;
428
- }
429
- writeln ! ( file) . unwrap ( ) ;
430
- writeln ! ( file, "| failed | passed | ignored | filtered out |" ) . unwrap ( ) ;
431
- writeln ! ( file, "| --- | --- | --- | --- |" ) . unwrap ( ) ;
432
- writeln ! (
433
- file,
434
- "| {} | {} | {} | {} |" ,
435
- self . failures. len( ) ,
436
- self . succeeded,
437
- self . ignored,
438
- self . filtered,
439
- )
440
- . unwrap ( ) ;
441
- }
442
- }
443
- }
444
-
445
- Box :: new ( Summarizer :: < GROUP > {
446
- failures : vec ! [ ] ,
447
- succeeded,
448
- ignored,
449
- filtered,
450
- name : self . name . clone ( ) ,
451
- } )
452
- }
453
- }
454
- }
455
-
456
144
impl < T : TestStatus , U : TestStatus > TestStatus for ( T , U ) {
457
145
fn done ( & self , result : & TestResult , aborted : bool ) {
458
146
self . 0 . done ( result, aborted) ;
0 commit comments