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
21 changes: 21 additions & 0 deletions e2e/tasks/test_task_ls_complete_monorepo
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Verify task completion output includes monorepo tasks when using // paths

# Root config marks repo as monorepo
cat <<'CONFIG' >mise.toml
experimental_monorepo_root = true

[tasks.root-task]
run = 'echo root'
CONFIG

# App subproject task that should appear in completions
mkdir -p apps/web
cat <<'CONFIG' >apps/web/mise.toml
[tasks.update-snapshots]
description = "Update monorepo snapshots"
run = 'echo updating snapshots'
CONFIG

# Completion output should include the //-prefixed task path with escaped colon
assert_contains "mise task ls --complete" '//apps/web\:update-snapshots:Update monorepo snapshots'
5 changes: 3 additions & 2 deletions src/cli/tasks/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ impl TasksLs {

let config = Config::get().await?;

// Create context based on --all flag
let ctx = if self.all {
// Create context based on --all flag or when generating completions/usage specs
// to ensure monorepo tasks (e.g., `//app:task`) are available for autocomplete.
let ctx = if self.all || self.complete || self.usage {
Some(TaskLoadContext::all())
} else {
None
Expand Down
24 changes: 22 additions & 2 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,9 +1544,11 @@ async fn load_local_tasks_with_context(
async move {
let mut all_tasks = Vec::new();
// Load config files from subdirectory
let mut found_config = false;
for config_filename in DEFAULT_CONFIG_FILENAMES.iter() {
let config_path = subdir.join(config_filename);
if config_path.exists() {
found_config = true;
match config_file::parse(&config_path).await {
Ok(cf) => {
let mut subdir_tasks =
Expand Down Expand Up @@ -1574,6 +1576,17 @@ async fn load_local_tasks_with_context(
}
}
}

// If no config file exists, still load default task include dirs
if !found_config {
let includes = task_includes_for_dir(&subdir, &config.config_files);
for include in includes {
let mut subdir_tasks =
load_tasks_includes(&config, &include, &subdir).await?;
prefix_monorepo_task_names(&mut subdir_tasks, &subdir, &monorepo_root);
all_tasks.extend(subdir_tasks);
}
}
Ok::<Vec<Task>, eyre::Report>(all_tasks)
}
})
Expand All @@ -1599,6 +1612,11 @@ fn discover_monorepo_subdirs(
ctx: Option<&crate::task::TaskLoadContext>,
) -> Result<Vec<PathBuf>> {
const DEFAULT_IGNORED_DIRS: &[&str] = &["node_modules", "target", "dist", "build"];
let has_task_includes = |dir: &Path| {
default_task_includes()
.into_iter()
.any(|include| dir.join(include).exists())
};

let mut subdirs = Vec::new();
let settings = Settings::get();
Expand Down Expand Up @@ -1649,7 +1667,8 @@ fn discover_monorepo_subdirs(
let has_config = DEFAULT_CONFIG_FILENAMES
.iter()
.any(|f| dir.join(f).exists());
if has_config {
let has_task_includes = has_task_includes(dir);
if has_config || has_task_includes {
// Apply context filtering if provided
if let Some(ctx) = ctx {
let rel_path = dir
Expand Down Expand Up @@ -1685,7 +1704,8 @@ fn discover_monorepo_subdirs(
let has_config = DEFAULT_CONFIG_FILENAMES
.iter()
.any(|f| dir.join(f).exists());
if has_config {
let has_task_includes = has_task_includes(dir);
if has_config || has_task_includes {
// Apply context filtering if provided
if let Some(ctx) = ctx {
let rel_path = dir
Expand Down
Loading