husky: Cannot execute precommit hook if triggered inside `yarn run` or `npm run`

Do you want to request a feature or report a bug?

Husky cannot execute precommit hook in yarn run <script>, because nvm cannot load correctly.

What is the current behavior?

Yarn cannot run this script:

yarn run release --prerelease
yarn run v1.3.2
$ standard-version --prerelease
✔ bumping version in package.json from 2.0.1 to 2.0.2-0
✔ outputting changes to CHANGELOG.md
✔ committing package.json and CHANGELOG.md
nvm is not compatible with the "PREFIX" environment variable: currently set to "/usr/local"
Run `unset PREFIX` to unset it.
.git/hooks/pre-commit: line 49: node: command not found
husky > npm run -s precommit (node )

env: node: No such file or directory

husky > pre-commit hook failed (add --no-verify to bypass)

Command failed: git commit CHANGELOG.md package.json -m "chore(release): 2.0.2-0"
nvm is not compatible with the "PREFIX" environment variable: currently set to "/usr/local"
Run `unset PREFIX` to unset it.
.git/hooks/pre-commit: line 49: node: command not found
husky > npm run -s precommit (node )

env: node: No such file or directory

husky > pre-commit hook failed (add --no-verify to bypass)

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

But npm can:

npm run release -- --pre-release

> xxd-backend@2.0.0-alpha.1 release /Users/linkeo/Projects/service/xxd-backend
> standard-version "--pre-release"

✔ bumping version in package.json from 2.0.0-alpha.1 to 2.0.0
✔ outputting changes to CHANGELOG.md
✔ committing package.json and CHANGELOG.md
husky > npm run -s precommit (node v8.9.1)

yarn run v1.3.2
$ bash bin/_internal/lint.sh
 - Lint using eslint (incremental scan)
 - Code not changed, linting is skipped.
Done in 0.27s.
husky > npm run -s commitmsg (node v8.9.1)

⧗   input: chore(release): 2.0.0
✔   found 0 problems, 0 warnings


✔ tagging release 2.0.0
ℹ Run `git push --follow-tags origin master; npm publish` to publish

Because PREFIX is mentioned above, I run these commands to check env:

yarn run debug # env
npm run debug # env

Comparing the results, I notice yarn add PREFIX=/local/bin in yarn run <script> command.

So nvm cannot be correctly loaded in this environment.

If the current behavior is a bug, please provide the steps to reproduce.

My project is using standard-version to auto-generate CHANGELOG.md, and husky to check code style(eslint) or commit message(commitlint) during commiting.

So you can quickly reproduce by:

Execute:

mkdir test && cd test
touch package.json index.js .gitignore

Edit package.json

{
  "name": "test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "commitlint": "^4.3.0",
    "eslint": "^4.11.0",
    "husky": "^0.14.3",
    "standard-version": "^4.2.0"
  },
  "scripts": {
    "release": "standard-version",
    "precommit": "eslint .",
    "commitmsg": "commitlint -e $GIT_PARAMS",
    "debug": "env | grep PREFIX"
  }
}

Edit index.js

This cannot be passed by eslint.

Edit .gitignore

node_modules

Execute:

git init
git add .
git commit -m 'init'
yarn
yarn run release

Then you will get the error above.

What is the expected behavior?

husky git hooks should correctly executed even triggered by yarn run <script> commands.

Please mention your node.js, yarn and operating system version. OS: macOS Sierra 10.12.6 nvm: v0.33.6 yarn: v1.3.2 node: v8.9.1 (managed by nvm) npm: 5.5.1

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 16
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

@leohxj That don’t solve my problem.

And I’m facing a new problem… It seems if git commit is happened inside a npm script, husky hooks cannot work fine because ‘nvm is not compatible with the “npm_config_prefix” environment variable’, and npm run <script-name> will set “npm_config_*” environment itself…

I can reproduce this problem inside docker:

docker pull ubuntu
docker run -it ubuntu
# inside docker image now
apt-get update; apt-get install -y git vim wget
# install nvm, official install script in github repo.
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
source ~/.bashrc
nvm install 8
mkdir test; cd test
npm init -y
git init
# edit package.json
# add script: "git-commit": "git add . && git commit -m \"npm run git-commit\""
# add script: "precommit": "echo \"precommit hook: running script\""
npm install -S husky
npm run git-commit
# script finished successfully, but with these output:
# ```
# nvm is not compatible with the "npm_config_prefix" environment variable: currently set to "/root/.nvm/versions/node/v8.9.4"
# Run `unset npm_config_prefix` to unset it.
# husky > can't find npm in PATH, skipping precommit script in package.json
# ```
# The precommit script is skipped...

Actually, I’m using standard-version to manage my package versions (run npm run release to release an new version). This script will commit changes to git repo, then husky’s precommit hook will be triggered with environment variables inside the npm script.

I can’t see the solution to this problem by myself by now.

A possible solution with husky is: Check if the git hook is executed inside an npm script, if so, do not load nvm. Reason: Since git commit is happened inside the npm run, some version of node/npm is used already, so there is no need to load nvm again in git hook.

yarn add husky@next --dev gives this error:

internal/modules/cjs/loader.js:596
    throw err;
    ^

Error: Cannot find module 'please-upgrade-node'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:594:15)
    at Function.Module._load (internal/modules/cjs/loader.js:520:25)
    at Module.require (internal/modules/cjs/loader.js:650:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/roland/dev/billy/public/vendor/husky/husky.js:1:89)
    at Module._compile (internal/modules/cjs/loader.js:702:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)

macOS 10.13.5, yarn 1.7.0, npm 6.1.0

I’d suggest trying with husky@next as the code has changed quite a lot since this issue.

yarn add husky@next --dev # should install 1.0.0-rc.10

Let me know if you still doesn’t work.

That worked!

Toms-MacBook-Pro-2:tshape tommedema$ yarn add husky@next --dev
yarn add v1.7.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 24 new dependencies.
info Direct dependencies
└─ husky@1.0.0-rc.11
info All dependencies
├─ builtin-modules@1.1.1
├─ get-stdin@6.0.0
├─ graceful-fs@4.1.11
├─ hosted-git-info@2.6.1
├─ husky@1.0.0-rc.11
├─ is-builtin-module@1.0.0
├─ is-ci@1.1.0
├─ load-json-file@4.0.0
├─ locate-path@2.0.0
├─ normalize-package-data@2.4.0
├─ p-limit@1.3.0
├─ p-locate@2.0.0
├─ p-try@1.0.0
├─ path-exists@3.0.0
├─ path-type@3.0.0
├─ pkg-dir@2.0.0
├─ read-pkg@3.0.0
├─ run-node@1.0.0
├─ semver@5.5.0
├─ slash@2.0.0
├─ spdx-correct@3.0.0
├─ spdx-exceptions@2.1.0
├─ strip-bom@3.0.0
└─ validate-npm-package-license@3.0.3
✨  Done in 3.17s.
Toms-MacBook-Pro-2:tshape tommedema$

Toms-MacBook-Pro-2:tshape tommedema$ cat .git/hooks/pre-commit
#!/bin/sh
# husky
# v1.0.0-rc.11 darwin

scriptPath="node_modules/husky/lib/runner/bin.js"
hookName=`basename "$0"`
gitParams="$*"

if [ -f $scriptPath ]; then
  node_modules/run-node/run-node $scriptPath $hookName "$gitParams"
else
  echo "Can't find husky, skipping $hookName hook"
  echo "You can reinstall it using 'npm install husky --save-dev' or delete this hook"
fi
Toms-MacBook-Pro-2:tshape tommedema$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   package.json
        modified:   yarn.lock

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        package-lock.json

no changes added to commit (use "git add" and/or "git commit -a")
Toms-MacBook-Pro-2:tshape tommedema$ git add -A
Toms-MacBook-Pro-2:tshape tommedema$ git commit -m "new husky"

Warning: Setting pre-commit script in package.json > scripts will be deprecated in v1.0
Please move it to husky.hooks in package.json, a .huskyrc file, or a husky.config.js file
Or run ./node_modules/.bin/husky-upgrade for automatic update

See https://github.com/typicode/husky for usage

husky > pre-commit (node v8.11.3)
 ↓ Running tasks for *.ts [skipped]
   → No staged files match *.ts
[master fe5be39] new husky
 3 files changed, 2178 insertions(+), 15 deletions(-)
 create mode 100644 package-lock.json

yarn add husky@next --dev

solve the problems

rm -rf node_modules/ yarn clean cache and yarn install won’t work

Hi @mrextreme,

I’m not reproducing, I would try running yarn remove husky && yarn add husky@next --dev, just to ensure that all husky’s dependencies get installed correctly.

If it doesn’t work, I’d try removing node_modules and running yarn again.

I tried to edit .git/hooks/pre-commit inside my project, change line 34 and 37:

# nvm path with standard installation
- load_nvm /Users/linkeo/.nvm
+ PREFIX="" load_nvm /Users/linkeo/.nvm

# nvm path installed with Brew
- load_nvm /usr/local/opt/nvm
+ PREFIX="" load_nvm /usr/local/opt/nvm 

Then it works.

But I’m not sure which is the better solution:

  1. yarn should keep the environment of script clean, the same as the environment executing yarn run.
  2. when husky loading nvm, ensure the environment is compatible with nvm (like what I do).