@@ -359,8 +359,13 @@ export default class PRChecker {
359359 return false ;
360360 }
361361
362+ let hasFailures = false ;
363+ const failedJobs = [ ] ;
364+ const cancelledJobs = [ ] ;
365+ const pendingJobs = [ ] ;
366+
362367 // GitHub new Check API
363- for ( const { status, conclusion, app } of checkSuites . nodes ) {
368+ for ( const { status, conclusion, app, checkRuns } of checkSuites . nodes ) {
364369 if ( app . slug !== 'github-actions' ) {
365370 // Ignore all non-github check suites, such as Dependabot and Codecov.
366371 // They are expected to show up on PRs whose head branch is not on a
@@ -369,16 +374,80 @@ export default class PRChecker {
369374 }
370375
371376 if ( status !== 'COMPLETED' ) {
372- cli . error ( 'GitHub CI is still running' ) ;
373- return false ;
377+ pendingJobs . push ( { app : app . slug , status , conclusion } ) ;
378+ continue ;
374379 }
375380
376381 if ( ! GITHUB_SUCCESS_CONCLUSIONS . includes ( conclusion ) ) {
377- cli . error ( 'Last GitHub CI failed' ) ;
378- return false ;
382+ hasFailures = true ;
383+
384+ // If we have detailed checkRuns, show specific failing jobs
385+ if ( checkRuns && checkRuns . nodes && checkRuns . nodes . length > 0 ) {
386+ for ( const checkRun of checkRuns . nodes ) {
387+ if ( checkRun . status === 'COMPLETED' &&
388+ ! GITHUB_SUCCESS_CONCLUSIONS . includes ( checkRun . conclusion ) ) {
389+ if ( checkRun . conclusion === 'CANCELLED' ) {
390+ cancelledJobs . push ( {
391+ name : checkRun . name ,
392+ conclusion : checkRun . conclusion ,
393+ url : checkRun . detailsUrl
394+ } ) ;
395+ } else {
396+ failedJobs . push ( {
397+ name : checkRun . name ,
398+ conclusion : checkRun . conclusion ,
399+ url : checkRun . detailsUrl
400+ } ) ;
401+ }
402+ }
403+ }
404+ } else {
405+ // Fallback to check suite level information if no checkRuns
406+ if ( conclusion === 'CANCELLED' ) {
407+ cancelledJobs . push ( {
408+ name : app . slug ,
409+ conclusion,
410+ url : null
411+ } ) ;
412+ } else {
413+ failedJobs . push ( {
414+ name : app . slug ,
415+ conclusion,
416+ url : null
417+ } ) ;
418+ }
419+ }
420+ }
421+ }
422+
423+ // Report pending jobs
424+ if ( pendingJobs . length > 0 ) {
425+ cli . error ( 'GitHub CI is still running' ) ;
426+ return false ;
427+ }
428+
429+ // Report failed jobs
430+ if ( failedJobs . length > 0 ) {
431+ cli . error ( `${ failedJobs . length } GitHub CI job(s) failed:` ) ;
432+ for ( const job of failedJobs ) {
433+ const urlInfo = job . url ? ` (${ job . url } )` : '' ;
434+ cli . error ( ` - ${ job . name } : ${ job . conclusion } ${ urlInfo } ` ) ;
379435 }
380436 }
381437
438+ // Report cancelled jobs
439+ if ( cancelledJobs . length > 0 ) {
440+ cli . error ( `${ cancelledJobs . length } GitHub CI job(s) cancelled:` ) ;
441+ for ( const job of cancelledJobs ) {
442+ const urlInfo = job . url ? ` (${ job . url } )` : '' ;
443+ cli . error ( ` - ${ job . name } : ${ job . conclusion } ${ urlInfo } ` ) ;
444+ }
445+ }
446+
447+ if ( hasFailures ) {
448+ return false ;
449+ }
450+
382451 // GitHub old commit status API
383452 if ( commit . status ) {
384453 const { state } = commit . status ;
@@ -388,7 +457,7 @@ export default class PRChecker {
388457 }
389458
390459 if ( ! [ 'SUCCESS' , 'EXPECTED' ] . includes ( state ) ) {
391- cli . error ( 'Last GitHub CI failed' ) ;
460+ cli . error ( ` GitHub CI failed with status: ${ state } ` ) ;
392461 return false ;
393462 }
394463 }
0 commit comments