skip to content
jgarivera.com

Run tests before pushing to remote repo using husky

/ 3 min read

Last Updated:

Foreword

I’ve been playing around with a neat tool called husky for my TypeScript repositories. It allows you to create Git hooks that you could subscribe to. I use it as part of my development tools.

I use husky, alongside commitlint, to lint commit messages so that they are guaranteed to adhere to the Conventional Commits standard. I’ve been discovering some interesting use cases for it like running the code linter on staged files using lint-staged.

I have recently come across an interesting article that demonstrates how to run tests before code is pushed to a remote repository. It used husky v0 so it still configured its hooks using JavaScript. Nevertheless, it makes use of a pre-push hook which is conceptually the same with the current version of husky today.

When the pre-push hook is triggered, husky executes a git diff HEAD --quiet && npm test command. The git diff command is used to check whether there are local uncommitted changes in the repository. It silently exits with an exit code of 1 if there are changes. Thus, the npm test command only runs when there are no local uncommitted changes.

Problem

When there are local uncommitted changes in the repository, husky throws an ambiguous error: failed to push some refs exception message. This can definitely baffle a developer. There should be a better way to directly convey the error message.

Solution

The solution can be to tinker with the bash scripts individually provided by husky. Edit the .husky/pre-push file, like so:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
if git diff HEAD --quiet; then
npm run test
else
echo "Cannot run pre-push tests due to local uncommitted changes"
exit 1
fi

In this bash script, the same git diff command is ran and returns an exit code of 0 (no difference) or 1 (with difference). If there are differences, the tests are ran. Otherwise, a friendly error message is presented and exits.

Closing Thoughts

Running tests before pushing to a remote repository is a cool idea indeed. It is worth noting that this approach is only feasible when your tests can be run locally and fast. If you are going to run a lot of tests that take a while, you should better delegate that task to your continuous integration (CI) pipeline instead.

Special thanks to Kacper Wdowik for writing the article that served as inspiration for this one. Cheers!

The discussion for this post can be found here as well.