Skip to content

Commit b3f1f3b

Browse files
authored
feat: deno run <task> (#24891)
This PR updates `deno run` to fallback to executing tasks when there is no script with the specified name. If there are both script and a task with the same name then `deno run` will prioritise executing the script.
1 parent 897159d commit b3f1f3b

File tree

8 files changed

+60
-5
lines changed

8 files changed

+60
-5
lines changed

cli/main.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::util::display;
3737
use crate::util::v8::get_v8_flags_from_env;
3838
use crate::util::v8::init_v8_flags;
3939

40+
use args::TaskFlags;
4041
use deno_runtime::WorkerExecutionMode;
4142
pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS;
4243

@@ -50,8 +51,10 @@ use deno_runtime::fmt_errors::format_js_error;
5051
use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics;
5152
use deno_terminal::colors;
5253
use factory::CliFactory;
54+
use standalone::MODULE_NOT_FOUND;
5355
use std::env;
5456
use std::future::Future;
57+
use std::ops::Deref;
5558
use std::path::PathBuf;
5659
use std::sync::Arc;
5760

@@ -177,16 +180,39 @@ async fn run_subcommand(flags: Arc<Flags>) -> Result<i32, AnyError> {
177180
}
178181
DenoSubcommand::Run(run_flags) => spawn_subcommand(async move {
179182
if run_flags.is_stdin() {
180-
tools::run::run_from_stdin(flags).await
183+
tools::run::run_from_stdin(flags.clone()).await
181184
} else {
182-
tools::run::run_script(WorkerExecutionMode::Run, flags, run_flags.watch).await
185+
let result = tools::run::run_script(WorkerExecutionMode::Run, flags.clone(), run_flags.watch).await;
186+
match result {
187+
Ok(v) => Ok(v),
188+
Err(script_err) => {
189+
if script_err.to_string().starts_with(MODULE_NOT_FOUND) {
190+
let mut new_flags = flags.deref().clone();
191+
let task_flags = TaskFlags {
192+
cwd: None,
193+
task: Some(run_flags.script.clone()),
194+
};
195+
new_flags.subcommand = DenoSubcommand::Task(task_flags.clone());
196+
let result = tools::task::execute_script(Arc::new(new_flags), task_flags.clone(), true).await;
197+
match result {
198+
Ok(v) => Ok(v),
199+
Err(_) => {
200+
// Return script error for backwards compatibility.
201+
Err(script_err)
202+
}
203+
}
204+
} else {
205+
Err(script_err)
206+
}
207+
},
208+
}
183209
}
184210
}),
185211
DenoSubcommand::Serve(serve_flags) => spawn_subcommand(async move {
186212
tools::run::run_script(WorkerExecutionMode::Serve, flags, serve_flags.watch).await
187213
}),
188214
DenoSubcommand::Task(task_flags) => spawn_subcommand(async {
189-
tools::task::execute_script(flags, task_flags).await
215+
tools::task::execute_script(flags, task_flags, false).await
190216
}),
191217
DenoSubcommand::Test(test_flags) => {
192218
spawn_subcommand(async {

cli/standalone/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ struct EmbeddedModuleLoader {
131131
dynamic_permissions: PermissionsContainer,
132132
}
133133

134+
pub const MODULE_NOT_FOUND: &str = "Module not found";
135+
134136
impl ModuleLoader for EmbeddedModuleLoader {
135137
fn resolve(
136138
&self,
@@ -336,7 +338,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
336338

337339
let Some(module) = self.shared.eszip.get_module(original_specifier) else {
338340
return deno_core::ModuleLoadResponse::Sync(Err(type_error(format!(
339-
"Module not found: {}",
341+
"{MODULE_NOT_FOUND}: {}",
340342
original_specifier
341343
))));
342344
};

cli/tools/task.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use deno_config::deno_json::Task;
1212
use deno_config::workspace::TaskOrScript;
1313
use deno_config::workspace::WorkspaceDirectory;
1414
use deno_config::workspace::WorkspaceTasksConfig;
15+
use deno_core::anyhow::anyhow;
1516
use deno_core::anyhow::bail;
1617
use deno_core::anyhow::Context;
1718
use deno_core::error::AnyError;
@@ -28,6 +29,7 @@ use std::sync::Arc;
2829
pub async fn execute_script(
2930
flags: Arc<Flags>,
3031
task_flags: TaskFlags,
32+
using_run: bool,
3133
) -> Result<i32, AnyError> {
3234
let factory = CliFactory::from_flags(flags);
3335
let cli_options = factory.cli_options()?;
@@ -140,7 +142,10 @@ pub async fn execute_script(
140142
}
141143
},
142144
None => {
143-
log::error!("Task not found: {task_name}");
145+
if using_run {
146+
return Err(anyhow!("Task not found: {}", task_name));
147+
}
148+
log::error!("Task not found: {}", task_name);
144149
if log::log_enabled!(log::Level::Error) {
145150
print_available_tasks(
146151
&mut std::io::stderr(),
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"tests": {
3+
"deno_run_task": {
4+
"args": "run main",
5+
"output": "main.out"
6+
},
7+
"deno_run_module_task_not_found": {
8+
"args": "run not_found",
9+
"output": "not_found.out",
10+
"exitCode": 1
11+
}
12+
}
13+
}

tests/specs/run/run_task/deno.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"tasks": {
3+
"main": "deno run main.ts"
4+
}
5+
}

tests/specs/run/run_task/main.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Task main deno run main.ts
2+
main

tests/specs/run/run_task/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("main");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
error: Module not found "file:///[WILDCARD]/not_found".

0 commit comments

Comments
 (0)