There’s Lint in my CI
It is a common practice to run your linter in your CI test suite, to ensure that your code adheres to the lint before it is released. However, actually running the linter requires a manual step that often goes overlooked. What happens is that you push a commit, only to have CI tell you that your lint failed. Now, you have to go back and fix the lint errors, and then push it again.
Ideally, you can rebase the commit to avoid a bunch of “linting…” commit messages strewn throughout your code, but this means more work to clean up the Git history. Overall, this whole linting issue has been a long-time annoyance for me, but until recently, I had never thought about a better solution.
Git Hooks to the Rescue
A few months ago, as I was starting on my current project, I took a stab at solving this problem. I just want my code to stay linted, and to make sure that the linter is run before I push out any code in Git. I thought to myself, “If only there were hooks for Git…” Then I remembered that there are–and logically, they’re called Git hooks.
Git hooks are just scripts which Git will execute before or after various lifecycle events. For example, pre-commit, pre-rebase, post-checkout, pre-push, etc. In particular, the pre-push was the one that interested me. Before the
git push command succeeds, I want to check if I changed any applicable files. If I did, I want to run the linter and bail if the linter fails, preventing code from leaving my machine with failing lint.
Below is the simple Bash script to perform the lint check. Just place this in
.git/hooks/pre-push, and you’re all set!
#!/bin/bash set -e remote="$1" url="$2" z40=0000000000000000000000000000000000000000 while read local_ref local_sha remote_ref remote_sha do if [ "$local_sha" = $z40 ]; then # branch deleted : else if [ "$remote_sha" = $z40 ]; then jshint=1 scsslint=1 else range="$remote_sha..$local_sha" files=`git diff --name-only $range` [ -n "`echo $files | grep -E '\.js$|\.jsx|\.ts|\.tsx$'`" ] && jshint=1 [ -n "`echo $files | grep \.scss$`" ] && scsslint=1 # if you have other file types to lint, regex for them here fi if [[ $jshint -eq 1 ]]; then # run your lint script for js/ts here yarn lint-ts --target=production -c ./tslint-git-push.json fi if [[ $scsslint -eq 1 ]]; then yarn lint-css --target=production fi fi done exit 0
This is definitely a brute-force solution, but it does the trick pretty nicely. Nothing is worse than failing a build on CI, only to discover that it was because you used double quotes instead of single quotes.
I should also note that using an editor/IDE with lint support (ESLint, TSLint, RuboCop, etc.) is also an effective way to eliminate lint errors in the first place. However, even with proper IDE support, it’s still nice to know that Git has your back and will prevent you from pushing un-linted code to CI.
I hope you found this helpful, but I am also curious what tools you have used to help with this issue. I’d appreciate some feedback!