Skip to content

Commit

Permalink
feat(hook): Support setups with CWD below Git project root (#112)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ta2edchimp authored and Kent C. Dodds committed Jul 2, 2016
1 parent 3ea9139 commit 4786985
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 10 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ npm install ghooks --save-dev

_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`._

_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)._

## Setup

Add a `config.ghooks` entry in your `package.json` and simply specify which git hooks you want and their corresponding commands, like the following:
Expand Down
2 changes: 2 additions & 0 deletions lib/hook.template.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const fs = require('fs')
const resolve = require('path').resolve
const path = require('path')

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

exports.content = fs
.readFileSync(resolve(`${__dirname}/hook.template.raw`), 'UTF-8')
.replace('{{generated_message}}', exports.generatedMessage)
.replace('{{node_modules_path}}', path.join(process.cwd(), '..'))
14 changes: 12 additions & 2 deletions lib/hook.template.raw
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,28 @@

const fs = require('fs')
const path = require('path')
const nodeModulesPath = '{{node_modules_path}}'
const ghooks = getGhooksEntryPoint()

if (checkForGHooks(ghooks)) {
require(ghooks)(__dirname, __filename)
require(ghooks)(nodeModulesPath, __filename)
}

function getGhooksEntryPoint() {
try {
require('ghooks')
return 'ghooks'
} catch (e) {
return getGhooksAbsoluteEntryPoint()
}
}

function getGhooksAbsoluteEntryPoint() {
const worktree = getWorkTree()
if (worktree) {
return path.resolve(__dirname, '../', worktree, 'node_modules', 'ghooks')
}
return 'ghooks'
return path.resolve(nodeModulesPath, 'ghooks')
}

function checkForGHooks(ghooksPath) {
Expand Down
12 changes: 6 additions & 6 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ const resolve = require('path').resolve
const findup = require('findup')
const fs = require('fs')

module.exports = function run(dirname, filename, env) {
const command = commandFor(hook(dirname, filename))
module.exports = function run(nodeModulesPath, filename, env) {
const command = commandFor(nodeModulesPath, hook(filename))
if (command) {
runCommand(command, env)
}
}

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

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

function commandFor(hookName) {
const pkgFile = findup.sync(process.cwd(), 'package.json')
function commandFor(nodeModulesPath, hookName) {
const pkgFile = findup.sync(nodeModulesPath, 'package.json')
return commandFromPackage(resolve(pkgFile, 'package.json'), hookName)
}

Expand Down
22 changes: 20 additions & 2 deletions test/hook.template.raw.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('hook.template.raw', function describeHookTemplateRaw() {
it('delegates the hook execution to ghooks', () => {
const dirname = process.cwd() + '/lib'
const filename = dirname + '/hook.template.raw'
expect(this.ghooks).to.have.been.calledWith(dirname, filename)
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
})

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

})

describe('when ghooks is installed, but the node working dir is below the project dir', () => {

beforeEach(() => {
const path = require('path')
const ghooksEntryPoint = path.resolve(__dirname, '..', '{{node_modules_path}}', 'ghooks')
this.ghooks = sinon.stub()
proxyquire('../lib/hook.template.raw', {ghooks: null, [ghooksEntryPoint]: this.ghooks})
})

it('delegates the hook execution to ghooks', () => {
const dirname = process.cwd() + '/lib'
const filename = dirname + '/hook.template.raw'
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
})

})

describe('when ghooks is installed, using worktree / in a submodule', () => {

beforeEach(() => {
const path = require('path')
const worktree = '../../a/path/somewhere/else'
const ghooksResolved = path.resolve(process.cwd(), worktree, 'node_modules', 'ghooks')
const stub = {
ghooks: null,
fs: {
statSync: () => {
return {isFile: () => true}
Expand All @@ -47,7 +65,7 @@ describe('hook.template.raw', function describeHookTemplateRaw() {
it('delegates the hook execution to ghooks', () => {
const dirname = process.cwd() + '/lib'
const filename = dirname + '/hook.template.raw'
expect(this.ghooks).to.have.been.calledWith(dirname, filename)
expect(this.ghooks).to.have.been.calledWith('{{node_modules_path}}', filename)
})

})
Expand Down

0 comments on commit 4786985

Please sign in to comment.