moon
moon copied to clipboard
[feature] Run code block / multiple commands for a task
Is your feature request related to a problem? Please describe.
It's not convenient to run a code block in tasks currently, which is quite common if we want moon to be "language agnostic and easily pluggable in the future."
Describe the solution you'd like
Add running code block support for tasks, like
tasks:
build:
shell: bash # It will be better if we can change to other shells, support syntax like `['bash', '-c']` or `bash -c`
load-dotenv: true # load a `.env` file automatically for the following code block
run: | # Writing multi-line commands for better readability
npm ci
npm run build
echo 'Done'
REF: https://docs.github.com/en/github-ae@latest/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
Describe alternatives you've considered
Additional context
@hustcer This is something that won't happen for a while, as it's quite a drastic change from how things work, for the following reasons:
-
A task is more akin to a singular unit of work, and as such, is represented by a single command and its unique arguments. Think of it like a function that accepts inputs and will always return the same output(s). Running a block of commands may produce side-effects. This leads to the next point...
-
Multiline or multiple commands are better represented with task chains through the
depsoption (https://moonrepo.dev/docs/config/project#deps), as this allows for incremental caching at every layer in the chain. It's a bit more verbose, but provides more out of the box functionality in the end. So in your example, you may have something like:tasks: clean: command: '...' build: command: 'npm' args: 'run build' deps: ['~:clean']Also, the
npm ciin your example is not necessary, because in moon you never need to do that, as it will automatically install node modules when applicable. -
Since this is written in Rust and not Node.js, we don't have access to
require,require.resolve, thechild_processorexecamodules, or the entire Node.js module resolution algorithm. We implement it ourselves around our toolchain abstraction (https://moonrepo.dev/docs/concepts/toolchain).Because of this, we need to know which binary you are running (the
commandfield) and how to find it (thetypefield). With this information, we traverse the file system. Iftypeis "node", we recursively traverse upwards and look withinnode_modules/.binand resolve a path to the npm binary to run. If thetypeis "system", we currently assume it exists in$PATH. Multi-commands make this much more difficult. -
Also because this is Rust, there's no concept of a "shell" (excluding some processes in Windows that use cmd.exe). In Node.js, the
child_processmodule emulates this functionality for you. With a task, you simple do it yourself:tasks: build: command: 'bash' args: '-c scripts/build.sh' type: 'system' -
As for
.envsupport, this will land at somepoint in the future. In the meantime, you can use theenvfield itself. https://moonrepo.dev/docs/config/project#env
With all that being said, I'll leave this open to gauge feedback.
Got it, thanks for your reply
@hustcer It may not be apparent from my previous post, but you could always run multiple commands by encapsulating them within a runnable script. This is kind of an escape hatch.
tasks:
build:
command: 'node'
args: './script.js'
# Or bash
build:
command: 'bash'
args: './script.sh'
type: 'system'
Tasks now support .env files: https://moonrepo.dev/docs/config/project#envfile
System tasks now support shells in v1. I'm going to close this as we won't support multi-commands in a single task.