-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow interactive commands through @nrwl/workspace:run-commands #8269
Comments
@JakeGinnivan I think it should be straightforward and just come down to patching in a stdio-forwarding mode to the If you look there you'll see it uses For the purpose you describe, this would probably be achievable by just adding a mode that uses |
For the moment I have just created my own executor in tools.
Happy to dig in, but a few of my other PRs have been closed with please discuss with the team the solution first. So now I don't invest my time into contributing without getting acknowledgement from the team about the solution |
I ran into this issue. In my case, I need to run the command inside a docker container so the environment has access to mongodb/etc.
When I run the For now I just have bash file that runs the watch command as presented above, but it would be nice to have interactivity when using @nrwl/workspace:run-commands, or a similar command that supported interactivity. |
@JakeGinnivan that makes a lot of sense, execa is a nice library. I'm pretty new to the nx community so that's a little disappointing that they treat PRs that way, but maintaining open source is a lot of work, just like contributing to open source, so I get it 🤷 In this case I do think there's totally room for the wrapper you built to be turned into a plugin that provides that executor. It wouldn't need to be merged with the core nx project that way... Let me know if that's something you're interested in doing and I'll see if I can help out! |
Yeah, that is my end goal. I actually don't use many of the core NX plugins because I use TypeScript project references, vitest and vite a lot. Time is the main blocker for getting things up and running. |
👍 to this issue. Thank you @JakeGinnivan for reporting and providing some workarounds! Adding another use case and a bug this is causing:
|
Wanting to confirm that the workaround (quoted below) from @JakeGinnivan is a perfect solve to my above issues. Additionally, wanted to add a couple of tweaks/notes that would help others in the future using this executor:
|
@JakeGinnivan For single command runs, or serial command runs, does this not already work? I.e. changing to use "command" instead of "commands", or adding "parallel: false" to your target. When running in parallel forwarding stdin doesn't make much sense, but in serial its doable (and the default behavior) |
@AgentEnder I don't think that's necessarily true. The nx/packages/workspace/src/executors/run-commands/run-commands.impl.ts Lines 212 to 219 in efedd2e
I tested a fork of this implementation and switched the stdio settings to:
which has yielded a working result. |
@AgentEnder It does not. My example above uses a single command and it does not work. |
Anyone know why when trying to run this executor I'm getting this common error:
I mean normally u can fix this by adding for example |
You probably need to ensure tslib is installed correctly. Also what command are you running that's producing the error? |
I'm trying to run |
I made it work by building the ts file and running the js file. Also changed it a bit so u can run multiple commands:
schema.json
|
@robbesettlemint make sure you install execa@^5 rather than the latest. https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c latest version is ESM only |
Hi @JakeGinnivan, thank you so much for your workaround. Regarding this, what are your thoughts about nx lifecycles? It seems the actual packages/nx/src/tasks-runner/life-cycles/dynamic-run-one-terminal-output-life-cycle.ts const clearDependentTargets = () => {
for (let i = 0; i < dependentTargetsNumLines; i++) {
readline.moveCursor(process.stdout, 0, -1);
readline.clearLine(process.stdout, 0);
}
}; It seems these life cycles are not designed for this interactive approach, in my case I can successfully pipe stdio, but my output is cleared providing a poor experience. I'm not an expert of the project but it seems nx@13 introduced some sort of life cycle API (I could not find any docs), so maybe there's still hope to deal with this in any way. Edit: nvm, It seems |
@Coly010, thanks for linking that fix! I created a simple run-interactive-command executor and added "outputCapture": "direct-nodejs" in schema.json. Then, I was able to use execSync from child_process (instead of execa), like so: execSync(command, {
cwd: options.cwd,
stdio: ['inherit', 'inherit', 'inherit'],
}) |
+1 to fixing this in main. Appreciate the provided workarounds, but Nx should provide a command runner that does not swallow interactive output. |
Adding |
Would be great to have a |
I have a workaround for this.
"deploy": {
"executor": "nx:run-script",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"cwd": "packages/hologram-bos",
"script": "bos:deploy"
}
}, and id my script: "scripts": {
"bos:deploy": "bos components deploy"
} |
The interactive commands were working until we updated from Nx 15.4.5 to 16.0.0. I think this change might have broken it by removing the child process being created with inherited stdio. Adding this line to process.stdin.pipe(childProcess.stdin); |
thanks @JakeGinnivan for the nice solution! I'm using this to run The only thing I find now is that when I want to bring down the cluster via CTRL+C, the NX process group is killed while docker-compose is still coming down, leading to some dangling log lines after control has been returned to the terminal Does anyone know how this could be fixed? I've tried using |
This also breaks |
Same issue here, we have a little CLI tool (using |
When I upgraded to NX 16 prisma now thinks it's being run from a non-interactive prompt. See: https://www.prisma.io/docs/concepts/components/prisma-migrate/prisma-migrate-limitations-issues#prisma-migrate-in-non-interactive-environments I've applied this patch hack and input does work in other scripts, but prisma still complains. |
This would become a deal breaker. |
Thanks for solution. I made this gist based on exactly this response for easier copy-paste. |
I couldn't get any of these custom executors solutions to work with nx 16.8. When I wrap a CLI with I've also posted a related question on Stack Overflow. If anybody happens to solve this (or if NX fixes the likely culprit), feel free to answer on SO as well. |
Prisma is a pain to use with NX because of this CLI interactivity issue |
Recommend: nx-prisma |
@JakeGinnivan Good job, your method is feasible, if someone encounters the same problem as me that the last line prompt is missing: you can refer to my code: import { RunInteractiveCommandExecutorSchema } from './schema'
import execa from 'execa'
const sleep = async ms =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, ms)
})
export default async function runExecutor(options: RunInteractiveCommandExecutorSchema) {
console.log('Executing run-interactive-command...')
try {
let isSuccess = true,
isEnd = false
const childProcess = execa.command(`${options.command} ${options._.join(' ')}`, {
cwd: options.cwd,
stdio: [process.stdin, 'pipe', 'pipe']
})
childProcess.stdout?.on('data', data => {
console.log(data.toString())
})
childProcess.stderr?.on('data', data => {
console.error(data.toString())
isSuccess = false
})
childProcess.addListener('exit', () => {
isEnd = true
})
while (!isEnd) {
await sleep(1000)
}
return {
success: isSuccess
}
} catch (error) {
console.error(error)
}
} |
FYI, doesn't work with env vars. |
An important issue, I believe worth mentioning is this Talking about using the cjs version of exa, I needed to install it to make this executor work. For my particular use case I wanted to create this target to interactively use "shell": {
"executor": "./tools/executors/workspace:run-command",
"options": {
"command": "poetry run ipython",
"cwd": "libs/testproject"
}
} but I needed to pass in stdin, stdout, & stderr as so:
resulting in this:
|
Just tested, works as expected! Here is an example:
Thanks @AgentEnder and @FrozenPandaz for getting this resolved! |
Extra Kudos to @Cammisuli to - a lot of this rust stuff is absolutely thanks to him. |
great work @Cammisuli 🎉 was able to remove the manual patch. One thing I noticed is that if I'm interacting with a menu, I need to press up/down a couple of times before it registers. Not sure if perhaps the input is buffering somewhere? |
It does not work when running with |
@mattfysh there shouldn't be any buffering. We send all binary data to the underlying process without doing anything on our side. I just did some changes that affect unix systems that should make it more consistent though. @hco no, it does not work when using |
@Cammisuli I want to run an interactive foreground task, and a supporting background task in parallel. Can nx do that somehow? |
If anyone comes here wondering why it does not work, e.g.: {
"name": "some-cli-tool",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/some-cli-tool/src",
"projectType": "application",
"targets": {
"start": {
"executor": "nx:run-commands",
"options": {
"cwd": "apps/some-cli-tool/src",
"commands": ["ts-node index.ts"],
"parallel": false // this is mandatory
}
}
}
}
|
This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context. |
Description
Sometimes you just want to be able to wrap a CLI tool for a project without using a plugin. For example:
When you run this, sometimes it prompts you
But all I see is
Motivation
There are so many useful CLI tools out there which do not default to --non-interactive (or even have a non-interactive version) and when they prompt you can't actually see what is printed to the console.
Suggested Implementation
I think there are multiple execution layers, i'm not sure how to do this. Given a few pointers I could take a crack.
Alternate Implementations
The text was updated successfully, but these errors were encountered: