Skip to main content

moon v1.0 - Official release! Project constraints, tagging, and more!

ยท 5 min read
Miles Johnson

๐ŸŽ‰ It's finally here! After almost a year of development, a handful of breaking changes, we've officially reached a stable v1 of moon! This release is feature packed with quality of life improvements.

The road to v1โ€‹

It's been 10 months since moon launched publicly, and since that time we have landed 501 pull requests, fixed 100's of bugs, made 16 breaking changes, released 26 versions, and have been used by companies like Ikea, SumUp, Depot, and Gallery. It's been a wild ride, and we're excited to finally reach a stable v1 release.

Project boundaries with constraintsโ€‹

One feature that moon has not supported, but is critical for large monorepos, is project boundaries. A project boundary is a concept that enforces a strict relationship between projects, and is a common pattern in monorepos. For example, a project may only be allowed to depend on projects with a specific tag, or a project of a specific type.

moon now supports this functionality through the new constraints setting in .moon/workspace.yml. The primary constraint we're introducing is enforceProjectTypeRelationships, which enforces relationships between projects based on their type field.

For example, an application can only depend on library or tool based projects, but not other applications (this is a code smell). This setting is enabled by default!

.moon/workspace.yml
constraints:
enforceProjectTypeRelationships: true

And that's not all, continue reading for more information on tag based constraints!

Project taggingโ€‹

Everyone is familiar with the concept of tagging, and moon's implementation is no different. Tags are a simple mechanism for categorizing projects, and can be defined through the tags setting in moon.yml.

moon.yml
tags:
- 'react'
- 'prisma'

Tags can be used to group projects together for easier querying, enforcing of project boundaries, applying constraints, and more in the future. Tags will become a staple for maintaining repositories at scale. Continue reading for more information!

Querying projects by tagโ€‹

The first integration with tags is project querying. You can now query for projects by tag using the new --tags option in the moon query projects command. For example, say you want to find all projects that are tagged with vue or trpc:

$ moon query projects --tags 'vue|trpc'

Enforce relationships with tagsโ€‹

Another feature of tags is enforcing relationships between projects using our new constraints setting. When a tagged constraint is defined, it requires all dependencies of a tagged project to require 1 of the configured tags, otherwise an error is thrown during project graph creation.

To demonstrate this, take the following configuration:

.moon/workspace.yml
constraints:
tagRelationships:
next: ['react', 'trpc']

This dictates that all dependencies of a project with the next tag, must declare either react, trpc, or next in their own tags. This is great for crafting a monorepo with strict project boundaries!

Shells for system tasksโ€‹

Up until now, all executed tasks would not be wrapped in a shell for 1 reason, to ensure tasks are deterministic. A major goal for moon is that tasks are deterministic and easily reproducible across all machines. Shells break this guarantee, as they can introduce subtle bugs that are difficult to diagnose, and may differ wildly between developers and machines.

However in practice, not supporting shells has been a major pain point for many users, and for the most part, most system tasks typically run common commands or execute pre-defined scripts. The chance of a non-deterministic build is very small. As such, we've decided to make a compromise, and allow shells for system tasks, but not for language based tasks.

For example, the following tasks:

moon.yml
tasks:
example:
command: 'echo $PWD'
platform: 'system'
global:
command: 'bin-on-path'
platform: 'system'

Would now be executed as /bin/sh -c 'echo $PWD' and /bin/sh -c 'bin-on-path' on Unix platforms respectively. On Windows, we execute tasks with pwsh.exe -c and pass arguments via stdin.

We're also taking this a step further, by introducing a new task option called shell, that can be used to toggle the shell wrapping on or off. When turned off, this allows you to customize and execute the shell as you please.

moon.yml
tasks:
example:
command: 'bash -c "echo $PWD"'
platform: 'system'
options:
shell: false

Environment variable substitutionโ€‹

moon supports granular environment variables through the project-level env setting, task-level env setting, and the task envFile option. We're expanding their functionality with variable substitution, allowing the value of another environment variable to be interpolated using the syntax ${VAR_NAME}. This is especially useful for composing complex environment variables.

moon.yml
tasks:
dev:
command: 'app start'
env:
APP_TARGET: '${REGION}-${ENVIRONMENT}'

The same substitution syntax can also be used within .env files.

.env
APP_TARGET="${REGION}-${ENVIRONMENT}"

Date/time token variablesโ€‹

Tokens are a mechanism used in task configuration for dynamically injecting values from the current project or task, especially when task inheritance is involved. Tokens have existed since moon's inception, without much change... until now.

We're excited to introduce a new set of tokens for referencing the current date or time: $date, $time, $datetime, and $timestamp. With these new tokens, you're now able to implement clever or unusual solutions, like grouping builds or deploys based on the current timestamp.

moon.yml
tasks:
deploy:
command: 'app deploy --output ./build/$timestamp'

Other changesโ€‹

View the official release for a full list of changes.

  • Added a hasher.warnOnMissingInputs setting to .moon/workspace.yml.
  • Added a $projectAlias task token.
  • Added a telemetry setting to .moon/workspace.yml.
  • Updated the new version check to only run on the check, ci, run, and sync commands.

What's next?โ€‹

Expect the following in the v1.1 release!

  • Polish and stability initiatives.
  • Task inheritance based on tags.
  • Deno tier 3 support.