@@ -433,8 +433,16 @@ impl<'a> EngineBuilder<'a> {
433
433
} ;
434
434
435
435
let task_id_as_name = task_id. as_task_name ( ) ;
436
- if turbo_json. tasks . contains_key ( & task_id_as_name)
436
+ if
437
+ // See if pkg#task is defined e.g. `docs#build`. This can only happen in root turbo.json
438
+ turbo_json. tasks . contains_key ( & task_id_as_name)
439
+ // See if task is defined e.g. `build`. This can happen in root or workspace turbo.json
440
+ // This will fail if the user provided a task id e.g. turbo `docs#build`
437
441
|| turbo_json. tasks . contains_key ( task_name)
442
+ // If user provided a task id, then we see if the task is defined
443
+ // e.g. `docs#build` should resolve if there's a `build` in root turbo.json or docs workspace level turbo.json
444
+ || ( matches ! ( workspace, PackageName :: Root ) && turbo_json. tasks . contains_key ( & TaskName :: from ( task_name. task ( ) ) ) )
445
+ || ( workspace == & PackageName :: from ( task_id. package ( ) ) && turbo_json. tasks . contains_key ( & TaskName :: from ( task_name. task ( ) ) ) )
438
446
{
439
447
Ok ( true )
440
448
} else if !matches ! ( workspace, PackageName :: Root ) {
@@ -553,6 +561,7 @@ fn validate_task_name(task: Spanned<&str>) -> Result<(), Error> {
553
561
mod test {
554
562
use std:: assert_matches:: assert_matches;
555
563
564
+ use insta:: assert_json_snapshot;
556
565
use pretty_assertions:: assert_eq;
557
566
use serde_json:: json;
558
567
use tempfile:: TempDir ;
@@ -680,6 +689,10 @@ mod test {
680
689
#[ test_case( PackageName :: from( "b" ) , "build" , "b#build" , true ; "workspace task in workspace" ) ]
681
690
#[ test_case( PackageName :: from( "b" ) , "test" , "b#test" , true ; "task missing from workspace" ) ]
682
691
#[ test_case( PackageName :: from( "c" ) , "missing" , "c#missing" , false ; "task missing" ) ]
692
+ #[ test_case( PackageName :: from( "c" ) , "c#curse" , "c#curse" , true ; "root defined task" ) ]
693
+ #[ test_case( PackageName :: from( "b" ) , "c#curse" , "c#curse" , true ; "non-workspace root defined task" ) ]
694
+ #[ test_case( PackageName :: from( "b" ) , "b#special" , "b#special" , true ; "workspace defined task" ) ]
695
+ #[ test_case( PackageName :: from( "c" ) , "b#special" , "b#special" , false ; "non-workspace defined task" ) ]
683
696
fn test_task_definition (
684
697
workspace : PackageName ,
685
698
task_name : & ' static str ,
@@ -694,6 +707,7 @@ mod test {
694
707
"test" : { "inputs" : [ "testing" ] } ,
695
708
"build" : { "inputs" : [ "primary" ] } ,
696
709
"a#build" : { "inputs" : [ "special" ] } ,
710
+ "c#curse" : { } ,
697
711
}
698
712
} ) ) ,
699
713
) ,
@@ -702,6 +716,7 @@ mod test {
702
716
turbo_json( json!( {
703
717
"tasks" : {
704
718
"build" : { "inputs" : [ "outer" ] } ,
719
+ "special" : { } ,
705
720
}
706
721
} ) ) ,
707
722
) ,
@@ -1245,4 +1260,116 @@ mod test {
1245
1260
. err ( ) ;
1246
1261
assert_eq ! ( result. as_deref( ) , reason) ;
1247
1262
}
1263
+
1264
+ #[ test]
1265
+ fn test_run_package_task_exact ( ) {
1266
+ let repo_root_dir = TempDir :: with_prefix ( "repo" ) . unwrap ( ) ;
1267
+ let repo_root = AbsoluteSystemPathBuf :: new ( repo_root_dir. path ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
1268
+ let package_graph = mock_package_graph (
1269
+ & repo_root,
1270
+ package_jsons ! {
1271
+ repo_root,
1272
+ "app1" => [ "libA" ] ,
1273
+ "app2" => [ "libA" ] ,
1274
+ "libA" => [ ]
1275
+ } ,
1276
+ ) ;
1277
+ let turbo_jsons = vec ! [
1278
+ (
1279
+ PackageName :: Root ,
1280
+ turbo_json( json!( {
1281
+ "tasks" : {
1282
+ "build" : { "dependsOn" : [ "^build" ] } ,
1283
+ "special" : { "dependsOn" : [ "^build" ] } ,
1284
+ }
1285
+ } ) ) ,
1286
+ ) ,
1287
+ (
1288
+ PackageName :: from( "app2" ) ,
1289
+ turbo_json( json!( {
1290
+ "extends" : [ "//" ] ,
1291
+ "tasks" : {
1292
+ "another" : { "dependsOn" : [ "^build" ] } ,
1293
+ }
1294
+ } ) ) ,
1295
+ ) ,
1296
+ ]
1297
+ . into_iter ( )
1298
+ . collect ( ) ;
1299
+ let loader = TurboJsonLoader :: noop ( turbo_jsons) ;
1300
+ let engine = EngineBuilder :: new ( & repo_root, & package_graph, loader, false )
1301
+ . with_tasks ( vec ! [
1302
+ Spanned :: new( TaskName :: from( "app1#special" ) ) ,
1303
+ Spanned :: new( TaskName :: from( "app2#another" ) ) ,
1304
+ ] )
1305
+ . with_workspaces ( vec ! [ PackageName :: from( "app1" ) , PackageName :: from( "app2" ) ] )
1306
+ . build ( )
1307
+ . unwrap ( ) ;
1308
+
1309
+ let expected = deps ! {
1310
+ "app1#special" => [ "libA#build" ] ,
1311
+ "app2#another" => [ "libA#build" ] ,
1312
+ "libA#build" => [ "___ROOT___" ]
1313
+ } ;
1314
+ assert_eq ! ( all_dependencies( & engine) , expected) ;
1315
+ }
1316
+
1317
+ #[ test]
1318
+ fn test_run_package_task_exact_error ( ) {
1319
+ let repo_root_dir = TempDir :: with_prefix ( "repo" ) . unwrap ( ) ;
1320
+ let repo_root = AbsoluteSystemPathBuf :: new ( repo_root_dir. path ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
1321
+ let package_graph = mock_package_graph (
1322
+ & repo_root,
1323
+ package_jsons ! {
1324
+ repo_root,
1325
+ "app1" => [ "libA" ] ,
1326
+ "libA" => [ ]
1327
+ } ,
1328
+ ) ;
1329
+ let turbo_jsons = vec ! [
1330
+ (
1331
+ PackageName :: Root ,
1332
+ turbo_json( json!( {
1333
+ "tasks" : {
1334
+ "build" : { "dependsOn" : [ "^build" ] } ,
1335
+ }
1336
+ } ) ) ,
1337
+ ) ,
1338
+ (
1339
+ PackageName :: from( "app1" ) ,
1340
+ turbo_json( json!( {
1341
+ "extends" : [ "//" ] ,
1342
+ "tasks" : {
1343
+ "another" : { "dependsOn" : [ "^build" ] } ,
1344
+ }
1345
+ } ) ) ,
1346
+ ) ,
1347
+ ]
1348
+ . into_iter ( )
1349
+ . collect ( ) ;
1350
+ let loader = TurboJsonLoader :: noop ( turbo_jsons) ;
1351
+ let engine = EngineBuilder :: new ( & repo_root, & package_graph, loader. clone ( ) , false )
1352
+ . with_tasks ( vec ! [ Spanned :: new( TaskName :: from( "app1#special" ) ) ] )
1353
+ . with_workspaces ( vec ! [ PackageName :: from( "app1" ) ] )
1354
+ . build ( ) ;
1355
+ assert ! ( engine. is_err( ) ) ;
1356
+ let report = miette:: Report :: new ( engine. unwrap_err ( ) ) ;
1357
+ let mut msg = String :: new ( ) ;
1358
+ miette:: JSONReportHandler :: new ( )
1359
+ . render_report ( & mut msg, report. as_ref ( ) )
1360
+ . unwrap ( ) ;
1361
+ assert_json_snapshot ! ( msg) ;
1362
+
1363
+ let engine = EngineBuilder :: new ( & repo_root, & package_graph, loader, false )
1364
+ . with_tasks ( vec ! [ Spanned :: new( TaskName :: from( "app1#another" ) ) ] )
1365
+ . with_workspaces ( vec ! [ PackageName :: from( "libA" ) ] )
1366
+ . build ( ) ;
1367
+ assert ! ( engine. is_err( ) ) ;
1368
+ let report = miette:: Report :: new ( engine. unwrap_err ( ) ) ;
1369
+ let mut msg = String :: new ( ) ;
1370
+ miette:: JSONReportHandler :: new ( )
1371
+ . render_report ( & mut msg, report. as_ref ( ) )
1372
+ . unwrap ( ) ;
1373
+ assert_json_snapshot ! ( msg) ;
1374
+ }
1248
1375
}
0 commit comments