Skip to main content

moon v2.1 - Execution plans, target deps scopes, toolchain/task settings, and more

· 5 min read
Miles Johnson
Founder, developer

It's been about a month since our major v2.0 release, and we're back with a smaller, but still impactful, v2.1 release! This release includes a new execution plan feature for moon exec, the ability to target project dependencies by scope, new common toolchain settings for aliases and dependency installation, new task options for affectedFiles, and more.

Execution plans

The moon exec command is powerful, but complex invocations can mean long CLI commands that are hard to read and easy to get wrong. In v2.1, you can now define an execution plan — a JSON file that declaratively configures targets, affected filtering, graph traversal, and pipeline behavior — and pass it with a single flag:

plan.json
{
"pipeline": {
"jobTotal": 3
},
"targets": {
"jobs": [["app:build", "app:test"], ["lib:build", "lib:test"], ["docs:build"]]
}
}
# Runs docs:build only!
$ moon exec --plan plan.json --job 2

This is especially useful for CI pipelines where you need partitioned jobs, affected-only runs, or specific failure handling. Instead of stitching together a dozen flags, drop a plan.json into your repo and version-control your execution strategy.

Check out the execution plan guide for the full structure and examples.

Target project dependencies by scope

moon has always allowed you to reference dependencies of a project (external projects) within a task using ^ syntax, for both inputs and deps. However, it was quite restrictive in that it referenced all project dependencies, regardless of scope (production, development, etc).

We felt it was time to change this, and in v2.1 we're introducing a new syntax that allows you to target dependencies by scope. By default, the ^ syntax will still reference all dependencies, but you can now specify a scope by suffixing the ^ with one of the following:

  • development / dev
  • production / prod
  • build
  • peer
tasks:
build:
command: 'tsc'
deps:
# Depend on build tasks in production level project dependencies
- '^production:build'
inputs:
# Source files of all production level project dependencies
- 'project:^production'

New common toolchain settings

Going forward, we want to provide more customization for toolchains, enabling you to curate the experience you want. The first step in this process is introducing 2 new settings that are common across all toolchains.

inheritAliases

Aliases are a feature of projects that allow for alternate names to be used when referencing them. Aliases cannot be configured manually and instead are inferred from toolchains, typically by extracting the name field from a manifest file (package.json, Cargo.toml, pyproject.toml, etc).

This happens automatically, but what if you don't want to use aliases? Or there are conflicting aliases across projects? In v2.1, we're introducing a new common toolchain setting called inheritAliases that allows you to disable this feature. When set to false, no aliases will be inferred for any projects using that toolchain.

.moon/toolchains.yml
javascript:
inheritAliases: false

We've also updated duplicate aliases to no longer be a hard error, and instead will apply to the first encountered project.

installDependencies

When you run a task, all toolchains associated with the task will automatically install dependencies if they've determined that they need to (lockfile changes, dependency updates, etc). This is a great feature for ensuring that your environment is always up to date, especially when switching branches, but it can be a bit too much for some use cases.

In v2.1, we're introducing another common toolchain setting called installDependencies that allows you to disable this feature. When set to false, toolchains will not automatically install dependencies before running a task.

.moon/toolchains.yml
python:
installDependencies: false

Not all toolchains support this tier 2 feature.

New task affectedFiles settings

In v2 we introduced an object form for the the task option affectedFiles, allowing you to further customize this feature. Based on feedback from the community, we're introducing 3 new settings to this object:

  • filter - A list of glob patterns to filter the affected files list before passing to the task.
  • ignoreProjectBoundary - When matching affected files, ignore the project boundary and include workspace relative files. Otherwise, only files within the project are matched.
  • passDotWhenNoResults - When there are no affected files after matching and filtering, use . instead of an empty value.
tasks:
lint:
command: 'eslint'
inputs:
- 'src/**/*.{ts,tsx}'
- '**/*.json'
- 'eslint.config.*'
options:
affectedFiles:
filter: ['**/*.tsx?']
ignoreProjectBoundary: true
passDotWhenNoResults: false

Other changes

View the official release for a full list of changes.

  • Improved our local and remote detection logic. We now also check for common remote devboxes (GitHub Codespaces, Gitpod, etc) in addition to CI environments.
  • Added a new task option, runInSyncPhase, that will run the task during moon sync commands.
  • Go
    • Will now run go list --deps to determine project relationships while extending the project graph.
  • Python
    • Normalized package/dependency names to PEP 503 during graph extending.
    • Fixed an issue where package manager toolchain settings were not being inherited correctly.
  • TypeScript
    • Added a pruneProjectReferences setting that prunes non-moon managed project references when syncing.