Skip to content

Commit 4786985

Browse files
ta2edchimpKent C. Dodds
authored andcommitted
feat(hook): Support setups with CWD below Git project root (#112)
* add node_modules_path variable to template * surround template variable in quotes * testing * pass node_modules path instead of __dirname, change hook() to use regex * test(hook): Modify package name resolution to fit. * fix(hook): try to resolve simple `ghooks` first The former default way to resolve the package (default project setup: cwd === project dir), fixes own `npm install` after cloneing the repo. * test(hook): test default and cwd !== project dir setups * docs(readme): advise to not install globally Fixes #108
1 parent 3ea9139 commit 4786985

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ npm install ghooks --save-dev
2222

2323
_It is not advised to install `ghooks` as a production dependency, as it will install git hooks in your production environment as well. Please install it under the `devDependencies` section of your `package.json`._
2424

25+
_Please also note, that it is absolutely **not advised** to install `ghooks` globally. To work as expected, make it a development dependency of your project(s)._
26+
2527
## Setup
2628

2729
Add a `config.ghooks` entry in your `package.json` and simply specify which git hooks you want and their corresponding commands, like the following:

lib/hook.template.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const fs = require('fs')
22
const resolve = require('path').resolve
3+
const path = require('path')
34

45
exports.generatedMessage = 'Generated by ghooks. Do not edit this file.'
56

67
exports.content = fs
78
.readFileSync(resolve(`${__dirname}/hook.template.raw`), 'UTF-8')
89
.replace('{{generated_message}}', exports.generatedMessage)
10+
.replace('{{node_modules_path}}', path.join(process.cwd(), '..'))

lib/hook.template.raw

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,28 @@
33

44
const fs = require('fs')
55
const path = require('path')
6+
const nodeModulesPath = '{{node_modules_path}}'
67
const ghooks = getGhooksEntryPoint()
78

89
if (checkForGHooks(ghooks)) {
9-
require(ghooks)(__dirname, __filename)
10+
require(ghooks)(nodeModulesPath, __filename)
1011
}
1112

1213
function getGhooksEntryPoint() {
14+
try {
15+
require('ghooks')
16+
return 'ghooks'
17+
} catch (e) {
18+
return getGhooksAbsoluteEntryPoint()
19+
}
20+
}
21+
22+
function getGhooksAbsoluteEntryPoint() {
1323
const worktree = getWorkTree()
1424
if (worktree) {
1525
return path.resolve(__dirname, '../', worktree, 'node_modules', 'ghooks')
1626
}
17-
return 'ghooks'
27+
return path.resolve(nodeModulesPath, 'ghooks')
1828
}
1929

2030
function checkForGHooks(ghooksPath) {

lib/runner.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ const resolve = require('path').resolve
55
const findup = require('findup')
66
const fs = require('fs')
77

8-
module.exports = function run(dirname, filename, env) {
9-
const command = commandFor(hook(dirname, filename))
8+
module.exports = function run(nodeModulesPath, filename, env) {
9+
const command = commandFor(nodeModulesPath, hook(filename))
1010
if (command) {
1111
runCommand(command, env)
1212
}
1313
}
1414

15-
function hook(dirname, filename) {
16-
return filename.replace(dirname, '').substr(1)
15+
function hook(filename) {
16+
return filename.match(/\/([^\/]+)\/?$/)[1]
1717
}
1818

1919
// replace any instance of $1 or $2 etc. to that item as an process.argv
@@ -32,8 +32,8 @@ function commandFromPackage(packagePath, hookName) {
3232
}
3333
}
3434

35-
function commandFor(hookName) {
36-
const pkgFile = findup.sync(process.cwd(), 'package.json')
35+
function commandFor(nodeModulesPath, hookName) {
36+
const pkgFile = findup.sync(nodeModulesPath, 'package.json')
3737
return commandFromPackage(resolve(pkgFile, 'package.json'), hookName)
3838
}
3939

test/hook.template.raw.test.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ describe('hook.template.raw', function describeHookTemplateRaw() {
1212
it('delegates the hook execution to ghooks', () => {
1313
const dirname = process.cwd() + '/lib'
1414
const filename = dirname + '/hook.template.raw'
15-
expect(this.ghooks).to.have.been.calledWith(dirname, filename)
15+
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
1616
})
1717

1818
})
@@ -26,13 +26,31 @@ describe('hook.template.raw', function describeHookTemplateRaw() {
2626

2727
})
2828

29+
describe('when ghooks is installed, but the node working dir is below the project dir', () => {
30+
31+
beforeEach(() => {
32+
const path = require('path')
33+
const ghooksEntryPoint = path.resolve(__dirname, '..', '{{node_modules_path}}', 'ghooks')
34+
this.ghooks = sinon.stub()
35+
proxyquire('../lib/hook.template.raw', {ghooks: null, [ghooksEntryPoint]: this.ghooks})
36+
})
37+
38+
it('delegates the hook execution to ghooks', () => {
39+
const dirname = process.cwd() + '/lib'
40+
const filename = dirname + '/hook.template.raw'
41+
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
42+
})
43+
44+
})
45+
2946
describe('when ghooks is installed, using worktree / in a submodule', () => {
3047

3148
beforeEach(() => {
3249
const path = require('path')
3350
const worktree = '../../a/path/somewhere/else'
3451
const ghooksResolved = path.resolve(process.cwd(), worktree, 'node_modules', 'ghooks')
3552
const stub = {
53+
ghooks: null,
3654
fs: {
3755
statSync: () => {
3856
return {isFile: () => true}
@@ -47,7 +65,7 @@ describe('hook.template.raw', function describeHookTemplateRaw() {
4765
it('delegates the hook execution to ghooks', () => {
4866
const dirname = process.cwd() + '/lib'
4967
const filename = dirname + '/hook.template.raw'
50-
expect(this.ghooks).to.have.been.calledWith(dirname, filename)
68+
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
5169
})
5270

5371
})

0 commit comments

Comments
 (0)