From 118ece0323d94701b79a6a11b73c9d3fcad5fcb2 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Fri, 22 Sep 2023 14:20:28 -0700 Subject: [PATCH] new: Allow task configs to be nested in folders. (#1067) * Update docs. * Update impl. * Add tests. * Fix tests. * Fix windows. * Fix windows. --- crates/cli/src/commands/docker/scaffold.rs | 2 +- nextgen/app/src/systems/startup.rs | 2 +- nextgen/config/src/inherited_tasks_config.rs | 115 ++++++++++-------- .../__fixtures__/inheritance/nested/tasks.yml | 4 + .../tasks/dotnet/dotnet-application.yml | 4 + .../nested/tasks/dotnet/dotnet.yml | 4 + .../nested/tasks/node/node-library.yml | 4 + .../inheritance/nested/tasks/node/node.yml | 4 + .../tests/inherited_tasks_config_test.rs | 67 +++++++--- .../src/project_graph_builder.rs | 2 +- .../project-graph/tests/project_graph_test.rs | 21 ++-- .../task-builder/tests/tasks_builder_test.rs | 8 +- nextgen/workspace/src/workspace.rs | 40 ++---- packages/cli/CHANGELOG.md | 1 + website/blog/2023-09-25_moon-v1.14.mdx | 1 + website/docs/concepts/task-inheritance.mdx | 6 +- website/docs/config/tasks.mdx | 4 +- website/docs/guides/debug-task.mdx | 2 +- 18 files changed, 171 insertions(+), 120 deletions(-) create mode 100644 nextgen/config/tests/__fixtures__/inheritance/nested/tasks.yml create mode 100644 nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet-application.yml create mode 100644 nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet.yml create mode 100644 nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node-library.yml create mode 100644 nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node.yml diff --git a/crates/cli/src/commands/docker/scaffold.rs b/crates/cli/src/commands/docker/scaffold.rs index e3e6a7a8946..f25c33035a0 100644 --- a/crates/cli/src/commands/docker/scaffold.rs +++ b/crates/cli/src/commands/docker/scaffold.rs @@ -109,7 +109,7 @@ fn scaffold_workspace( // Copy moon configuration let moon_configs = glob::walk( workspace.root.join(CONFIG_DIRNAME), - ["*.yml", "tasks/*.yml"], + ["*.yml", "tasks/**/*.yml"], )?; let moon_configs = moon_configs .iter() diff --git a/nextgen/app/src/systems/startup.rs b/nextgen/app/src/systems/startup.rs index e58bc56682f..15466010532 100644 --- a/nextgen/app/src/systems/startup.rs +++ b/nextgen/app/src/systems/startup.rs @@ -169,7 +169,7 @@ pub fn load_tasks_config(workspace_root: StateRef, resources: Res file = ?config_path, "Attempting to load {} and {} (optional)", color::file(&config_name), - color::file(format!("{}/tasks/*.yml", consts::CONFIG_DIRNAME)), + color::file(format!("{}/tasks/**/*.yml", consts::CONFIG_DIRNAME)), ); let manager = InheritedTasksManager::load_from(workspace_root)?; diff --git a/nextgen/config/src/inherited_tasks_config.rs b/nextgen/config/src/inherited_tasks_config.rs index acc31131462..5c7621c2c59 100644 --- a/nextgen/config/src/inherited_tasks_config.rs +++ b/nextgen/config/src/inherited_tasks_config.rs @@ -3,14 +3,15 @@ use crate::project::{validate_deps, TaskConfig}; use crate::project_config::{validate_tasks, ProjectType}; use crate::shapes::InputPath; use crate::validate::check_yml_extension; -use moon_common::cacheable; -use moon_common::{consts, Id}; +use moon_common::path::standardize_separators; +use moon_common::{cacheable, consts, Id}; use moon_target::Target; use once_map::OnceMap; use rustc_hash::FxHashMap; use schematic::{merge, validate, Config, ConfigError, ConfigLoader, PartialConfig}; use std::fs; use std::hash::Hash; +use std::path::PathBuf; use std::{collections::BTreeMap, path::Path}; pub fn merge_fxhashmap( @@ -88,10 +89,16 @@ cacheable!( } ); +#[derive(Debug, Default)] +pub struct InheritedTasksEntry { + pub input: PathBuf, + pub config: PartialInheritedTasksConfig, +} + #[derive(Debug, Default)] pub struct InheritedTasksManager { cache: OnceMap, - pub configs: FxHashMap, + pub configs: FxHashMap, } impl InheritedTasksManager { @@ -108,40 +115,17 @@ impl InheritedTasksManager { if tasks_file.exists() { manager.add_config( + workspace_root, &tasks_file, InheritedTasksConfig::load_partial(workspace_root, &tasks_file)?, ); } - // tasks/*.yml + // tasks/**/*.yml let tasks_dir = moon_dir.join("tasks"); - if !tasks_dir.exists() { - return Ok(manager); - } - - for file in fs::read_dir(&tasks_dir) - .map_err(|error| ConfigError::ReadFileFailed { - path: tasks_dir, - error, - })? - .flatten() - { - let path = file.path(); - - if file - .file_type() - .map_err(|error| ConfigError::ReadFileFailed { - path: path.to_path_buf(), - error, - })? - .is_file() - { - manager.add_config( - &path, - InheritedTasksConfig::load_partial(workspace_root, &path)?, - ); - } + if tasks_dir.exists() { + load_dir(&mut manager, workspace_root, &tasks_dir)?; } Ok(manager) @@ -153,26 +137,33 @@ impl InheritedTasksManager { Self::load(workspace_root, workspace_root.join(consts::CONFIG_DIRNAME)) } - pub fn add_config(&mut self, path: &Path, config: PartialInheritedTasksConfig) { + pub fn add_config( + &mut self, + workspace_root: &Path, + path: &Path, + config: PartialInheritedTasksConfig, + ) { let name = path .file_name() .unwrap_or_default() .to_str() .unwrap_or_default(); - if !name.ends_with(".yml") { - return; - } - let name = if name == consts::CONFIG_TASKS_FILENAME { "*" } else if let Some(stripped_name) = name.strip_suffix(".yml") { stripped_name } else { - name + return; }; - self.configs.insert(name.to_owned(), config); + self.configs.insert( + name.to_owned(), + InheritedTasksEntry { + input: path.strip_prefix(workspace_root).unwrap().to_path_buf(), + config, + }, + ); } pub fn get_lookup_order( @@ -223,18 +214,10 @@ impl InheritedTasksManager { let context = (); for lookup in &lookup_order { - if let Some(managed_config) = self.configs.get(lookup) { - let mut managed_config = managed_config.clone(); - - let source_path = if lookup == "*" { - format!( - "{}/{}", - consts::CONFIG_DIRNAME, - consts::CONFIG_TASKS_FILENAME - ) - } else { - format!("{}/tasks/{lookup}.yml", consts::CONFIG_DIRNAME) - }; + if let Some(config_entry) = self.configs.get(lookup) { + let source_path = + standardize_separators(format!("{}", config_entry.input.display())); + let mut managed_config = config_entry.config.clone(); // Only modify tasks for `tasks/*.yml` files instead of `tasks.yml`, // as the latter will be globbed alongside toolchain/workspace configs. @@ -284,3 +267,37 @@ impl InheritedTasksManager { }) } } + +fn load_dir( + manager: &mut InheritedTasksManager, + workspace_root: &Path, + dir: &Path, +) -> miette::Result<()> { + for entry in fs::read_dir(dir) + .map_err(|error| ConfigError::ReadFileFailed { + path: dir.to_path_buf(), + error, + })? + .flatten() + { + let path = entry.path(); + let file_type = entry + .file_type() + .map_err(|error| ConfigError::ReadFileFailed { + path: path.to_path_buf(), + error, + })?; + + if file_type.is_file() { + manager.add_config( + workspace_root, + &path, + InheritedTasksConfig::load_partial(workspace_root, &path)?, + ); + } else if file_type.is_dir() { + load_dir(manager, workspace_root, &path)?; + } + } + + Ok(()) +} diff --git a/nextgen/config/tests/__fixtures__/inheritance/nested/tasks.yml b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks.yml new file mode 100644 index 00000000000..581332aff16 --- /dev/null +++ b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks.yml @@ -0,0 +1,4 @@ +tasks: + command: + command: 'global' + inputs: ['a'] diff --git a/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet-application.yml b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet-application.yml new file mode 100644 index 00000000000..d090b2d7070 --- /dev/null +++ b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet-application.yml @@ -0,0 +1,4 @@ +tasks: + command: + command: 'dotnet-application' + inputs: ['c'] diff --git a/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet.yml b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet.yml new file mode 100644 index 00000000000..73b7ac0c7aa --- /dev/null +++ b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/dotnet/dotnet.yml @@ -0,0 +1,4 @@ +tasks: + command: + command: 'node' + inputs: ['b'] diff --git a/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node-library.yml b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node-library.yml new file mode 100644 index 00000000000..a890ae067ca --- /dev/null +++ b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node-library.yml @@ -0,0 +1,4 @@ +tasks: + command: + command: 'node-library' + inputs: ['c'] diff --git a/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node.yml b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node.yml new file mode 100644 index 00000000000..bfaf1c89227 --- /dev/null +++ b/nextgen/config/tests/__fixtures__/inheritance/nested/tasks/node/node.yml @@ -0,0 +1,4 @@ +tasks: + command: + command: 'dotnet' + inputs: ['b'] diff --git a/nextgen/config/tests/inherited_tasks_config_test.rs b/nextgen/config/tests/inherited_tasks_config_test.rs index e3a5b1f89f8..bdf2be65f73 100644 --- a/nextgen/config/tests/inherited_tasks_config_test.rs +++ b/nextgen/config/tests/inherited_tasks_config_test.rs @@ -12,7 +12,7 @@ use starbase_sandbox::{create_empty_sandbox, create_sandbox}; use std::collections::BTreeMap; use utils::*; -const FILENAME: &str = ".moon/tasks.yml"; +const FILENAME: &str = "tasks.yml"; mod tasks_config { use super::*; @@ -393,9 +393,8 @@ mod task_manager { let mut global_inputs = vec![]; if command != "global" { - global_inputs.push(InputPath::WorkspaceFile(format!( - ".moon/tasks/{command}.yml" - ))); + // No .moon prefix since the fixture is contrived + global_inputs.push(InputPath::WorkspaceFile(format!("tasks/{command}.yml"))); } TaskConfig { @@ -436,6 +435,38 @@ mod task_manager { ); } + #[test] + fn can_nest_configs_in_folders() { + let sandbox = create_sandbox("inheritance/nested"); + let manager = InheritedTasksManager::load(sandbox.path(), sandbox.path()).unwrap(); + + let mut keys = manager.configs.keys().collect::>(); + keys.sort(); + + assert_eq!( + keys, + vec!["*", "dotnet", "dotnet-application", "node", "node-library",] + ); + + let mut inputs = manager + .configs + .values() + .map(|c| c.input.to_string_lossy().replace('\\', "/")) + .collect::>(); + inputs.sort(); + + assert_eq!( + inputs, + vec![ + "tasks.yml", + "tasks/dotnet/dotnet-application.yml", + "tasks/dotnet/dotnet.yml", + "tasks/node/node-library.yml", + "tasks/node/node.yml" + ] + ); + } + mod lookup_order { use super::*; @@ -583,10 +614,10 @@ mod task_manager { assert_eq!( config.layers.keys().collect::>(), vec![ - ".moon/tasks.yml", - ".moon/tasks/javascript.yml", - ".moon/tasks/node-application.yml", - ".moon/tasks/node.yml", + "tasks.yml", + "tasks/javascript.yml", + "tasks/node-application.yml", + "tasks/node.yml", ] ); } @@ -619,11 +650,7 @@ mod task_manager { assert_eq!( config.layers.keys().collect::>(), - vec![ - ".moon/tasks.yml", - ".moon/tasks/node.yml", - ".moon/tasks/typescript.yml", - ] + vec!["tasks.yml", "tasks/node.yml", "tasks/typescript.yml",] ); } @@ -651,7 +678,7 @@ mod task_manager { assert_eq!( config.layers.keys().collect::>(), - vec![".moon/tasks.yml", ".moon/tasks/rust.yml",] + vec!["tasks.yml", "tasks/rust.yml",] ); } @@ -688,11 +715,11 @@ mod task_manager { assert_eq!( config.layers.keys().collect::>(), vec![ - ".moon/tasks.yml", - ".moon/tasks/node.yml", - ".moon/tasks/tag-kebab-case.yml", - ".moon/tasks/tag-normal.yml", - ".moon/tasks/typescript.yml", + "tasks.yml", + "tasks/node.yml", + "tasks/tag-kebab-case.yml", + "tasks/tag-normal.yml", + "tasks/typescript.yml", ] ); } @@ -721,7 +748,7 @@ mod task_manager { assert_eq!( config.layers.keys().collect::>(), - vec![".moon/tasks.yml", ".moon/tasks/kotlin.yml",] + vec!["tasks.yml", "tasks/kotlin.yml",] ); } } diff --git a/nextgen/project-graph/src/project_graph_builder.rs b/nextgen/project-graph/src/project_graph_builder.rs index 71512ca1e5b..54917f625f7 100644 --- a/nextgen/project-graph/src/project_graph_builder.rs +++ b/nextgen/project-graph/src/project_graph_builder.rs @@ -409,7 +409,7 @@ impl<'app> ProjectGraphBuilder<'app> { // Hash all workspace-level config files for file in glob::walk( context.workspace_root.join(consts::CONFIG_DIRNAME), - ["*.yml", "tasks/*.yml"], + ["*.yml", "tasks/**/*.yml"], )? { configs.push(to_virtual_string( file.strip_prefix(context.workspace_root).unwrap(), diff --git a/nextgen/project-graph/tests/project_graph_test.rs b/nextgen/project-graph/tests/project_graph_test.rs index 5afb7d7bbb5..59c352fc85d 100644 --- a/nextgen/project-graph/tests/project_graph_test.rs +++ b/nextgen/project-graph/tests/project_graph_test.rs @@ -1,9 +1,9 @@ use moon_common::{path::WorkspaceRelativePathBuf, Id}; use moon_config::PartialTaskConfig; use moon_config::{ - DependencyConfig, DependencyScope, DependencySource, InheritedTasksManager, NodeConfig, - PartialInheritedTasksConfig, ToolchainConfig, WorkspaceConfig, WorkspaceProjects, - WorkspaceProjectsConfig, + DependencyConfig, DependencyScope, DependencySource, InheritedTasksEntry, + InheritedTasksManager, NodeConfig, PartialInheritedTasksConfig, ToolchainConfig, + WorkspaceConfig, WorkspaceProjects, WorkspaceProjectsConfig, }; use moon_project::{FileGroup, Project}; use moon_project_builder::DetectLanguageEvent; @@ -46,12 +46,15 @@ impl GraphContainer { // Add a global task to all projects graph.inherited_tasks.configs.insert( "*".into(), - PartialInheritedTasksConfig { - tasks: Some(BTreeMap::from_iter([( - "global".into(), - PartialTaskConfig::default(), - )])), - ..PartialInheritedTasksConfig::default() + InheritedTasksEntry { + input: ".moon/tasks.yml".into(), + config: PartialInheritedTasksConfig { + tasks: Some(BTreeMap::from_iter([( + "global".into(), + PartialTaskConfig::default(), + )])), + ..PartialInheritedTasksConfig::default() + }, }, ); diff --git a/nextgen/task-builder/tests/tasks_builder_test.rs b/nextgen/task-builder/tests/tasks_builder_test.rs index 8d85911cc51..217d78fc5ea 100644 --- a/nextgen/task-builder/tests/tasks_builder_test.rs +++ b/nextgen/task-builder/tests/tasks_builder_test.rs @@ -745,7 +745,7 @@ mod tasks_builder { InputPath::ProjectFile("global".into()), InputPath::ProjectFile("local".into()), InputPath::WorkspaceGlob(".moon/*.yml".into()), - InputPath::WorkspaceFile(".moon/tasks/tag-merge.yml".into()), + InputPath::WorkspaceFile("global/tasks/tag-merge.yml".into()), ] ); @@ -798,7 +798,7 @@ mod tasks_builder { InputPath::ProjectFile("local".into()), InputPath::ProjectFile("global".into()), InputPath::WorkspaceGlob(".moon/*.yml".into()), - InputPath::WorkspaceFile(".moon/tasks/tag-merge.yml".into()), + InputPath::WorkspaceFile("global/tasks/tag-merge.yml".into()), ] ); @@ -843,7 +843,7 @@ mod tasks_builder { vec![ InputPath::ProjectFile("local".into()), InputPath::WorkspaceGlob(".moon/*.yml".into()), - InputPath::WorkspaceFile(".moon/tasks/tag-merge.yml".into()), + InputPath::WorkspaceFile("global/tasks/tag-merge.yml".into()), ] ); @@ -1276,7 +1276,7 @@ mod tasks_builder { InputPath::ProjectFile("local-base".into()), InputPath::ProjectFile("local-extender".into()), InputPath::WorkspaceGlob(".moon/*.yml".into()), - InputPath::WorkspaceFile(".moon/tasks/tag-extends.yml".into()), + InputPath::WorkspaceFile("global/tasks/tag-extends.yml".into()), ] ); diff --git a/nextgen/workspace/src/workspace.rs b/nextgen/workspace/src/workspace.rs index ee620b72468..abb37f46527 100644 --- a/nextgen/workspace/src/workspace.rs +++ b/nextgen/workspace/src/workspace.rs @@ -2,13 +2,13 @@ use crate::workspace_error::WorkspaceError; use moon_api::Moonbase; use moon_cache::CacheEngine; use moon_common::consts; -use moon_config::{InheritedTasksConfig, InheritedTasksManager, ToolchainConfig, WorkspaceConfig}; +use moon_config::{InheritedTasksManager, ToolchainConfig, WorkspaceConfig}; use moon_hash::HashEngine; use moon_vcs::{BoxedVcs, Git}; use proto_core::{ProtoEnvironment, ToolsConfig, Version, TOOLS_CONFIG_NAME}; use starbase::Resource; use starbase_styles::color; -use starbase_utils::{dirs, fs, glob}; +use starbase_utils::{dirs, fs}; use std::env; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -49,19 +49,8 @@ fn find_workspace_root>(working_dir: P) -> miette::Result miette::Result { - let mut manager = InheritedTasksManager::default(); - - let mut do_load = |config_path: &Path| -> miette::Result<()> { - manager.add_config( - config_path, - InheritedTasksConfig::load_partial(root_dir, config_path)?, - ); - - Ok(()) - }; - debug!( workspace_root = ?root_dir, "Attempting to load {}", @@ -72,26 +61,19 @@ fn load_tasks_config(root_dir: &Path) -> miette::Result { )), ); - let config_path = root_dir - .join(consts::CONFIG_DIRNAME) - .join(consts::CONFIG_TASKS_FILENAME); - - if config_path.exists() { - do_load(&config_path)?; - } - debug!( workspace_root = ?root_dir, "Attempting to load {}", - color::file(format!("{}/{}", consts::CONFIG_DIRNAME, "tasks/*.yml")), + color::file(format!("{}/{}", consts::CONFIG_DIRNAME, "tasks/**/*.yml")), ); - for config_path in glob::walk_files( - root_dir.join(consts::CONFIG_DIRNAME).join("tasks"), - ["*.yml"], - )? { - do_load(&config_path)?; - } + let manager = InheritedTasksManager::load_from(root_dir)?; + + debug!( + scopes = ?manager.configs.keys(), + "Loaded {} task configs to inherit", + manager.configs.len(), + ); Ok(manager) } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 2a78f6ea3b1..2fc602c1b54 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -20,6 +20,7 @@ - Updated `moon ci` to support running an explicit list of targets, instead of running everything. - Updated `node.version`, `npm.version`, `pnpm.version`, `yarn.version`, and `rust.version` to support partial versions and requirements/ranges like `1.2`, `1`, or `^1.2`. +- Updated `.moon/tasks` to support nested folders, for better organization of task files. #### ⚙️ Internal diff --git a/website/blog/2023-09-25_moon-v1.14.mdx b/website/blog/2023-09-25_moon-v1.14.mdx index 572148659b6..8852bb978c3 100644 --- a/website/blog/2023-09-25_moon-v1.14.mdx +++ b/website/blog/2023-09-25_moon-v1.14.mdx @@ -63,5 +63,6 @@ Learn more about how this works under the hood in the View the [official release](https://github.com/moonrepo/moon/releases/tag/v1.14.0) for a full list of changes. +- Updated `.moon/tasks` to support nested folders, for better organization of task files. - Improved handling of certificates and proxies. - Updated to proto v0.18. diff --git a/website/docs/concepts/task-inheritance.mdx b/website/docs/concepts/task-inheritance.mdx index 51ca8a45634..88b09453c4f 100644 --- a/website/docs/concepts/task-inheritance.mdx +++ b/website/docs/concepts/task-inheritance.mdx @@ -9,8 +9,8 @@ moon uses an inheritance model where tasks can be defined once at the workspace- inherited by _many or all_ projects. Workspace-level tasks (also known as global tasks) are defined in [`.moon/tasks.yml`][tasks] or -[`.moon/tasks/*.yml`][tasks], and are inherited by default. However, projects are able to include, -exclude, or rename inherited tasks using the +[`.moon/tasks/**/*.yml`][tasks], and are inherited by default. However, projects are able to +include, exclude, or rename inherited tasks using the [`workspace.inheritedTasks`](../config/project#inheritedtasks) in [`moon.yml`](../config/project). ## Scope by project metadata @@ -19,7 +19,7 @@ By default tasks defined in [`.moon/tasks.yml`][tasks] will be inherited by _all approach works well when a monorepo is comprised of a single programming language, but breaks down quickly in multi-language setups. -To support these complex repositories, we support scoped tasks with [`.moon/tasks/*.yml`][tasks], +To support these complex repositories, we support scoped tasks with [`.moon/tasks/**/*.yml`][tasks], where `*.yml` maps to a project based on a combination of its [language][language], [type][type], or [tags][tags]. This enables you to easily declare tasks for "JavaScript projects", "Go applications", "Ruby libraries", so on and so forth. diff --git a/website/docs/config/tasks.mdx b/website/docs/config/tasks.mdx index 69f84bac43b..d8f0f6e7f84 100644 --- a/website/docs/config/tasks.mdx +++ b/website/docs/config/tasks.mdx @@ -1,12 +1,12 @@ --- -title: .moon/tasks.yml, .moon/tasks/*.yml +title: .moon/tasks.yml, .moon/tasks/**/*.yml sidebar_label: .moon/tasks... --- import HeadingApiLink from '@site/src/components/Docs/HeadingApiLink'; The `.moon/tasks.yml` file configures file groups and tasks that are inherited by _every_ project in -the workspace, while `.moon/tasks/*.yml` configures for projects based on their language or type. +the workspace, while `.moon/tasks/**/*.yml` configures for projects based on their language or type. [Learn more about task inheritance!](../concepts/task-inheritance) Projects can override or merge with these settings within their respective [`moon.yml`](./project). diff --git a/website/docs/guides/debug-task.mdx b/website/docs/guides/debug-task.mdx index 75c82bbd145..98148272d6b 100644 --- a/website/docs/guides/debug-task.mdx +++ b/website/docs/guides/debug-task.mdx @@ -43,7 +43,7 @@ root `inherited` object, which is structured as follows: - `order` - The order in which configuration files from `.moon` are loaded, from lowest to highest priority, and the order files are merged. The `*` entry is `.moon/tasks.yml`, while other entries - map to `.moon/tasks/*.yml`. + map to `.moon/tasks/**/*.yml`. - `layers` - A mapping of configuration files that were loaded, derived from the `order`. Each layer represents a partial object (not expanded or resolved). Only files that exist will be mapped here. - `config` - A partial configuration object representing the state of all merged layers. This is