How to configure husky when .git is in a different folder? - javascript

I'm trying to set up automatic linting on commit for my company's project, and the best way I've seen to do so has been the husky NPM package. I'm following instructions on setting up Husky with eslint , prettier , and lint-staged but I keep hitting on the same issue that I can't figure out how to resolve.
My problem is that my project is set up like so:
- Parent Directory
- .git
- Working Project Directory
- node_modules
- package.json
When i attempt to install husky, I get an error that I am missing the .git file, however it's there, just one level up in the file structure!!
I have seen some things in other posts about using the following technique to fix it:
npx mrm lint-staged This will fail, that’s expected
Then fix the npm prepare script
"prepare": "husky install" -> "prepare": "cd .. && husky install some-folder/.husky"
Then run npm i
However it doesn't work for me.
I have also attempted to install husky in the parent directory but it doesn't quite work and it makes the install process of our project more difficult
Does anyone have any suggestions?
EDIT: Here is the error message I get:
% npx husky-ini
t && npm install
Need to install the following packages:
husky-init
Ok to proceed? (y) y
husky-init updating package.json
setting prepare script to command "husky install"
/Users/me/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky/lib/index.js:22
throw new Error(`.git can't be found (see ${url})`);
^
Error: .git can't be found (see https://typicode.github.io/husky/#/?id=custom-directory)
at install (/Users/me/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky/lib/index.js:22:15)
at Object.<anonymous> (/Users/me/.npm/_npx/1ab9c0f68ac2536e/node_modules/husky-init/lib/bin.js:16:21)

By default, husky assumes that your project's package.json file is at the same level as the .git file.
In your case, as you say, they are at different levels.
To fix this, you should modify the package.json file.
Even though you have this error
Error(`.git can't be found (see ${url})`);)
you should have this inside the script
"scripts": {
...
"prepare": "husky install"
...
}
You should replaceit by:
"scripts": {
...
"prepare": "cd .. && husky install [child-folder]/.husky"
...
}
EXAMPLE:
parent-folder
.git
project-folder
node_modules
package.json
SOLUTION
"scripts": {
...
"prepare": "cd .. && husky install project-folder/.husky"
...
}

Related

How to setup lint-staged for Vue projects?

I created a new Vue3 app using the Vue CLI and selected Prettier for my linter config. I want to use commitlint, husky and lint-staged to validate commit messages and lint the code before pushing it.
What I did
Based on https://commitlint.js.org/#/guides-local-setup I setup commitlint with husky
npm install --save-dev #commitlint/{cli,config-conventional}
echo "module.exports = { extends: ['#commitlint/config-conventional'] };" > commitlint.config.js
npm install husky --save-dev
npx husky install
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
Based on https://github.com/okonet/lint-staged#installation-and-setup I setup lint-staged
npx mrm#2 lint-staged
and inside the package.json I replace
"lint-staged": {
"*.js": "eslint --cache --fix"
}
with
"lint-staged": {
"*": "npm run lint"
}
The problem
When modifying the README.md file in the project to
# my-repo
---
new commit
and try to commit that I get the following error message
> git -c user.useConfigOnly=true commit --quiet --allow-empty-message --file -
[STARTED] Preparing...
[SUCCESS] Preparing...
[STARTED] Running tasks...
[STARTED] Running tasks for *
[STARTED] npm run lint
[FAILED] npm run lint [FAILED]
[SUCCESS] Running tasks...
[STARTED] Applying modifications...
[SKIPPED] Skipped because of errors from tasks.
[STARTED] Reverting to original state because of errors...
[SUCCESS] Reverting to original state because of errors...
[STARTED] Cleaning up...
[SUCCESS] Cleaning up...
✖ npm run lint:
> my-repo#0.1.0 lint
> vue-cli-service lint "/home/.../my-repo/README.md"
error: Parsing error: Invalid character at README.md:1:1:
> 1 | # my-repo
| ^
2 |
3 | ---
4 |
1 error found.
npm ERR! code 1
npm ERR! path /home/my-repo
npm ERR! command failed
npm ERR! command sh -c lint-staged
npm ERR! A complete log of this run can be found in:
npm ERR! /home/.../.npm/_logs/2021-12-27T10_07_27_498Z-debug.log
husky - pre-commit hook exited with code 1 (error)
What it should do
Only fix the files that have been modified. The linter knows about files it is able to fix (js, ts, vue, html, ...).
When having a modified markdown file I get no errors when opening the terminal and run npm run lint. But I do get errors when using lint-staged with this setup "*": "npm run lint"
What is the correct setup for lint-staged to lint "lintable" files only?
Update regarding the comments
Other lint-staged syntaxes
I've suggested "**/*.{js,vue}": ["npm run lint:js:fix"], first of, lint:js:fix is subjective and up to you. This is what Kent C Dodds is using, so I'm just naming it in the same way.
But you could totally have lint:watermelon-potato-hehe instead, doesn't matter.
Now, about your propositions:
"**/*.{vue,js,jsx,ts,tsx}": "npm run lint", this one is targeting more extensions, which is totally fine. You may not really use .tsx/.jsx since it's not really popular among Vue devs.
About .ts itself, it may probably work good enough (maybe you'll need to add some plugins to your ESlint configuration). I'm not into TS so I can't really help on this one but it's out of the husky/lint-staged scope anyway.
Last time I started a Vue3 project, I've used Vitesse which has some nice defaults with TS, this may be a good start for you maybe.
As for the second part, since I like to setup my own ESlint config, with some simple and well documented API, we're using eslint --ext .js,.vue --fix. That way I'm sure of what is happening and how to troubleshoot it if needed.
vue-cli-service lint may be a good default package aimed towards Vue with some defaults, I'm not sure what's inside it and even if it's probably just an ESlint with some baked-in configuration, again we prefer to make our own Vue configuration with vanilla ESlint.
So yeah, if you need to go fast, use vue-cli-service lint for some quick linting, if you want to have a better flow in your project and want to fine grain your config, use vanilla ESlint, you'll get less trouble overall IMO.
"**/*.{vue,js,jsx,ts,tsx}": "eslint --ext .vue,.js,.jsx,.ts,.tsx --fix". On the right side, we globally have the same lint:js:fix scripts but with additional extensions.
So, you may ask why are we even writing the extensions on the left side for lint-staged and on the right side for lint:js:fix? I'd answer that those are not really needed on the right side (AFAIK), because lint-staged will only run the command to the left list of extensions.
Here, we wanted to be more explicit about the exact extensions we're targeting and also, it enables you to run npm run lint:js:fix in your CLI at any given point without getting errors on files ESlint is not handling (.txt, .json, .md, .jpg etc...).
So it could maybe be removed (not sure), fastest way to be sure is to try!
"**/*.{vue,js,jsx,ts,tsx}": "eslint --fix", this one may work fine as explained in the previous paragraph. Didn't tried it myself thought.
What about the other extensions?
Regarding .html, you should not have a lot of those in your Vue project. You could use the W3C validator to check for any errors if you really need it.
If you're speaking about your HTML in the template tags in your .vue files, those will be ESlint'ed properly. If you setup a Prettier on top of it, you will also get some nice auto-formatting which is really awesome to work with (once your team has agreed on a .prettierrc config).
Regarding .json files, those are not handled by ESlint. ESlint is only for JavaScript-ish files. If you want to lint/format your .json or even any other extensions at all, you can aim towards NPM, find a package that suits your team's needs and add it to your chain like "**/*.json": ["npm run lint-my-json-please"] and you should be good!
At the end, husky + lint-staged are not doing anything special really. They are tools to automate what you could write yourself in a CLI, so if it's working when done manually and you're happy with the result, you can put it in your config but you need to first found what the proper package and it's configuration.
In your package.json, you could have the following
"scripts": {
"lint:js": "eslint . --ext .js,.vue",
"lint:js:fix": "eslint --ext .js,.vue --fix",
},
In your .lintstagedrc
{
"**/*.{js,vue}": ["npm run lint:js:fix"]
}
In .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint-staged
In .husky/commit-msg
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit ""
You can setup ESlint to watch any errors in your files in VScode (a lint + formatter when your files are saved is also doable pretty easily).
That way, you can run npm run lint:js to check the issues by yourself.
Otherwise, let husky run lint-staged and apply the eslint --fix to all of your .js and .vue files.
Your commitlint.config.js config should be okay!
As a reminder here, lint:js will scan all of your JS and Vue files.
While, when you commit and husky is executed (by running the lint:js:fix script), ONLY the files that you have touched will be linted (that's the whole point of lint-staged).

"npm run dev" Command Doesn't Work - Giving "missing script: dev" error

I was trying to run this SVELT GitHub repo on local server:
https://github.com/fusioncharts/svelte-fusioncharts
I tried to launch it with "npm run dev" command. But I am seeing this error:
npm ERR! missing script: dev
I have tried to fix the issue by setting 'ignore-scripts' to false with this command:
npm config set ignore-scripts false
But it doesn't work.
How can I fix the issue?
npm ERR! missing script: dev means you are there isn't a script having dev. You are likely running on an incorrect directory.
Fusion charts seem to work with svelte codesandbox.
npm ERR! missing script: dev means it cannot find a script called dev inside package.json.
That makes sense!
It looks at the package.json inside the svelte-fusioncharts repo. In that file, there is a scripts property.
Notice how that property looks as follows:
"scripts": {
"build": "rollup -c",
"prepublishOnly": "npm run build"
}
It does not contain a dev script. That’s why it says there’s a missing script. Other commands will work, like npm run build or npm run prepublishOnly.
Md. Ehsanul Haque Kanan,
"scripts": {
"build": "cross-env NODE_ENV=production webpack",
"dev": "webpack-dev-server --content-base public" }
The above is the script from the examples folder in the repo: https://github.com/fusioncharts/svelte-fusioncharts/blob/develop/examples/package.json
You have missed out on the "dev" script in your package.json file.
Please check the "package.json" file in your project and just add the "dev" script as in the repo link and then retry.
Alright. I have fixed the issue. I just go inside examples folder. Then I run the following commands:
npm install
npm run dev
I had the same problem.
It is due to changes in script object in package.json by me. I had installed nodemon and to run the code, I changed the script lifecycle events start and dev in package.json to run the code via nodemon.
But even after installing nodemon, it was not reflecting in devDependencies, so I made manual entry in package.json with its version seeing from package-lock.json.
"devDependencies": {
"nodemon":"^2.0.15"
}
Making this arrangement, my code started as expected.
So, check your recent npm package installation and verify its reflection in devDependencies or dependencies in package.json.

lint-staged not running on precommit

prettier is not running on precommit. This worked with the same configuration in other projects, so I'm baffled why it's not working this time.
This is the relevant section of my package.json file:
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"*.{js,json,css,scss,html,md}": [
"prettier --write",
"git add"
]
},
Edit. Here are the relevant devDependencies:
"devDependencies": {
"husky": "^0.14.3",
"lint-staged": "^7.0.4",
"prettier": "1.12.0"
},
In 2021
Sometimes hooks are not added by husky so you need to add it using a simple easy hack.
You need to uninstall husky first after that install V4 of husky because it ensures that your hooks are correctly installed and after that install the latest version of husky so you get the latest updates.
NPM
npm uninstall husky
npm install -D husky#4
npm install -D husky
YARN
yarn remove husky
yarn add -D husky#4
yarn add -D husky
If sometimes above trick not works, so let's add the hook into husky, below mention method is used only in V6 and I am showing the husky with lint-staged example.
NPM
npm install -D husky
npm set-script prepare "husky install" && npm run prepare
npx husky add .husky/pre-commit "npx lint-staged"
git commit -m "added husky and lint-stagged" // here you will notice the lint-staged checking the files with help of husky
YARN
yarn add -D husky
npm set-script prepare "husky install" && yarn prepare
npx husky add .husky/pre-commit "yarn lint-staged"
git commit -m "added husky and lint-stagged" // here you will notice the lint-staged checking the files with help of husky
I tried so many solutions on here but a combination finally worked!
Make sure Husky v4 is installed. v6 was never triggering for me.
Check the output of git config core.hooksPath. This should not return anything. If it does run,
git config --unset core.hookspath
And FINALLY it worked!
The problem for me was I ran "npx mrm lint-staged" like the official website says but it only set the husky and lint-staged configurations in package.json. It does not add then as dependency or installed them.
The solution for me was:
npm i -D husky lint-staged
npx mrm lint-staged
Reinstalled husky and now seems to be working. Thanks #mpasko256 for your help!
For me the issue was resolved by uninstalling and installing lower version
npm uninstall husky
npm install -D husky#4 //after this it will work
Probably your husky package already in your node_modules before you configured this script. Try to reinstall the hooks, you can run:
npm rebuild
Or if you're using yarn:
npm rebuild --update-binary
It solved my problem.
You are missing dependencies:
npm install --save-dev prettier husky lint-staged
For anyone with this problem and using Husky 5, the hooks aren't automatically installed. So you probably just don't have the required hooks in your .git/hooks folder at all. You need to either add a postinstall to your package.json (recommended), or run npx husky install after you've npm installed the package.
Or just downgrade to Husky 4. You'll actually have to do this, if, like me, you're working on a commercial project and don't want to be a Husky sponsor.
https://dev.to/typicode/what-s-new-in-husky-5-32g5
Wasted hours in figuring out the cause and using the solutions above
Read the documentation and avoid googling:
https://typicode.github.io/husky/#/?id=automatic-recommended
Or follow the steps below:
husky-init is a one-time command to quickly initialize a project with husky.
npx husky-init && npm install # npm
npx husky-init && yarn # Yarn 1
yarn dlx husky-init --yarn2 && yarn # Yarn 2
I think there was something wrong with your package.json.
"scripts":{
...
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm test"
}
},
"lint-staged": {
"*.ts": ["tslint", "prettier --write", "git add"]
}
By the way, after installed husky, just check .git/hooks/pre-commit content. If no husky like word in it, just remove the .git/hooks/pre-commit file and reinstall husky or run npx husky. Because husky will skip modifying the .git/hooks/pre-commit file if it is not GHook alike or PreCommit alike.
You may find it out by following this link.
https://github.com/typicode/husky/blob/master/src/installer/hooks.ts#L58
One alternative is to use pre-commit.
yarn add --dev pre-commit
"scripts":{
...
},
"pre-commit":"lint-staged",
...
This was happening to me and none of these answers helped. So for future reference, it was because I was using npm#7 which looks like it doesn't know how to properly execute husky.
The way I found out it was a problem with husky and npm was because I found out that I had no pre-commit file inside my-project/.git/hooks directory.
When you install husky, it automatically do its magic for you in such folder. So for that, I had to:
Downgrade to npm i -g npm#6
Be sure everything was freshly reinstalled with rm -rf node_modules package-lock.json && npm i (you should see Husky output in the console)
And although it isn't really needed, I executed again npx mrm lint-staged
Finally, it worked.
I solved my problem by adding yarn at the beginning of commands.
(husky v6)
.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint-staged
.husky/commit-msg
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn commitlint -e $HUSKY_GIT_PARAMS
In case it helps someone else: another thing to try is to delete your node_modules folder and rerun npm install
I originally ran npm install in the linux subsystem on my Windows 10 machine. Everything worked fine using git through bash. I received the error after switching over to git in
Powershell. Uninstalling and reinstalling prettier, husky, and lint-staged did not work for me.
I deleted my node_modules folder and reran npm install from the Windows side and now it works.
For windows users, simply do the following in command line/bash:
set HUSKY_DEBUG = 1
or
set HUSKY_DEBUG = true
This solved , my hours of head scratching.
Also see this
For me the problem was that the pre-commit hook was not executable which was easily fixed:
chmod +x .husky/pre-commit
Thanks. this one work for me
npm install -D husky
npm set-script prepare "husky install" && npm run prepare
npx husky add .husky/pre-commit "npx lint-staged"
git commit -m "added husky and lint-stagged"
The problem in my case was that there were some existing hooks and husky does not override them (more info here).
Just putting it here in case someone else runs into the same issue.
The git add command is no longer required in the lint-stage v10 onwards. It is automatically inserted to the commit as the docs describe it:
From v10.0.0 onwards any new modifications to originally staged files will be automatically added to the commit. If your task previously contained a git add step, please remove this. The automatic behaviour ensures there are less race-conditions, since trying to run multiple git operations at the same time usually results in an error.
https://github.com/okonet/lint-staged#configuration
To follow #typicode's message here:
I suspect it's because npm run modifies PATH to include node_modules/.bin. On the other side, when hook commands are run PATH isn't modified.
If you change your .husky/pre-commit to include this path, it works with husky#latest:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
node_modules/.bin/lint-staged
I had the same problem, but I did this mistake.
I have added lint-staged object inside husky object, but later realized I need to add lint-staged key-value pairs as direct key-value pairs in package.json
"lint-staged": {
"*.{js,json,css,scss,html,md}": [
"prettier --write",
"git add"
]
Please pay attention to the node version you are using. Husky requires node >= 10 and lint-staged requires node >= 10.13
Make sure you installed husky
add the below scripts to package.json script
"prepare": "husky install && npx husky add .husky/pre-commit \"npm run lint-fix\"",
"lint": "eslint ./",
"lint-fix": "eslint ./ --fix"
you scripts will be looking something like this
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"prepare": "husky install && npx husky add .husky/pre-commit \"npm run lint-fix\"",
"lint": "eslint ./",
"lint-fix": "eslint ./ --fix",
"format": "prettier --write \"**/*.{js,jsx,json,md}\""
},
run the following command
npm run prepare
this script will create a .husky folder to your working directory and adds pre-commit file to it with script npm run lint-fix to it.
congrats ... now you can commit your files and see precommit checks your eslint error if any
you can add below line to your .git ignore file
/.husky
you can also use pre-commit library. You don't have to configure any thing, It works like charm.
How to use ⬇️
{
"name": "437464d0899504fb6b7b",
"version": "0.0.0",
"description": "ERROR: No README.md file found!",
"main": "index.js",
"scripts": {
"test": "echo \"Error: I SHOULD FAIL LOLOLOLOLOL \" && exit 1",
"foo": "echo \"fooo\" && exit 0",
"bar": "echo \"bar\" && exit 0"
},
"pre-commit": [
"foo",
"bar",
"test"
]
}
If you are using the latest husky version, make sure to install the hook after you add it. In husky 4, this was done automatically.
npx husky add .husky/pre-commit "lint-staged; git add ."
husky install .husky
This solved issue for me.
Breaking changes
Be aware that there were breaking changes in the 5x > version.
If you're struggling to get it working, here's how I got Husky(v6) working with lint-staged.
Assuming that you already have it installed otherwise skip to step number 3.
1 - yarn remove husky
2 - yarn add -D husky
3 - husky install
4 - husky add .husky/pre-commit "pre-comit"
5 - chmod a+x .husky/pre-commit
6 - In the package.json add the following script "pre-commit": "lint-staged"
7 - Add your lint-staged configuration e.g
...
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
"prettier --write"
]
}
...
I have the same problem for another reason. Just had the HKEY_CURRENT_USER \ Software \ Microsoft \ Command Processor \ AutoRun set to cd \python. After deleting this "AutoRun", lint-staged is running on precommit without any errors.

How Do I Run Prettier Only on Files That I Want to Commit?

Using Husky, I've set up my package.json with a precommit hook so that my JavaScript code is formatted using Prettier before every commit:
{
"name": "prettier-demo",
"scripts": {
"precommit": "prettier --write **/*.js && git add ."
},
"devDependencies": {
"husky": "^0.14.3",
"prettier": "^1.8.2"
}
}
This works fine, but there are two drawbacks:
If I have a large project with thousands of JavaScript files, I have to wait for Prettier to process all of them, even if only a few have changed; this can take very long and gets on my nerves quickly when it is done with every commit
Sometimes I want to stage just a couple of files for committing, leaving other changes out of the commit; because I do a git add . after running Prettier, all my changes will always end up in the commit
How can I run Prettier before every commit only on the files that have been staged, ignoring unstaged or unchanged files?
You can do that using lint-staged:
Linting makes more sense when running before committing your code. By doing that you can ensure no errors are going into repository and enforce code style. But running a lint process on a whole project is slow and linting results can be irrelevant. Ultimately you only want to lint files that will be committed.
This project contains a script that will run arbitrary npm and shell tasks with a list of staged files as an argument, filtered by a specified glob pattern.
Install lint-staged and husky, which is required for pre-commit hooks, with this command:
npm install --save-dev lint-staged husky
Change your package.json as follows:
{
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"*.js": [
"prettier --write",
"git add"
]
}
}
I found that just running:
prettier --write $(git diff --name-only --diff-filter d | grep '\.js$' | xargs)
was quite enough for my needs, just made an alias and used that.
If you don't want to add the devDependency lint-staged you can also do the same with a Bash script:
#!/usr/bin/env bash
# chmod +x this and save in your PATH. Assumes `prettier` is in your `devDependencies` already
BASE=$(git merge-base master HEAD) # change master to whatever your trunk branch is
FILES=$(git diff --name-only $BASE HEAD | xargs)
npx prettier --list-different $FILES
# Want eslint too?
# npx eslint --ignore-path=.prettierignore $FILES
I use this package pretty-quick
add add a script in my package.json
"pretty-quick": "pretty-quick"
under scripts {}
Then in my pre-commit hook under .husky/pre-commit
I add
npm run pretty-quick
The prettier docs has a section on this.
I use pretty-quick
npx husky-init
npm install --save-dev pretty-quick
npx husky set .husky/pre-commit "npx pretty-quick --staged"

git hooks pre-push is not working

Inside git hook folder, I have pre push file inside it i am running "npm run coverage" i.e. command for unit test coverage.
git-hook > pre-push > npm run coverage
but it is not working, can somebody please help me.
Check if its name is precisely pre-push (not pre-push.sh, not pre-push.py, precisely pre-push, with no file extension).
Check if it's in .git/hooks/. If you have set core.hooksPath=xxx in the config, make sure it's under the directory xxx.
Check if it's executable.
Check if the user that runs pre-push also has the permission to run npm run coverage.
check .git/hooks. If it's empty try to uninstall husky and install again. my sh history
ls .git/hooks
npm uninstall husky
npm i husky -D
ls .git/hooks
it helped me
for your short description,I can't locate the reason. But you can tryhusky or ghooks.
husky or ghooks provide git hooks,such as precommit,prepush:
//husky
{
"scripts": {
"precommit": "npm test",
"prepush": "npm run coverage",
"...": "..."
}
}

Categories