npm / cli

the package manager for JavaScript
https://docs.npmjs.com/cli/
Other
8.2k stars 2.99k forks source link

[BUG] npx opening the PowerShell script with the default editor instead of executing it. #3843

Open akunaatrium opened 2 years ago

akunaatrium commented 2 years ago

Is there an existing issue for this?

Current Behavior

I created a package containing a bunch of PowerShell scripts. In the package.json file of the package, there's such a block:

"bin": {
    "say-hello": "./hello.ps1"
}

The package is pushed to an npm registry.

In another location, I want to use the package and have a very simple way to be able to execute scripts from the package, let's say the hello.ps1 that is defined as a binary in the package. So, when I installed the package using another package.json file like this:

{
  "name": "blaa",
  "private": true,
  "version": "1.0.0",
  "devDependencies": {
    "tooling": "0.0.11"
  }
}

where tooling is the name of the package to be installed, the node_modules/.bin folder gets populated with three files:

Now, using PowerShell in the same folder where the package.json resides, I execute npx say-hello but I get:

This program is blocked by group policy. For more information, contact your system administrator.

The computer is corporate managed and enforces a lot of policies. Looks like the say-hello.cmd file was attempted to be executed but failed. I know that I can execute PowerShell scripts. Why is npx defaulting to run the .cmd file if it can detect that the shell is PowerShell? Is it possible to configure npm/npx to execute the .ps1 file instead? Trying to run npx say-hello.ps1 command opens the script in Notepad++ in my case, instead of executing it.

Expected Behavior

npx should understand that PowerShell is the current shell and executes the say-hello.ps1 file. Or at least executes it when specifying the extension of the file, like in this command: npx say-hello.ps1. If this is not possible, then there should be a configurable option in a .npmrc or package.json to specify which shell must be used to execute scripts.

Steps To Reproduce

No response

Environment

BinToss commented 2 years ago

Trying to run npx say-hello.ps1 command opens the script in Notepad++ in my case, instead of executing it. npx say-hello.ps1 is processed by a Command Prompt terminal inside the current terminal shell. The command is then processed by the Windows shell, meaning that it will run with with the file type/extensions's Open shell command. In your case, it seems the Open shell command (in either the user namespace or the system namespace) uses the following command or something like it: notepad++.exe %1. Check in the Registry at HKCR\Microsoft.PowerShellModule.1\Shell\Open\Command and HKCU\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell\Open\Command for the current file extension app association.

Sometimes, executing a file via the OS shell is desired behavior, though it does invite issues like this in which the file type's associated app isn't what was expected.


npx should understand that PowerShell is the current shell and executes the say-hello.ps1 file. Or at least executes it when specifying the extension of the file, like in this command: npx say-hello.ps1.

I agree that it would be helpful if npx were be aware of its current context in relation to file association, but how will it know when a .ps1 file should be executed with powershell.exe instead of pwsh.exe? In the same line of logic, how would it know to execute a .sh script with BASH instead of ZSH or a similar terminal shell?

The preferred solution is as you suggested: add the ability to specify which shell to use. Better yet, failover to another shell if the current shell encounters an exception. The former is partly implemented via npx's command line (i.e. npx pwsh hello-world.ps1), but this does not cater to cross-platform reproducibility. The latter does not require NPM to be changed. A script in your package.json should suffice if NPX can catch exceptions or process If-Then script blocks. However, this workaround would be a pain to maintain across multiple repositories that depend on your package's app.


In the first place, the real issue that your organization requires the usage of shell scripts, yet it prohibits the use of shell scripts its products depend on.

nlf commented 2 years ago

if your script-shell setting is still cmd (which is the default) then this problem makes some sense, you might try something like npm config set script-shell pwsh --location=user and then retry running the script.

we do not attempt to run in the same shell the user is already running, rather we default to sh in posix systems and cmd in windows. if you want something else you'll have to set it explicitly.

let me know if that takes care of the issue for you

OmgImAlexis commented 2 years ago

I don't understand the point of npm generating the extra files like .cmd and .ps1 if it always uses the .cmd?

Or am I missing something here?

nlf commented 2 years ago

it doesn't always use cmd it uses it by default. you are always free to tell npm to run under whatever shell you want it to. in addition to that, the extra files let globally installed packages work more consistently. just because you did an npm i -g foo in cmd doesn't mean you don't want to be able to run that package's binaries from pwsh or even bash.

from your original post:

If this is not possible, then there should be a configurable option in a .npmrc or package.json to specify which shell must be used to execute scripts.

this is the script-shell option, and why i suggested using it.

fwiw i do agree with you that it would be better if we tried to reuse the same shell you're currently in, however that would be an enormous breaking change and not something we can do lightly (like we're at least 2 semver-major releases away from making that the default)

zachleat commented 1 year ago

Stumbled into this one today per https://github.com/11ty/eleventy/issues/2875. I would say it is quite confusing (for me personally) that with our bin value pointing eleventy to cmd.js would also execute eleventy.js from the npx @11ty/eleventy command. That seems bug-ish to me.