Prevent Bad Commits with husky
I've been contributing to the amazing A-Frame project, a library with allows you to create VR experiences using web technologies, and it's been a blast. The JavaScript code is very concise and uniform, making contribution a joy while keeping the code standards strict. Why is it so concise? The A-Frame project uses a combination of JSHint, which we're all familiar with, but another package I was unfamiliar with: husky. Husky builds precommit
and other git hooks to run commands within your package.json
before a commit is allowed.
package.json
You'll add husky
to the devDependencies
object within package.json
to gain access to the utility during npm install
. Within your scripts
object, you'll create a key, precommit
for instance, to run JSHint or any other routines you desire. Here's a reduced sample:
{ /* ... */ "scripts": { "lint": "semistandard -v | snazzy", "precommit": "npm run lint" }, /* ... */ "devDependencies": { /* ... */ "husky": "^0.10.1", "semistandard": "^7.0.2", "snazzy": "^3.0.0" } /* ... */ }
The Hook
A hook is generated that looks as follows (.git/hooks/pre-commit
as an example):
#!/bin/sh # husky PATH="/usr/local/lib/node_modules/npm/bin/node-gyp-bin:/Users/YOURUSER/Projects/aframe/node_modules/husky/node_modules/.bin:/Users/YOURUSER/Projects/aframe/node_modules/.bin:/usr/local/bin:/Users/YOURUSER/.rvm/gems/ruby-2.1.1/bin:/Users/YOURUSER/.rvm/gems/ruby-2.1.1@global/bin:/Users/YOURUSER/.rvm/rubies/ruby-2.1.1/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/YOURUSER/.rvm/bin" cd . [ -f package.json ] && cat package.json | grep -q '"precommit"\s*:' [ $? -ne 0 ] && exit 0 npm run precommit if [ $? -ne 0 ]; then echo echo "husky - pre-commit hook failed (add --no-verify to bypass)" echo exit 1 fi
The hook checks for a package.json
file, then checks to see if there's a scripts
key for the hook file it's in; if so, the scripts
key command is executed and only if it returns 0
allows the commit to be completed; if there are any lint errors, for example, the commit is not executed and you'll have to fix the nits presented by JSHint.
Using husky for JSHint is just an example usage; you can use husky to run any command you like, like spellchecking or security vulnerability checks, to ensure the commit meets your standards. I wish I knew about husky long ago -- it makes setting up hooks structured and easy!