husky: Husky setting wrong folder in monorepo (lerna/yarn workspace)
Today I’ve noticed that Husky hooks suddenly stopped working in a monorepo. After investigating I’ve found out that file husky.local.sh
inside .git\hooks
had an entry on last line cd "packages/shared/"
. After removing this line Husky hooks started to work again.
My folder structure is like: root: -package.json (with Husky hooks setup) -.git –packages —shared -----package.json —web ------package.json
Could this happen when I ran yarn add/install
or lerna clean && lerna bootstrap
from a sub-directory? Is Husky aware of lerna/yarn workspaces? One solution to always use the right directory would be to check package.json for husky
key.
OS: Windows 10 Terminal: webstorm, CMD, cygwin Since issue was pinpointed I’m not including command’s outputs.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 41
- Comments: 34 (2 by maintainers)
Commits related to this issue
- :bug: (.git/hooks/husky.local.sh) Fixing pre-commit hook not running post install script was set to all workspaces to reset husky.local.sh -> see https://github.com/typicode/husky/issues/677 — committed to flaves/peintagone by deleted user 3 years ago
- chore: Update to storybook 6.3.1 Fixes: #3000 Fixes: #3011 Disabled react-scripts preflight check Also downgraded husky to 4.2.3 as v6 has an issue with monorepo - https://github.com/typicode/husky/i... — committed to igarashitm/atlasmap by igarashitm 3 years ago
- chore: Update to storybook 6.3.1 Fixes: #3000 Fixes: #3011 Disabled react-scripts preflight check Also downgraded husky to 4.2.3 as v6 has an issue with monorepo - https://github.com/typicode/husky/i... — committed to atlasmap/atlasmap by igarashitm 3 years ago
- Update to husky@7.0.0 Summary: It [should fix](https://github.com/typicode/husky/issues/677#issuecomment-873395214) the issue where `yarn add` or `yarn remove` break `lint-staged`, which was occurrin... — committed to CommE2E/comm by Ashoat 3 years ago
- docs: update README.md — committed to typicode/husky by typicode 3 years ago
@tad3j , @bertdeblock thank you guys, now I see, I have reproduced the issue.
Steps to reproduce
pre-commit
hook in the root package.yarn remove <any dependency>
.Expected result The specified
pre-commit
hook is executed by husky prior to commit. Actual result The hook is not executed.Presumably, the same behaviour can be observed with other commands that trigger package reinstallation, like
yarn install <...>
.I will take a closer look at this issue later today.
Update: For the record,
.git/hooks/husky.local.sh
is updated as follows. Before:After:
+1, git hooks have been a terrible problem in yarn workspaces.
+1 for this issue’s priority, a team I’m on is running into this issue often as well. The workaround of only running
yarn
commands in a monorepo’s root is hard to engrain in devs’ workflow and things that get past some githooks take some extra coordination to fix again. For the time being, we’ll be using the patch in #728How about a flag to prevents husky from overriding the
cd "."
ingit/hooks/husky.local.sh
? something like:I thought I would add my two cents as I had a junior dev bypass the postinstall script suggestion @nickgieschen suggested using
--ignore-scripts
I created a
huskypostinstall.ts
at the top level of the monorepo containing:and then added it as the “postinstall” script in each repo:
"postinstall": "cross-env TS_NODE_COMPILER_OPTIONS={\\\"module\\\":\\\"commonjs\\\"} ts-node ../../huskypostinstall.ts"
Your mileage may vary with the above (we’re using TS & modules etc.) but the general principles are:
fs
to read from the hooks script file/cd.*$/gim
to replace the cd line withcd "."
The issue is not about removing Husky itself, but about removing another dependency from inside a package directory.
I’m also using the same setup (Yarn Workspaces + Lerna) and I’ve noticed the exact same issue.
@naorzr, although we have a pretty good understanding of why this is happening, fixing this behavior is not trivial. As far as I can tell, this behavior is due to the way the hooks were designed in husky in the first place. Fixing the issue requires a substantial change in the way hooks are managed by husky and the risks are high that fixing this issue might break other use cases. Making the situation worse, if hooks stop working, it might not be immediately apparent to the users because hooks tend to fail without notice. Given the wide adoption of husky and the limited attention that this issue has received, I believe that fixing this issue at the risk of breaking mainstream scenarios is not worthwhile.
To support this fix and make sure it doesn’t break anything we’ll need to extend our tests to cover many more use cases than we’ve got today for all supported package managers, which is quite a bit of work. I’ve started adding tests but I am not done yet. I have even considered releasing a separate package with the redesigned approach to hooks management, but it seems to be overkill to fork and maintain a new repository to only fix one issue.
I am using husky in most of my monorepos myself and though, as @fixpunkt has correctly pointed out, “being able to just run yarn install from any place in the monorepo” is a valid use case, I think the best workaround, for now, is to avoid running yarn install and similar commands from anywhere except the repository root.
@dcastil’s solution fails if the build from inside the package. E.g. Netlify does this for monorepos. A slight adjustment to get it to work is:
"postinstall": "if [[ -f ../../.git/hooks/husky.local.sh ]]; then sed -i '' -E 's/cd \".+\"/cd \".\"/' ../../.git/hooks/husky.local.sh; fi" }
My setup is almost identical (using Yarn workspaces only, no Lerna) and I’m getting the same. This is what my structure looks like:
I just did some testing and it’s only happening with the
yarn remove ...
command, and not withyarn add ...
.Changes the
husky.local.sh
from this (which works fine):to this (the hook stops running on commit):
@Ashoat we found that if you upgrade to husky v6 it fixed this
@JonKrone can you please merge #728. I added testing instructions.
I didn’t test it sufficiently, but it seems like husky saves the location from which the initial
yarn install
was run after husky was added by someone else in.git/hooks/husky.local.sh
. E.g. if the initialyarn install
was run inpackages/web-app
, it contains a line like this:which needs to be changed to
in order for husky to run properly.
My workaround for this is to add a postinstall script into the package.json of all workspaces:
Hey, just wanted to ping this thread to make sure it doesn’t get closed as stale. We’re experiencing this issue with Yarn Workspaces and would love to see it fixed.
I commented back on the patch PR https://github.com/typicode/husky/pull/728 - I think it is ready to merge.
There is a special node on using husky with monorepos: https://github.com/typicode/husky#monorepos In short for monorepos, it is recommended to only install husky into the root package. Otherwise, all sorts of conflicts are expected when husky installation script is run for several packages in the repo.
I use husky with lerna and yarn workspaces by installing husky to the root package via
yarn add --dev -W husky
. The-W
/--ignore-workspace-root-check
flag allows installation into the root package (https://classic.yarnpkg.com/en/docs/cli/add#toc-yarn-add-ignore-workspace-root-check-w). Personally, I haven’t seen any downsides of this approach so far.