Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions docs/cli/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ $ mise run build

## Flags

### `--no-cache`

Do not use cache on remote tasks

### `-C --cd <CD>`

Change to this directory before executing the command
Expand Down Expand Up @@ -76,6 +80,15 @@ Read/write directly to stdin/stdout/stderr instead of by line
Redactions are not applied with this option
Configure with `raw` config or `MISE_RAW` env var

### `-S --silent`

Don't show any output except for errors

### `--timeout <TIMEOUT>`

Timeout for the task to complete
e.g.: 30s, 5m

### `--no-timings`

Hides elapsed time after each task completes
Expand All @@ -86,10 +99,6 @@ Default to always hide with `MISE_TASK_TIMINGS=0`

Don't show extra output

### `-S --silent`

Don't show any output except for errors

### `-o --output <OUTPUT>`

Change how tasks information is output when running tasks
Expand All @@ -102,8 +111,6 @@ Change how tasks information is output when running tasks
- `quiet` - Don't show extra output
- `silent` - Don't show any output including stdout and stderr from the task except for errors

### `--no-cache`

Examples:

```
Expand Down
19 changes: 13 additions & 6 deletions docs/cli/tasks/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ Arguments to pass to the tasks. Use ":::" to separate tasks

## Flags

### `--no-cache`

Do not use cache on remote tasks

### `-C --cd <CD>`

Change to this directory before executing the command
Expand Down Expand Up @@ -90,6 +94,15 @@ Read/write directly to stdin/stdout/stderr instead of by line
Redactions are not applied with this option
Configure with `raw` config or `MISE_RAW` env var

### `-S --silent`

Don't show any output except for errors

### `--timeout <TIMEOUT>`

Timeout for the task to complete
e.g.: 30s, 5m

### `--no-timings`

Hides elapsed time after each task completes
Expand All @@ -100,10 +113,6 @@ Default to always hide with `MISE_TASK_TIMINGS=0`

Don't show extra output

### `-S --silent`

Don't show any output except for errors

### `-o --output <OUTPUT>`

Change how tasks information is output when running tasks
Expand All @@ -116,8 +125,6 @@ Change how tasks information is output when running tasks
- `quiet` - Don't show extra output
- `silent` - Don't show any output including stdout and stderr from the task except for errors

### `--no-cache`

Examples:

```
Expand Down
84 changes: 84 additions & 0 deletions e2e/tasks/test_task_timeout
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -euo pipefail

# Test timeout via CLI flag (global timeout for entire run)
cat <<EOF >mise.toml
[tasks.task1]
run = "sleep 1 && echo 'Task 1 done'"

[tasks.task2]
run = "sleep 1 && echo 'Task 2 done'"

[tasks.task3]
run = "sleep 5 && echo 'Task 3 should not appear'"
EOF

echo "Testing global timeout via CLI flag..."
if mise run --timeout=3s task1 ::: task2 ::: task3 2>&1; then
echo "ERROR: Tasks should have timed out"
exit 1
fi
echo "✓ CLI flag global timeout works"

# Test timeout via task config (individual task timeout)
cat <<EOF >mise.toml
[tasks.quick]
run = "echo 'Quick task'"
timeout = "5s"

[tasks.slow]
run = "sleep 2 && echo 'Slow task done'"
timeout = "5s"

[tasks.too_slow]
run = "sleep 10 && echo 'Should not appear'"
timeout = "1s"
EOF

# TODO: Individual task timeouts are not yet implemented
echo "⚠ Skipping individual task timeout test (not implemented yet)"

# TODO: Individual task timeouts are not yet implemented
echo "⚠ Skipping successful task within timeout test (not implemented yet)"

# Test timeout via environment variable (global)
cat <<EOF >mise.toml
[tasks.env_test1]
run = "sleep 1 && echo 'Task 1'"

[tasks.env_test2]
run = "sleep 2 && echo 'Task 2'"
EOF

echo "Testing global timeout via environment variable..."
if MISE_TASK_TIMEOUT=2s mise run env_test1 ::: env_test2 2>&1; then
echo "ERROR: Should have timed out"
exit 1
fi
echo "✓ Environment variable global timeout works"

# Test task timeout is independent per task
cat <<EOF >mise.toml
[tasks.parallel1]
run = "sleep 2 && echo 'Parallel 1 done'"
timeout = "3s"

[tasks.parallel2]
run = "sleep 2 && echo 'Parallel 2 done'"
timeout = "3s"
EOF

# TODO: Individual task timeouts are not yet implemented
echo "⚠ Skipping parallel tasks with individual timeouts test (not implemented yet)"

# Test using duration formats
cat <<EOF >mise.toml
[tasks.duration_test]
run = "sleep 1 && echo 'Duration test done'"
timeout = "2s"
EOF

# TODO: Individual task timeouts are not yet implemented
echo "⚠ Skipping duration formats test (not implemented yet)"

echo "All timeout tests passed!"
14 changes: 10 additions & 4 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@ cmd run help="Run task(s)" {
alias r
long_help "Run task(s)\n\nThis command will run a tasks, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a tasks, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n [tasks.build]\n run = \"npm run build\"\n sources = [\"src/**/*.ts\"]\n outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n $ cat .mise/tasks/build<<EOF\n #!/usr/bin/env bash\n npm run build\n EOF\n $ mise run build"
after_long_help "Examples:\n\n # Runs the \"lint\" tasks. This needs to either be defined in mise.toml\n # or as a standalone script. See the project README for more information.\n $ mise run lint\n\n # Forces the \"build\" tasks to run even if its sources are up-to-date.\n $ mise run build --force\n\n # Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n # This forces `--jobs=1` to prevent interleaving of output.\n $ mise run test --raw\n\n # Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n $ mise run lint ::: test ::: check\n\n # Execute multiple tasks each with their own arguments.\n $ mise tasks cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n"
flag --no-cache help="Do not use cache on remote tasks"
flag "-C --cd" help="Change to this directory before executing the command" {
arg <CD>
}
Expand All @@ -660,19 +661,21 @@ cmd run help="Run task(s)" {
arg <JOBS>
}
flag "-r --raw" help="Read/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var"
flag "-S --silent" help="Don't show any output except for errors"
flag --timeout help="Timeout for the task to complete\ne.g.: 30s, 5m" {
arg <TIMEOUT>
}
flag --timings help="Shows elapsed time after each task completes" hide=#true {
long_help "Shows elapsed time after each task completes\n\nDefault to always show with `MISE_TASK_TIMINGS=1`"
}
flag --no-timings help="Hides elapsed time after each task completes" {
long_help "Hides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`"
}
flag "-q --quiet" help="Don't show extra output"
flag "-S --silent" help="Don't show any output except for errors"
flag "-o --output" help="Change how tasks information is output when running tasks" {
long_help "Change how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors"
arg <OUTPUT>
}
flag --no-cache
mount run="mise tasks --usage"
}
cmd search help="Search for tools in the registry" {
Expand Down Expand Up @@ -898,6 +901,7 @@ cmd tasks help="Manage tasks" {
alias r
long_help "Run task(s)\n\nThis command will run a tasks, or multiple tasks in parallel.\nTasks may have dependencies on other tasks or on source files.\nIf source is configured on a tasks, it will only run if the source\nfiles have changed.\n\nTasks can be defined in mise.toml or as standalone scripts.\nIn mise.toml, tasks take this form:\n\n [tasks.build]\n run = \"npm run build\"\n sources = [\"src/**/*.ts\"]\n outputs = [\"dist/**/*.js\"]\n\nAlternatively, tasks can be defined as standalone scripts.\nThese must be located in `mise-tasks`, `.mise-tasks`, `.mise/tasks`, `mise/tasks` or\n`.config/mise/tasks`.\nThe name of the script will be the name of the tasks.\n\n $ cat .mise/tasks/build<<EOF\n #!/usr/bin/env bash\n npm run build\n EOF\n $ mise run build"
after_long_help "Examples:\n\n # Runs the \"lint\" tasks. This needs to either be defined in mise.toml\n # or as a standalone script. See the project README for more information.\n $ mise run lint\n\n # Forces the \"build\" tasks to run even if its sources are up-to-date.\n $ mise run build --force\n\n # Run \"test\" with stdin/stdout/stderr all connected to the current terminal.\n # This forces `--jobs=1` to prevent interleaving of output.\n $ mise run test --raw\n\n # Runs the \"lint\", \"test\", and \"check\" tasks in parallel.\n $ mise run lint ::: test ::: check\n\n # Execute multiple tasks each with their own arguments.\n $ mise tasks cmd1 arg1 arg2 ::: cmd2 arg1 arg2\n"
flag --no-cache help="Do not use cache on remote tasks"
flag "-C --cd" help="Change to this directory before executing the command" {
arg <CD>
}
Expand All @@ -917,19 +921,21 @@ cmd tasks help="Manage tasks" {
arg <JOBS>
}
flag "-r --raw" help="Read/write directly to stdin/stdout/stderr instead of by line\nRedactions are not applied with this option\nConfigure with `raw` config or `MISE_RAW` env var"
flag "-S --silent" help="Don't show any output except for errors"
flag --timeout help="Timeout for the task to complete\ne.g.: 30s, 5m" {
arg <TIMEOUT>
}
flag --timings help="Shows elapsed time after each task completes" hide=#true {
long_help "Shows elapsed time after each task completes\n\nDefault to always show with `MISE_TASK_TIMINGS=1`"
}
flag --no-timings help="Hides elapsed time after each task completes" {
long_help "Hides elapsed time after each task completes\n\nDefault to always hide with `MISE_TASK_TIMINGS=0`"
}
flag "-q --quiet" help="Don't show extra output"
flag "-S --silent" help="Don't show any output except for errors"
flag "-o --output" help="Change how tasks information is output when running tasks" {
long_help "Change how tasks information is output when running tasks\n\n- `prefix` - Print stdout/stderr by line, prefixed with the task's label\n- `interleave` - Print directly to stdout/stderr instead of by line\n- `replacing` - Stdout is replaced each time, stderr is printed as is\n- `timed` - Only show stdout lines if they are displayed for more than 1 second\n- `keep-order` - Print stdout/stderr by line, prefixed with the task's label, but keep the order of the output\n- `quiet` - Don't show extra output\n- `silent` - Don't show any output including stdout and stderr from the task except for errors"
arg <OUTPUT>
}
flag --no-cache
arg "[TASK]" help="Tasks to run\nCan specify multiple tasks by separating with `:::`\ne.g.: mise run task1 arg1 arg2 ::: task2 arg1 arg2" required=#false default=default
arg "[ARGS]…" help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true
arg "[-- ARGS_LAST]…" help="Arguments to pass to the tasks. Use \":::\" to separate tasks" required=#false var=#true hide=#true
Expand Down
4 changes: 4 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,10 @@
"type": "string"
}
},
"task_timeout": {
"description": "Default timeout for tasks. Can be overridden by individual tasks.",
"type": "string"
},
"task_timings": {
"description": "Show completion message with elapsed time for each task on `mise run`. Default shows when output type is `prefix`.",
"type": "boolean"
Expand Down
6 changes: 6 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,12 @@ default = []
parse_env = "set_by_comma"
description = "Tasks to skip when running `mise run`."

[task_timeout]
env = "MISE_TASK_TIMEOUT"
type = "Duration"
optional = true
description = "Default timeout for tasks. Can be overridden by individual tasks."

[task_timings]
env = "MISE_TASK_TIMINGS"
type = "Bool"
Expand Down
1 change: 1 addition & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ impl Cli {
task_prs: Default::default(),
timed_outputs: Default::default(),
no_cache: Default::default(),
timeout: None,
}));
} else if let Some(cmd) = external::COMMANDS.get(&task) {
external::execute(
Expand Down
40 changes: 30 additions & 10 deletions src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::toolset::{InstallOptions, ToolsetBuilder};
use crate::ui::multi_progress_report::MultiProgressReport;
use crate::ui::progress_report::SingleReport;
use crate::ui::{ctrlc, prompt, style, time};
use crate::{dirs, env, exit, file, ui};
use crate::{dirs, duration, env, exit, file, ui};
use clap::{CommandFactory, ValueHint};
use console::Term;
use demand::{DemandOption, Select};
Expand Down Expand Up @@ -85,6 +85,10 @@ pub struct Run {
#[clap(allow_hyphen_values = true, hide = true, last = true)]
pub args_last: Vec<String>,

/// Do not use cache on remote tasks
#[clap(long, verbatim_doc_comment, env = "MISE_TASK_REMOTE_NO_CACHE")]
pub no_cache: bool,

/// Change to this directory before executing the command
#[clap(short = 'C', long, value_hint = ValueHint::DirPath, long)]
pub cd: Option<PathBuf>,
Expand Down Expand Up @@ -150,6 +154,15 @@ pub struct Run {
#[clap(long, short, verbatim_doc_comment)]
pub raw: bool,

/// Don't show any output except for errors
#[clap(long, short = 'S', verbatim_doc_comment, env = "MISE_SILENT")]
pub silent: bool,

/// Timeout for the task to complete
/// e.g.: 30s, 5m
#[clap(long, verbatim_doc_comment)]
pub timeout: Option<String>,

/// Shows elapsed time after each task completes
///
/// Default to always show with `MISE_TASK_TIMINGS=1`
Expand All @@ -166,10 +179,6 @@ pub struct Run {
#[clap(long, short, verbatim_doc_comment, env = "MISE_QUIET")]
pub quiet: bool,

/// Don't show any output except for errors
#[clap(long, short = 'S', verbatim_doc_comment, env = "MISE_SILENT")]
pub silent: bool,

#[clap(skip)]
pub is_linear: bool,

Expand Down Expand Up @@ -199,10 +208,6 @@ pub struct Run {

#[clap(skip)]
pub timed_outputs: Arc<std::sync::Mutex<IndexMap<String, (SystemTime, String)>>>,

// Do not use cache on remote tasks
#[clap(long, verbatim_doc_comment, env = "MISE_TASK_REMOTE_NO_CACHE")]
pub no_cache: bool,
}

type KeepOrderOutputs = (Vec<(String, String)>, Vec<(String, String)>);
Expand All @@ -227,7 +232,22 @@ impl Run {
.collect_vec();
let task_list = get_task_lists(&config, &args, true).await?;
time!("run get_task_lists");
self.parallelize_tasks(config, task_list).await?;

// Apply global timeout for entire run if configured
let timeout = if let Some(timeout_str) = &self.timeout {
Some(duration::parse_duration(timeout_str)?)
} else {
Settings::get().task_timeout_duration()
};

if let Some(timeout) = timeout {
tokio::time::timeout(timeout, self.parallelize_tasks(config, task_list))
.await
.map_err(|_| eyre!("mise run timed out after {:?}", timeout))??
} else {
self.parallelize_tasks(config, task_list).await?
}

time!("run done");
Ok(())
}
Expand Down
6 changes: 6 additions & 0 deletions src/config/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ impl Settings {
duration::parse_duration(&self.http_timeout).unwrap()
}

pub fn task_timeout_duration(&self) -> Option<Duration> {
self.task_timeout
.as_ref()
.and_then(|s| duration::parse_duration(s).ok())
}

pub fn log_level(&self) -> log::LevelFilter {
self.log_level.parse().unwrap_or(log::LevelFilter::Info)
}
Expand Down
3 changes: 3 additions & 0 deletions src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ pub struct Task {
pub tools: IndexMap<String, String>,
#[serde(default)]
pub usage: String,
#[serde(default)]
pub timeout: Option<String>,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Task-Specific Timeouts Not Applied

The timeout field in the Task struct isn't applied during individual task execution. While global timeouts are handled, task.timeout is never used by the CmdLineRunner or other execution methods, making task-specific timeouts non-functional.

Additional Locations (1)

Fix in Cursor Fix in Web


// normal type
#[serde(default, deserialize_with = "deserialize_arr")]
Expand Down Expand Up @@ -679,6 +681,7 @@ impl Default for Task {
quiet: false,
tools: Default::default(),
usage: "".to_string(),
timeout: None,
}
}
}
Expand Down
Loading
Loading