setup pre-commit hook jshint

20,222

Solution 1

But is this possible...

Yes! This is possible. I recently wrote about it. Note that it's not specific to GitHub, just Git in general - as it's a pre-commit hook, it runs before any data is sent to GitHub.

Any appropriately-named executable files in the /.git/hooks directory of your repository will be run as hooks. There will likely be a bunch of example hooks in there already by default. Here's a simple shell script that I use as a JSLint pre-commit hook (you could modify it very easily to work with JSHint instead):

#!/bin/sh

files=$(git diff --cached --name-only --diff-filter=ACM | grep "\.js$")
if [ "$files" = "" ]; then 
    exit 0 
fi

pass=true

echo "\nValidating JavaScript:\n"

for file in ${files}; do
    result=$(jslint ${file} | grep "${file} is OK")
    if [ "$result" != "" ]; then
        echo "\t\033[32mJSLint Passed: ${file}\033[0m"
    else
        echo "\t\033[31mJSLint Failed: ${file}\033[0m"
        pass=false
    fi
done

echo "\nJavaScript validation complete\n"

if ! $pass; then
    echo "\033[41mCOMMIT FAILED:\033[0m Your commit contains files that should pass JSLint but do not. Please fix the JSLint errors and try again.\n"
    exit 1
else
    echo "\033[42mCOMMIT SUCCEEDED\033[0m\n"
fi

You can simply put that in an executable file named pre-commit in your Git hooks directory, and it will run before every commit.

Solution 2

There's an easier way of doing pre-commit checks (e.g. JSHint) in your Node.js workflow:

Install jshint from NPM:

npm install jshint

Next create a .jshintrc file in your project if you don't already have one. e.g: https://github.com/nelsonic/learn-jshint/blob/master/.jshintrc

Now install pre-commit module (and save it as a dev dependency):

npm install pre-commit --save-dev

Next you will need to define the task (script) that will be run for JSHint in your package.json

e.g:

{ "scripts": { "jshint": "jshint -c .jshintrc --exclude-path .gitignore ." } }

then you register the scripts you want to be run pre-commit (also in package.json) e.g:

"pre-commit": [ "jshint", "coverage", "etc" ]

This allows you to have more than just one check in your pre-commit workflow. (We have checks to ensure team members code complies with JSHint, Code Style and Test Coverage is 100%)

For a more detailed tutorial you can share with your team see: https://github.com/nelsonic/learn-pre-commit

Solution 3

Some changes to @James Allardice script to accommodate JSHint. Thanks for the original code.

#!/bin/sh
#
# Run JSHint validation before commit.

files=$(git diff --cached --name-only --diff-filter=ACMR -- *.js **/*.js)
pass=true


if [ "$files" != "" ]; then
    for file in ${files}; do
        result=$(jshint ${file})

        if [ "$result" != "" ]; then
            echo "$result"
            echo "\n"
            pass=false
        fi
    done
fi


if $pass; then
    exit 0
else
    echo ""
    echo "COMMIT FAILED:"
    echo "Some JavaScript files are invalid. Please fix errors and try committing again."
    exit 1
fi

Solution 4

A similar script to the @igor's one with some improvements:

  • color indicators
  • no --diff-filter, grep used insead
  • help message (git style) to avoid pre-commit call

#!/bin/sh
#
# Run JSHint validation before commit.

RED='\033[0;31m'
REDBOLD='\033[1;31m'
ORANGE='\033[0;33m'
NC='\033[0m' # No Color

files=$(git diff --cached --name-only | grep .js)
pass=true
totalErrors=0

if [ "$files" != "" ]; then
    for file in ${files}; do
        result=$(jshint ${file})
        if [ "$result" != "" ]; then
            echo "${RED}$result${NC}"
            pass=false
            totalErrors=$((totalErrors+1))
        fi
        echo ""
    done
fi

if $pass; then
    exit 0
else
    echo "${ORANGE}===== ${totalErrors} JSHint Error${NC}"
    echo ""
    echo "${REDBOLD}COMMIT FAILED: Some JavaScript files are invalid. Please fix errors and try committing again.${NC}"
    echo ""
    echo "  (use -n option \"git commit -n -m <message>\" to avoid call pre-commit hook and JSHint check)"
    echo ""
    exit 1
fi
Share:
20,222
Jeanluca Scaljeri
Author by

Jeanluca Scaljeri

Updated on September 02, 2020

Comments

  • Jeanluca Scaljeri
    Jeanluca Scaljeri over 3 years

    I recently started a project on github. I've managed to setup automatic testing after each commit using Travis. But now I would like to setup a pre-commit hook with jshint too. So if jshint reports errors, the commit should fail. But is this possible, and if so, how to do this ?

  • Jeanluca Scaljeri
    Jeanluca Scaljeri about 11 years
    thnx a lot!! However, I must be doing something wrong, because I can't get it to work. I've created the file inside .git/hooks and made it executable. Now when I commit a file with "too many errors" it simply commits it. Also, when I run the hook manually, I get trapped in the /bin/sh. Now when I type "exit" I get the "COMMIT FAILED" message. Any suggestions ?
  • Jeanluca Scaljeri
    Jeanluca Scaljeri about 11 years
    just one other thing. If I remove the /bin/sh, the hook works from the command line. But I can still commit :(
  • James Allardice
    James Allardice about 11 years
    @JeanlucaScaljeri - Have you modified it for JSHint? In it's current state the strings it looks for are specific to JSLint.
  • Jeanluca Scaljeri
    Jeanluca Scaljeri about 11 years
    I just noticed that even the pre-commit hooks in a 'git init' project didn't work. So I found out that a pre-commit hook should be named 'pre-commit' :) So it works great now. I modified jsLint to jsHint and the grep to: "egrep "errors?$". But what if I want multiple pre-commit hooks, is that possible ?
  • James Allardice
    James Allardice about 11 years
    Glad you got it working :) As far as I know you can't have multiple hooks unfortunately. The easiest way around that will be to simply combine them in one file.
  • Vincent
    Vincent over 10 years
    For those wondering what the final version for JSHint looks like: pastie.org/pastes/8392390/text
  • Alexander
    Alexander almost 9 years
    Note that there's mistake in grep. It should be "\.js$"
  • AlexeiBerkov
    AlexeiBerkov over 7 years
    Hi. Do you know how to set up the folder I wana scan ?
  • nelsonic
    nelsonic over 7 years
    @AlexeiBerkov are you asking about which folder you want jshint to scan? see: jshint.com/docs/cli
  • igor
    igor about 7 years
    Looks nice! :) This is *nix only though.
  • napstercake
    napstercake over 6 years
    @nelsonic Is pre-commit hook only works with a set of rules from jshint? can I use another linter?
  • nelsonic
    nelsonic over 6 years
    @RicardoGonzales you can use any command in pre-commit so yes, any other linter will work. :-)
  • napstercake
    napstercake over 6 years
    @nelsonic weird because my lint is not working, is just paused, stackoverflow.com/questions/47761550/pre-commit-hook-with-li‌​nt