Task inheritance
Unlike other task runners that require the same tasks to be repeatedly defined for every project, moon uses an inheritance model where tasks can be defined once at the workspace-level, and are then inherited by many or all projects.
Workspace-level tasks (also known as global tasks) are defined in .moon/tasks.yml
or
.moon/tasks/**/*.yml
, and are inherited by default. However, projects are able to
include, exclude, or rename inherited tasks using the
workspace.inheritedTasks
in moon.yml
.
Scope by project metadata
By default tasks defined in .moon/tasks.yml
will be inherited by all projects. This
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
,
where *.yml
maps to a project based on a combination of its language, stack,
type, or tags. This enables you to easily declare tasks for "JavaScript projects",
"Go applications", "Ruby libraries", so on and so forth.
When resolving configuration files, moon will locate and shallow merge files in the following order, from widest scope to narrowest scope:
.moon/tasks.yml
- All projects..moon/tasks/<language>.yml
- Projects with a matchinglanguage
setting..moon/tasks/<stack>.yml
- Projects with a matchingstack
setting. v1.23.0.moon/tasks/<language>-<stack>.yml
- Projects with a matchinglanguage
andstack
settings. v1.23.0.moon/tasks/<stack>-<type>.yml
- Projects with matchingstack
andtype
settings. v1.23.0.moon/tasks/<language>-<type>.yml
- Projects with matchinglanguage
andtype
settings..moon/tasks/<language>-<stack>-<type>.yml
- Projects with matchinglanguage
,stack
, andtype
settings. v1.23.0.moon/tasks/tag-<name>.yml
- Projects with a matchingtag
. v1.2.0
As mentioned above, all of these files are shallow merged into a single "global tasks" configuration that is unique per-project. Merging does not utilize the merge strategies below, as those strategies are only utilized when merging global and local tasks.
Tags are resolved in the order they are defined in
moon.yml
tags
setting.
JavaScript platforms
Unlike most languages that have 1 runtime, JavaScript has 3 (Node.js, Deno, Bun), and we must
support repositories that are comprised of any combination of these 3. As such, JavaScript (and
TypeScript) based projects have the following additional lookups using
platform
to account for this:
.moon/tasks/<platform>.yml
.moon/tasks/<platform>-<stack>.yml
.moon/tasks/<platform>-<type>.yml
.moon/tasks/<platform>-<stack>-<type>.yml
For example, node.yml
would be inherited for Node.js projects, bun-library.yml
for Bun
libraries, and deno-application.yml
for Deno applications. While javascript.yml
,
typescript-library.yml
, etc, will be inherited for all platforms.
Merge strategies
When a global task and local task of the same name exist, they are merged into a single task. To accomplish this, one of many merge strategies can be used.
Merging is applied to the parameters args
,
deps
, env
,
inputs
, and outputs
, using the
merge
, mergeArgs
,
mergeDeps
, mergeEnv
,
mergeInputs
and mergeOutputs
options respectively. Each of these options support one of the following strategy values.
append
(default) - Values found in the local task are merged after the values found in the global task. For example, this strategy is useful for toggling flag arguments.prepend
- Values found in the local task are merged before the values found in the global task. For example, this strategy is useful for applying option arguments that must come before positional arguments.preserve
- Preserve the original global task values. This should rarely be used, but exists for situations where an inheritance chain is super long and complex, but we simply want to the base values. v1.29.0replace
- Values found in the local task entirely replaces the values in the global task. This strategy is useful when you need full control.
All 3 of these strategies are demonstrated below, with a somewhat contrived example, but you get the point.
# Global
tasks:
build:
command:
- 'webpack'
- '--mode'
- 'production'
- '--color'
deps:
- 'designSystem:build'
inputs:
- '/webpack.config.js'
outputs:
- 'build/'
# Local
tasks:
build:
args: '--no-color --no-stats'
deps:
- 'reactHooks:build'
inputs:
- 'webpack.config.js'
options:
mergeArgs: 'append'
mergeDeps: 'prepend'
mergeInputs: 'replace'
# Merged result
tasks:
build:
command:
- 'webpack'
- '--mode'
- 'production'
- '--color'
- '--no-color'
- '--no-stats'
deps:
- 'reactHooks:build'
- 'designSystem:build'
inputs:
- 'webpack.config.js'
outputs:
- 'build/'
options:
mergeArgs: 'append'
mergeDeps: 'prepend'
mergeInputs: 'replace'