@@ -24,6 +24,30 @@ impl MatrixCombination {
2424 }
2525}
2626
27+ fn resolve_runs_on ( runs_on : Option < & serde_yaml:: Value > , matrix_combo : Option < & MatrixCombination > ) -> String {
28+ let Some ( value) = runs_on else {
29+ return "ubuntu-latest" . to_string ( ) ;
30+ } ;
31+
32+ if let Some ( label) = value. as_str ( ) {
33+ return matrix_combo. map_or_else ( || label. to_string ( ) , |combo| combo. interpolate ( label) ) ;
34+ }
35+
36+ if let Some ( labels) = value. as_sequence ( ) {
37+ let resolved = labels
38+ . iter ( )
39+ . filter_map ( |item| item. as_str ( ) )
40+ . map ( |label| matrix_combo. map_or_else ( || label. to_string ( ) , |combo| combo. interpolate ( label) ) )
41+ . collect :: < Vec < _ > > ( ) ;
42+
43+ if !resolved. is_empty ( ) {
44+ return resolved. join ( ", " ) ;
45+ }
46+ }
47+
48+ "ubuntu-latest" . to_string ( )
49+ }
50+
2751/// Expand matrix configuration into all possible combinations
2852fn expand_matrix ( matrix : & serde_yaml:: Value ) -> Result < Vec < MatrixCombination > > {
2953 let matrix_obj = matrix
@@ -408,15 +432,7 @@ pub async fn run_job_from_file(
408432 println ! ( " {}" , combo_str. yellow( ) ) ;
409433
410434 // Interpolate runs_on with matrix values
411- let runs_on_str = if let Some ( runs_on_val) = & job. runs_on {
412- if let Some ( s) = runs_on_val. as_str ( ) {
413- combo. interpolate ( s)
414- } else {
415- "ubuntu-latest" . to_string ( )
416- }
417- } else {
418- "ubuntu-latest" . to_string ( )
419- } ;
435+ let runs_on_str = resolve_runs_on ( job. runs_on . as_ref ( ) , Some ( combo) ) ;
420436
421437 println ! ( " Runs on: {}" , runs_on_str. blue( ) ) ;
422438
@@ -464,11 +480,7 @@ pub async fn run_job_from_file(
464480 format!( "▶ Executing job: {}" , job_name) . green( ) . bold( )
465481 ) ;
466482
467- let runs_on = job
468- . runs_on
469- . as_ref ( )
470- . and_then ( |v| v. as_str ( ) )
471- . unwrap_or ( "ubuntu-latest" ) ;
483+ let runs_on = resolve_runs_on ( job. runs_on . as_ref ( ) , None ) ;
472484 println ! ( " Runs on: {}" , runs_on. blue( ) ) ;
473485
474486 if let Some ( steps) = & job. steps {
@@ -515,13 +527,17 @@ pub async fn run_job_from_file(
515527 let runtime = container:: detect_runtime ( ) . await ;
516528
517529 // Map runner to image
518- let image = container:: map_runner_to_image ( runs_on) ;
530+ let image = container:: map_runner_to_image ( & runs_on) ;
519531
520532 if image. is_some ( ) {
521533 if let Some ( img) = image {
522534 println ! ( " Mapped {} → {}" , runs_on. blue( ) , img. yellow( ) ) ;
523535 }
524- } else if runs_on. starts_with ( "macos" ) || runs_on. starts_with ( "windows" ) {
536+ } else if runs_on. contains ( "macOS" )
537+ || runs_on. contains ( "macos" )
538+ || runs_on. contains ( "windows" )
539+ || runs_on. contains ( "Windows" )
540+ {
525541 println ! (
526542 "\n {} {} runners not supported in containers, using host execution" ,
527543 "⚠" . yellow( ) ,
@@ -693,4 +709,34 @@ node: [16, 18, 20]
693709 let result = combo. interpolate ( "${{ matrix.os }}" ) ;
694710 assert_eq ! ( result, "ubuntu-latest" ) ;
695711 }
712+
713+ #[ test]
714+ fn test_resolve_runs_on_array_for_self_hosted_runner ( ) {
715+ let yaml = r#"
716+ - self-hosted
717+ - macOS
718+ - ARM64
719+ - custom-runner
720+ "# ;
721+ let runs_on: serde_yaml:: Value = serde_yaml:: from_str ( yaml) . unwrap ( ) ;
722+ let result = resolve_runs_on ( Some ( & runs_on) , None ) ;
723+ assert_eq ! ( result, "self-hosted, macOS, ARM64, custom-runner" ) ;
724+ }
725+
726+ #[ test]
727+ fn test_resolve_runs_on_array_with_matrix_interpolation ( ) {
728+ let yaml = r#"
729+ - self-hosted
730+ - ${{ matrix.os }}
731+ - ARM64
732+ "# ;
733+ let runs_on: serde_yaml:: Value = serde_yaml:: from_str ( yaml) . unwrap ( ) ;
734+ let mut combo = MatrixCombination {
735+ values : HashMap :: new ( ) ,
736+ } ;
737+ combo. values . insert ( "os" . to_string ( ) , "macOS" . to_string ( ) ) ;
738+
739+ let result = resolve_runs_on ( Some ( & runs_on) , Some ( & combo) ) ;
740+ assert_eq ! ( result, "self-hosted, macOS, ARM64" ) ;
741+ }
696742}
0 commit comments