I’m sure you’ve had that sinking feeling in your stomach. You know, the one that hits you after you realize you are unintentionally responsible for something catastrophic … like your site going down right after you’ve deployed to Production. We’ve all been there. We’re all human, and we all make mistakes. In spite of our human nature, there’s a simple way to prevent disaster: checklists. Checklists are a wonderfully simple antidote to our own imperfections.
A checklist eliminates ambiguity and is a great way to ensure that you don’t forget the important parts of a task. Airline pilots use checklists as a standard during every stage of the flight to ensure maximum safety. Doctors use them as reminder of simple, routine actions that can be forgotten in a stressful situation: a simple checklist during major surgeries was found to improve patient survival by nearly 40% in a worldwide study. Software Engineers can use checklists, too – we use Git pre-commit hooks programmatically for peace of mind, to improve our system reliability and bolster our confidence about production readiness of our code.
Pre-commits hooks are quite handy in Git version control:
- The hooks are just scripts that are fired off by Git before the actual commit is about to take place. “It’s used to inspect the snapshot that’s about to be committed…”
- Scripts can be in any language as long as it’s a) executable, and b) supported by the operating systems they are running on.
- The scripts reside under the ‘.git/hooks’ folder in your repository on the client side – meaning on your local machine only. The hooks are never part of the git commit history and as such are never under version control.
Not Under Version Control?
Really? Yes. As these git hooks only exist on your local machine, they are never under version control. Whoa. Naturally, this leads to some questions:
- How can we maintain these scripts?
- How do we ensure everyone in the team will use the same set of scripts every time they commit to the respective repositories?
Yelp to the Rescue
There are a few solutions for git pre-commit hooks that are out there for various languages, but in recent months, Yelp released the pre-commit project to the open source community and caught our attention.
A pre-commit by Yelp is “a framework for managing and maintaining multi-language pre-commit hooks”. We took a liking to it because it’s a framework, easy to setup, non-invasive, and easy to extend.
It’s a simple framework to build git hooks around and supports multiple languages out of the box.
As of the time of this writing, pre-commit by Yelp supports these languages:
- pcre – “Perl Compatible Regular Expression”
- script – An executable script existing inside of a repository
- system – Executables available at the system level
Open-Source Support for PHP
PHP is not supported (yet), so we open sourced our own pre-commit hooks specific for PHP development on Github that are built around Yelp’s pre-commit hook.
The repo provides the following pre-commit hooks:
- php-lint – runs php -l against stage files that are php. Exits on the first error it finds.
- php-lint-all – similar to the above but only exits after all files are linted and reports the errors on all if any are found.
- php-unit – runs the appropriate PHP Unit executable
- php-cs – runs the appropriate PHP Code Sniffer executable.
Read through the README at the repository for more information on its usage.
Easy to Setup
Once those requirements are met, you can then follow the easy installation instructions for different levels of usage.
Shareable and Easy-to-Maintain Consistency
The integration of the pre-commit framework into a repository is pretty minimal, and does not require ugly solutions like having a dedicated folder for the hook scripts.
In fact, the hooks themselves are stored in separate git repositories. Through a config yaml file, pre-commit will download these hooks in separate location from your repository. This makes it easy to both share your pre-commit hooks and to reuse ones that are already out there, such as some of the already pre-made hooks by Yelp or even ours.
To use it in your repository after you install it:
- Create a file called .pre-commit-config.yaml at the root of your repository. This file contains all the information that pre-commit will use to manage the hooks (visit the installation page for more information).
- Initialize the pre-commit by running pre-commit install at the root of your repository
That’s all you need to enable pre-commit on your current local repository.
Easy to Extend
The hooks of pre-commit by Yelp simple to make. In summary, all it needs you to do:
- create a new git repo
- add hooks.yaml to the root with the appropriate settings
- commit and push to your remote source
Here is one example that simply calls the PHP local executable to do a syntax check:
https://gist.github.com/mechastorm/07792d2eb818ef20ee0b.jsOn your repository where you want this hook to run, add an entry to your .pre-commit-config.yaml:https://gist.github.com/mechastorm/e1e4867e21987cd78342.js
The pre-commit team has even provided some pre-built hooks that you can use including hooks for linting (js, coffee, scss, python), yaml/json check and many more.
There have been some challenges in using Yelp’s pre-commit:
The lack of PHP support is a big drawback of us, as a large majority of our engineering team deals with PHP. Open sourcing a PHP pre-commit hook of our own making was our workaround.
Sparse Documentation on Extending
The minimal documentation available made things a little challenging, especially when doing hooks in bash. A lot of trial and error was required to figure out the arguments that pre-commit will pass to your script. Thankfully a recent documentation update eliminates this issue going forward.
When the right hooks are run in conjunction with an existing continuous integration system, having git pre-commit hooks is a great way to help alleviate the fear of bad code going into Production. One example is basic valid syntax check in our code – even with the help of IDEs, human error happens. Such checks help us avoid having a bad build and release scenario. Another is having unit tests run automatically before every commit to avoid having bad builds in the system.
We are currently using Yelp’s pre-commit framework on one engineering team. If this change proves beneficial, it will provide a good foundation on which to build our future pre-commit hooks across other teams.
Some helpful documentation:
- Installing Yelp’s pre-commit hook
- Adding it to your repository
- Creating new hooks
- List of supported hooks
To Luke Kysow for bringing this project to my attention, and to Chris McGuire, George Pajari, Noel Pullen, and Kimli Welsh for their support in helping me write this article.
About the Author
Shih Oon is an Operations Engineer at Hootsuite, as part of the Campaigns team. An anime mecha enthusiast who builds scale model robots, he also enjoys pushing the boundaries of web technology. Follow him on Twitter @mechastorm.