Skip to content

Commit bad8802

Browse files
authored
Merge pull request #62 from lamartire/feat-multiple-configurations
feat: custom configuration
2 parents 1333537 + 7ae0943 commit bad8802

File tree

6 files changed

+97
-56
lines changed

6 files changed

+97
-56
lines changed

README.md

+48-51
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,42 @@
11
# simple-git-hooks
22

3-
4-
![](https://img.shields.io/badge/dependencies-zero-green) [![Tests](https://github.com/toplenboren/simple-git-hooks/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/toplenboren/simple-git-hooks/actions/workflows/tests.yml)
3+
![](https://img.shields.io/badge/dependencies-zero-green) [![Tests](https://github.com/toplenboren/simple-git-hooks/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/toplenboren/simple-git-hooks/actions/workflows/tests.yml)
54

65
A tool that lets you easily manage git hooks
76

8-
> The package was recently renamed from `simple-pre-commit`.
9-
7+
> The package was recently renamed from `simple-pre-commit`.
108
119
> See **Releases** for the `simple-pre-commit` documentation and changelog
1210
1311
- Zero dependency
1412
- Small configuration (1 object in package.json)
1513
- Lightweight:
1614

17-
| Package | Unpacked size | With deps |
18-
| ------------- | ------------- | ------------- |
19-
| husky v4 `4.3.8` | `53.5 kB` | `~1 mB` |
20-
| husky v6 `6.0.0` | `6.86 kB` | `6.86 kB` |
21-
| pre-commit `1.2.2` | `~80 kB` | `~850 kB` |
22-
| **simple-git-hooks** `2.2.0` | `10.1 kB` | `10.1 kB` |
15+
| Package | Unpacked size | With deps |
16+
| ---------------------------- | ------------- | --------- |
17+
| husky v4 `4.3.8` | `53.5 kB` | `~1 mB` |
18+
| husky v6 `6.0.0` | `6.86 kB` | `6.86 kB` |
19+
| pre-commit `1.2.2` | `~80 kB` | `~850 kB` |
20+
| **simple-git-hooks** `2.2.0` | `10.1 kB` | `10.1 kB` |
2321

2422
### Who uses simple-git-hooks?
2523

26-
> The package is recommended by [`lint-staged`](https://github.com/okonet/lint-staged)
24+
> The package is recommended by [`lint-staged`](https://github.com/okonet/lint-staged)
2725
28-
* [Autoprefixer](https://github.com/postcss/autoprefixer)
29-
* [PostCSS](https://github.com/postcss/postcss.org)
30-
* [Browserslist](https://github.com/browserslist/browserslist)
31-
* [Nano ID](https://github.com/ai/nanoid)
32-
* [Size Limit](https://github.com/ai/size-limit)
33-
* [Storeon](https://github.com/storeon/storeon)
34-
* [Directus](https://github.com/directus/directus)
35-
* [Vercel/pkg](https://github.com/vercel/pkg)
36-
* More, see [full list](https://github.com/toplenboren/simple-git-hooks/network/dependents?package_id=UGFja2FnZS0xOTk1ODMzMTA4)
26+
- [Autoprefixer](https://github.com/postcss/autoprefixer)
27+
- [PostCSS](https://github.com/postcss/postcss.org)
28+
- [Browserslist](https://github.com/browserslist/browserslist)
29+
- [Nano ID](https://github.com/ai/nanoid)
30+
- [Size Limit](https://github.com/ai/size-limit)
31+
- [Storeon](https://github.com/storeon/storeon)
32+
- [Directus](https://github.com/directus/directus)
33+
- [Vercel/pkg](https://github.com/vercel/pkg)
34+
- More, see [full list](https://github.com/toplenboren/simple-git-hooks/network/dependents?package_id=UGFja2FnZS0xOTk1ODMzMTA4)
3735

3836
### What is a git hook?
3937

4038
A git hook is a command or script that is going to be run every time you perform a git action, like `git commit` or `git push`.
41-
39+
4240
If the execution of a git hook fails, then the git action aborts.
4341

4442
For example, if you want to run `linter` on every commit to ensure code quality in your project, then you can create a `pre-commit` hook that would call `npx lint-staged`.
@@ -53,57 +51,56 @@ You can look up about git hooks on the [Pro Git book](https://git-scm.com/book/e
5351

5452
However, this package requires you to manually apply the changes to git hooks. If you update them often, this is probably not the best choice.
5553

56-
Also, this package allows you to set only one command per git hook.
54+
Also, this package allows you to set only one command per git hook.
5755

5856
If you need multiple verbose commands per git hook, flexible configuration or automatic update of git hooks, please check out the other packages:
59-
60-
* [Lefthook](https://github.com/Arkweid/lefthook)
61-
* [husky](https://github.com/typicode/husky)
62-
* [pre-commit](https://github.com/pre-commit/pre-commit)
6357

58+
- [Lefthook](https://github.com/Arkweid/lefthook)
59+
- [husky](https://github.com/typicode/husky)
60+
- [pre-commit](https://github.com/pre-commit/pre-commit)
6461

6562
## Usage
6663

6764
### Add simple-git-hooks to the project
6865

6966
1. Install simple-git-hooks as a dev dependency:
70-
67+
7168
```sh
7269
npm install simple-git-hooks --save-dev
7370
```
7471

7572
2. Add `simple-git-hooks` to your `package.json`. Fill it with git hooks and the corresponding commands.
7673

77-
For example:
74+
For example:
7875

79-
```jsonc
80-
{
81-
"simple-git-hooks": {
82-
"pre-commit": "npx lint-staged",
83-
"pre-push": "cd ../../ && npm run format",
76+
```jsonc
77+
{
78+
"simple-git-hooks": {
79+
"pre-commit": "npx lint-staged",
80+
"pre-push": "cd ../../ && npm run format",
8481

85-
// All unused hooks will be removed automatically by default
86-
// but you can use the `preserveUnused` option like following to prevent this behavior
82+
// All unused hooks will be removed automatically by default
83+
// but you can use the `preserveUnused` option like following to prevent this behavior
8784

88-
// if you'd prefer preserve all unused hooks
89-
"preserveUnused": true,
85+
// if you'd prefer preserve all unused hooks
86+
"preserveUnused": true,
9087

91-
// if you'd prefer preserve specific unused hooks
92-
"preserveUnused": ["commit-msg"]
93-
}
94-
}
95-
```
88+
// if you'd prefer preserve specific unused hooks
89+
"preserveUnused": ["commit-msg"]
90+
}
91+
}
92+
```
93+
94+
This configuration is going to run all linters on every `commit` and formatter on `push`.
9695

97-
This configuration is going to run all linters on every `commit` and formatter on `push`.
98-
9996
> There are more ways to configure the package. Check out [Additional configuration options](#additional-configuration-options).
100-
97+
10198
3. Run the CLI script to update the git hooks with the commands from the config:
10299

103100
```sh
104101
npx simple-git-hooks
105102
```
106-
103+
107104
Now all the git hooks are created.
108105

109106
### Update git hooks command
@@ -116,7 +113,6 @@ Note for **yarn2** users: Please run `yarn dlx simple-git-hooks` instead of the
116113

117114
Note that you should manually run `npx simple-git-hooks` **every time you change a command**.
118115

119-
120116
### Additional configuration options
121117

122118
You can also add a `.simple-git-hooks.cjs`, `.simple-git-hooks.js`, `simple-git-hooks.cjs`, `simple-git-hooks.js`, `.simple-git-hooks.json` or `simple-git-hooks.json` file to the project and write the configuration inside it.
@@ -128,8 +124,8 @@ This way `simple-git-hooks` configuration in `package.json` will not take effect
128124
```js
129125
module.exports = {
130126
"pre-commit": "npx lint-staged",
131-
"pre-push": "cd ../../ && npm run format"
132-
}
127+
"pre-push": "cd ../../ && npm run format",
128+
};
133129
```
134130

135131
`.simple-git-hooks.json` or `simple-git-hooks.json` should look like the following.
@@ -141,6 +137,8 @@ module.exports = {
141137
}
142138
```
143139

140+
If you need to have multiple configuration files or just your-own configuration file, you install hooks manually from it by `npx simple-git-hooks ./my-config.js`.
141+
144142
### Uninstall simple-git-hooks
145143

146144
> Uninstallation will remove all the existing git hooks.
@@ -149,14 +147,13 @@ module.exports = {
149147
npm uninstall simple-git-hooks
150148
```
151149

152-
153150
## Common issues
154151

155152
### When migrating from `husky` git hooks are not running
156153

157154
**Why is this happening?**
158155

159-
Husky might change the `core.gitHooks` value to `.husky`, this way, git hooks would search `.husky` directory instead of `.git/hooks/`.
156+
Husky might change the `core.gitHooks` value to `.husky`, this way, git hooks would search `.husky` directory instead of `.git/hooks/`.
160157

161158
Read more on git configuration in [Git book](https://git-scm.com/docs/githooks)
162159

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"pre-push": "exit 1",
3+
"pre-commit": "exit 1"
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "simple-pre-commit-test-package",
3+
"version": "1.0.0",
4+
"devDependencies": {
5+
"simple-git-hooks": "1.0.0"
6+
}
7+
}

cli.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
const {setHooksFromConfig} = require('./simple-git-hooks')
88

99
try {
10-
setHooksFromConfig()
10+
setHooksFromConfig(process.cwd(), process.argv)
1111
console.log('[INFO] Successfully set all git hooks')
1212
} catch (e) {
1313
console.log('[ERROR], Was not able to set git hooks. Error: ' + e)

simple-git-hooks.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const fs = require('fs')
2-
const path = require('path');
2+
const path = require('path')
33

44
const VALID_GIT_HOOKS = [
55
'applypatch-msg',
@@ -131,9 +131,11 @@ function checkSimpleGitHooksInDependencies(projectRootPath) {
131131
/**
132132
* Parses the config and sets git hooks
133133
* @param {string} projectRootPath
134+
* @param {string[]} [argv]
134135
*/
135-
function setHooksFromConfig(projectRootPath=process.cwd()) {
136-
const config = _getConfig(projectRootPath)
136+
function setHooksFromConfig(projectRootPath=process.cwd(), argv=process.argv) {
137+
const customConfigPath = _getCustomConfigPath(argv)
138+
const config = _getConfig(projectRootPath, customConfigPath)
137139

138140
if (!config) {
139141
throw('[ERROR] Config was not found! Please add `.simple-git-hooks.js` or `simple-git-hooks.js` or `.simple-git-hooks.json` or `simple-git-hooks.json` or `simple-git-hooks` entry in package.json.\r\nCheck README for details')
@@ -222,16 +224,31 @@ function _getPackageJson(projectPath = process.cwd()) {
222224
return { packageJsonContent: JSON.parse(packageJsonDataRaw), packageJsonPath: targetPackageJson }
223225
}
224226

227+
/**
228+
* Takes the first argument from current process argv and returns it
229+
* Returns empty string when argument wasn't passed
230+
* @param {string[]} [argv]
231+
* @returns {string}
232+
*/
233+
function _getCustomConfigPath(argv=[]) {
234+
const cmdIdx = argv.findIndex(val => val === 'simple-git-hooks')
235+
236+
if (cmdIdx === -1) return ''
237+
238+
return argv[cmdIdx + 1] || ''
239+
}
240+
225241
/**
226242
* Gets user-set command either from sources
227243
* First try to get command from .simple-pre-commit.json
228244
* If not found -> try to get command from package.json
229245
* @param {string} projectRootPath
246+
* @param {string} [configFileName]
230247
* @throws TypeError if projectRootPath is not string
231248
* @return {{string: string} | undefined}
232249
* @private
233250
*/
234-
function _getConfig(projectRootPath) {
251+
function _getConfig(projectRootPath, configFileName='') {
235252
if (typeof projectRootPath !== 'string') {
236253
throw TypeError("Check project root path! Expected a string, but got " + typeof projectRootPath)
237254
}
@@ -247,6 +264,11 @@ function _getConfig(projectRootPath) {
247264
() => _getConfigFromPackageJson(projectRootPath),
248265
]
249266

267+
// if user pass his-own config path prepend custom path before the default ones
268+
if (configFileName) {
269+
sources.unshift(() => _getConfigFromFile(projectRootPath, configFileName))
270+
}
271+
250272
for (let executeSource of sources) {
251273
let config = executeSource()
252274
if (config && _validateHooks(config)) {

simple-git-hooks.test.js

+11
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const projectWithConfigurationInAlternativeSeparateJsPath = path.normalize(path.
7777
const projectWithConfigurationInSeparateJsonPath = path.normalize(path.join(testsFolder, 'project_with_configuration_in_separate_json'))
7878
const projectWithConfigurationInAlternativeSeparateJsonPath = path.normalize(path.join(testsFolder, 'project_with_configuration_in_alternative_separate_json'))
7979
const projectWithUnusedConfigurationInPackageJsonPath = path.normalize(path.join(testsFolder, 'project_with_unused_configuration_in_package_json'))
80+
const projectWithCustomConfigurationFilePath = path.normalize(path.join(testsFolder, 'project_with_custom_configuration'))
8081

8182
// Incorrect configurations
8283

@@ -260,3 +261,13 @@ test('creates git hooks and removes unused but preserves specific git hooks', ()
260261

261262
removeGitHooksFolder(projectWithUnusedConfigurationInPackageJsonPath)
262263
})
264+
265+
test('creates git hooks and removes unused but preserves specific git hooks', () => {
266+
createGitHooksFolder(projectWithCustomConfigurationFilePath)
267+
268+
spc.setHooksFromConfig(projectWithCustomConfigurationFilePath, ['npx', 'simple-git-hooks', './git-hooks.js'])
269+
const installedHooks = getInstalledGitHooks(path.normalize(path.join(projectWithCustomConfigurationFilePath, '.git', 'hooks')))
270+
expect(JSON.stringify(installedHooks)).toBe(JSON.stringify({'pre-commit':`#!/bin/sh\nexit 1`, 'pre-push':`#!/bin/sh\nexit 1`}))
271+
272+
removeGitHooksFolder(projectWithCustomConfigurationFilePath)
273+
})

0 commit comments

Comments
 (0)