Skip to content

Commit cbafa22

Browse files
committed
Refactor task selection logic to improve scope handling and error messages
- Extract `select_discovered_task` function for clarity - Enable exact name matching with scope delimiters - Improve error reporting when tasks are not found in a scope - Update `run_with_discovery` to handle discovered tasks uniformly - Add test for exact name and scope delimiter matching
1 parent 527049f commit cbafa22

1 file changed

Lines changed: 60 additions & 33 deletions

File tree

‎src/tasks.rs‎

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,32 @@ pub fn run_with_discovery(task_name: &str, args: Vec<String>) -> Result<()> {
605605
bail!("No tasks defined in {} or subdirectories", root.display());
606606
}
607607

608+
let discovered = select_discovered_task(&discovery, task_name)?;
609+
if let Some(discovered) = discovered {
610+
return run(TaskRunOpts {
611+
config: discovered.config_path.clone(),
612+
delegate_to_hub: false,
613+
hub_host: std::net::IpAddr::from([127, 0, 0, 1]),
614+
hub_port: 9050,
615+
name: discovered.task.name.clone(),
616+
args,
617+
});
618+
}
619+
620+
// List available tasks in error message
621+
let available: Vec<_> = discovery.tasks.iter().map(task_reference).collect();
622+
bail!(
623+
"task '{}' not found.\nAvailable tasks: {}",
624+
task_name,
625+
available.join(", ")
626+
);
627+
}
628+
629+
fn select_discovered_task<'a>(
630+
discovery: &'a discover::DiscoveryResult,
631+
task_name: &str,
632+
) -> Result<Option<&'a discover::DiscoveredTask>> {
633+
let mut scoped_not_found: Option<(String, String, Vec<String>)> = None;
608634
if let Some((scope, scoped_task)) = parse_scoped_selector(task_name) {
609635
let scope_exists = discovery.tasks.iter().any(|d| d.matches_scope(&scope));
610636
if scope_exists {
@@ -640,14 +666,7 @@ pub fn run_with_discovery(task_name: &str, args: Vec<String>) -> Result<()> {
640666
};
641667

642668
if let Some(discovered) = selected {
643-
return run(TaskRunOpts {
644-
config: discovered.config_path.clone(),
645-
delegate_to_hub: false,
646-
hub_host: std::net::IpAddr::from([127, 0, 0, 1]),
647-
hub_port: 9050,
648-
name: discovered.task.name.clone(),
649-
args,
650-
});
669+
return Ok(Some(discovered));
651670
}
652671

653672
let scoped_available: Vec<String> = discovery
@@ -656,16 +675,7 @@ pub fn run_with_discovery(task_name: &str, args: Vec<String>) -> Result<()> {
656675
.filter(|d| d.matches_scope(&scope))
657676
.map(task_reference)
658677
.collect();
659-
bail!(
660-
"task '{}' not found in scope '{}'.\nAvailable in scope: {}",
661-
scoped_task,
662-
scope,
663-
if scoped_available.is_empty() {
664-
"(none)".to_string()
665-
} else {
666-
scoped_available.join(", ")
667-
}
668-
);
678+
scoped_not_found = Some((scope, scoped_task, scoped_available));
669679
}
670680
}
671681

@@ -706,23 +716,23 @@ pub fn run_with_discovery(task_name: &str, args: Vec<String>) -> Result<()> {
706716
};
707717

708718
if let Some(discovered) = discovered {
709-
return run(TaskRunOpts {
710-
config: discovered.config_path.clone(),
711-
delegate_to_hub: false,
712-
hub_host: std::net::IpAddr::from([127, 0, 0, 1]),
713-
hub_port: 9050,
714-
name: discovered.task.name.clone(),
715-
args,
716-
});
719+
return Ok(Some(discovered));
717720
}
718721

719-
// List available tasks in error message
720-
let available: Vec<_> = discovery.tasks.iter().map(task_reference).collect();
721-
bail!(
722-
"task '{}' not found.\nAvailable tasks: {}",
723-
task_name,
724-
available.join(", ")
725-
);
722+
if let Some((scope, scoped_task, scoped_available)) = scoped_not_found {
723+
bail!(
724+
"task '{}' not found in scope '{}'.\nAvailable in scope: {}",
725+
scoped_task,
726+
scope,
727+
if scoped_available.is_empty() {
728+
"(none)".to_string()
729+
} else {
730+
scoped_available.join(", ")
731+
}
732+
);
733+
}
734+
735+
Ok(None)
726736
}
727737

728738
fn parse_scoped_selector(selector: &str) -> Option<(String, String)> {
@@ -3172,6 +3182,23 @@ mod tests {
31723182
assert_eq!(selected.scope, "root");
31733183
}
31743184

3185+
#[test]
3186+
fn select_discovered_task_allows_exact_names_with_scope_delimiters() {
3187+
let scoped = discovered_task("mobile", "mobile", "run");
3188+
let exact = discovered_task("root", "", "mobile:dev");
3189+
let discovery = discover::DiscoveryResult {
3190+
tasks: vec![scoped, exact],
3191+
root_config: None,
3192+
root_cfg: None,
3193+
};
3194+
3195+
let selected = select_discovered_task(&discovery, "mobile:dev")
3196+
.expect("selection should succeed")
3197+
.expect("exact task should resolve");
3198+
assert_eq!(selected.scope, "root");
3199+
assert_eq!(selected.task.name, "mobile:dev");
3200+
}
3201+
31753202
#[test]
31763203
fn format_discovered_task_lines_prefixes_scope() {
31773204
let entries = vec![discovered_task("mobile", "mobile", "dev")];

0 commit comments

Comments
 (0)