Pre-commit hooks let you run checks before allowing a commit (e.g. JSLint or Test Coverage).
Think of pre-commit as an automatic checklist for your code. The checks prevent people from committing code that does not meet the required standards, saving everyone time. Imagine never having to read sloppy code again...!
Git Hooks are a a way to fire off custom scripts when certain important actions occur. e.g: commit, push, and merge. There are two groups of these hooks: client side and server side. The client-side hooks are for client operations such as committing and merging. The server-side hooks are for Git server operations such as automatically starting the build/test server or notifying team-mates of changes.
You can use these hooks for all sorts of reasons, but here we are going to focus on client-side pre-commit hooks (checks that are run before code is allowed to be committed).
- Code Consistency (Lint)
- Code Style (e.g. )
- All Unit Tests Pass
- Code Coverage standards met (100%)
- Performance tests / benchmarks met.
- Security Checks pass.
In node-land there are two popular modules we can use to run pre-commit checks:
- precommit-hook: https://www.npmjs.org/package/precommit-hook
- pre-commit: https://www.npmjs.org/package/pre-commit
Both are functionally equivalent so take your pick.
I'm covering pre-commit
because it has more concise documentation.
Install the node module and save it as a development dependency for your project:
npm install pre-commit --save-dev
Example package.json file:
{
"name": "learn-pre-commit",
"version": "1.0.0",
"description": "Node.js pre-commit tutorial",
"repository": {
"type": "git",
"url": "https://github.com/nelsonic/learn-pre-commit"
},
"devDependencies": {
"istanbul": "^0.3.2",
"pre-commit": "0.0.9",
"tape": "^3.0.1"
},
"scripts": {
"test": "tape ./test/*.js",
"coverage": "istanbul cover tape ./test/*.js && istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100",
"jshint": "jshint -c .jshintrc --exclude-path .gitignore .",
},
"pre-commit": [
"jshint",
"coverage"
]
}
The interesting bits here are:
a) scripts - a list of tasks that can be run.
Each script can be run by issuing the command:
npm run script-name
(e.g: npm run coverage
to check the test coverage).
b) pre-commit - an array of the scripts we want to run (in order) before we allow a commit. In this case jshint ensures our code is consistent according to the rules for the project and coverage ensures that our desired level of code/test coverage (100%) is met.
See /example for a Hello World example.
Try it in your own projects! If you have any questions, submit an issue on GitHub or tweet me @nelsonic
As Phoenix comes with Node.js as standard, we can take advantage of this and use the same method as above. The only difference is the script we use to run our tests/coverage:
...
"scripts": {
"coverage": "mix coveralls"
},
"pre-commit": [
"coverage"
]
}
While using pre-commit, we found this issue.
On installation pre-commit uses symlink to copy a pre-commit hook into your .git/hooks
folder. Symlink is useful as it allows you to repeatedly change your hook script without having to copy it into your private .git/
folder.
This script will then use the package.json to find other scripts to call. But this sometimes causes a problem as in some cases Windows' default security policy will only allow administrators to create symbolic links. Solution...
If you inspect the .git/hooks
folder you will find you can add/remove hooks easily.
Hooks can be written in most scripting languages so you can find some online to use or write your own with your favourite language.
Modify your hooks directly by copy and pasting manually or with a script. The latter is better as it enables all developers in a team to do so easily, but...
You will need to find a mechanism to make sure developers first install them and second keep them up to date.
An example of custom hooks written with node and a script to copy them into .git
folder can be found here.
Would it have been easier to just adjust the security policy? Probably, but it turns out writing git hooks is easy too! See below for more information on types of hooks.
- Gentle introduction to Git Hooks: https://githooks.com
- Way more than you will ever need to know about Git Hooks: https://git-scm.com/book/en/Customizing-Git-Git-Hooks (the official Git guide to Hooks)
- Addy Osmani on Code Style: https://addyosmani.com/blog/javascript-style-guides-and-beautifiers
- JavaScript Code Style checker (NPM) module: https://www.npmjs.org/package/jscs
- How do we define Code Quality? https://stackoverflow.com/questions/405243/how-do-we-define-code-quality (interesting discussion. mostly opinion - I want an objective measure!)
- Software Quality (in depth): https://en.wikipedia.org/wiki/Software_quality
- ISO/IEC 9126 Software engineering — Product quality: https://en.wikipedia.org/wiki/ISO/IEC_9126 (old but human-readable!)
- Full ISO/IEC 25010 Software Quality Standard (current): https://www.iso.org/obp/ui/#iso:std:iso-iec:25010:ed-1:v1:en (tldr)
If you don't want to write your own pre-commit hooks:
-
Ruby & Python - check out pre-commit.com (its multi-language).
-
Java - We haven't found a good tool (yet). Our Java Team are using sonar to run code quality checks. (Sadly, this is not pre-commit!)
If you find better pre-commit tools for any language, please inform me or send a PR!