Introduction
Who hasn't faced the problem of forgetting to run tests or adjust the code formatting before pushing it, encountering a pipeline failure that validates them? Or having to manually execute routines to follow project standard definition?
The idea of this article is to introduce two libraries that, when used together, allow configuring actions in the pre-commit stage, blocking a commit with failed tests, formatting the code before committing, or performing any other defined action.
Libs
- husky: It's the library that will allow running pre-commit actions.
- lint-staged: It's the library that will define the actions to be executed for files that are staged in git.
Libs setup
1- Husky
To add Husky to the application, it's necessary to run the following command:
yarn add --dev husky
To start the configuration, I suggest executing the following command:
npx husky init
It will generate a pre-commit
file inside the .husky
folder, which will define the execution of pre-commit actions. It will have the following content:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm test
Initially, by default, it's configured to run npm test, but with the addition of lint-staged, we'll update this file.
Also, a script to install Husky will be generated inside package.json
.
"scripts": {
(...)
"prepare": "husky install"
},
2 - lint-staged
To add lint-staged, it's necessary to run the following command:
yarn add --dev lint-staged
To configure the actions that will be executed pre-commit, add to package.json:
"lint-staged": {
"*.js": [
]
}
*.js
is the type of files added in stage where pre-commit actions will be executed (I used this type as an example, but it depends on the type defined in your application). Inside "[ ]" is where the actions to be executed in the pre-commit stage will be placed.
Finally, for the lint-staged usage from Husky, it will be necessary to update the pre-commit
file, resulting in the following:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no-install lint-staged
To start running Husky to perform pre-commit actions, it's necessary to install it by running: yarn prepare
.
Execution example
Now I will present an example of execution with two objectives: formatting the code before committing and validating if the tests are passing to allow the commit to be made.
For this example, it will be considered an app with a component inside App.js
and a test file App.test.js
, both inside the src
folder. App that uses the Jest
library to perform tests and prettier
for code formatting.
In the package.json, it's presented the following scripts:
"scripts": {
"test": "jest",
"format": "prettier --write \"**/src/*.js\"",
"prepare": "husky install"
}
The test
is responsible for running the tests, and format
for formatting the code.
To define what will be executed on pre-commit, define the commands to be executed inside lint-staged
in package.json
:
"lint-staged": {
"src/*.js": [
"yarn format",
"yarn test --findRelatedTests --bail"
]
}
This way, it's defined that for the files staged in git, execute yarn format
and yarn test --findRelatedTests --bail
pre-commit.
The --findRelatedTests
allows that when the App.js component is modified, it runs the associated tests (those presents in App.test.js), and the --bail
cancels the commit if any test fails. Those comands are for tests executed with Jest, depending of test lib can be other commands to not allow the commit.
Finally, to test the libraries, it's possible to change the App.js component, stage it with git add
, and then commit. Before the commit is made, the actions defined inside lint-staged
will be executed. In this example, the modified file will be formatted, and the associated tests will run. If any test fails, the commit will not be completed. If the tests pass, the commit will be completed.
Execution in the terminal:
In case you want to generate a commit without pre-commit actions, simply add --no-verify
at the end of the git commit command, and Husky will not be executed.
Conclusion
Finally, the idea of this article is to introduce two libraries that, together, enable performing pre-commit actions to prevent pipeline failures or allow running processes that are commonly used in the app, for files staged in git. This aims to streamline the development process.
Top comments (2)
why do we need prepare script, if husky will be installed on npm i command as dev dependency?
Hello, thanks for the comment.
To enable git hooks (pre-commit is one type) in the project, it is needed to run
husky install
. This is necessary to execute husky.For the first configuration (adding husky to the project), using
npx husky init
already install it. But other people that clones the project will need to execute thehusky install
to enable git hooks.Defining this command in
prepare
script, when another person clones the project and runnpm i
, automatically will run theprepare
script and allows the person to use husky, without the need to executehusky install
manually